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