1b018dcd1SHidetoshi Shimokawa /* 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 * $FreeBSD$ 35b018dcd1SHidetoshi Shimokawa */ 36b018dcd1SHidetoshi Shimokawa 37b018dcd1SHidetoshi Shimokawa #include <sys/param.h> 3877ee030bSHidetoshi Shimokawa #if defined(_KERNEL) || defined(TEST) 3977ee030bSHidetoshi Shimokawa #include <sys/queue.h> 4077ee030bSHidetoshi Shimokawa #endif 41b018dcd1SHidetoshi Shimokawa #ifdef _KERNEL 42b018dcd1SHidetoshi Shimokawa #include <sys/systm.h> 43b018dcd1SHidetoshi Shimokawa #include <sys/kernel.h> 44b018dcd1SHidetoshi Shimokawa #else 45b018dcd1SHidetoshi Shimokawa #include <netinet/in.h> 46b018dcd1SHidetoshi Shimokawa #include <fcntl.h> 47b018dcd1SHidetoshi Shimokawa #include <stdio.h> 48b018dcd1SHidetoshi Shimokawa #include <err.h> 49b018dcd1SHidetoshi Shimokawa #include <stdlib.h> 50b018dcd1SHidetoshi Shimokawa #include <string.h> 51b018dcd1SHidetoshi Shimokawa #endif 5277ee030bSHidetoshi Shimokawa #include <dev/firewire/firewire.h> 5377ee030bSHidetoshi Shimokawa #include <dev/firewire/iec13213.h> 54b018dcd1SHidetoshi Shimokawa 5588e7cb59SHidetoshi Shimokawa #define MAX_ROM (1024 - sizeof(u_int32_t) * 5) 5688e7cb59SHidetoshi Shimokawa #define CROM_END(cc) ((vm_offset_t)(cc)->stack[0].dir + MAX_ROM - 1) 5788e7cb59SHidetoshi Shimokawa 58b018dcd1SHidetoshi Shimokawa void 59b018dcd1SHidetoshi Shimokawa crom_init_context(struct crom_context *cc, u_int32_t *p) 60b018dcd1SHidetoshi Shimokawa { 61b018dcd1SHidetoshi Shimokawa struct csrhdr *hdr; 62b018dcd1SHidetoshi Shimokawa 63b018dcd1SHidetoshi Shimokawa hdr = (struct csrhdr *)p; 64b018dcd1SHidetoshi Shimokawa if (hdr->info_len == 1) { 65b018dcd1SHidetoshi Shimokawa /* minimum ROM */ 66b018dcd1SHidetoshi Shimokawa cc->depth = -1; 67b018dcd1SHidetoshi Shimokawa } 68b018dcd1SHidetoshi Shimokawa p += 1 + hdr->info_len; 695e286c32SHidetoshi Shimokawa 705e286c32SHidetoshi Shimokawa /* check size of root directory */ 715e286c32SHidetoshi Shimokawa if (((struct csrdirectory *)p)->crc_len == 0) { 725e286c32SHidetoshi Shimokawa cc->depth = -1; 735e286c32SHidetoshi Shimokawa return; 745e286c32SHidetoshi Shimokawa } 75b018dcd1SHidetoshi Shimokawa cc->depth = 0; 76b018dcd1SHidetoshi Shimokawa cc->stack[0].dir = (struct csrdirectory *)p; 77b018dcd1SHidetoshi Shimokawa cc->stack[0].index = 0; 78b018dcd1SHidetoshi Shimokawa } 79b018dcd1SHidetoshi Shimokawa 80b018dcd1SHidetoshi Shimokawa struct csrreg * 81b018dcd1SHidetoshi Shimokawa crom_get(struct crom_context *cc) 82b018dcd1SHidetoshi Shimokawa { 83b018dcd1SHidetoshi Shimokawa struct crom_ptr *ptr; 84b018dcd1SHidetoshi Shimokawa 85b018dcd1SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 86b018dcd1SHidetoshi Shimokawa return (&ptr->dir->entry[ptr->index]); 87b018dcd1SHidetoshi Shimokawa } 88b018dcd1SHidetoshi Shimokawa 89b018dcd1SHidetoshi Shimokawa void 90b018dcd1SHidetoshi Shimokawa crom_next(struct crom_context *cc) 91b018dcd1SHidetoshi Shimokawa { 92b018dcd1SHidetoshi Shimokawa struct crom_ptr *ptr; 93b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 94b018dcd1SHidetoshi Shimokawa 95b018dcd1SHidetoshi Shimokawa if (cc->depth < 0) 96b018dcd1SHidetoshi Shimokawa return; 97b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 98b018dcd1SHidetoshi Shimokawa if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { 9988e7cb59SHidetoshi Shimokawa if (cc->depth >= CROM_MAX_DEPTH) { 100b018dcd1SHidetoshi Shimokawa printf("crom_next: too deep\n"); 101b018dcd1SHidetoshi Shimokawa goto again; 102b018dcd1SHidetoshi Shimokawa } 10388e7cb59SHidetoshi Shimokawa cc->depth ++; 10488e7cb59SHidetoshi Shimokawa 1057ddbf617SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 1067ddbf617SHidetoshi Shimokawa ptr->dir = (struct csrdirectory *) (reg + reg->val); 1077ddbf617SHidetoshi Shimokawa ptr->index = 0; 1087ddbf617SHidetoshi Shimokawa goto check; 109b018dcd1SHidetoshi Shimokawa } 110b018dcd1SHidetoshi Shimokawa again: 111b018dcd1SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 112b018dcd1SHidetoshi Shimokawa ptr->index ++; 1137ddbf617SHidetoshi Shimokawa check: 11488e7cb59SHidetoshi Shimokawa if (ptr->index < ptr->dir->crc_len && 11588e7cb59SHidetoshi Shimokawa (vm_offset_t)crom_get(cc) <= CROM_END(cc)) 116b018dcd1SHidetoshi Shimokawa return; 11788e7cb59SHidetoshi Shimokawa 11888e7cb59SHidetoshi Shimokawa if (ptr->index < ptr->dir->crc_len) 11988e7cb59SHidetoshi Shimokawa printf("crom_next: bound check failed\n"); 12088e7cb59SHidetoshi Shimokawa 121b018dcd1SHidetoshi Shimokawa if (cc->depth > 0) { 122b018dcd1SHidetoshi Shimokawa cc->depth--; 123b018dcd1SHidetoshi Shimokawa goto again; 124b018dcd1SHidetoshi Shimokawa } 125b018dcd1SHidetoshi Shimokawa /* no more data */ 126b018dcd1SHidetoshi Shimokawa cc->depth = -1; 127b018dcd1SHidetoshi Shimokawa } 128b018dcd1SHidetoshi Shimokawa 129b018dcd1SHidetoshi Shimokawa 130b018dcd1SHidetoshi Shimokawa struct csrreg * 131b018dcd1SHidetoshi Shimokawa crom_search_key(struct crom_context *cc, u_int8_t key) 132b018dcd1SHidetoshi Shimokawa { 133b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 134b018dcd1SHidetoshi Shimokawa 135b018dcd1SHidetoshi Shimokawa while(cc->depth >= 0) { 136b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 137b018dcd1SHidetoshi Shimokawa if (reg->key == key) 138b018dcd1SHidetoshi Shimokawa return reg; 139b018dcd1SHidetoshi Shimokawa crom_next(cc); 140b018dcd1SHidetoshi Shimokawa } 141b018dcd1SHidetoshi Shimokawa return NULL; 142b018dcd1SHidetoshi Shimokawa } 143b018dcd1SHidetoshi Shimokawa 1445e286c32SHidetoshi Shimokawa int 1455e286c32SHidetoshi Shimokawa crom_has_specver(u_int32_t *p, u_int32_t spec, u_int32_t ver) 1465e286c32SHidetoshi Shimokawa { 1475e286c32SHidetoshi Shimokawa struct csrreg *reg; 1485e286c32SHidetoshi Shimokawa struct crom_context c, *cc; 1495e286c32SHidetoshi Shimokawa int state = 0; 1505e286c32SHidetoshi Shimokawa 1515e286c32SHidetoshi Shimokawa cc = &c; 1525e286c32SHidetoshi Shimokawa crom_init_context(cc, p); 1535e286c32SHidetoshi Shimokawa while(cc->depth >= 0) { 1545e286c32SHidetoshi Shimokawa reg = crom_get(cc); 1555e286c32SHidetoshi Shimokawa if (state == 0) { 1565e286c32SHidetoshi Shimokawa if (reg->key == CSRKEY_SPEC && reg->val == spec) 1575e286c32SHidetoshi Shimokawa state = 1; 1585e286c32SHidetoshi Shimokawa else 1595e286c32SHidetoshi Shimokawa state = 0; 1605e286c32SHidetoshi Shimokawa } else { 1615e286c32SHidetoshi Shimokawa if (reg->key == CSRKEY_VER && reg->val == ver) 1625e286c32SHidetoshi Shimokawa return 1; 1635e286c32SHidetoshi Shimokawa else 1645e286c32SHidetoshi Shimokawa state = 0; 1655e286c32SHidetoshi Shimokawa } 1665e286c32SHidetoshi Shimokawa crom_next(cc); 1675e286c32SHidetoshi Shimokawa } 1685e286c32SHidetoshi Shimokawa return 0; 1695e286c32SHidetoshi Shimokawa } 1705e286c32SHidetoshi Shimokawa 171b018dcd1SHidetoshi Shimokawa void 172b018dcd1SHidetoshi Shimokawa crom_parse_text(struct crom_context *cc, char *buf, int len) 173b018dcd1SHidetoshi Shimokawa { 174b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 175b018dcd1SHidetoshi Shimokawa struct csrtext *textleaf; 176b018dcd1SHidetoshi Shimokawa u_int32_t *bp; 177b018dcd1SHidetoshi Shimokawa int i, qlen; 178b018dcd1SHidetoshi Shimokawa static char *nullstr = "(null)"; 179b018dcd1SHidetoshi Shimokawa 1805e286c32SHidetoshi Shimokawa if (cc->depth < 0) 1815e286c32SHidetoshi Shimokawa return; 1825e286c32SHidetoshi Shimokawa 183b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 18488e7cb59SHidetoshi Shimokawa if (reg->key != CROM_TEXTLEAF || 18588e7cb59SHidetoshi Shimokawa (vm_offset_t)(reg + reg->val) > CROM_END(cc)) { 186b018dcd1SHidetoshi Shimokawa strncpy(buf, nullstr, len); 187b018dcd1SHidetoshi Shimokawa return; 188b018dcd1SHidetoshi Shimokawa } 189b018dcd1SHidetoshi Shimokawa textleaf = (struct csrtext *)(reg + reg->val); 190b018dcd1SHidetoshi Shimokawa 19188e7cb59SHidetoshi Shimokawa if ((vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc)) { 19288e7cb59SHidetoshi Shimokawa strncpy(buf, nullstr, len); 19388e7cb59SHidetoshi Shimokawa return; 19488e7cb59SHidetoshi Shimokawa } 19588e7cb59SHidetoshi Shimokawa 196b018dcd1SHidetoshi Shimokawa /* XXX should check spec and type */ 197b018dcd1SHidetoshi Shimokawa 198b018dcd1SHidetoshi Shimokawa bp = (u_int32_t *)&buf[0]; 199b018dcd1SHidetoshi Shimokawa qlen = textleaf->crc_len - 2; 200b018dcd1SHidetoshi Shimokawa if (len < qlen * 4) 201b018dcd1SHidetoshi Shimokawa qlen = len/4; 202b018dcd1SHidetoshi Shimokawa for (i = 0; i < qlen; i ++) 203b018dcd1SHidetoshi Shimokawa *bp++ = ntohl(textleaf->text[i]); 204b018dcd1SHidetoshi Shimokawa /* make sure to terminate the string */ 205b018dcd1SHidetoshi Shimokawa if (len <= qlen * 4) 206b018dcd1SHidetoshi Shimokawa buf[len - 1] = 0; 207b018dcd1SHidetoshi Shimokawa else 208b018dcd1SHidetoshi Shimokawa buf[qlen * 4] = 0; 209b018dcd1SHidetoshi Shimokawa } 210b018dcd1SHidetoshi Shimokawa 211b018dcd1SHidetoshi Shimokawa u_int16_t 212b018dcd1SHidetoshi Shimokawa crom_crc(u_int32_t *ptr, int len) 213b018dcd1SHidetoshi Shimokawa { 214b018dcd1SHidetoshi Shimokawa int i, shift; 215b018dcd1SHidetoshi Shimokawa u_int32_t data, sum, crc = 0; 216b018dcd1SHidetoshi Shimokawa 217b018dcd1SHidetoshi Shimokawa for (i = 0; i < len; i++) { 218b018dcd1SHidetoshi Shimokawa data = ptr[i]; 219b018dcd1SHidetoshi Shimokawa for (shift = 28; shift >= 0; shift -= 4) { 220b018dcd1SHidetoshi Shimokawa sum = ((crc >> 12) ^ (data >> shift)) & 0xf; 221b018dcd1SHidetoshi Shimokawa crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 222b018dcd1SHidetoshi Shimokawa } 223b018dcd1SHidetoshi Shimokawa crc &= 0xffff; 224b018dcd1SHidetoshi Shimokawa } 225b018dcd1SHidetoshi Shimokawa return((u_int16_t) crc); 226b018dcd1SHidetoshi Shimokawa } 227b018dcd1SHidetoshi Shimokawa 228b018dcd1SHidetoshi Shimokawa #ifndef _KERNEL 2295e286c32SHidetoshi Shimokawa static void 2305e286c32SHidetoshi Shimokawa crom_desc_specver(u_int32_t spec, u_int32_t ver, char *buf, int len) 2315e286c32SHidetoshi Shimokawa { 2325e286c32SHidetoshi Shimokawa char *s = NULL; 2335e286c32SHidetoshi Shimokawa 2345e286c32SHidetoshi Shimokawa if (spec == CSRVAL_ANSIT10 || spec == 0) { 2355e286c32SHidetoshi Shimokawa switch (ver) { 2365e286c32SHidetoshi Shimokawa case CSRVAL_T10SBP2: 2375e286c32SHidetoshi Shimokawa s = "SBP-2"; 2385e286c32SHidetoshi Shimokawa break; 2395e286c32SHidetoshi Shimokawa default: 2405e286c32SHidetoshi Shimokawa if (spec != 0) 2415e286c32SHidetoshi Shimokawa s = "unknown ANSIT10"; 2425e286c32SHidetoshi Shimokawa } 2435e286c32SHidetoshi Shimokawa } 2445e286c32SHidetoshi Shimokawa if (spec == CSRVAL_1394TA || spec == 0) { 2455e286c32SHidetoshi Shimokawa switch (ver) { 2465e286c32SHidetoshi Shimokawa case CSR_PROTAVC: 2475e286c32SHidetoshi Shimokawa s = "AV/C"; 2485e286c32SHidetoshi Shimokawa break; 2495e286c32SHidetoshi Shimokawa case CSR_PROTCAL: 2505e286c32SHidetoshi Shimokawa s = "CAL"; 2515e286c32SHidetoshi Shimokawa break; 2525e286c32SHidetoshi Shimokawa case CSR_PROTEHS: 2535e286c32SHidetoshi Shimokawa s = "EHS"; 2545e286c32SHidetoshi Shimokawa break; 2555e286c32SHidetoshi Shimokawa case CSR_PROTHAVI: 2565e286c32SHidetoshi Shimokawa s = "HAVi"; 2575e286c32SHidetoshi Shimokawa break; 2585e286c32SHidetoshi Shimokawa case CSR_PROTCAM104: 2595e286c32SHidetoshi Shimokawa s = "1394 Cam 1.04"; 2605e286c32SHidetoshi Shimokawa break; 2615e286c32SHidetoshi Shimokawa case CSR_PROTCAM120: 2625e286c32SHidetoshi Shimokawa s = "1394 Cam 1.20"; 2635e286c32SHidetoshi Shimokawa break; 2645e286c32SHidetoshi Shimokawa case CSR_PROTCAM130: 2655e286c32SHidetoshi Shimokawa s = "1394 Cam 1.30"; 2665e286c32SHidetoshi Shimokawa break; 2675e286c32SHidetoshi Shimokawa case CSR_PROTDPP: 2685e286c32SHidetoshi Shimokawa s = "1394 Direct print"; 2695e286c32SHidetoshi Shimokawa break; 2705e286c32SHidetoshi Shimokawa case CSR_PROTIICP: 2715e286c32SHidetoshi Shimokawa s = "Industrial & Instrument"; 2725e286c32SHidetoshi Shimokawa break; 2735e286c32SHidetoshi Shimokawa default: 2745e286c32SHidetoshi Shimokawa if (spec != 0) 2755e286c32SHidetoshi Shimokawa s = "unknown 1394TA"; 2765e286c32SHidetoshi Shimokawa } 2775e286c32SHidetoshi Shimokawa } 2785e286c32SHidetoshi Shimokawa if (s != NULL) 2795e286c32SHidetoshi Shimokawa snprintf(buf, len, "%s", s); 2805e286c32SHidetoshi Shimokawa } 2815e286c32SHidetoshi Shimokawa 282b018dcd1SHidetoshi Shimokawa char * 283b018dcd1SHidetoshi Shimokawa crom_desc(struct crom_context *cc, char *buf, int len) 284b018dcd1SHidetoshi Shimokawa { 285b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 286b018dcd1SHidetoshi Shimokawa struct csrdirectory *dir; 2875e286c32SHidetoshi Shimokawa char *desc, st; 28877ee030bSHidetoshi Shimokawa u_int16_t crc; 289b018dcd1SHidetoshi Shimokawa 290b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 291b018dcd1SHidetoshi Shimokawa switch (reg->key & CSRTYPE_MASK) { 292b018dcd1SHidetoshi Shimokawa case CSRTYPE_I: 2935e286c32SHidetoshi Shimokawa #if 0 2945e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "%d", reg->val); 2955e286c32SHidetoshi Shimokawa buf += strlen(buf); 2965e286c32SHidetoshi Shimokawa #else 2975e286c32SHidetoshi Shimokawa *buf = '\0'; 2985e286c32SHidetoshi Shimokawa #endif 299b018dcd1SHidetoshi Shimokawa break; 300b018dcd1SHidetoshi Shimokawa case CSRTYPE_C: 3015e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "offset=0x%04x(%d)", 3025e286c32SHidetoshi Shimokawa reg->val, reg->val); 3035e286c32SHidetoshi Shimokawa buf += strlen(buf); 304b018dcd1SHidetoshi Shimokawa break; 30577ee030bSHidetoshi Shimokawa case CSRTYPE_L: 30677ee030bSHidetoshi Shimokawa /* XXX fall through */ 307b018dcd1SHidetoshi Shimokawa case CSRTYPE_D: 308b018dcd1SHidetoshi Shimokawa dir = (struct csrdirectory *) (reg + reg->val); 30977ee030bSHidetoshi Shimokawa crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); 3105e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "len=%d crc=0x%04x(%s) ", 3115e286c32SHidetoshi Shimokawa dir->crc_len, dir->crc, 3125e286c32SHidetoshi Shimokawa (crc == dir->crc) ? "OK" : "NG"); 3135e286c32SHidetoshi Shimokawa buf += strlen(buf); 314b018dcd1SHidetoshi Shimokawa } 315b018dcd1SHidetoshi Shimokawa switch (reg->key) { 316b018dcd1SHidetoshi Shimokawa case 0x03: 317b018dcd1SHidetoshi Shimokawa desc = "module_vendor_ID"; 318b018dcd1SHidetoshi Shimokawa break; 319b018dcd1SHidetoshi Shimokawa case 0x04: 320b018dcd1SHidetoshi Shimokawa desc = "hardware_version"; 321b018dcd1SHidetoshi Shimokawa break; 322b018dcd1SHidetoshi Shimokawa case 0x0c: 323b018dcd1SHidetoshi Shimokawa desc = "node_capabilities"; 324b018dcd1SHidetoshi Shimokawa break; 325b018dcd1SHidetoshi Shimokawa case 0x12: 326b018dcd1SHidetoshi Shimokawa desc = "unit_spec_ID"; 327b018dcd1SHidetoshi Shimokawa break; 328b018dcd1SHidetoshi Shimokawa case 0x13: 329b018dcd1SHidetoshi Shimokawa desc = "unit_sw_version"; 3305e286c32SHidetoshi Shimokawa crom_desc_specver(0, reg->val, buf, len); 331b018dcd1SHidetoshi Shimokawa break; 332b018dcd1SHidetoshi Shimokawa case 0x14: 333b018dcd1SHidetoshi Shimokawa desc = "logical_unit_number"; 334b018dcd1SHidetoshi Shimokawa break; 335b018dcd1SHidetoshi Shimokawa case 0x17: 336b018dcd1SHidetoshi Shimokawa desc = "model_ID"; 337b018dcd1SHidetoshi Shimokawa break; 338b018dcd1SHidetoshi Shimokawa case 0x38: 339b018dcd1SHidetoshi Shimokawa desc = "command_set_spec_ID"; 340b018dcd1SHidetoshi Shimokawa break; 341b018dcd1SHidetoshi Shimokawa case 0x39: 342b018dcd1SHidetoshi Shimokawa desc = "command_set"; 343b018dcd1SHidetoshi Shimokawa break; 344b018dcd1SHidetoshi Shimokawa case 0x3a: 345b018dcd1SHidetoshi Shimokawa desc = "unit_characteristics"; 346b018dcd1SHidetoshi Shimokawa break; 347b018dcd1SHidetoshi Shimokawa case 0x3b: 348b018dcd1SHidetoshi Shimokawa desc = "command_set_revision"; 349b018dcd1SHidetoshi Shimokawa break; 350b018dcd1SHidetoshi Shimokawa case 0x3c: 351b018dcd1SHidetoshi Shimokawa desc = "firmware_revision"; 352b018dcd1SHidetoshi Shimokawa break; 353b018dcd1SHidetoshi Shimokawa case 0x3d: 354b018dcd1SHidetoshi Shimokawa desc = "reconnect_timeout"; 355b018dcd1SHidetoshi Shimokawa break; 356b018dcd1SHidetoshi Shimokawa case 0x54: 357b018dcd1SHidetoshi Shimokawa desc = "management_agent"; 358b018dcd1SHidetoshi Shimokawa break; 359b018dcd1SHidetoshi Shimokawa case 0x81: 360b018dcd1SHidetoshi Shimokawa desc = "text_leaf"; 36177ee030bSHidetoshi Shimokawa crom_parse_text(cc, buf + strlen(buf), len); 362b018dcd1SHidetoshi Shimokawa break; 363b018dcd1SHidetoshi Shimokawa case 0xd1: 364b018dcd1SHidetoshi Shimokawa desc = "unit_directory"; 365b018dcd1SHidetoshi Shimokawa break; 366b018dcd1SHidetoshi Shimokawa case 0xd4: 367b018dcd1SHidetoshi Shimokawa desc = "logical_unit_directory"; 368b018dcd1SHidetoshi Shimokawa break; 369b018dcd1SHidetoshi Shimokawa default: 370b018dcd1SHidetoshi Shimokawa desc = "unknown"; 371b018dcd1SHidetoshi Shimokawa } 372b018dcd1SHidetoshi Shimokawa return desc; 373b018dcd1SHidetoshi Shimokawa } 374b018dcd1SHidetoshi Shimokawa #endif 37577ee030bSHidetoshi Shimokawa 37677ee030bSHidetoshi Shimokawa #if defined(_KERNEL) || defined(TEST) 37777ee030bSHidetoshi Shimokawa 37877ee030bSHidetoshi Shimokawa int 37977ee030bSHidetoshi Shimokawa crom_add_quad(struct crom_chunk *chunk, u_int32_t entry) 38077ee030bSHidetoshi Shimokawa { 38177ee030bSHidetoshi Shimokawa int index; 38277ee030bSHidetoshi Shimokawa 38377ee030bSHidetoshi Shimokawa index = chunk->data.crc_len; 38477ee030bSHidetoshi Shimokawa if (index >= CROM_MAX_CHUNK_LEN - 1) { 38577ee030bSHidetoshi Shimokawa printf("too large chunk %d\n", index); 38677ee030bSHidetoshi Shimokawa return(-1); 38777ee030bSHidetoshi Shimokawa } 38877ee030bSHidetoshi Shimokawa chunk->data.buf[index] = entry; 38977ee030bSHidetoshi Shimokawa chunk->data.crc_len++; 39077ee030bSHidetoshi Shimokawa return(index); 39177ee030bSHidetoshi Shimokawa } 39277ee030bSHidetoshi Shimokawa 39377ee030bSHidetoshi Shimokawa int 39477ee030bSHidetoshi Shimokawa crom_add_entry(struct crom_chunk *chunk, int key, int val) 39577ee030bSHidetoshi Shimokawa { 39677ee030bSHidetoshi Shimokawa struct csrreg *reg; 39777ee030bSHidetoshi Shimokawa u_int32_t i; 39877ee030bSHidetoshi Shimokawa 39977ee030bSHidetoshi Shimokawa reg = (struct csrreg *)&i; 40077ee030bSHidetoshi Shimokawa reg->key = key; 40177ee030bSHidetoshi Shimokawa reg->val = val; 40277ee030bSHidetoshi Shimokawa return(crom_add_quad(chunk, (u_int32_t) i)); 40377ee030bSHidetoshi Shimokawa } 40477ee030bSHidetoshi Shimokawa 40577ee030bSHidetoshi Shimokawa int 40677ee030bSHidetoshi Shimokawa crom_add_chunk(struct crom_src *src, struct crom_chunk *parent, 40777ee030bSHidetoshi Shimokawa struct crom_chunk *child, int key) 40877ee030bSHidetoshi Shimokawa { 40977ee030bSHidetoshi Shimokawa int index; 41077ee030bSHidetoshi Shimokawa 41177ee030bSHidetoshi Shimokawa if (parent == NULL) { 41277ee030bSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 41377ee030bSHidetoshi Shimokawa return(0); 41477ee030bSHidetoshi Shimokawa } 41577ee030bSHidetoshi Shimokawa 41677ee030bSHidetoshi Shimokawa index = crom_add_entry(parent, key, 0); 41777ee030bSHidetoshi Shimokawa if (index < 0) { 41877ee030bSHidetoshi Shimokawa return(-1); 41977ee030bSHidetoshi Shimokawa } 42077ee030bSHidetoshi Shimokawa child->ref_chunk = parent; 42177ee030bSHidetoshi Shimokawa child->ref_index = index; 42277ee030bSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 42377ee030bSHidetoshi Shimokawa return(index); 42477ee030bSHidetoshi Shimokawa } 42577ee030bSHidetoshi Shimokawa 42677ee030bSHidetoshi Shimokawa int 42777ee030bSHidetoshi Shimokawa crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent, 42877ee030bSHidetoshi Shimokawa struct crom_chunk *chunk, char *buf) 42977ee030bSHidetoshi Shimokawa { 43077ee030bSHidetoshi Shimokawa struct csrtext *tl; 43177ee030bSHidetoshi Shimokawa u_int32_t *p; 43277ee030bSHidetoshi Shimokawa int len, i; 43377ee030bSHidetoshi Shimokawa 43477ee030bSHidetoshi Shimokawa len = strlen(buf); 43577ee030bSHidetoshi Shimokawa #define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext)) 43677ee030bSHidetoshi Shimokawa if (len > MAX_TEXT) { 43777ee030bSHidetoshi Shimokawa #if __FreeBSD_version < 500000 43877ee030bSHidetoshi Shimokawa printf("text(%d) trancated to %d.\n", len, MAX_TEXT); 43977ee030bSHidetoshi Shimokawa #else 44077ee030bSHidetoshi Shimokawa printf("text(%d) trancated to %td.\n", len, MAX_TEXT); 44177ee030bSHidetoshi Shimokawa #endif 44277ee030bSHidetoshi Shimokawa len = MAX_TEXT; 44377ee030bSHidetoshi Shimokawa } 44477ee030bSHidetoshi Shimokawa 44577ee030bSHidetoshi Shimokawa tl = (struct csrtext *) &chunk->data; 44677ee030bSHidetoshi Shimokawa tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t)); 44777ee030bSHidetoshi Shimokawa tl->spec_id = 0; 44877ee030bSHidetoshi Shimokawa tl->spec_type = 0; 44977ee030bSHidetoshi Shimokawa tl->lang_id = 0; 45077ee030bSHidetoshi Shimokawa p = (u_int32_t *) buf; 451b83977f0SHidetoshi Shimokawa for (i = 0; i < howmany(len, sizeof(u_int32_t)); i ++) 45277ee030bSHidetoshi Shimokawa tl->text[i] = ntohl(*p++); 45377ee030bSHidetoshi Shimokawa return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF)); 45477ee030bSHidetoshi Shimokawa } 45577ee030bSHidetoshi Shimokawa 45677ee030bSHidetoshi Shimokawa static int 45777ee030bSHidetoshi Shimokawa crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen) 45877ee030bSHidetoshi Shimokawa { 45977ee030bSHidetoshi Shimokawa if (*offset + len > maxlen) { 46077ee030bSHidetoshi Shimokawa printf("Config. ROM is too large for the buffer\n"); 46177ee030bSHidetoshi Shimokawa return(-1); 46277ee030bSHidetoshi Shimokawa } 46377ee030bSHidetoshi Shimokawa bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t)); 46477ee030bSHidetoshi Shimokawa *offset += len; 46577ee030bSHidetoshi Shimokawa return(0); 46677ee030bSHidetoshi Shimokawa } 46777ee030bSHidetoshi Shimokawa 46877ee030bSHidetoshi Shimokawa int 46977ee030bSHidetoshi Shimokawa crom_load(struct crom_src *src, u_int32_t *buf, int maxlen) 47077ee030bSHidetoshi Shimokawa { 47177ee030bSHidetoshi Shimokawa struct crom_chunk *chunk, *parent; 47277ee030bSHidetoshi Shimokawa struct csrhdr *hdr; 473b83977f0SHidetoshi Shimokawa #ifdef _KERNEL 47477ee030bSHidetoshi Shimokawa u_int32_t *ptr; 475b83977f0SHidetoshi Shimokawa int i; 47677ee030bSHidetoshi Shimokawa #endif 47777ee030bSHidetoshi Shimokawa int count, offset; 47877ee030bSHidetoshi Shimokawa int len; 47977ee030bSHidetoshi Shimokawa 48077ee030bSHidetoshi Shimokawa offset = 0; 48177ee030bSHidetoshi Shimokawa /* Determine offset */ 48277ee030bSHidetoshi Shimokawa STAILQ_FOREACH(chunk, &src->chunk_list, link) { 48377ee030bSHidetoshi Shimokawa chunk->offset = offset; 48477ee030bSHidetoshi Shimokawa /* Assume the offset of the parent is already known */ 48577ee030bSHidetoshi Shimokawa parent = chunk->ref_chunk; 48677ee030bSHidetoshi Shimokawa if (parent != NULL) { 48777ee030bSHidetoshi Shimokawa struct csrreg *reg; 48877ee030bSHidetoshi Shimokawa reg = (struct csrreg *) 48977ee030bSHidetoshi Shimokawa &parent->data.buf[chunk->ref_index]; 49077ee030bSHidetoshi Shimokawa reg->val = offset - 49177ee030bSHidetoshi Shimokawa (parent->offset + 1 + chunk->ref_index); 49277ee030bSHidetoshi Shimokawa } 49377ee030bSHidetoshi Shimokawa offset += 1 + chunk->data.crc_len; 49477ee030bSHidetoshi Shimokawa } 49577ee030bSHidetoshi Shimokawa 49677ee030bSHidetoshi Shimokawa /* Calculate CRC and dump to the buffer */ 49777ee030bSHidetoshi Shimokawa len = 1 + src->hdr.info_len; 49877ee030bSHidetoshi Shimokawa count = 0; 49977ee030bSHidetoshi Shimokawa if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0) 50077ee030bSHidetoshi Shimokawa return(-1); 50177ee030bSHidetoshi Shimokawa STAILQ_FOREACH(chunk, &src->chunk_list, link) { 50277ee030bSHidetoshi Shimokawa chunk->data.crc = 50377ee030bSHidetoshi Shimokawa crom_crc(&chunk->data.buf[0], chunk->data.crc_len); 50477ee030bSHidetoshi Shimokawa 50577ee030bSHidetoshi Shimokawa len = 1 + chunk->data.crc_len; 50677ee030bSHidetoshi Shimokawa if (crom_copy((u_int32_t *)&chunk->data, buf, 50777ee030bSHidetoshi Shimokawa &count, len, maxlen) < 0) 50877ee030bSHidetoshi Shimokawa return(-1); 50977ee030bSHidetoshi Shimokawa } 51077ee030bSHidetoshi Shimokawa hdr = (struct csrhdr *)buf; 51177ee030bSHidetoshi Shimokawa hdr->crc_len = count - 1; 512b83977f0SHidetoshi Shimokawa hdr->crc = crom_crc(&buf[1], hdr->crc_len); 51377ee030bSHidetoshi Shimokawa 514b83977f0SHidetoshi Shimokawa #ifdef _KERNEL 51577ee030bSHidetoshi Shimokawa /* byte swap */ 51677ee030bSHidetoshi Shimokawa ptr = buf; 51777ee030bSHidetoshi Shimokawa for (i = 0; i < count; i ++) { 51877ee030bSHidetoshi Shimokawa *ptr = htonl(*ptr); 51977ee030bSHidetoshi Shimokawa ptr++; 52077ee030bSHidetoshi Shimokawa } 52177ee030bSHidetoshi Shimokawa #endif 52277ee030bSHidetoshi Shimokawa 52377ee030bSHidetoshi Shimokawa return(count); 52477ee030bSHidetoshi Shimokawa } 52577ee030bSHidetoshi Shimokawa #endif 52677ee030bSHidetoshi Shimokawa 52777ee030bSHidetoshi Shimokawa #ifdef TEST 52877ee030bSHidetoshi Shimokawa int 52977ee030bSHidetoshi Shimokawa main () { 53077ee030bSHidetoshi Shimokawa struct crom_src src; 53177ee030bSHidetoshi Shimokawa struct crom_chunk root,unit1,unit2,unit3; 53277ee030bSHidetoshi Shimokawa struct crom_chunk text1,text2,text3,text4,text5,text6,text7; 53377ee030bSHidetoshi Shimokawa u_int32_t buf[256], *p; 53477ee030bSHidetoshi Shimokawa int i; 53577ee030bSHidetoshi Shimokawa 53677ee030bSHidetoshi Shimokawa bzero(&src, sizeof(src)); 53777ee030bSHidetoshi Shimokawa bzero(&root, sizeof(root)); 53877ee030bSHidetoshi Shimokawa bzero(&unit1, sizeof(unit1)); 53977ee030bSHidetoshi Shimokawa bzero(&unit2, sizeof(unit2)); 54077ee030bSHidetoshi Shimokawa bzero(&unit3, sizeof(unit3)); 54177ee030bSHidetoshi Shimokawa bzero(&text1, sizeof(text1)); 54277ee030bSHidetoshi Shimokawa bzero(&text2, sizeof(text2)); 54377ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text3)); 54477ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text4)); 54577ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text5)); 54677ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text6)); 54777ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text7)); 54877ee030bSHidetoshi Shimokawa bzero(buf, sizeof(buf)); 54977ee030bSHidetoshi Shimokawa 55077ee030bSHidetoshi Shimokawa /* BUS info sample */ 55177ee030bSHidetoshi Shimokawa src.hdr.info_len = 4; 55277ee030bSHidetoshi Shimokawa src.businfo.bus_name = CSR_BUS_NAME_IEEE1394; 55377ee030bSHidetoshi Shimokawa src.businfo.eui64.hi = 0x11223344; 55477ee030bSHidetoshi Shimokawa src.businfo.eui64.lo = 0x55667788; 55577ee030bSHidetoshi Shimokawa src.businfo.link_spd = FWSPD_S400; 55677ee030bSHidetoshi Shimokawa src.businfo.generation = 0; 55777ee030bSHidetoshi Shimokawa src.businfo.max_rom = MAXROM_4; 55877ee030bSHidetoshi Shimokawa src.businfo.max_rec = 10; 55977ee030bSHidetoshi Shimokawa src.businfo.cyc_clk_acc = 100; 56077ee030bSHidetoshi Shimokawa src.businfo.pmc = 0; 56177ee030bSHidetoshi Shimokawa src.businfo.bmc = 1; 56277ee030bSHidetoshi Shimokawa src.businfo.isc = 1; 56377ee030bSHidetoshi Shimokawa src.businfo.cmc = 1; 56477ee030bSHidetoshi Shimokawa src.businfo.irmc = 1; 56577ee030bSHidetoshi Shimokawa STAILQ_INIT(&src.chunk_list); 56677ee030bSHidetoshi Shimokawa 56777ee030bSHidetoshi Shimokawa /* Root directory */ 56877ee030bSHidetoshi Shimokawa crom_add_chunk(&src, NULL, &root, 0); 56977ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_NCAP, 0x123456); 57077ee030bSHidetoshi Shimokawa /* private company_id */ 57177ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48); 57277ee030bSHidetoshi Shimokawa 57377ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text1, "FreeBSD"); 57477ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version); 57577ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text2, "FreeBSD-5"); 57677ee030bSHidetoshi Shimokawa 57777ee030bSHidetoshi Shimokawa /* SBP unit directory */ 57877ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit1, CROM_UDIR); 57977ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10); 58077ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2); 58177ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); 58277ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI); 58377ee030bSHidetoshi Shimokawa /* management_agent */ 58477ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CROM_MGM, 0x1000); 58577ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8); 58677ee030bSHidetoshi Shimokawa /* Device type and LUN */ 58777ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CROM_LUN, 0); 58877ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_MODEL, 1); 58977ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit1, &text3, "scsi_target"); 59077ee030bSHidetoshi Shimokawa 59177ee030bSHidetoshi Shimokawa /* RFC2734 IPv4 over IEEE1394 */ 59277ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit2, CROM_UDIR); 59377ee030bSHidetoshi Shimokawa crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF); 59477ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit2, &text4, "IANA"); 59577ee030bSHidetoshi Shimokawa crom_add_entry(&unit2, CSRKEY_VER, 1); 59677ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit2, &text5, "IPv4"); 59777ee030bSHidetoshi Shimokawa 59877ee030bSHidetoshi Shimokawa /* RFC3146 IPv6 over IEEE1394 */ 59977ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit3, CROM_UDIR); 60077ee030bSHidetoshi Shimokawa crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF); 60177ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit3, &text6, "IANA"); 60277ee030bSHidetoshi Shimokawa crom_add_entry(&unit3, CSRKEY_VER, 2); 60377ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit3, &text7, "IPv6"); 60477ee030bSHidetoshi Shimokawa 60577ee030bSHidetoshi Shimokawa crom_load(&src, buf, 256); 60677ee030bSHidetoshi Shimokawa p = buf; 60777ee030bSHidetoshi Shimokawa #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" 60877ee030bSHidetoshi Shimokawa for (i = 0; i < 256/8; i ++) { 60977ee030bSHidetoshi Shimokawa printf(DUMP_FORMAT, 61077ee030bSHidetoshi Shimokawa p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 61177ee030bSHidetoshi Shimokawa p += 8; 61277ee030bSHidetoshi Shimokawa } 61377ee030bSHidetoshi Shimokawa return(0); 61477ee030bSHidetoshi Shimokawa } 61577ee030bSHidetoshi Shimokawa #endif 616