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 3510d3ed64SHidetoshi Shimokawa #ifdef __FreeBSD__ 36aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 37aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3810d3ed64SHidetoshi Shimokawa #endif 39aad970f1SDavid E. O'Brien 40b018dcd1SHidetoshi Shimokawa #include <sys/param.h> 4177ee030bSHidetoshi Shimokawa #if defined(_KERNEL) || defined(TEST) 4277ee030bSHidetoshi Shimokawa #include <sys/queue.h> 4377ee030bSHidetoshi Shimokawa #endif 44b018dcd1SHidetoshi Shimokawa #ifdef _KERNEL 45b018dcd1SHidetoshi Shimokawa #include <sys/systm.h> 46b018dcd1SHidetoshi Shimokawa #include <sys/kernel.h> 47b018dcd1SHidetoshi Shimokawa #else 48b018dcd1SHidetoshi Shimokawa #include <netinet/in.h> 49b018dcd1SHidetoshi Shimokawa #include <fcntl.h> 50b018dcd1SHidetoshi Shimokawa #include <stdio.h> 51b018dcd1SHidetoshi Shimokawa #include <err.h> 52b018dcd1SHidetoshi Shimokawa #include <stdlib.h> 53b018dcd1SHidetoshi Shimokawa #include <string.h> 54b018dcd1SHidetoshi Shimokawa #endif 5510d3ed64SHidetoshi Shimokawa 5610d3ed64SHidetoshi Shimokawa #ifdef __DragonFly__ 5710d3ed64SHidetoshi Shimokawa #include "firewire.h" 5810d3ed64SHidetoshi Shimokawa #include "iec13213.h" 5910d3ed64SHidetoshi Shimokawa #else 6077ee030bSHidetoshi Shimokawa #include <dev/firewire/firewire.h> 6177ee030bSHidetoshi Shimokawa #include <dev/firewire/iec13213.h> 6210d3ed64SHidetoshi Shimokawa #endif 63b018dcd1SHidetoshi Shimokawa 6403161bbcSDoug Rabson #define MAX_ROM (1024 - sizeof(uint32_t) * 5) 6588e7cb59SHidetoshi Shimokawa #define CROM_END(cc) ((vm_offset_t)(cc)->stack[0].dir + MAX_ROM - 1) 6688e7cb59SHidetoshi Shimokawa 67b018dcd1SHidetoshi Shimokawa void 6803161bbcSDoug Rabson crom_init_context(struct crom_context *cc, uint32_t *p) 69b018dcd1SHidetoshi Shimokawa { 70b018dcd1SHidetoshi Shimokawa struct csrhdr *hdr; 71b018dcd1SHidetoshi Shimokawa 72b018dcd1SHidetoshi Shimokawa hdr = (struct csrhdr *)p; 7310d3ed64SHidetoshi Shimokawa if (hdr->info_len <= 1) { 7410d3ed64SHidetoshi Shimokawa /* minimum or invalid ROM */ 75b018dcd1SHidetoshi Shimokawa cc->depth = -1; 7610d3ed64SHidetoshi Shimokawa return; 77b018dcd1SHidetoshi Shimokawa } 78b018dcd1SHidetoshi Shimokawa p += 1 + hdr->info_len; 795e286c32SHidetoshi Shimokawa 805e286c32SHidetoshi Shimokawa /* check size of root directory */ 815e286c32SHidetoshi Shimokawa if (((struct csrdirectory *)p)->crc_len == 0) { 825e286c32SHidetoshi Shimokawa cc->depth = -1; 835e286c32SHidetoshi Shimokawa return; 845e286c32SHidetoshi Shimokawa } 85b018dcd1SHidetoshi Shimokawa cc->depth = 0; 86b018dcd1SHidetoshi Shimokawa cc->stack[0].dir = (struct csrdirectory *)p; 87b018dcd1SHidetoshi Shimokawa cc->stack[0].index = 0; 88b018dcd1SHidetoshi Shimokawa } 89b018dcd1SHidetoshi Shimokawa 90b018dcd1SHidetoshi Shimokawa struct csrreg * 91b018dcd1SHidetoshi Shimokawa crom_get(struct crom_context *cc) 92b018dcd1SHidetoshi Shimokawa { 93b018dcd1SHidetoshi Shimokawa struct crom_ptr *ptr; 94b018dcd1SHidetoshi Shimokawa 95b018dcd1SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 96b018dcd1SHidetoshi Shimokawa return (&ptr->dir->entry[ptr->index]); 97b018dcd1SHidetoshi Shimokawa } 98b018dcd1SHidetoshi Shimokawa 99b018dcd1SHidetoshi Shimokawa void 100b018dcd1SHidetoshi Shimokawa crom_next(struct crom_context *cc) 101b018dcd1SHidetoshi Shimokawa { 102b018dcd1SHidetoshi Shimokawa struct crom_ptr *ptr; 103b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 104b018dcd1SHidetoshi Shimokawa 105b018dcd1SHidetoshi Shimokawa if (cc->depth < 0) 106b018dcd1SHidetoshi Shimokawa return; 107b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 108b018dcd1SHidetoshi Shimokawa if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { 10988e7cb59SHidetoshi Shimokawa if (cc->depth >= CROM_MAX_DEPTH) { 110b018dcd1SHidetoshi Shimokawa printf("crom_next: too deep\n"); 111b018dcd1SHidetoshi Shimokawa goto again; 112b018dcd1SHidetoshi Shimokawa } 11388e7cb59SHidetoshi Shimokawa cc->depth ++; 11488e7cb59SHidetoshi Shimokawa 1157ddbf617SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 1167ddbf617SHidetoshi Shimokawa ptr->dir = (struct csrdirectory *) (reg + reg->val); 1177ddbf617SHidetoshi Shimokawa ptr->index = 0; 1187ddbf617SHidetoshi Shimokawa goto check; 119b018dcd1SHidetoshi Shimokawa } 120b018dcd1SHidetoshi Shimokawa again: 121b018dcd1SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 122b018dcd1SHidetoshi Shimokawa ptr->index ++; 1237ddbf617SHidetoshi Shimokawa check: 12488e7cb59SHidetoshi Shimokawa if (ptr->index < ptr->dir->crc_len && 12588e7cb59SHidetoshi Shimokawa (vm_offset_t)crom_get(cc) <= CROM_END(cc)) 126b018dcd1SHidetoshi Shimokawa return; 12788e7cb59SHidetoshi Shimokawa 12888e7cb59SHidetoshi Shimokawa if (ptr->index < ptr->dir->crc_len) 12988e7cb59SHidetoshi Shimokawa printf("crom_next: bound check failed\n"); 13088e7cb59SHidetoshi Shimokawa 131b018dcd1SHidetoshi Shimokawa if (cc->depth > 0) { 132b018dcd1SHidetoshi Shimokawa cc->depth--; 133b018dcd1SHidetoshi Shimokawa goto again; 134b018dcd1SHidetoshi Shimokawa } 135b018dcd1SHidetoshi Shimokawa /* no more data */ 136b018dcd1SHidetoshi Shimokawa cc->depth = -1; 137b018dcd1SHidetoshi Shimokawa } 138b018dcd1SHidetoshi Shimokawa 139b018dcd1SHidetoshi Shimokawa 140b018dcd1SHidetoshi Shimokawa struct csrreg * 14103161bbcSDoug Rabson crom_search_key(struct crom_context *cc, uint8_t key) 142b018dcd1SHidetoshi Shimokawa { 143b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 144b018dcd1SHidetoshi Shimokawa 145b018dcd1SHidetoshi Shimokawa while(cc->depth >= 0) { 146b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 147b018dcd1SHidetoshi Shimokawa if (reg->key == key) 148b018dcd1SHidetoshi Shimokawa return reg; 149b018dcd1SHidetoshi Shimokawa crom_next(cc); 150b018dcd1SHidetoshi Shimokawa } 151b018dcd1SHidetoshi Shimokawa return NULL; 152b018dcd1SHidetoshi Shimokawa } 153b018dcd1SHidetoshi Shimokawa 1545e286c32SHidetoshi Shimokawa int 15503161bbcSDoug Rabson crom_has_specver(uint32_t *p, uint32_t spec, uint32_t ver) 1565e286c32SHidetoshi Shimokawa { 1575e286c32SHidetoshi Shimokawa struct csrreg *reg; 1585e286c32SHidetoshi Shimokawa struct crom_context c, *cc; 1595e286c32SHidetoshi Shimokawa int state = 0; 1605e286c32SHidetoshi Shimokawa 1615e286c32SHidetoshi Shimokawa cc = &c; 1625e286c32SHidetoshi Shimokawa crom_init_context(cc, p); 1635e286c32SHidetoshi Shimokawa while(cc->depth >= 0) { 1645e286c32SHidetoshi Shimokawa reg = crom_get(cc); 1655e286c32SHidetoshi Shimokawa if (state == 0) { 1665e286c32SHidetoshi Shimokawa if (reg->key == CSRKEY_SPEC && reg->val == spec) 1675e286c32SHidetoshi Shimokawa state = 1; 1685e286c32SHidetoshi Shimokawa else 1695e286c32SHidetoshi Shimokawa state = 0; 1705e286c32SHidetoshi Shimokawa } else { 1715e286c32SHidetoshi Shimokawa if (reg->key == CSRKEY_VER && reg->val == ver) 1725e286c32SHidetoshi Shimokawa return 1; 1735e286c32SHidetoshi Shimokawa else 1745e286c32SHidetoshi Shimokawa state = 0; 1755e286c32SHidetoshi Shimokawa } 1765e286c32SHidetoshi Shimokawa crom_next(cc); 1775e286c32SHidetoshi Shimokawa } 1785e286c32SHidetoshi Shimokawa return 0; 1795e286c32SHidetoshi Shimokawa } 1805e286c32SHidetoshi Shimokawa 181b018dcd1SHidetoshi Shimokawa void 182b018dcd1SHidetoshi Shimokawa crom_parse_text(struct crom_context *cc, char *buf, int len) 183b018dcd1SHidetoshi Shimokawa { 184b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 185b018dcd1SHidetoshi Shimokawa struct csrtext *textleaf; 18603161bbcSDoug Rabson uint32_t *bp; 187b018dcd1SHidetoshi Shimokawa int i, qlen; 188b018dcd1SHidetoshi Shimokawa static char *nullstr = "(null)"; 189b018dcd1SHidetoshi Shimokawa 1905e286c32SHidetoshi Shimokawa if (cc->depth < 0) 1915e286c32SHidetoshi Shimokawa return; 1925e286c32SHidetoshi Shimokawa 193b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 19488e7cb59SHidetoshi Shimokawa if (reg->key != CROM_TEXTLEAF || 19588e7cb59SHidetoshi Shimokawa (vm_offset_t)(reg + reg->val) > CROM_END(cc)) { 196b018dcd1SHidetoshi Shimokawa strncpy(buf, nullstr, len); 197b018dcd1SHidetoshi Shimokawa return; 198b018dcd1SHidetoshi Shimokawa } 199b018dcd1SHidetoshi Shimokawa textleaf = (struct csrtext *)(reg + reg->val); 200b018dcd1SHidetoshi Shimokawa 20188e7cb59SHidetoshi Shimokawa if ((vm_offset_t)textleaf + textleaf->crc_len > CROM_END(cc)) { 20288e7cb59SHidetoshi Shimokawa strncpy(buf, nullstr, len); 20388e7cb59SHidetoshi Shimokawa return; 20488e7cb59SHidetoshi Shimokawa } 20588e7cb59SHidetoshi Shimokawa 206b018dcd1SHidetoshi Shimokawa /* XXX should check spec and type */ 207b018dcd1SHidetoshi Shimokawa 20803161bbcSDoug Rabson bp = (uint32_t *)&buf[0]; 209b018dcd1SHidetoshi Shimokawa qlen = textleaf->crc_len - 2; 210b018dcd1SHidetoshi Shimokawa if (len < qlen * 4) 211b018dcd1SHidetoshi Shimokawa qlen = len/4; 212b018dcd1SHidetoshi Shimokawa for (i = 0; i < qlen; i ++) 213b018dcd1SHidetoshi Shimokawa *bp++ = ntohl(textleaf->text[i]); 214b018dcd1SHidetoshi Shimokawa /* make sure to terminate the string */ 215b018dcd1SHidetoshi Shimokawa if (len <= qlen * 4) 216b018dcd1SHidetoshi Shimokawa buf[len - 1] = 0; 217b018dcd1SHidetoshi Shimokawa else 218b018dcd1SHidetoshi Shimokawa buf[qlen * 4] = 0; 219b018dcd1SHidetoshi Shimokawa } 220b018dcd1SHidetoshi Shimokawa 22103161bbcSDoug Rabson uint16_t 22203161bbcSDoug Rabson crom_crc(uint32_t *ptr, int len) 223b018dcd1SHidetoshi Shimokawa { 224b018dcd1SHidetoshi Shimokawa int i, shift; 22503161bbcSDoug Rabson uint32_t data, sum, crc = 0; 226b018dcd1SHidetoshi Shimokawa 227b018dcd1SHidetoshi Shimokawa for (i = 0; i < len; i++) { 228b018dcd1SHidetoshi Shimokawa data = ptr[i]; 229b018dcd1SHidetoshi Shimokawa for (shift = 28; shift >= 0; shift -= 4) { 230b018dcd1SHidetoshi Shimokawa sum = ((crc >> 12) ^ (data >> shift)) & 0xf; 231b018dcd1SHidetoshi Shimokawa crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 232b018dcd1SHidetoshi Shimokawa } 233b018dcd1SHidetoshi Shimokawa crc &= 0xffff; 234b018dcd1SHidetoshi Shimokawa } 23503161bbcSDoug Rabson return((uint16_t) crc); 236b018dcd1SHidetoshi Shimokawa } 237b018dcd1SHidetoshi Shimokawa 238b018dcd1SHidetoshi Shimokawa #ifndef _KERNEL 2395e286c32SHidetoshi Shimokawa static void 24003161bbcSDoug Rabson crom_desc_specver(uint32_t spec, uint32_t ver, char *buf, int len) 2415e286c32SHidetoshi Shimokawa { 2425e286c32SHidetoshi Shimokawa char *s = NULL; 2435e286c32SHidetoshi Shimokawa 2445e286c32SHidetoshi Shimokawa if (spec == CSRVAL_ANSIT10 || spec == 0) { 2455e286c32SHidetoshi Shimokawa switch (ver) { 2465e286c32SHidetoshi Shimokawa case CSRVAL_T10SBP2: 2475e286c32SHidetoshi Shimokawa s = "SBP-2"; 2485e286c32SHidetoshi Shimokawa break; 2495e286c32SHidetoshi Shimokawa default: 2505e286c32SHidetoshi Shimokawa if (spec != 0) 2515e286c32SHidetoshi Shimokawa s = "unknown ANSIT10"; 2525e286c32SHidetoshi Shimokawa } 2535e286c32SHidetoshi Shimokawa } 2545e286c32SHidetoshi Shimokawa if (spec == CSRVAL_1394TA || spec == 0) { 2555e286c32SHidetoshi Shimokawa switch (ver) { 2565e286c32SHidetoshi Shimokawa case CSR_PROTAVC: 2575e286c32SHidetoshi Shimokawa s = "AV/C"; 2585e286c32SHidetoshi Shimokawa break; 2595e286c32SHidetoshi Shimokawa case CSR_PROTCAL: 2605e286c32SHidetoshi Shimokawa s = "CAL"; 2615e286c32SHidetoshi Shimokawa break; 2625e286c32SHidetoshi Shimokawa case CSR_PROTEHS: 2635e286c32SHidetoshi Shimokawa s = "EHS"; 2645e286c32SHidetoshi Shimokawa break; 2655e286c32SHidetoshi Shimokawa case CSR_PROTHAVI: 2665e286c32SHidetoshi Shimokawa s = "HAVi"; 2675e286c32SHidetoshi Shimokawa break; 2685e286c32SHidetoshi Shimokawa case CSR_PROTCAM104: 2695e286c32SHidetoshi Shimokawa s = "1394 Cam 1.04"; 2705e286c32SHidetoshi Shimokawa break; 2715e286c32SHidetoshi Shimokawa case CSR_PROTCAM120: 2725e286c32SHidetoshi Shimokawa s = "1394 Cam 1.20"; 2735e286c32SHidetoshi Shimokawa break; 2745e286c32SHidetoshi Shimokawa case CSR_PROTCAM130: 2755e286c32SHidetoshi Shimokawa s = "1394 Cam 1.30"; 2765e286c32SHidetoshi Shimokawa break; 2775e286c32SHidetoshi Shimokawa case CSR_PROTDPP: 2785e286c32SHidetoshi Shimokawa s = "1394 Direct print"; 2795e286c32SHidetoshi Shimokawa break; 2805e286c32SHidetoshi Shimokawa case CSR_PROTIICP: 2815e286c32SHidetoshi Shimokawa s = "Industrial & Instrument"; 2825e286c32SHidetoshi Shimokawa break; 2835e286c32SHidetoshi Shimokawa default: 2845e286c32SHidetoshi Shimokawa if (spec != 0) 2855e286c32SHidetoshi Shimokawa s = "unknown 1394TA"; 2865e286c32SHidetoshi Shimokawa } 2875e286c32SHidetoshi Shimokawa } 2885e286c32SHidetoshi Shimokawa if (s != NULL) 2895e286c32SHidetoshi Shimokawa snprintf(buf, len, "%s", s); 2905e286c32SHidetoshi Shimokawa } 2915e286c32SHidetoshi Shimokawa 292b018dcd1SHidetoshi Shimokawa char * 293b018dcd1SHidetoshi Shimokawa crom_desc(struct crom_context *cc, char *buf, int len) 294b018dcd1SHidetoshi Shimokawa { 295b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 296b018dcd1SHidetoshi Shimokawa struct csrdirectory *dir; 297ce7bda46SHidetoshi Shimokawa char *desc; 29803161bbcSDoug Rabson uint16_t crc; 299b018dcd1SHidetoshi Shimokawa 300b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 301b018dcd1SHidetoshi Shimokawa switch (reg->key & CSRTYPE_MASK) { 302b018dcd1SHidetoshi Shimokawa case CSRTYPE_I: 3035e286c32SHidetoshi Shimokawa #if 0 3045e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "%d", reg->val); 3055e286c32SHidetoshi Shimokawa buf += strlen(buf); 3065e286c32SHidetoshi Shimokawa #else 3075e286c32SHidetoshi Shimokawa *buf = '\0'; 3085e286c32SHidetoshi Shimokawa #endif 309b018dcd1SHidetoshi Shimokawa break; 310b018dcd1SHidetoshi Shimokawa case CSRTYPE_C: 3115e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "offset=0x%04x(%d)", 3125e286c32SHidetoshi Shimokawa reg->val, reg->val); 3135e286c32SHidetoshi Shimokawa buf += strlen(buf); 314b018dcd1SHidetoshi Shimokawa break; 31577ee030bSHidetoshi Shimokawa case CSRTYPE_L: 31677ee030bSHidetoshi Shimokawa /* XXX fall through */ 317b018dcd1SHidetoshi Shimokawa case CSRTYPE_D: 318b018dcd1SHidetoshi Shimokawa dir = (struct csrdirectory *) (reg + reg->val); 31903161bbcSDoug Rabson crc = crom_crc((uint32_t *)&dir->entry[0], dir->crc_len); 3205e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "len=%d crc=0x%04x(%s) ", 3215e286c32SHidetoshi Shimokawa dir->crc_len, dir->crc, 3225e286c32SHidetoshi Shimokawa (crc == dir->crc) ? "OK" : "NG"); 3235e286c32SHidetoshi Shimokawa buf += strlen(buf); 324b018dcd1SHidetoshi Shimokawa } 325b018dcd1SHidetoshi Shimokawa switch (reg->key) { 326b018dcd1SHidetoshi Shimokawa case 0x03: 327b018dcd1SHidetoshi Shimokawa desc = "module_vendor_ID"; 328b018dcd1SHidetoshi Shimokawa break; 329b018dcd1SHidetoshi Shimokawa case 0x04: 330b018dcd1SHidetoshi Shimokawa desc = "hardware_version"; 331b018dcd1SHidetoshi Shimokawa break; 332b018dcd1SHidetoshi Shimokawa case 0x0c: 333b018dcd1SHidetoshi Shimokawa desc = "node_capabilities"; 334b018dcd1SHidetoshi Shimokawa break; 335b018dcd1SHidetoshi Shimokawa case 0x12: 336b018dcd1SHidetoshi Shimokawa desc = "unit_spec_ID"; 337b018dcd1SHidetoshi Shimokawa break; 338b018dcd1SHidetoshi Shimokawa case 0x13: 339b018dcd1SHidetoshi Shimokawa desc = "unit_sw_version"; 3405e286c32SHidetoshi Shimokawa crom_desc_specver(0, reg->val, buf, len); 341b018dcd1SHidetoshi Shimokawa break; 342b018dcd1SHidetoshi Shimokawa case 0x14: 343b018dcd1SHidetoshi Shimokawa desc = "logical_unit_number"; 344b018dcd1SHidetoshi Shimokawa break; 345b018dcd1SHidetoshi Shimokawa case 0x17: 346b018dcd1SHidetoshi Shimokawa desc = "model_ID"; 347b018dcd1SHidetoshi Shimokawa break; 348b018dcd1SHidetoshi Shimokawa case 0x38: 349b018dcd1SHidetoshi Shimokawa desc = "command_set_spec_ID"; 350b018dcd1SHidetoshi Shimokawa break; 351b018dcd1SHidetoshi Shimokawa case 0x39: 352b018dcd1SHidetoshi Shimokawa desc = "command_set"; 353b018dcd1SHidetoshi Shimokawa break; 354b018dcd1SHidetoshi Shimokawa case 0x3a: 355b018dcd1SHidetoshi Shimokawa desc = "unit_characteristics"; 356b018dcd1SHidetoshi Shimokawa break; 357b018dcd1SHidetoshi Shimokawa case 0x3b: 358b018dcd1SHidetoshi Shimokawa desc = "command_set_revision"; 359b018dcd1SHidetoshi Shimokawa break; 360b018dcd1SHidetoshi Shimokawa case 0x3c: 361b018dcd1SHidetoshi Shimokawa desc = "firmware_revision"; 362b018dcd1SHidetoshi Shimokawa break; 363b018dcd1SHidetoshi Shimokawa case 0x3d: 364b018dcd1SHidetoshi Shimokawa desc = "reconnect_timeout"; 365b018dcd1SHidetoshi Shimokawa break; 366b018dcd1SHidetoshi Shimokawa case 0x54: 367b018dcd1SHidetoshi Shimokawa desc = "management_agent"; 368b018dcd1SHidetoshi Shimokawa break; 369b018dcd1SHidetoshi Shimokawa case 0x81: 370b018dcd1SHidetoshi Shimokawa desc = "text_leaf"; 37177ee030bSHidetoshi Shimokawa crom_parse_text(cc, buf + strlen(buf), len); 372b018dcd1SHidetoshi Shimokawa break; 373b018dcd1SHidetoshi Shimokawa case 0xd1: 374b018dcd1SHidetoshi Shimokawa desc = "unit_directory"; 375b018dcd1SHidetoshi Shimokawa break; 376b018dcd1SHidetoshi Shimokawa case 0xd4: 377b018dcd1SHidetoshi Shimokawa desc = "logical_unit_directory"; 378b018dcd1SHidetoshi Shimokawa break; 379b018dcd1SHidetoshi Shimokawa default: 380b018dcd1SHidetoshi Shimokawa desc = "unknown"; 381b018dcd1SHidetoshi Shimokawa } 382b018dcd1SHidetoshi Shimokawa return desc; 383b018dcd1SHidetoshi Shimokawa } 384b018dcd1SHidetoshi Shimokawa #endif 38577ee030bSHidetoshi Shimokawa 38677ee030bSHidetoshi Shimokawa #if defined(_KERNEL) || defined(TEST) 38777ee030bSHidetoshi Shimokawa 38877ee030bSHidetoshi Shimokawa int 38903161bbcSDoug Rabson crom_add_quad(struct crom_chunk *chunk, uint32_t entry) 39077ee030bSHidetoshi Shimokawa { 39177ee030bSHidetoshi Shimokawa int index; 39277ee030bSHidetoshi Shimokawa 39377ee030bSHidetoshi Shimokawa index = chunk->data.crc_len; 39477ee030bSHidetoshi Shimokawa if (index >= CROM_MAX_CHUNK_LEN - 1) { 39577ee030bSHidetoshi Shimokawa printf("too large chunk %d\n", index); 39677ee030bSHidetoshi Shimokawa return(-1); 39777ee030bSHidetoshi Shimokawa } 39877ee030bSHidetoshi Shimokawa chunk->data.buf[index] = entry; 39977ee030bSHidetoshi Shimokawa chunk->data.crc_len++; 40077ee030bSHidetoshi Shimokawa return(index); 40177ee030bSHidetoshi Shimokawa } 40277ee030bSHidetoshi Shimokawa 40377ee030bSHidetoshi Shimokawa int 40477ee030bSHidetoshi Shimokawa crom_add_entry(struct crom_chunk *chunk, int key, int val) 40577ee030bSHidetoshi Shimokawa { 40677ee030bSHidetoshi Shimokawa struct csrreg *reg; 40703161bbcSDoug Rabson uint32_t i; 40877ee030bSHidetoshi Shimokawa 40977ee030bSHidetoshi Shimokawa reg = (struct csrreg *)&i; 41077ee030bSHidetoshi Shimokawa reg->key = key; 41177ee030bSHidetoshi Shimokawa reg->val = val; 41203161bbcSDoug Rabson return(crom_add_quad(chunk, (uint32_t) i)); 41377ee030bSHidetoshi Shimokawa } 41477ee030bSHidetoshi Shimokawa 41577ee030bSHidetoshi Shimokawa int 41677ee030bSHidetoshi Shimokawa crom_add_chunk(struct crom_src *src, struct crom_chunk *parent, 41777ee030bSHidetoshi Shimokawa struct crom_chunk *child, int key) 41877ee030bSHidetoshi Shimokawa { 41977ee030bSHidetoshi Shimokawa int index; 42077ee030bSHidetoshi Shimokawa 42177ee030bSHidetoshi Shimokawa if (parent == NULL) { 42277ee030bSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 42377ee030bSHidetoshi Shimokawa return(0); 42477ee030bSHidetoshi Shimokawa } 42577ee030bSHidetoshi Shimokawa 42677ee030bSHidetoshi Shimokawa index = crom_add_entry(parent, key, 0); 42777ee030bSHidetoshi Shimokawa if (index < 0) { 42877ee030bSHidetoshi Shimokawa return(-1); 42977ee030bSHidetoshi Shimokawa } 43077ee030bSHidetoshi Shimokawa child->ref_chunk = parent; 43177ee030bSHidetoshi Shimokawa child->ref_index = index; 43277ee030bSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 43377ee030bSHidetoshi Shimokawa return(index); 43477ee030bSHidetoshi Shimokawa } 43577ee030bSHidetoshi Shimokawa 436c4778b5dSHidetoshi Shimokawa #define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext)) 43777ee030bSHidetoshi Shimokawa int 43877ee030bSHidetoshi Shimokawa crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent, 43977ee030bSHidetoshi Shimokawa struct crom_chunk *chunk, char *buf) 44077ee030bSHidetoshi Shimokawa { 44177ee030bSHidetoshi Shimokawa struct csrtext *tl; 44203161bbcSDoug Rabson uint32_t *p; 44377ee030bSHidetoshi Shimokawa int len, i; 444c4778b5dSHidetoshi Shimokawa char t[MAX_TEXT]; 44577ee030bSHidetoshi Shimokawa 44677ee030bSHidetoshi Shimokawa len = strlen(buf); 44777ee030bSHidetoshi Shimokawa if (len > MAX_TEXT) { 44810d3ed64SHidetoshi Shimokawa #if defined(__DragonFly__) || __FreeBSD_version < 500000 44977ee030bSHidetoshi Shimokawa printf("text(%d) trancated to %d.\n", len, MAX_TEXT); 45077ee030bSHidetoshi Shimokawa #else 45177ee030bSHidetoshi Shimokawa printf("text(%d) trancated to %td.\n", len, MAX_TEXT); 45277ee030bSHidetoshi Shimokawa #endif 45377ee030bSHidetoshi Shimokawa len = MAX_TEXT; 45477ee030bSHidetoshi Shimokawa } 45577ee030bSHidetoshi Shimokawa 45677ee030bSHidetoshi Shimokawa tl = (struct csrtext *) &chunk->data; 45703161bbcSDoug Rabson tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(uint32_t)); 45877ee030bSHidetoshi Shimokawa tl->spec_id = 0; 45977ee030bSHidetoshi Shimokawa tl->spec_type = 0; 46077ee030bSHidetoshi Shimokawa tl->lang_id = 0; 46103161bbcSDoug Rabson bzero(&t[0], roundup2(len, sizeof(uint32_t))); 462c4778b5dSHidetoshi Shimokawa bcopy(buf, &t[0], len); 46303161bbcSDoug Rabson p = (uint32_t *)&t[0]; 46403161bbcSDoug Rabson for (i = 0; i < howmany(len, sizeof(uint32_t)); i ++) 46577ee030bSHidetoshi Shimokawa tl->text[i] = ntohl(*p++); 46677ee030bSHidetoshi Shimokawa return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF)); 46777ee030bSHidetoshi Shimokawa } 46877ee030bSHidetoshi Shimokawa 46977ee030bSHidetoshi Shimokawa static int 47003161bbcSDoug Rabson crom_copy(uint32_t *src, uint32_t *dst, int *offset, int len, int maxlen) 47177ee030bSHidetoshi Shimokawa { 47277ee030bSHidetoshi Shimokawa if (*offset + len > maxlen) { 47377ee030bSHidetoshi Shimokawa printf("Config. ROM is too large for the buffer\n"); 47477ee030bSHidetoshi Shimokawa return(-1); 47577ee030bSHidetoshi Shimokawa } 47603161bbcSDoug Rabson bcopy(src, (char *)(dst + *offset), len * sizeof(uint32_t)); 47777ee030bSHidetoshi Shimokawa *offset += len; 47877ee030bSHidetoshi Shimokawa return(0); 47977ee030bSHidetoshi Shimokawa } 48077ee030bSHidetoshi Shimokawa 48177ee030bSHidetoshi Shimokawa int 48203161bbcSDoug Rabson crom_load(struct crom_src *src, uint32_t *buf, int maxlen) 48377ee030bSHidetoshi Shimokawa { 48477ee030bSHidetoshi Shimokawa struct crom_chunk *chunk, *parent; 48577ee030bSHidetoshi Shimokawa struct csrhdr *hdr; 486b83977f0SHidetoshi Shimokawa #ifdef _KERNEL 48703161bbcSDoug Rabson uint32_t *ptr; 488b83977f0SHidetoshi Shimokawa int i; 48977ee030bSHidetoshi Shimokawa #endif 49077ee030bSHidetoshi Shimokawa int count, offset; 49177ee030bSHidetoshi Shimokawa int len; 49277ee030bSHidetoshi Shimokawa 49377ee030bSHidetoshi Shimokawa offset = 0; 49477ee030bSHidetoshi Shimokawa /* Determine offset */ 49577ee030bSHidetoshi Shimokawa STAILQ_FOREACH(chunk, &src->chunk_list, link) { 49677ee030bSHidetoshi Shimokawa chunk->offset = offset; 49777ee030bSHidetoshi Shimokawa /* Assume the offset of the parent is already known */ 49877ee030bSHidetoshi Shimokawa parent = chunk->ref_chunk; 49977ee030bSHidetoshi Shimokawa if (parent != NULL) { 50077ee030bSHidetoshi Shimokawa struct csrreg *reg; 50177ee030bSHidetoshi Shimokawa reg = (struct csrreg *) 50277ee030bSHidetoshi Shimokawa &parent->data.buf[chunk->ref_index]; 50377ee030bSHidetoshi Shimokawa reg->val = offset - 50477ee030bSHidetoshi Shimokawa (parent->offset + 1 + chunk->ref_index); 50577ee030bSHidetoshi Shimokawa } 50677ee030bSHidetoshi Shimokawa offset += 1 + chunk->data.crc_len; 50777ee030bSHidetoshi Shimokawa } 50877ee030bSHidetoshi Shimokawa 50977ee030bSHidetoshi Shimokawa /* Calculate CRC and dump to the buffer */ 51077ee030bSHidetoshi Shimokawa len = 1 + src->hdr.info_len; 51177ee030bSHidetoshi Shimokawa count = 0; 51203161bbcSDoug Rabson if (crom_copy((uint32_t *)&src->hdr, buf, &count, len, maxlen) < 0) 51377ee030bSHidetoshi Shimokawa return(-1); 51477ee030bSHidetoshi Shimokawa STAILQ_FOREACH(chunk, &src->chunk_list, link) { 51577ee030bSHidetoshi Shimokawa chunk->data.crc = 51677ee030bSHidetoshi Shimokawa crom_crc(&chunk->data.buf[0], chunk->data.crc_len); 51777ee030bSHidetoshi Shimokawa 51877ee030bSHidetoshi Shimokawa len = 1 + chunk->data.crc_len; 51903161bbcSDoug Rabson if (crom_copy((uint32_t *)&chunk->data, buf, 52077ee030bSHidetoshi Shimokawa &count, len, maxlen) < 0) 52177ee030bSHidetoshi Shimokawa return(-1); 52277ee030bSHidetoshi Shimokawa } 52377ee030bSHidetoshi Shimokawa hdr = (struct csrhdr *)buf; 52477ee030bSHidetoshi Shimokawa hdr->crc_len = count - 1; 525b83977f0SHidetoshi Shimokawa hdr->crc = crom_crc(&buf[1], hdr->crc_len); 52677ee030bSHidetoshi Shimokawa 527b83977f0SHidetoshi Shimokawa #ifdef _KERNEL 52877ee030bSHidetoshi Shimokawa /* byte swap */ 52977ee030bSHidetoshi Shimokawa ptr = buf; 53077ee030bSHidetoshi Shimokawa for (i = 0; i < count; i ++) { 53177ee030bSHidetoshi Shimokawa *ptr = htonl(*ptr); 53277ee030bSHidetoshi Shimokawa ptr++; 53377ee030bSHidetoshi Shimokawa } 53477ee030bSHidetoshi Shimokawa #endif 53577ee030bSHidetoshi Shimokawa 53677ee030bSHidetoshi Shimokawa return(count); 53777ee030bSHidetoshi Shimokawa } 53877ee030bSHidetoshi Shimokawa #endif 53977ee030bSHidetoshi Shimokawa 54077ee030bSHidetoshi Shimokawa #ifdef TEST 54177ee030bSHidetoshi Shimokawa int 54277ee030bSHidetoshi Shimokawa main () { 54377ee030bSHidetoshi Shimokawa struct crom_src src; 54477ee030bSHidetoshi Shimokawa struct crom_chunk root,unit1,unit2,unit3; 54577ee030bSHidetoshi Shimokawa struct crom_chunk text1,text2,text3,text4,text5,text6,text7; 54603161bbcSDoug Rabson uint32_t buf[256], *p; 54777ee030bSHidetoshi Shimokawa int i; 54877ee030bSHidetoshi Shimokawa 54977ee030bSHidetoshi Shimokawa bzero(&src, sizeof(src)); 55077ee030bSHidetoshi Shimokawa bzero(&root, sizeof(root)); 55177ee030bSHidetoshi Shimokawa bzero(&unit1, sizeof(unit1)); 55277ee030bSHidetoshi Shimokawa bzero(&unit2, sizeof(unit2)); 55377ee030bSHidetoshi Shimokawa bzero(&unit3, sizeof(unit3)); 55477ee030bSHidetoshi Shimokawa bzero(&text1, sizeof(text1)); 55577ee030bSHidetoshi Shimokawa bzero(&text2, sizeof(text2)); 55677ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text3)); 55777ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text4)); 55877ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text5)); 55977ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text6)); 56077ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text7)); 56177ee030bSHidetoshi Shimokawa bzero(buf, sizeof(buf)); 56277ee030bSHidetoshi Shimokawa 56377ee030bSHidetoshi Shimokawa /* BUS info sample */ 56477ee030bSHidetoshi Shimokawa src.hdr.info_len = 4; 56577ee030bSHidetoshi Shimokawa src.businfo.bus_name = CSR_BUS_NAME_IEEE1394; 56677ee030bSHidetoshi Shimokawa src.businfo.eui64.hi = 0x11223344; 56777ee030bSHidetoshi Shimokawa src.businfo.eui64.lo = 0x55667788; 56877ee030bSHidetoshi Shimokawa src.businfo.link_spd = FWSPD_S400; 56977ee030bSHidetoshi Shimokawa src.businfo.generation = 0; 57077ee030bSHidetoshi Shimokawa src.businfo.max_rom = MAXROM_4; 57177ee030bSHidetoshi Shimokawa src.businfo.max_rec = 10; 57277ee030bSHidetoshi Shimokawa src.businfo.cyc_clk_acc = 100; 57377ee030bSHidetoshi Shimokawa src.businfo.pmc = 0; 57477ee030bSHidetoshi Shimokawa src.businfo.bmc = 1; 57577ee030bSHidetoshi Shimokawa src.businfo.isc = 1; 57677ee030bSHidetoshi Shimokawa src.businfo.cmc = 1; 57777ee030bSHidetoshi Shimokawa src.businfo.irmc = 1; 57877ee030bSHidetoshi Shimokawa STAILQ_INIT(&src.chunk_list); 57977ee030bSHidetoshi Shimokawa 58077ee030bSHidetoshi Shimokawa /* Root directory */ 58177ee030bSHidetoshi Shimokawa crom_add_chunk(&src, NULL, &root, 0); 58277ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_NCAP, 0x123456); 58377ee030bSHidetoshi Shimokawa /* private company_id */ 58477ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48); 58577ee030bSHidetoshi Shimokawa 58610d3ed64SHidetoshi Shimokawa #ifdef __DragonFly__ 58710d3ed64SHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text1, "DragonFly"); 58810d3ed64SHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_HW, __DragonFly_cc_version); 58910d3ed64SHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text2, "DragonFly-1"); 59010d3ed64SHidetoshi Shimokawa #else 59177ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text1, "FreeBSD"); 59277ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version); 59377ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text2, "FreeBSD-5"); 59410d3ed64SHidetoshi Shimokawa #endif 59577ee030bSHidetoshi Shimokawa 59677ee030bSHidetoshi Shimokawa /* SBP unit directory */ 59777ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit1, CROM_UDIR); 59877ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10); 59977ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2); 60077ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); 60177ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI); 60277ee030bSHidetoshi Shimokawa /* management_agent */ 60377ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CROM_MGM, 0x1000); 60477ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8); 60577ee030bSHidetoshi Shimokawa /* Device type and LUN */ 60677ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CROM_LUN, 0); 60777ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_MODEL, 1); 60877ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit1, &text3, "scsi_target"); 60977ee030bSHidetoshi Shimokawa 61077ee030bSHidetoshi Shimokawa /* RFC2734 IPv4 over IEEE1394 */ 61177ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit2, CROM_UDIR); 61277ee030bSHidetoshi Shimokawa crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF); 61377ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit2, &text4, "IANA"); 61477ee030bSHidetoshi Shimokawa crom_add_entry(&unit2, CSRKEY_VER, 1); 61577ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit2, &text5, "IPv4"); 61677ee030bSHidetoshi Shimokawa 61777ee030bSHidetoshi Shimokawa /* RFC3146 IPv6 over IEEE1394 */ 61877ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit3, CROM_UDIR); 61977ee030bSHidetoshi Shimokawa crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF); 62077ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit3, &text6, "IANA"); 62177ee030bSHidetoshi Shimokawa crom_add_entry(&unit3, CSRKEY_VER, 2); 62277ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit3, &text7, "IPv6"); 62377ee030bSHidetoshi Shimokawa 62477ee030bSHidetoshi Shimokawa crom_load(&src, buf, 256); 62577ee030bSHidetoshi Shimokawa p = buf; 62677ee030bSHidetoshi Shimokawa #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" 62777ee030bSHidetoshi Shimokawa for (i = 0; i < 256/8; i ++) { 62877ee030bSHidetoshi Shimokawa printf(DUMP_FORMAT, 62977ee030bSHidetoshi Shimokawa p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 63077ee030bSHidetoshi Shimokawa p += 8; 63177ee030bSHidetoshi Shimokawa } 63277ee030bSHidetoshi Shimokawa return(0); 63377ee030bSHidetoshi Shimokawa } 63477ee030bSHidetoshi Shimokawa #endif 635