1aad970f1SDavid E. O'Brien /*- 277ee030bSHidetoshi Shimokawa * Copyright (c) 2002-2003 3b018dcd1SHidetoshi Shimokawa * Hidetoshi Shimokawa. All rights reserved. 4b018dcd1SHidetoshi Shimokawa * 5b018dcd1SHidetoshi Shimokawa * Redistribution and use in source and binary forms, with or without 6b018dcd1SHidetoshi Shimokawa * modification, are permitted provided that the following conditions 7b018dcd1SHidetoshi Shimokawa * are met: 8b018dcd1SHidetoshi Shimokawa * 1. Redistributions of source code must retain the above copyright 9b018dcd1SHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer. 10b018dcd1SHidetoshi Shimokawa * 2. Redistributions in binary form must reproduce the above copyright 11b018dcd1SHidetoshi Shimokawa * notice, this list of conditions and the following disclaimer in the 12b018dcd1SHidetoshi Shimokawa * documentation and/or other materials provided with the distribution. 13b018dcd1SHidetoshi Shimokawa * 3. All advertising materials mentioning features or use of this software 14b018dcd1SHidetoshi Shimokawa * must display the following acknowledgement: 15b018dcd1SHidetoshi Shimokawa * 16b018dcd1SHidetoshi Shimokawa * This product includes software developed by Hidetoshi Shimokawa. 17b018dcd1SHidetoshi Shimokawa * 18b018dcd1SHidetoshi Shimokawa * 4. Neither the name of the author nor the names of its contributors 19b018dcd1SHidetoshi Shimokawa * may be used to endorse or promote products derived from this software 20b018dcd1SHidetoshi Shimokawa * without specific prior written permission. 21b018dcd1SHidetoshi Shimokawa * 22b018dcd1SHidetoshi Shimokawa * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23b018dcd1SHidetoshi Shimokawa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24b018dcd1SHidetoshi Shimokawa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25b018dcd1SHidetoshi Shimokawa * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26b018dcd1SHidetoshi Shimokawa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27b018dcd1SHidetoshi Shimokawa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28b018dcd1SHidetoshi Shimokawa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29b018dcd1SHidetoshi Shimokawa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30b018dcd1SHidetoshi Shimokawa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31b018dcd1SHidetoshi Shimokawa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32b018dcd1SHidetoshi Shimokawa * SUCH DAMAGE. 33b018dcd1SHidetoshi Shimokawa */ 34b018dcd1SHidetoshi Shimokawa 35aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 36aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 37aad970f1SDavid E. O'Brien 38b018dcd1SHidetoshi Shimokawa #include <sys/param.h> 3977ee030bSHidetoshi Shimokawa #if defined(_KERNEL) || defined(TEST) 4077ee030bSHidetoshi Shimokawa #include <sys/queue.h> 4177ee030bSHidetoshi Shimokawa #endif 42b018dcd1SHidetoshi Shimokawa #ifdef _KERNEL 43b018dcd1SHidetoshi Shimokawa #include <sys/systm.h> 44b018dcd1SHidetoshi Shimokawa #include <sys/kernel.h> 45b018dcd1SHidetoshi Shimokawa #else 46b018dcd1SHidetoshi Shimokawa #include <netinet/in.h> 47b018dcd1SHidetoshi Shimokawa #include <fcntl.h> 48b018dcd1SHidetoshi Shimokawa #include <stdio.h> 49b018dcd1SHidetoshi Shimokawa #include <err.h> 50b018dcd1SHidetoshi Shimokawa #include <stdlib.h> 51b018dcd1SHidetoshi Shimokawa #include <string.h> 52b018dcd1SHidetoshi Shimokawa #endif 5377ee030bSHidetoshi Shimokawa #include <dev/firewire/firewire.h> 5477ee030bSHidetoshi Shimokawa #include <dev/firewire/iec13213.h> 55b018dcd1SHidetoshi Shimokawa 5688e7cb59SHidetoshi Shimokawa #define MAX_ROM (1024 - sizeof(u_int32_t) * 5) 5788e7cb59SHidetoshi Shimokawa #define CROM_END(cc) ((vm_offset_t)(cc)->stack[0].dir + MAX_ROM - 1) 5888e7cb59SHidetoshi Shimokawa 59b018dcd1SHidetoshi Shimokawa void 60b018dcd1SHidetoshi Shimokawa crom_init_context(struct crom_context *cc, u_int32_t *p) 61b018dcd1SHidetoshi Shimokawa { 62b018dcd1SHidetoshi Shimokawa struct csrhdr *hdr; 63b018dcd1SHidetoshi Shimokawa 64b018dcd1SHidetoshi Shimokawa hdr = (struct csrhdr *)p; 65b018dcd1SHidetoshi Shimokawa if (hdr->info_len == 1) { 66b018dcd1SHidetoshi Shimokawa /* minimum ROM */ 67b018dcd1SHidetoshi Shimokawa cc->depth = -1; 68b018dcd1SHidetoshi Shimokawa } 69b018dcd1SHidetoshi Shimokawa p += 1 + hdr->info_len; 705e286c32SHidetoshi Shimokawa 715e286c32SHidetoshi Shimokawa /* check size of root directory */ 725e286c32SHidetoshi Shimokawa if (((struct csrdirectory *)p)->crc_len == 0) { 735e286c32SHidetoshi Shimokawa cc->depth = -1; 745e286c32SHidetoshi Shimokawa return; 755e286c32SHidetoshi Shimokawa } 76b018dcd1SHidetoshi Shimokawa cc->depth = 0; 77b018dcd1SHidetoshi Shimokawa cc->stack[0].dir = (struct csrdirectory *)p; 78b018dcd1SHidetoshi Shimokawa cc->stack[0].index = 0; 79b018dcd1SHidetoshi Shimokawa } 80b018dcd1SHidetoshi Shimokawa 81b018dcd1SHidetoshi Shimokawa struct csrreg * 82b018dcd1SHidetoshi Shimokawa crom_get(struct crom_context *cc) 83b018dcd1SHidetoshi Shimokawa { 84b018dcd1SHidetoshi Shimokawa struct crom_ptr *ptr; 85b018dcd1SHidetoshi Shimokawa 86b018dcd1SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 87b018dcd1SHidetoshi Shimokawa return (&ptr->dir->entry[ptr->index]); 88b018dcd1SHidetoshi Shimokawa } 89b018dcd1SHidetoshi Shimokawa 90b018dcd1SHidetoshi Shimokawa void 91b018dcd1SHidetoshi Shimokawa crom_next(struct crom_context *cc) 92b018dcd1SHidetoshi Shimokawa { 93b018dcd1SHidetoshi Shimokawa struct crom_ptr *ptr; 94b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 95b018dcd1SHidetoshi Shimokawa 96b018dcd1SHidetoshi Shimokawa if (cc->depth < 0) 97b018dcd1SHidetoshi Shimokawa return; 98b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 99b018dcd1SHidetoshi Shimokawa if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { 10088e7cb59SHidetoshi Shimokawa if (cc->depth >= CROM_MAX_DEPTH) { 101b018dcd1SHidetoshi Shimokawa printf("crom_next: too deep\n"); 102b018dcd1SHidetoshi Shimokawa goto again; 103b018dcd1SHidetoshi Shimokawa } 10488e7cb59SHidetoshi Shimokawa cc->depth ++; 10588e7cb59SHidetoshi Shimokawa 1067ddbf617SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 1077ddbf617SHidetoshi Shimokawa ptr->dir = (struct csrdirectory *) (reg + reg->val); 1087ddbf617SHidetoshi Shimokawa ptr->index = 0; 1097ddbf617SHidetoshi Shimokawa goto check; 110b018dcd1SHidetoshi Shimokawa } 111b018dcd1SHidetoshi Shimokawa again: 112b018dcd1SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 113b018dcd1SHidetoshi Shimokawa ptr->index ++; 1147ddbf617SHidetoshi Shimokawa check: 11588e7cb59SHidetoshi Shimokawa if (ptr->index < ptr->dir->crc_len && 11688e7cb59SHidetoshi Shimokawa (vm_offset_t)crom_get(cc) <= CROM_END(cc)) 117b018dcd1SHidetoshi Shimokawa return; 11888e7cb59SHidetoshi Shimokawa 11988e7cb59SHidetoshi Shimokawa if (ptr->index < ptr->dir->crc_len) 12088e7cb59SHidetoshi Shimokawa printf("crom_next: bound check failed\n"); 12188e7cb59SHidetoshi Shimokawa 122b018dcd1SHidetoshi Shimokawa if (cc->depth > 0) { 123b018dcd1SHidetoshi Shimokawa cc->depth--; 124b018dcd1SHidetoshi Shimokawa goto again; 125b018dcd1SHidetoshi Shimokawa } 126b018dcd1SHidetoshi Shimokawa /* no more data */ 127b018dcd1SHidetoshi Shimokawa cc->depth = -1; 128b018dcd1SHidetoshi Shimokawa } 129b018dcd1SHidetoshi Shimokawa 130b018dcd1SHidetoshi Shimokawa 131b018dcd1SHidetoshi Shimokawa struct csrreg * 132b018dcd1SHidetoshi Shimokawa crom_search_key(struct crom_context *cc, u_int8_t key) 133b018dcd1SHidetoshi Shimokawa { 134b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 135b018dcd1SHidetoshi Shimokawa 136b018dcd1SHidetoshi Shimokawa while(cc->depth >= 0) { 137b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 138b018dcd1SHidetoshi Shimokawa if (reg->key == key) 139b018dcd1SHidetoshi Shimokawa return reg; 140b018dcd1SHidetoshi Shimokawa crom_next(cc); 141b018dcd1SHidetoshi Shimokawa } 142b018dcd1SHidetoshi Shimokawa return NULL; 143b018dcd1SHidetoshi Shimokawa } 144b018dcd1SHidetoshi Shimokawa 1455e286c32SHidetoshi Shimokawa int 1465e286c32SHidetoshi Shimokawa crom_has_specver(u_int32_t *p, u_int32_t spec, u_int32_t ver) 1475e286c32SHidetoshi Shimokawa { 1485e286c32SHidetoshi Shimokawa struct csrreg *reg; 1495e286c32SHidetoshi Shimokawa struct crom_context c, *cc; 1505e286c32SHidetoshi Shimokawa int state = 0; 1515e286c32SHidetoshi Shimokawa 1525e286c32SHidetoshi Shimokawa cc = &c; 1535e286c32SHidetoshi Shimokawa crom_init_context(cc, p); 1545e286c32SHidetoshi Shimokawa while(cc->depth >= 0) { 1555e286c32SHidetoshi Shimokawa reg = crom_get(cc); 1565e286c32SHidetoshi Shimokawa if (state == 0) { 1575e286c32SHidetoshi Shimokawa if (reg->key == CSRKEY_SPEC && reg->val == spec) 1585e286c32SHidetoshi Shimokawa state = 1; 1595e286c32SHidetoshi Shimokawa else 1605e286c32SHidetoshi Shimokawa state = 0; 1615e286c32SHidetoshi Shimokawa } else { 1625e286c32SHidetoshi Shimokawa if (reg->key == CSRKEY_VER && reg->val == ver) 1635e286c32SHidetoshi Shimokawa return 1; 1645e286c32SHidetoshi Shimokawa else 1655e286c32SHidetoshi Shimokawa state = 0; 1665e286c32SHidetoshi Shimokawa } 1675e286c32SHidetoshi Shimokawa crom_next(cc); 1685e286c32SHidetoshi Shimokawa } 1695e286c32SHidetoshi Shimokawa return 0; 1705e286c32SHidetoshi Shimokawa } 1715e286c32SHidetoshi Shimokawa 172b018dcd1SHidetoshi Shimokawa void 173b018dcd1SHidetoshi Shimokawa crom_parse_text(struct crom_context *cc, char *buf, int len) 174b018dcd1SHidetoshi Shimokawa { 175b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 176b018dcd1SHidetoshi Shimokawa struct csrtext *textleaf; 177b018dcd1SHidetoshi Shimokawa u_int32_t *bp; 178b018dcd1SHidetoshi Shimokawa int i, qlen; 179b018dcd1SHidetoshi Shimokawa static char *nullstr = "(null)"; 180b018dcd1SHidetoshi Shimokawa 1815e286c32SHidetoshi Shimokawa if (cc->depth < 0) 1825e286c32SHidetoshi Shimokawa return; 1835e286c32SHidetoshi Shimokawa 184b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 18588e7cb59SHidetoshi Shimokawa if (reg->key != CROM_TEXTLEAF || 18688e7cb59SHidetoshi Shimokawa (vm_offset_t)(reg + reg->val) > CROM_END(cc)) { 187b018dcd1SHidetoshi Shimokawa strncpy(buf, nullstr, len); 188b018dcd1SHidetoshi Shimokawa return; 189b018dcd1SHidetoshi Shimokawa } 190b018dcd1SHidetoshi Shimokawa textleaf = (struct csrtext *)(reg + reg->val); 191b018dcd1SHidetoshi Shimokawa 19288e7cb59SHidetoshi Shimokawa if ((vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc)) { 19388e7cb59SHidetoshi Shimokawa strncpy(buf, nullstr, len); 19488e7cb59SHidetoshi Shimokawa return; 19588e7cb59SHidetoshi Shimokawa } 19688e7cb59SHidetoshi Shimokawa 197b018dcd1SHidetoshi Shimokawa /* XXX should check spec and type */ 198b018dcd1SHidetoshi Shimokawa 199b018dcd1SHidetoshi Shimokawa bp = (u_int32_t *)&buf[0]; 200b018dcd1SHidetoshi Shimokawa qlen = textleaf->crc_len - 2; 201b018dcd1SHidetoshi Shimokawa if (len < qlen * 4) 202b018dcd1SHidetoshi Shimokawa qlen = len/4; 203b018dcd1SHidetoshi Shimokawa for (i = 0; i < qlen; i ++) 204b018dcd1SHidetoshi Shimokawa *bp++ = ntohl(textleaf->text[i]); 205b018dcd1SHidetoshi Shimokawa /* make sure to terminate the string */ 206b018dcd1SHidetoshi Shimokawa if (len <= qlen * 4) 207b018dcd1SHidetoshi Shimokawa buf[len - 1] = 0; 208b018dcd1SHidetoshi Shimokawa else 209b018dcd1SHidetoshi Shimokawa buf[qlen * 4] = 0; 210b018dcd1SHidetoshi Shimokawa } 211b018dcd1SHidetoshi Shimokawa 212b018dcd1SHidetoshi Shimokawa u_int16_t 213b018dcd1SHidetoshi Shimokawa crom_crc(u_int32_t *ptr, int len) 214b018dcd1SHidetoshi Shimokawa { 215b018dcd1SHidetoshi Shimokawa int i, shift; 216b018dcd1SHidetoshi Shimokawa u_int32_t data, sum, crc = 0; 217b018dcd1SHidetoshi Shimokawa 218b018dcd1SHidetoshi Shimokawa for (i = 0; i < len; i++) { 219b018dcd1SHidetoshi Shimokawa data = ptr[i]; 220b018dcd1SHidetoshi Shimokawa for (shift = 28; shift >= 0; shift -= 4) { 221b018dcd1SHidetoshi Shimokawa sum = ((crc >> 12) ^ (data >> shift)) & 0xf; 222b018dcd1SHidetoshi Shimokawa crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 223b018dcd1SHidetoshi Shimokawa } 224b018dcd1SHidetoshi Shimokawa crc &= 0xffff; 225b018dcd1SHidetoshi Shimokawa } 226b018dcd1SHidetoshi Shimokawa return((u_int16_t) crc); 227b018dcd1SHidetoshi Shimokawa } 228b018dcd1SHidetoshi Shimokawa 229b018dcd1SHidetoshi Shimokawa #ifndef _KERNEL 2305e286c32SHidetoshi Shimokawa static void 2315e286c32SHidetoshi Shimokawa crom_desc_specver(u_int32_t spec, u_int32_t ver, char *buf, int len) 2325e286c32SHidetoshi Shimokawa { 2335e286c32SHidetoshi Shimokawa char *s = NULL; 2345e286c32SHidetoshi Shimokawa 2355e286c32SHidetoshi Shimokawa if (spec == CSRVAL_ANSIT10 || spec == 0) { 2365e286c32SHidetoshi Shimokawa switch (ver) { 2375e286c32SHidetoshi Shimokawa case CSRVAL_T10SBP2: 2385e286c32SHidetoshi Shimokawa s = "SBP-2"; 2395e286c32SHidetoshi Shimokawa break; 2405e286c32SHidetoshi Shimokawa default: 2415e286c32SHidetoshi Shimokawa if (spec != 0) 2425e286c32SHidetoshi Shimokawa s = "unknown ANSIT10"; 2435e286c32SHidetoshi Shimokawa } 2445e286c32SHidetoshi Shimokawa } 2455e286c32SHidetoshi Shimokawa if (spec == CSRVAL_1394TA || spec == 0) { 2465e286c32SHidetoshi Shimokawa switch (ver) { 2475e286c32SHidetoshi Shimokawa case CSR_PROTAVC: 2485e286c32SHidetoshi Shimokawa s = "AV/C"; 2495e286c32SHidetoshi Shimokawa break; 2505e286c32SHidetoshi Shimokawa case CSR_PROTCAL: 2515e286c32SHidetoshi Shimokawa s = "CAL"; 2525e286c32SHidetoshi Shimokawa break; 2535e286c32SHidetoshi Shimokawa case CSR_PROTEHS: 2545e286c32SHidetoshi Shimokawa s = "EHS"; 2555e286c32SHidetoshi Shimokawa break; 2565e286c32SHidetoshi Shimokawa case CSR_PROTHAVI: 2575e286c32SHidetoshi Shimokawa s = "HAVi"; 2585e286c32SHidetoshi Shimokawa break; 2595e286c32SHidetoshi Shimokawa case CSR_PROTCAM104: 2605e286c32SHidetoshi Shimokawa s = "1394 Cam 1.04"; 2615e286c32SHidetoshi Shimokawa break; 2625e286c32SHidetoshi Shimokawa case CSR_PROTCAM120: 2635e286c32SHidetoshi Shimokawa s = "1394 Cam 1.20"; 2645e286c32SHidetoshi Shimokawa break; 2655e286c32SHidetoshi Shimokawa case CSR_PROTCAM130: 2665e286c32SHidetoshi Shimokawa s = "1394 Cam 1.30"; 2675e286c32SHidetoshi Shimokawa break; 2685e286c32SHidetoshi Shimokawa case CSR_PROTDPP: 2695e286c32SHidetoshi Shimokawa s = "1394 Direct print"; 2705e286c32SHidetoshi Shimokawa break; 2715e286c32SHidetoshi Shimokawa case CSR_PROTIICP: 2725e286c32SHidetoshi Shimokawa s = "Industrial & Instrument"; 2735e286c32SHidetoshi Shimokawa break; 2745e286c32SHidetoshi Shimokawa default: 2755e286c32SHidetoshi Shimokawa if (spec != 0) 2765e286c32SHidetoshi Shimokawa s = "unknown 1394TA"; 2775e286c32SHidetoshi Shimokawa } 2785e286c32SHidetoshi Shimokawa } 2795e286c32SHidetoshi Shimokawa if (s != NULL) 2805e286c32SHidetoshi Shimokawa snprintf(buf, len, "%s", s); 2815e286c32SHidetoshi Shimokawa } 2825e286c32SHidetoshi Shimokawa 283b018dcd1SHidetoshi Shimokawa char * 284b018dcd1SHidetoshi Shimokawa crom_desc(struct crom_context *cc, char *buf, int len) 285b018dcd1SHidetoshi Shimokawa { 286b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 287b018dcd1SHidetoshi Shimokawa struct csrdirectory *dir; 2885e286c32SHidetoshi Shimokawa char *desc, st; 28977ee030bSHidetoshi Shimokawa u_int16_t crc; 290b018dcd1SHidetoshi Shimokawa 291b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 292b018dcd1SHidetoshi Shimokawa switch (reg->key & CSRTYPE_MASK) { 293b018dcd1SHidetoshi Shimokawa case CSRTYPE_I: 2945e286c32SHidetoshi Shimokawa #if 0 2955e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "%d", reg->val); 2965e286c32SHidetoshi Shimokawa buf += strlen(buf); 2975e286c32SHidetoshi Shimokawa #else 2985e286c32SHidetoshi Shimokawa *buf = '\0'; 2995e286c32SHidetoshi Shimokawa #endif 300b018dcd1SHidetoshi Shimokawa break; 301b018dcd1SHidetoshi Shimokawa case CSRTYPE_C: 3025e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "offset=0x%04x(%d)", 3035e286c32SHidetoshi Shimokawa reg->val, reg->val); 3045e286c32SHidetoshi Shimokawa buf += strlen(buf); 305b018dcd1SHidetoshi Shimokawa break; 30677ee030bSHidetoshi Shimokawa case CSRTYPE_L: 30777ee030bSHidetoshi Shimokawa /* XXX fall through */ 308b018dcd1SHidetoshi Shimokawa case CSRTYPE_D: 309b018dcd1SHidetoshi Shimokawa dir = (struct csrdirectory *) (reg + reg->val); 31077ee030bSHidetoshi Shimokawa crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); 3115e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "len=%d crc=0x%04x(%s) ", 3125e286c32SHidetoshi Shimokawa dir->crc_len, dir->crc, 3135e286c32SHidetoshi Shimokawa (crc == dir->crc) ? "OK" : "NG"); 3145e286c32SHidetoshi Shimokawa buf += strlen(buf); 315b018dcd1SHidetoshi Shimokawa } 316b018dcd1SHidetoshi Shimokawa switch (reg->key) { 317b018dcd1SHidetoshi Shimokawa case 0x03: 318b018dcd1SHidetoshi Shimokawa desc = "module_vendor_ID"; 319b018dcd1SHidetoshi Shimokawa break; 320b018dcd1SHidetoshi Shimokawa case 0x04: 321b018dcd1SHidetoshi Shimokawa desc = "hardware_version"; 322b018dcd1SHidetoshi Shimokawa break; 323b018dcd1SHidetoshi Shimokawa case 0x0c: 324b018dcd1SHidetoshi Shimokawa desc = "node_capabilities"; 325b018dcd1SHidetoshi Shimokawa break; 326b018dcd1SHidetoshi Shimokawa case 0x12: 327b018dcd1SHidetoshi Shimokawa desc = "unit_spec_ID"; 328b018dcd1SHidetoshi Shimokawa break; 329b018dcd1SHidetoshi Shimokawa case 0x13: 330b018dcd1SHidetoshi Shimokawa desc = "unit_sw_version"; 3315e286c32SHidetoshi Shimokawa crom_desc_specver(0, reg->val, buf, len); 332b018dcd1SHidetoshi Shimokawa break; 333b018dcd1SHidetoshi Shimokawa case 0x14: 334b018dcd1SHidetoshi Shimokawa desc = "logical_unit_number"; 335b018dcd1SHidetoshi Shimokawa break; 336b018dcd1SHidetoshi Shimokawa case 0x17: 337b018dcd1SHidetoshi Shimokawa desc = "model_ID"; 338b018dcd1SHidetoshi Shimokawa break; 339b018dcd1SHidetoshi Shimokawa case 0x38: 340b018dcd1SHidetoshi Shimokawa desc = "command_set_spec_ID"; 341b018dcd1SHidetoshi Shimokawa break; 342b018dcd1SHidetoshi Shimokawa case 0x39: 343b018dcd1SHidetoshi Shimokawa desc = "command_set"; 344b018dcd1SHidetoshi Shimokawa break; 345b018dcd1SHidetoshi Shimokawa case 0x3a: 346b018dcd1SHidetoshi Shimokawa desc = "unit_characteristics"; 347b018dcd1SHidetoshi Shimokawa break; 348b018dcd1SHidetoshi Shimokawa case 0x3b: 349b018dcd1SHidetoshi Shimokawa desc = "command_set_revision"; 350b018dcd1SHidetoshi Shimokawa break; 351b018dcd1SHidetoshi Shimokawa case 0x3c: 352b018dcd1SHidetoshi Shimokawa desc = "firmware_revision"; 353b018dcd1SHidetoshi Shimokawa break; 354b018dcd1SHidetoshi Shimokawa case 0x3d: 355b018dcd1SHidetoshi Shimokawa desc = "reconnect_timeout"; 356b018dcd1SHidetoshi Shimokawa break; 357b018dcd1SHidetoshi Shimokawa case 0x54: 358b018dcd1SHidetoshi Shimokawa desc = "management_agent"; 359b018dcd1SHidetoshi Shimokawa break; 360b018dcd1SHidetoshi Shimokawa case 0x81: 361b018dcd1SHidetoshi Shimokawa desc = "text_leaf"; 36277ee030bSHidetoshi Shimokawa crom_parse_text(cc, buf + strlen(buf), len); 363b018dcd1SHidetoshi Shimokawa break; 364b018dcd1SHidetoshi Shimokawa case 0xd1: 365b018dcd1SHidetoshi Shimokawa desc = "unit_directory"; 366b018dcd1SHidetoshi Shimokawa break; 367b018dcd1SHidetoshi Shimokawa case 0xd4: 368b018dcd1SHidetoshi Shimokawa desc = "logical_unit_directory"; 369b018dcd1SHidetoshi Shimokawa break; 370b018dcd1SHidetoshi Shimokawa default: 371b018dcd1SHidetoshi Shimokawa desc = "unknown"; 372b018dcd1SHidetoshi Shimokawa } 373b018dcd1SHidetoshi Shimokawa return desc; 374b018dcd1SHidetoshi Shimokawa } 375b018dcd1SHidetoshi Shimokawa #endif 37677ee030bSHidetoshi Shimokawa 37777ee030bSHidetoshi Shimokawa #if defined(_KERNEL) || defined(TEST) 37877ee030bSHidetoshi Shimokawa 37977ee030bSHidetoshi Shimokawa int 38077ee030bSHidetoshi Shimokawa crom_add_quad(struct crom_chunk *chunk, u_int32_t entry) 38177ee030bSHidetoshi Shimokawa { 38277ee030bSHidetoshi Shimokawa int index; 38377ee030bSHidetoshi Shimokawa 38477ee030bSHidetoshi Shimokawa index = chunk->data.crc_len; 38577ee030bSHidetoshi Shimokawa if (index >= CROM_MAX_CHUNK_LEN - 1) { 38677ee030bSHidetoshi Shimokawa printf("too large chunk %d\n", index); 38777ee030bSHidetoshi Shimokawa return(-1); 38877ee030bSHidetoshi Shimokawa } 38977ee030bSHidetoshi Shimokawa chunk->data.buf[index] = entry; 39077ee030bSHidetoshi Shimokawa chunk->data.crc_len++; 39177ee030bSHidetoshi Shimokawa return(index); 39277ee030bSHidetoshi Shimokawa } 39377ee030bSHidetoshi Shimokawa 39477ee030bSHidetoshi Shimokawa int 39577ee030bSHidetoshi Shimokawa crom_add_entry(struct crom_chunk *chunk, int key, int val) 39677ee030bSHidetoshi Shimokawa { 39777ee030bSHidetoshi Shimokawa struct csrreg *reg; 39877ee030bSHidetoshi Shimokawa u_int32_t i; 39977ee030bSHidetoshi Shimokawa 40077ee030bSHidetoshi Shimokawa reg = (struct csrreg *)&i; 40177ee030bSHidetoshi Shimokawa reg->key = key; 40277ee030bSHidetoshi Shimokawa reg->val = val; 40377ee030bSHidetoshi Shimokawa return(crom_add_quad(chunk, (u_int32_t) i)); 40477ee030bSHidetoshi Shimokawa } 40577ee030bSHidetoshi Shimokawa 40677ee030bSHidetoshi Shimokawa int 40777ee030bSHidetoshi Shimokawa crom_add_chunk(struct crom_src *src, struct crom_chunk *parent, 40877ee030bSHidetoshi Shimokawa struct crom_chunk *child, int key) 40977ee030bSHidetoshi Shimokawa { 41077ee030bSHidetoshi Shimokawa int index; 41177ee030bSHidetoshi Shimokawa 41277ee030bSHidetoshi Shimokawa if (parent == NULL) { 41377ee030bSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 41477ee030bSHidetoshi Shimokawa return(0); 41577ee030bSHidetoshi Shimokawa } 41677ee030bSHidetoshi Shimokawa 41777ee030bSHidetoshi Shimokawa index = crom_add_entry(parent, key, 0); 41877ee030bSHidetoshi Shimokawa if (index < 0) { 41977ee030bSHidetoshi Shimokawa return(-1); 42077ee030bSHidetoshi Shimokawa } 42177ee030bSHidetoshi Shimokawa child->ref_chunk = parent; 42277ee030bSHidetoshi Shimokawa child->ref_index = index; 42377ee030bSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 42477ee030bSHidetoshi Shimokawa return(index); 42577ee030bSHidetoshi Shimokawa } 42677ee030bSHidetoshi Shimokawa 42777ee030bSHidetoshi Shimokawa int 42877ee030bSHidetoshi Shimokawa crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent, 42977ee030bSHidetoshi Shimokawa struct crom_chunk *chunk, char *buf) 43077ee030bSHidetoshi Shimokawa { 43177ee030bSHidetoshi Shimokawa struct csrtext *tl; 43277ee030bSHidetoshi Shimokawa u_int32_t *p; 43377ee030bSHidetoshi Shimokawa int len, i; 43477ee030bSHidetoshi Shimokawa 43577ee030bSHidetoshi Shimokawa len = strlen(buf); 43677ee030bSHidetoshi Shimokawa #define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext)) 43777ee030bSHidetoshi Shimokawa if (len > MAX_TEXT) { 43877ee030bSHidetoshi Shimokawa #if __FreeBSD_version < 500000 43977ee030bSHidetoshi Shimokawa printf("text(%d) trancated to %d.\n", len, MAX_TEXT); 44077ee030bSHidetoshi Shimokawa #else 44177ee030bSHidetoshi Shimokawa printf("text(%d) trancated to %td.\n", len, MAX_TEXT); 44277ee030bSHidetoshi Shimokawa #endif 44377ee030bSHidetoshi Shimokawa len = MAX_TEXT; 44477ee030bSHidetoshi Shimokawa } 44577ee030bSHidetoshi Shimokawa 44677ee030bSHidetoshi Shimokawa tl = (struct csrtext *) &chunk->data; 44777ee030bSHidetoshi Shimokawa tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t)); 44877ee030bSHidetoshi Shimokawa tl->spec_id = 0; 44977ee030bSHidetoshi Shimokawa tl->spec_type = 0; 45077ee030bSHidetoshi Shimokawa tl->lang_id = 0; 45177ee030bSHidetoshi Shimokawa p = (u_int32_t *) buf; 452b83977f0SHidetoshi Shimokawa for (i = 0; i < howmany(len, sizeof(u_int32_t)); i ++) 45377ee030bSHidetoshi Shimokawa tl->text[i] = ntohl(*p++); 45477ee030bSHidetoshi Shimokawa return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF)); 45577ee030bSHidetoshi Shimokawa } 45677ee030bSHidetoshi Shimokawa 45777ee030bSHidetoshi Shimokawa static int 45877ee030bSHidetoshi Shimokawa crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen) 45977ee030bSHidetoshi Shimokawa { 46077ee030bSHidetoshi Shimokawa if (*offset + len > maxlen) { 46177ee030bSHidetoshi Shimokawa printf("Config. ROM is too large for the buffer\n"); 46277ee030bSHidetoshi Shimokawa return(-1); 46377ee030bSHidetoshi Shimokawa } 46477ee030bSHidetoshi Shimokawa bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t)); 46577ee030bSHidetoshi Shimokawa *offset += len; 46677ee030bSHidetoshi Shimokawa return(0); 46777ee030bSHidetoshi Shimokawa } 46877ee030bSHidetoshi Shimokawa 46977ee030bSHidetoshi Shimokawa int 47077ee030bSHidetoshi Shimokawa crom_load(struct crom_src *src, u_int32_t *buf, int maxlen) 47177ee030bSHidetoshi Shimokawa { 47277ee030bSHidetoshi Shimokawa struct crom_chunk *chunk, *parent; 47377ee030bSHidetoshi Shimokawa struct csrhdr *hdr; 474b83977f0SHidetoshi Shimokawa #ifdef _KERNEL 47577ee030bSHidetoshi Shimokawa u_int32_t *ptr; 476b83977f0SHidetoshi Shimokawa int i; 47777ee030bSHidetoshi Shimokawa #endif 47877ee030bSHidetoshi Shimokawa int count, offset; 47977ee030bSHidetoshi Shimokawa int len; 48077ee030bSHidetoshi Shimokawa 48177ee030bSHidetoshi Shimokawa offset = 0; 48277ee030bSHidetoshi Shimokawa /* Determine offset */ 48377ee030bSHidetoshi Shimokawa STAILQ_FOREACH(chunk, &src->chunk_list, link) { 48477ee030bSHidetoshi Shimokawa chunk->offset = offset; 48577ee030bSHidetoshi Shimokawa /* Assume the offset of the parent is already known */ 48677ee030bSHidetoshi Shimokawa parent = chunk->ref_chunk; 48777ee030bSHidetoshi Shimokawa if (parent != NULL) { 48877ee030bSHidetoshi Shimokawa struct csrreg *reg; 48977ee030bSHidetoshi Shimokawa reg = (struct csrreg *) 49077ee030bSHidetoshi Shimokawa &parent->data.buf[chunk->ref_index]; 49177ee030bSHidetoshi Shimokawa reg->val = offset - 49277ee030bSHidetoshi Shimokawa (parent->offset + 1 + chunk->ref_index); 49377ee030bSHidetoshi Shimokawa } 49477ee030bSHidetoshi Shimokawa offset += 1 + chunk->data.crc_len; 49577ee030bSHidetoshi Shimokawa } 49677ee030bSHidetoshi Shimokawa 49777ee030bSHidetoshi Shimokawa /* Calculate CRC and dump to the buffer */ 49877ee030bSHidetoshi Shimokawa len = 1 + src->hdr.info_len; 49977ee030bSHidetoshi Shimokawa count = 0; 50077ee030bSHidetoshi Shimokawa if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0) 50177ee030bSHidetoshi Shimokawa return(-1); 50277ee030bSHidetoshi Shimokawa STAILQ_FOREACH(chunk, &src->chunk_list, link) { 50377ee030bSHidetoshi Shimokawa chunk->data.crc = 50477ee030bSHidetoshi Shimokawa crom_crc(&chunk->data.buf[0], chunk->data.crc_len); 50577ee030bSHidetoshi Shimokawa 50677ee030bSHidetoshi Shimokawa len = 1 + chunk->data.crc_len; 50777ee030bSHidetoshi Shimokawa if (crom_copy((u_int32_t *)&chunk->data, buf, 50877ee030bSHidetoshi Shimokawa &count, len, maxlen) < 0) 50977ee030bSHidetoshi Shimokawa return(-1); 51077ee030bSHidetoshi Shimokawa } 51177ee030bSHidetoshi Shimokawa hdr = (struct csrhdr *)buf; 51277ee030bSHidetoshi Shimokawa hdr->crc_len = count - 1; 513b83977f0SHidetoshi Shimokawa hdr->crc = crom_crc(&buf[1], hdr->crc_len); 51477ee030bSHidetoshi Shimokawa 515b83977f0SHidetoshi Shimokawa #ifdef _KERNEL 51677ee030bSHidetoshi Shimokawa /* byte swap */ 51777ee030bSHidetoshi Shimokawa ptr = buf; 51877ee030bSHidetoshi Shimokawa for (i = 0; i < count; i ++) { 51977ee030bSHidetoshi Shimokawa *ptr = htonl(*ptr); 52077ee030bSHidetoshi Shimokawa ptr++; 52177ee030bSHidetoshi Shimokawa } 52277ee030bSHidetoshi Shimokawa #endif 52377ee030bSHidetoshi Shimokawa 52477ee030bSHidetoshi Shimokawa return(count); 52577ee030bSHidetoshi Shimokawa } 52677ee030bSHidetoshi Shimokawa #endif 52777ee030bSHidetoshi Shimokawa 52877ee030bSHidetoshi Shimokawa #ifdef TEST 52977ee030bSHidetoshi Shimokawa int 53077ee030bSHidetoshi Shimokawa main () { 53177ee030bSHidetoshi Shimokawa struct crom_src src; 53277ee030bSHidetoshi Shimokawa struct crom_chunk root,unit1,unit2,unit3; 53377ee030bSHidetoshi Shimokawa struct crom_chunk text1,text2,text3,text4,text5,text6,text7; 53477ee030bSHidetoshi Shimokawa u_int32_t buf[256], *p; 53577ee030bSHidetoshi Shimokawa int i; 53677ee030bSHidetoshi Shimokawa 53777ee030bSHidetoshi Shimokawa bzero(&src, sizeof(src)); 53877ee030bSHidetoshi Shimokawa bzero(&root, sizeof(root)); 53977ee030bSHidetoshi Shimokawa bzero(&unit1, sizeof(unit1)); 54077ee030bSHidetoshi Shimokawa bzero(&unit2, sizeof(unit2)); 54177ee030bSHidetoshi Shimokawa bzero(&unit3, sizeof(unit3)); 54277ee030bSHidetoshi Shimokawa bzero(&text1, sizeof(text1)); 54377ee030bSHidetoshi Shimokawa bzero(&text2, sizeof(text2)); 54477ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text3)); 54577ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text4)); 54677ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text5)); 54777ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text6)); 54877ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text7)); 54977ee030bSHidetoshi Shimokawa bzero(buf, sizeof(buf)); 55077ee030bSHidetoshi Shimokawa 55177ee030bSHidetoshi Shimokawa /* BUS info sample */ 55277ee030bSHidetoshi Shimokawa src.hdr.info_len = 4; 55377ee030bSHidetoshi Shimokawa src.businfo.bus_name = CSR_BUS_NAME_IEEE1394; 55477ee030bSHidetoshi Shimokawa src.businfo.eui64.hi = 0x11223344; 55577ee030bSHidetoshi Shimokawa src.businfo.eui64.lo = 0x55667788; 55677ee030bSHidetoshi Shimokawa src.businfo.link_spd = FWSPD_S400; 55777ee030bSHidetoshi Shimokawa src.businfo.generation = 0; 55877ee030bSHidetoshi Shimokawa src.businfo.max_rom = MAXROM_4; 55977ee030bSHidetoshi Shimokawa src.businfo.max_rec = 10; 56077ee030bSHidetoshi Shimokawa src.businfo.cyc_clk_acc = 100; 56177ee030bSHidetoshi Shimokawa src.businfo.pmc = 0; 56277ee030bSHidetoshi Shimokawa src.businfo.bmc = 1; 56377ee030bSHidetoshi Shimokawa src.businfo.isc = 1; 56477ee030bSHidetoshi Shimokawa src.businfo.cmc = 1; 56577ee030bSHidetoshi Shimokawa src.businfo.irmc = 1; 56677ee030bSHidetoshi Shimokawa STAILQ_INIT(&src.chunk_list); 56777ee030bSHidetoshi Shimokawa 56877ee030bSHidetoshi Shimokawa /* Root directory */ 56977ee030bSHidetoshi Shimokawa crom_add_chunk(&src, NULL, &root, 0); 57077ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_NCAP, 0x123456); 57177ee030bSHidetoshi Shimokawa /* private company_id */ 57277ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48); 57377ee030bSHidetoshi Shimokawa 57477ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text1, "FreeBSD"); 57577ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version); 57677ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text2, "FreeBSD-5"); 57777ee030bSHidetoshi Shimokawa 57877ee030bSHidetoshi Shimokawa /* SBP unit directory */ 57977ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit1, CROM_UDIR); 58077ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10); 58177ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2); 58277ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); 58377ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI); 58477ee030bSHidetoshi Shimokawa /* management_agent */ 58577ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CROM_MGM, 0x1000); 58677ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8); 58777ee030bSHidetoshi Shimokawa /* Device type and LUN */ 58877ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CROM_LUN, 0); 58977ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_MODEL, 1); 59077ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit1, &text3, "scsi_target"); 59177ee030bSHidetoshi Shimokawa 59277ee030bSHidetoshi Shimokawa /* RFC2734 IPv4 over IEEE1394 */ 59377ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit2, CROM_UDIR); 59477ee030bSHidetoshi Shimokawa crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF); 59577ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit2, &text4, "IANA"); 59677ee030bSHidetoshi Shimokawa crom_add_entry(&unit2, CSRKEY_VER, 1); 59777ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit2, &text5, "IPv4"); 59877ee030bSHidetoshi Shimokawa 59977ee030bSHidetoshi Shimokawa /* RFC3146 IPv6 over IEEE1394 */ 60077ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit3, CROM_UDIR); 60177ee030bSHidetoshi Shimokawa crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF); 60277ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit3, &text6, "IANA"); 60377ee030bSHidetoshi Shimokawa crom_add_entry(&unit3, CSRKEY_VER, 2); 60477ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit3, &text7, "IPv6"); 60577ee030bSHidetoshi Shimokawa 60677ee030bSHidetoshi Shimokawa crom_load(&src, buf, 256); 60777ee030bSHidetoshi Shimokawa p = buf; 60877ee030bSHidetoshi Shimokawa #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" 60977ee030bSHidetoshi Shimokawa for (i = 0; i < 256/8; i ++) { 61077ee030bSHidetoshi Shimokawa printf(DUMP_FORMAT, 61177ee030bSHidetoshi Shimokawa p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 61277ee030bSHidetoshi Shimokawa p += 8; 61377ee030bSHidetoshi Shimokawa } 61477ee030bSHidetoshi Shimokawa return(0); 61577ee030bSHidetoshi Shimokawa } 61677ee030bSHidetoshi Shimokawa #endif 617