1 /*- 2 * Copyright (c) 2002-2003 3 * Hidetoshi Shimokawa. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * 16 * This product includes software developed by Hidetoshi Shimokawa. 17 * 18 * 4. Neither the name of the author nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/bus/firewire/fwcrom.c,v 1.10 2007/05/13 18:33:56 swildner Exp $ 35 */ 36 37 #ifndef __DragonFly__ 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.9 2003/10/02 04:06:55 simokawa Exp $"); 40 #endif 41 42 #include <sys/param.h> 43 #if defined(_KERNEL) || defined(TEST) 44 #include <sys/queue.h> 45 #endif 46 #ifdef _KERNEL 47 #include <sys/systm.h> 48 #include <sys/kernel.h> 49 #else 50 #include <netinet/in.h> 51 #include <fcntl.h> 52 #include <stdio.h> 53 #include <err.h> 54 #include <stdlib.h> 55 #include <string.h> 56 #define ksnprintf snprintf /* sigh. used by fwcontrol */ 57 #define kprintf printf 58 #endif 59 60 #ifdef __DragonFly__ 61 #include "firewire.h" 62 #include "iec13213.h" 63 #else 64 #include <dev/firewire/firewire.h> 65 #include <dev/firewire/iec13213.h> 66 #endif 67 68 #define MAX_ROM (1024 - sizeof(u_int32_t) * 5) 69 #define CROM_END(cc) ((vm_offset_t)(cc)->stack[0].dir + MAX_ROM - 1) 70 71 void 72 crom_init_context(struct crom_context *cc, u_int32_t *p) 73 { 74 struct csrhdr *hdr; 75 76 hdr = (struct csrhdr *)p; 77 if (hdr->info_len == 0) { 78 /* 79 * This isn't supposed to happen but it does. The problem 80 * is possibly related to fw_attach_dev()'s going from an 81 * FWDEVINIT to a FWDEVATTACHED state, or in a host<->host 82 * situation where one host gets the root directory for 83 * another before the other has actually initialized it. 84 */ 85 kprintf("crom_init_context: WARNING, info_len is 0\n"); 86 cc->depth = -1; 87 return; 88 } 89 if (hdr->info_len == 1) { 90 /* minimum ROM */ 91 cc->depth = -1; 92 } 93 p += 1 + hdr->info_len; 94 95 /* check size of root directory */ 96 if (((struct csrdirectory *)p)->crc_len == 0) { 97 cc->depth = -1; 98 return; 99 } 100 cc->depth = 0; 101 cc->stack[0].dir = (struct csrdirectory *)p; 102 cc->stack[0].index = 0; 103 } 104 105 struct csrreg * 106 crom_get(struct crom_context *cc) 107 { 108 struct crom_ptr *ptr; 109 110 ptr = &cc->stack[cc->depth]; 111 return (&ptr->dir->entry[ptr->index]); 112 } 113 114 void 115 crom_next(struct crom_context *cc) 116 { 117 struct crom_ptr *ptr; 118 struct csrreg *reg; 119 120 if (cc->depth < 0) 121 return; 122 reg = crom_get(cc); 123 if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { 124 if (cc->depth >= CROM_MAX_DEPTH) { 125 kprintf("crom_next: too deep\n"); 126 goto again; 127 } 128 cc->depth ++; 129 130 ptr = &cc->stack[cc->depth]; 131 ptr->dir = (struct csrdirectory *) (reg + reg->val); 132 ptr->index = 0; 133 goto check; 134 } 135 again: 136 ptr = &cc->stack[cc->depth]; 137 ptr->index ++; 138 check: 139 if (ptr->index < ptr->dir->crc_len && 140 (vm_offset_t)crom_get(cc) <= CROM_END(cc)) 141 return; 142 143 if (ptr->index < ptr->dir->crc_len) 144 kprintf("crom_next: bound check failed\n"); 145 146 if (cc->depth > 0) { 147 cc->depth--; 148 goto again; 149 } 150 /* no more data */ 151 cc->depth = -1; 152 } 153 154 155 struct csrreg * 156 crom_search_key(struct crom_context *cc, u_int8_t key) 157 { 158 struct csrreg *reg; 159 160 while(cc->depth >= 0) { 161 reg = crom_get(cc); 162 if (reg->key == key) 163 return reg; 164 crom_next(cc); 165 } 166 return NULL; 167 } 168 169 int 170 crom_has_specver(u_int32_t *p, u_int32_t spec, u_int32_t ver) 171 { 172 struct csrreg *reg; 173 struct crom_context c, *cc; 174 int state = 0; 175 176 cc = &c; 177 crom_init_context(cc, p); 178 while(cc->depth >= 0) { 179 reg = crom_get(cc); 180 if (state == 0) { 181 if (reg->key == CSRKEY_SPEC && reg->val == spec) 182 state = 1; 183 else 184 state = 0; 185 } else { 186 if (reg->key == CSRKEY_VER && reg->val == ver) 187 return 1; 188 else 189 state = 0; 190 } 191 crom_next(cc); 192 } 193 return 0; 194 } 195 196 void 197 crom_parse_text(struct crom_context *cc, char *buf, int len) 198 { 199 struct csrreg *reg; 200 struct csrtext *textleaf; 201 u_int32_t *bp; 202 int i, qlen; 203 static char *nullstr = "(null)"; 204 205 if (cc->depth < 0) 206 return; 207 208 reg = crom_get(cc); 209 if (reg->key != CROM_TEXTLEAF || 210 (vm_offset_t)(reg + reg->val) > CROM_END(cc)) { 211 strncpy(buf, nullstr, len); 212 return; 213 } 214 textleaf = (struct csrtext *)(reg + reg->val); 215 216 if ((vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc)) { 217 strncpy(buf, nullstr, len); 218 return; 219 } 220 221 /* XXX should check spec and type */ 222 223 bp = (u_int32_t *)&buf[0]; 224 qlen = textleaf->crc_len - 2; 225 if (len < qlen * 4) 226 qlen = len/4; 227 for (i = 0; i < qlen; i ++) 228 *bp++ = ntohl(textleaf->text[i]); 229 /* make sure to terminate the string */ 230 if (len <= qlen * 4) 231 buf[len - 1] = 0; 232 else 233 buf[qlen * 4] = 0; 234 } 235 236 u_int16_t 237 crom_crc(u_int32_t *ptr, int len) 238 { 239 int i, shift; 240 u_int32_t data, sum, crc = 0; 241 242 for (i = 0; i < len; i++) { 243 data = ptr[i]; 244 for (shift = 28; shift >= 0; shift -= 4) { 245 sum = ((crc >> 12) ^ (data >> shift)) & 0xf; 246 crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 247 } 248 crc &= 0xffff; 249 } 250 return((u_int16_t) crc); 251 } 252 253 #ifndef _KERNEL 254 static void 255 crom_desc_specver(u_int32_t spec, u_int32_t ver, char *buf, int len) 256 { 257 char *s = NULL; 258 259 if (spec == CSRVAL_ANSIT10 || spec == 0) { 260 switch (ver) { 261 case CSRVAL_T10SBP2: 262 s = "SBP-2"; 263 break; 264 default: 265 if (spec != 0) 266 s = "unknown ANSIT10"; 267 } 268 } 269 if (spec == CSRVAL_1394TA || spec == 0) { 270 switch (ver) { 271 case CSR_PROTAVC: 272 s = "AV/C"; 273 break; 274 case CSR_PROTCAL: 275 s = "CAL"; 276 break; 277 case CSR_PROTEHS: 278 s = "EHS"; 279 break; 280 case CSR_PROTHAVI: 281 s = "HAVi"; 282 break; 283 case CSR_PROTCAM104: 284 s = "1394 Cam 1.04"; 285 break; 286 case CSR_PROTCAM120: 287 s = "1394 Cam 1.20"; 288 break; 289 case CSR_PROTCAM130: 290 s = "1394 Cam 1.30"; 291 break; 292 case CSR_PROTDPP: 293 s = "1394 Direct print"; 294 break; 295 case CSR_PROTIICP: 296 s = "Industrial & Instrument"; 297 break; 298 default: 299 if (spec != 0) 300 s = "unknown 1394TA"; 301 } 302 } 303 if (s != NULL) 304 ksnprintf(buf, len, "%s", s); 305 } 306 307 char * 308 crom_desc(struct crom_context *cc, char *buf, int len) 309 { 310 struct csrreg *reg; 311 struct csrdirectory *dir; 312 char *desc, st; 313 u_int16_t crc; 314 315 reg = crom_get(cc); 316 switch (reg->key & CSRTYPE_MASK) { 317 case CSRTYPE_I: 318 #if 0 319 len -= ksnprintf(buf, len, "%d", reg->val); 320 buf += strlen(buf); 321 #else 322 *buf = '\0'; 323 #endif 324 break; 325 case CSRTYPE_C: 326 len -= ksnprintf(buf, len, "offset=0x%04x(%d)", 327 reg->val, reg->val); 328 buf += strlen(buf); 329 break; 330 case CSRTYPE_L: 331 /* XXX fall through */ 332 case CSRTYPE_D: 333 dir = (struct csrdirectory *) (reg + reg->val); 334 crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); 335 len -= ksnprintf(buf, len, "len=%d crc=0x%04x(%s) ", 336 dir->crc_len, dir->crc, 337 (crc == dir->crc) ? "OK" : "NG"); 338 buf += strlen(buf); 339 } 340 switch (reg->key) { 341 case 0x03: 342 desc = "module_vendor_ID"; 343 break; 344 case 0x04: 345 desc = "hardware_version"; 346 break; 347 case 0x0c: 348 desc = "node_capabilities"; 349 break; 350 case 0x12: 351 desc = "unit_spec_ID"; 352 break; 353 case 0x13: 354 desc = "unit_sw_version"; 355 crom_desc_specver(0, reg->val, buf, len); 356 break; 357 case 0x14: 358 desc = "logical_unit_number"; 359 break; 360 case 0x17: 361 desc = "model_ID"; 362 break; 363 case 0x38: 364 desc = "command_set_spec_ID"; 365 break; 366 case 0x39: 367 desc = "command_set"; 368 break; 369 case 0x3a: 370 desc = "unit_characteristics"; 371 break; 372 case 0x3b: 373 desc = "command_set_revision"; 374 break; 375 case 0x3c: 376 desc = "firmware_revision"; 377 break; 378 case 0x3d: 379 desc = "reconnect_timeout"; 380 break; 381 case 0x54: 382 desc = "management_agent"; 383 break; 384 case 0x81: 385 desc = "text_leaf"; 386 crom_parse_text(cc, buf + strlen(buf), len); 387 break; 388 case 0xd1: 389 desc = "unit_directory"; 390 break; 391 case 0xd4: 392 desc = "logical_unit_directory"; 393 break; 394 default: 395 desc = "unknown"; 396 } 397 return desc; 398 } 399 #endif 400 401 #if defined(_KERNEL) || defined(TEST) 402 403 int 404 crom_add_quad(struct crom_chunk *chunk, u_int32_t entry) 405 { 406 int index; 407 408 index = chunk->data.crc_len; 409 if (index >= CROM_MAX_CHUNK_LEN - 1) { 410 kprintf("too large chunk %d\n", index); 411 return(-1); 412 } 413 chunk->data.buf[index] = entry; 414 chunk->data.crc_len++; 415 return(index); 416 } 417 418 int 419 crom_add_entry(struct crom_chunk *chunk, int key, int val) 420 { 421 struct csrreg *reg; 422 u_int32_t i; 423 424 reg = (struct csrreg *)&i; 425 reg->key = key; 426 reg->val = val; 427 return(crom_add_quad(chunk, (u_int32_t) i)); 428 } 429 430 int 431 crom_add_chunk(struct crom_src *src, struct crom_chunk *parent, 432 struct crom_chunk *child, int key) 433 { 434 int index; 435 436 if (parent == NULL) { 437 STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 438 return(0); 439 } 440 441 index = crom_add_entry(parent, key, 0); 442 if (index < 0) { 443 return(-1); 444 } 445 child->ref_chunk = parent; 446 child->ref_index = index; 447 STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 448 return(index); 449 } 450 451 #define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext)) 452 int 453 crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent, 454 struct crom_chunk *chunk, char *buf) 455 { 456 struct csrtext *tl; 457 u_int32_t *p; 458 int len, i; 459 char t[MAX_TEXT]; 460 461 len = strlen(buf); 462 if (len > MAX_TEXT) { 463 #if defined(__DragonFly__) || __FreeBSD_version < 500000 464 kprintf("text(%d) truncated to %lu.\n", len, (u_long)MAX_TEXT); 465 #else 466 kprintf("text(%d) truncated to %td.\n", len, MAX_TEXT); 467 #endif 468 len = MAX_TEXT; 469 } 470 471 tl = (struct csrtext *) &chunk->data; 472 tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t)); 473 tl->spec_id = 0; 474 tl->spec_type = 0; 475 tl->lang_id = 0; 476 bzero(&t[0], roundup2(len, sizeof(u_int32_t))); 477 bcopy(buf, &t[0], len); 478 p = (u_int32_t *)&t[0]; 479 for (i = 0; i < howmany(len, sizeof(u_int32_t)); i ++) 480 tl->text[i] = ntohl(*p++); 481 return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF)); 482 } 483 484 static int 485 crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen) 486 { 487 if (*offset + len > maxlen) { 488 kprintf("Config. ROM is too large for the buffer\n"); 489 return(-1); 490 } 491 bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t)); 492 *offset += len; 493 return(0); 494 } 495 496 int 497 crom_load(struct crom_src *src, u_int32_t *buf, int maxlen) 498 { 499 struct crom_chunk *chunk, *parent; 500 struct csrhdr *hdr; 501 #ifdef _KERNEL 502 u_int32_t *ptr; 503 int i; 504 #endif 505 int count, offset; 506 int len; 507 508 offset = 0; 509 /* Determine offset */ 510 STAILQ_FOREACH(chunk, &src->chunk_list, link) { 511 chunk->offset = offset; 512 /* Assume the offset of the parent is already known */ 513 parent = chunk->ref_chunk; 514 if (parent != NULL) { 515 struct csrreg *reg; 516 reg = (struct csrreg *) 517 &parent->data.buf[chunk->ref_index]; 518 reg->val = offset - 519 (parent->offset + 1 + chunk->ref_index); 520 } 521 offset += 1 + chunk->data.crc_len; 522 } 523 524 /* Calculate CRC and dump to the buffer */ 525 len = 1 + src->hdr.info_len; 526 count = 0; 527 if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0) 528 return(-1); 529 STAILQ_FOREACH(chunk, &src->chunk_list, link) { 530 chunk->data.crc = 531 crom_crc(&chunk->data.buf[0], chunk->data.crc_len); 532 533 len = 1 + chunk->data.crc_len; 534 if (crom_copy((u_int32_t *)&chunk->data, buf, 535 &count, len, maxlen) < 0) 536 return(-1); 537 } 538 hdr = (struct csrhdr *)buf; 539 hdr->crc_len = count - 1; 540 hdr->crc = crom_crc(&buf[1], hdr->crc_len); 541 542 #ifdef _KERNEL 543 /* byte swap */ 544 ptr = buf; 545 for (i = 0; i < count; i ++) { 546 *ptr = htonl(*ptr); 547 ptr++; 548 } 549 #endif 550 551 return(count); 552 } 553 #endif 554 555 #ifdef TEST 556 int 557 main(int argc, char *argv[]) 558 { 559 struct crom_src src; 560 struct crom_chunk root,unit1,unit2,unit3; 561 struct crom_chunk text1,text2,text3,text4,text5,text6,text7; 562 u_int32_t buf[256], *p; 563 int i; 564 565 bzero(&src, sizeof(src)); 566 bzero(&root, sizeof(root)); 567 bzero(&unit1, sizeof(unit1)); 568 bzero(&unit2, sizeof(unit2)); 569 bzero(&unit3, sizeof(unit3)); 570 bzero(&text1, sizeof(text1)); 571 bzero(&text2, sizeof(text2)); 572 bzero(&text3, sizeof(text3)); 573 bzero(&text3, sizeof(text4)); 574 bzero(&text3, sizeof(text5)); 575 bzero(&text3, sizeof(text6)); 576 bzero(&text3, sizeof(text7)); 577 bzero(buf, sizeof(buf)); 578 579 /* BUS info sample */ 580 src.hdr.info_len = 4; 581 src.businfo.bus_name = CSR_BUS_NAME_IEEE1394; 582 src.businfo.eui64.hi = 0x11223344; 583 src.businfo.eui64.lo = 0x55667788; 584 src.businfo.link_spd = FWSPD_S400; 585 src.businfo.generation = 0; 586 src.businfo.max_rom = MAXROM_4; 587 src.businfo.max_rec = 10; 588 src.businfo.cyc_clk_acc = 100; 589 src.businfo.pmc = 0; 590 src.businfo.bmc = 1; 591 src.businfo.isc = 1; 592 src.businfo.cmc = 1; 593 src.businfo.irmc = 1; 594 STAILQ_INIT(&src.chunk_list); 595 596 /* Root directory */ 597 crom_add_chunk(&src, NULL, &root, 0); 598 crom_add_entry(&root, CSRKEY_NCAP, 0x123456); 599 /* private company_id */ 600 crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48); 601 602 #ifdef __DragonFly__ 603 crom_add_simple_text(&src, &root, &text1, "DragonFly"); 604 crom_add_entry(&root, CSRKEY_HW, __DragonFly_cc_version); 605 crom_add_simple_text(&src, &root, &text2, "DragonFly-1"); 606 #else 607 crom_add_simple_text(&src, &root, &text1, "FreeBSD"); 608 crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version); 609 crom_add_simple_text(&src, &root, &text2, "FreeBSD-5"); 610 #endif 611 612 /* SBP unit directory */ 613 crom_add_chunk(&src, &root, &unit1, CROM_UDIR); 614 crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10); 615 crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2); 616 crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); 617 crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI); 618 /* management_agent */ 619 crom_add_entry(&unit1, CROM_MGM, 0x1000); 620 crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8); 621 /* Device type and LUN */ 622 crom_add_entry(&unit1, CROM_LUN, 0); 623 crom_add_entry(&unit1, CSRKEY_MODEL, 1); 624 crom_add_simple_text(&src, &unit1, &text3, "scsi_target"); 625 626 /* RFC2734 IPv4 over IEEE1394 */ 627 crom_add_chunk(&src, &root, &unit2, CROM_UDIR); 628 crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF); 629 crom_add_simple_text(&src, &unit2, &text4, "IANA"); 630 crom_add_entry(&unit2, CSRKEY_VER, 1); 631 crom_add_simple_text(&src, &unit2, &text5, "IPv4"); 632 633 /* RFC3146 IPv6 over IEEE1394 */ 634 crom_add_chunk(&src, &root, &unit3, CROM_UDIR); 635 crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF); 636 crom_add_simple_text(&src, &unit3, &text6, "IANA"); 637 crom_add_entry(&unit3, CSRKEY_VER, 2); 638 crom_add_simple_text(&src, &unit3, &text7, "IPv6"); 639 640 crom_load(&src, buf, 256); 641 p = buf; 642 #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" 643 for (i = 0; i < 256/8; i ++) { 644 kprintf(DUMP_FORMAT, 645 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 646 p += 8; 647 } 648 return(0); 649 } 650 #endif 651