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 55b018dcd1SHidetoshi Shimokawa void 56b018dcd1SHidetoshi Shimokawa crom_init_context(struct crom_context *cc, u_int32_t *p) 57b018dcd1SHidetoshi Shimokawa { 58b018dcd1SHidetoshi Shimokawa struct csrhdr *hdr; 59b018dcd1SHidetoshi Shimokawa 60b018dcd1SHidetoshi Shimokawa hdr = (struct csrhdr *)p; 61b018dcd1SHidetoshi Shimokawa if (hdr->info_len == 1) { 62b018dcd1SHidetoshi Shimokawa /* minimum ROM */ 63b018dcd1SHidetoshi Shimokawa cc->depth = -1; 64b018dcd1SHidetoshi Shimokawa } 65b018dcd1SHidetoshi Shimokawa p += 1 + hdr->info_len; 665e286c32SHidetoshi Shimokawa 675e286c32SHidetoshi Shimokawa /* check size of root directory */ 685e286c32SHidetoshi Shimokawa if (((struct csrdirectory *)p)->crc_len == 0) { 695e286c32SHidetoshi Shimokawa cc->depth = -1; 705e286c32SHidetoshi Shimokawa return; 715e286c32SHidetoshi Shimokawa } 72b018dcd1SHidetoshi Shimokawa cc->depth = 0; 73b018dcd1SHidetoshi Shimokawa cc->stack[0].dir = (struct csrdirectory *)p; 74b018dcd1SHidetoshi Shimokawa cc->stack[0].index = 0; 75b018dcd1SHidetoshi Shimokawa } 76b018dcd1SHidetoshi Shimokawa 77b018dcd1SHidetoshi Shimokawa struct csrreg * 78b018dcd1SHidetoshi Shimokawa crom_get(struct crom_context *cc) 79b018dcd1SHidetoshi Shimokawa { 80b018dcd1SHidetoshi Shimokawa struct crom_ptr *ptr; 81b018dcd1SHidetoshi Shimokawa 82b018dcd1SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 83b018dcd1SHidetoshi Shimokawa return (&ptr->dir->entry[ptr->index]); 84b018dcd1SHidetoshi Shimokawa } 85b018dcd1SHidetoshi Shimokawa 86b018dcd1SHidetoshi Shimokawa void 87b018dcd1SHidetoshi Shimokawa crom_next(struct crom_context *cc) 88b018dcd1SHidetoshi Shimokawa { 89b018dcd1SHidetoshi Shimokawa struct crom_ptr *ptr; 90b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 91b018dcd1SHidetoshi Shimokawa 92b018dcd1SHidetoshi Shimokawa if (cc->depth < 0) 93b018dcd1SHidetoshi Shimokawa return; 94b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 95b018dcd1SHidetoshi Shimokawa if ((reg->key & CSRTYPE_MASK) == CSRTYPE_D) { 96b018dcd1SHidetoshi Shimokawa cc->depth ++; 97b018dcd1SHidetoshi Shimokawa if (cc->depth > CROM_MAX_DEPTH) { 98b018dcd1SHidetoshi Shimokawa printf("crom_next: too deep\n"); 99b018dcd1SHidetoshi Shimokawa cc->depth --; 100b018dcd1SHidetoshi Shimokawa goto again; 101b018dcd1SHidetoshi Shimokawa } 1027ddbf617SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 1037ddbf617SHidetoshi Shimokawa ptr->dir = (struct csrdirectory *) (reg + reg->val); 1047ddbf617SHidetoshi Shimokawa ptr->index = 0; 1057ddbf617SHidetoshi Shimokawa goto check; 106b018dcd1SHidetoshi Shimokawa } 107b018dcd1SHidetoshi Shimokawa again: 108b018dcd1SHidetoshi Shimokawa ptr = &cc->stack[cc->depth]; 109b018dcd1SHidetoshi Shimokawa ptr->index ++; 1107ddbf617SHidetoshi Shimokawa check: 111b018dcd1SHidetoshi Shimokawa if (ptr->index < ptr->dir->crc_len) 112b018dcd1SHidetoshi Shimokawa return; 113b018dcd1SHidetoshi Shimokawa if (cc->depth > 0) { 114b018dcd1SHidetoshi Shimokawa cc->depth--; 115b018dcd1SHidetoshi Shimokawa goto again; 116b018dcd1SHidetoshi Shimokawa } 117b018dcd1SHidetoshi Shimokawa /* no more data */ 118b018dcd1SHidetoshi Shimokawa cc->depth = -1; 119b018dcd1SHidetoshi Shimokawa } 120b018dcd1SHidetoshi Shimokawa 121b018dcd1SHidetoshi Shimokawa 122b018dcd1SHidetoshi Shimokawa struct csrreg * 123b018dcd1SHidetoshi Shimokawa crom_search_key(struct crom_context *cc, u_int8_t key) 124b018dcd1SHidetoshi Shimokawa { 125b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 126b018dcd1SHidetoshi Shimokawa 127b018dcd1SHidetoshi Shimokawa while(cc->depth >= 0) { 128b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 129b018dcd1SHidetoshi Shimokawa if (reg->key == key) 130b018dcd1SHidetoshi Shimokawa return reg; 131b018dcd1SHidetoshi Shimokawa crom_next(cc); 132b018dcd1SHidetoshi Shimokawa } 133b018dcd1SHidetoshi Shimokawa return NULL; 134b018dcd1SHidetoshi Shimokawa } 135b018dcd1SHidetoshi Shimokawa 1365e286c32SHidetoshi Shimokawa int 1375e286c32SHidetoshi Shimokawa crom_has_specver(u_int32_t *p, u_int32_t spec, u_int32_t ver) 1385e286c32SHidetoshi Shimokawa { 1395e286c32SHidetoshi Shimokawa struct csrreg *reg; 1405e286c32SHidetoshi Shimokawa struct crom_context c, *cc; 1415e286c32SHidetoshi Shimokawa int state = 0; 1425e286c32SHidetoshi Shimokawa 1435e286c32SHidetoshi Shimokawa cc = &c; 1445e286c32SHidetoshi Shimokawa crom_init_context(cc, p); 1455e286c32SHidetoshi Shimokawa while(cc->depth >= 0) { 1465e286c32SHidetoshi Shimokawa reg = crom_get(cc); 1475e286c32SHidetoshi Shimokawa if (state == 0) { 1485e286c32SHidetoshi Shimokawa if (reg->key == CSRKEY_SPEC && reg->val == spec) 1495e286c32SHidetoshi Shimokawa state = 1; 1505e286c32SHidetoshi Shimokawa else 1515e286c32SHidetoshi Shimokawa state = 0; 1525e286c32SHidetoshi Shimokawa } else { 1535e286c32SHidetoshi Shimokawa if (reg->key == CSRKEY_VER && reg->val == ver) 1545e286c32SHidetoshi Shimokawa return 1; 1555e286c32SHidetoshi Shimokawa else 1565e286c32SHidetoshi Shimokawa state = 0; 1575e286c32SHidetoshi Shimokawa } 1585e286c32SHidetoshi Shimokawa crom_next(cc); 1595e286c32SHidetoshi Shimokawa } 1605e286c32SHidetoshi Shimokawa return 0; 1615e286c32SHidetoshi Shimokawa } 1625e286c32SHidetoshi Shimokawa 163b018dcd1SHidetoshi Shimokawa void 164b018dcd1SHidetoshi Shimokawa crom_parse_text(struct crom_context *cc, char *buf, int len) 165b018dcd1SHidetoshi Shimokawa { 166b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 167b018dcd1SHidetoshi Shimokawa struct csrtext *textleaf; 168b018dcd1SHidetoshi Shimokawa u_int32_t *bp; 169b018dcd1SHidetoshi Shimokawa int i, qlen; 170b018dcd1SHidetoshi Shimokawa static char *nullstr = "(null)"; 171b018dcd1SHidetoshi Shimokawa 1725e286c32SHidetoshi Shimokawa if (cc->depth < 0) 1735e286c32SHidetoshi Shimokawa return; 1745e286c32SHidetoshi Shimokawa 175b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 176b018dcd1SHidetoshi Shimokawa if (reg->key != CROM_TEXTLEAF) { 177b018dcd1SHidetoshi Shimokawa strncpy(buf, nullstr, len); 178b018dcd1SHidetoshi Shimokawa return; 179b018dcd1SHidetoshi Shimokawa } 180b018dcd1SHidetoshi Shimokawa textleaf = (struct csrtext *)(reg + reg->val); 181b018dcd1SHidetoshi Shimokawa 182b018dcd1SHidetoshi Shimokawa /* XXX should check spec and type */ 183b018dcd1SHidetoshi Shimokawa 184b018dcd1SHidetoshi Shimokawa bp = (u_int32_t *)&buf[0]; 185b018dcd1SHidetoshi Shimokawa qlen = textleaf->crc_len - 2; 186b018dcd1SHidetoshi Shimokawa if (len < qlen * 4) 187b018dcd1SHidetoshi Shimokawa qlen = len/4; 188b018dcd1SHidetoshi Shimokawa for (i = 0; i < qlen; i ++) 189b018dcd1SHidetoshi Shimokawa *bp++ = ntohl(textleaf->text[i]); 190b018dcd1SHidetoshi Shimokawa /* make sure to terminate the string */ 191b018dcd1SHidetoshi Shimokawa if (len <= qlen * 4) 192b018dcd1SHidetoshi Shimokawa buf[len - 1] = 0; 193b018dcd1SHidetoshi Shimokawa else 194b018dcd1SHidetoshi Shimokawa buf[qlen * 4] = 0; 195b018dcd1SHidetoshi Shimokawa } 196b018dcd1SHidetoshi Shimokawa 197b018dcd1SHidetoshi Shimokawa u_int16_t 198b018dcd1SHidetoshi Shimokawa crom_crc(u_int32_t *ptr, int len) 199b018dcd1SHidetoshi Shimokawa { 200b018dcd1SHidetoshi Shimokawa int i, shift; 201b018dcd1SHidetoshi Shimokawa u_int32_t data, sum, crc = 0; 202b018dcd1SHidetoshi Shimokawa 203b018dcd1SHidetoshi Shimokawa for (i = 0; i < len; i++) { 204b018dcd1SHidetoshi Shimokawa data = ptr[i]; 205b018dcd1SHidetoshi Shimokawa for (shift = 28; shift >= 0; shift -= 4) { 206b018dcd1SHidetoshi Shimokawa sum = ((crc >> 12) ^ (data >> shift)) & 0xf; 207b018dcd1SHidetoshi Shimokawa crc = (crc << 4) ^ (sum << 12) ^ (sum << 5) ^ sum; 208b018dcd1SHidetoshi Shimokawa } 209b018dcd1SHidetoshi Shimokawa crc &= 0xffff; 210b018dcd1SHidetoshi Shimokawa } 211b018dcd1SHidetoshi Shimokawa return((u_int16_t) crc); 212b018dcd1SHidetoshi Shimokawa } 213b018dcd1SHidetoshi Shimokawa 214b018dcd1SHidetoshi Shimokawa #ifndef _KERNEL 2155e286c32SHidetoshi Shimokawa static void 2165e286c32SHidetoshi Shimokawa crom_desc_specver(u_int32_t spec, u_int32_t ver, char *buf, int len) 2175e286c32SHidetoshi Shimokawa { 2185e286c32SHidetoshi Shimokawa char *s = NULL; 2195e286c32SHidetoshi Shimokawa 2205e286c32SHidetoshi Shimokawa if (spec == CSRVAL_ANSIT10 || spec == 0) { 2215e286c32SHidetoshi Shimokawa switch (ver) { 2225e286c32SHidetoshi Shimokawa case CSRVAL_T10SBP2: 2235e286c32SHidetoshi Shimokawa s = "SBP-2"; 2245e286c32SHidetoshi Shimokawa break; 2255e286c32SHidetoshi Shimokawa default: 2265e286c32SHidetoshi Shimokawa if (spec != 0) 2275e286c32SHidetoshi Shimokawa s = "unknown ANSIT10"; 2285e286c32SHidetoshi Shimokawa } 2295e286c32SHidetoshi Shimokawa } 2305e286c32SHidetoshi Shimokawa if (spec == CSRVAL_1394TA || spec == 0) { 2315e286c32SHidetoshi Shimokawa switch (ver) { 2325e286c32SHidetoshi Shimokawa case CSR_PROTAVC: 2335e286c32SHidetoshi Shimokawa s = "AV/C"; 2345e286c32SHidetoshi Shimokawa break; 2355e286c32SHidetoshi Shimokawa case CSR_PROTCAL: 2365e286c32SHidetoshi Shimokawa s = "CAL"; 2375e286c32SHidetoshi Shimokawa break; 2385e286c32SHidetoshi Shimokawa case CSR_PROTEHS: 2395e286c32SHidetoshi Shimokawa s = "EHS"; 2405e286c32SHidetoshi Shimokawa break; 2415e286c32SHidetoshi Shimokawa case CSR_PROTHAVI: 2425e286c32SHidetoshi Shimokawa s = "HAVi"; 2435e286c32SHidetoshi Shimokawa break; 2445e286c32SHidetoshi Shimokawa case CSR_PROTCAM104: 2455e286c32SHidetoshi Shimokawa s = "1394 Cam 1.04"; 2465e286c32SHidetoshi Shimokawa break; 2475e286c32SHidetoshi Shimokawa case CSR_PROTCAM120: 2485e286c32SHidetoshi Shimokawa s = "1394 Cam 1.20"; 2495e286c32SHidetoshi Shimokawa break; 2505e286c32SHidetoshi Shimokawa case CSR_PROTCAM130: 2515e286c32SHidetoshi Shimokawa s = "1394 Cam 1.30"; 2525e286c32SHidetoshi Shimokawa break; 2535e286c32SHidetoshi Shimokawa case CSR_PROTDPP: 2545e286c32SHidetoshi Shimokawa s = "1394 Direct print"; 2555e286c32SHidetoshi Shimokawa break; 2565e286c32SHidetoshi Shimokawa case CSR_PROTIICP: 2575e286c32SHidetoshi Shimokawa s = "Industrial & Instrument"; 2585e286c32SHidetoshi Shimokawa break; 2595e286c32SHidetoshi Shimokawa default: 2605e286c32SHidetoshi Shimokawa if (spec != 0) 2615e286c32SHidetoshi Shimokawa s = "unknown 1394TA"; 2625e286c32SHidetoshi Shimokawa } 2635e286c32SHidetoshi Shimokawa } 2645e286c32SHidetoshi Shimokawa if (s != NULL) 2655e286c32SHidetoshi Shimokawa snprintf(buf, len, "%s", s); 2665e286c32SHidetoshi Shimokawa } 2675e286c32SHidetoshi Shimokawa 268b018dcd1SHidetoshi Shimokawa char * 269b018dcd1SHidetoshi Shimokawa crom_desc(struct crom_context *cc, char *buf, int len) 270b018dcd1SHidetoshi Shimokawa { 271b018dcd1SHidetoshi Shimokawa struct csrreg *reg; 272b018dcd1SHidetoshi Shimokawa struct csrdirectory *dir; 2735e286c32SHidetoshi Shimokawa char *desc, st; 27477ee030bSHidetoshi Shimokawa u_int16_t crc; 275b018dcd1SHidetoshi Shimokawa 276b018dcd1SHidetoshi Shimokawa reg = crom_get(cc); 277b018dcd1SHidetoshi Shimokawa switch (reg->key & CSRTYPE_MASK) { 278b018dcd1SHidetoshi Shimokawa case CSRTYPE_I: 2795e286c32SHidetoshi Shimokawa #if 0 2805e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "%d", reg->val); 2815e286c32SHidetoshi Shimokawa buf += strlen(buf); 2825e286c32SHidetoshi Shimokawa #else 2835e286c32SHidetoshi Shimokawa *buf = '\0'; 2845e286c32SHidetoshi Shimokawa #endif 285b018dcd1SHidetoshi Shimokawa break; 286b018dcd1SHidetoshi Shimokawa case CSRTYPE_C: 2875e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "offset=0x%04x(%d)", 2885e286c32SHidetoshi Shimokawa reg->val, reg->val); 2895e286c32SHidetoshi Shimokawa buf += strlen(buf); 290b018dcd1SHidetoshi Shimokawa break; 29177ee030bSHidetoshi Shimokawa case CSRTYPE_L: 29277ee030bSHidetoshi Shimokawa /* XXX fall through */ 293b018dcd1SHidetoshi Shimokawa case CSRTYPE_D: 294b018dcd1SHidetoshi Shimokawa dir = (struct csrdirectory *) (reg + reg->val); 29577ee030bSHidetoshi Shimokawa crc = crom_crc((u_int32_t *)&dir->entry[0], dir->crc_len); 2965e286c32SHidetoshi Shimokawa len -= snprintf(buf, len, "len=%d crc=0x%04x(%s) ", 2975e286c32SHidetoshi Shimokawa dir->crc_len, dir->crc, 2985e286c32SHidetoshi Shimokawa (crc == dir->crc) ? "OK" : "NG"); 2995e286c32SHidetoshi Shimokawa buf += strlen(buf); 300b018dcd1SHidetoshi Shimokawa } 301b018dcd1SHidetoshi Shimokawa switch (reg->key) { 302b018dcd1SHidetoshi Shimokawa case 0x03: 303b018dcd1SHidetoshi Shimokawa desc = "module_vendor_ID"; 304b018dcd1SHidetoshi Shimokawa break; 305b018dcd1SHidetoshi Shimokawa case 0x04: 306b018dcd1SHidetoshi Shimokawa desc = "hardware_version"; 307b018dcd1SHidetoshi Shimokawa break; 308b018dcd1SHidetoshi Shimokawa case 0x0c: 309b018dcd1SHidetoshi Shimokawa desc = "node_capabilities"; 310b018dcd1SHidetoshi Shimokawa break; 311b018dcd1SHidetoshi Shimokawa case 0x12: 312b018dcd1SHidetoshi Shimokawa desc = "unit_spec_ID"; 313b018dcd1SHidetoshi Shimokawa break; 314b018dcd1SHidetoshi Shimokawa case 0x13: 315b018dcd1SHidetoshi Shimokawa desc = "unit_sw_version"; 3165e286c32SHidetoshi Shimokawa crom_desc_specver(0, reg->val, buf, len); 317b018dcd1SHidetoshi Shimokawa break; 318b018dcd1SHidetoshi Shimokawa case 0x14: 319b018dcd1SHidetoshi Shimokawa desc = "logical_unit_number"; 320b018dcd1SHidetoshi Shimokawa break; 321b018dcd1SHidetoshi Shimokawa case 0x17: 322b018dcd1SHidetoshi Shimokawa desc = "model_ID"; 323b018dcd1SHidetoshi Shimokawa break; 324b018dcd1SHidetoshi Shimokawa case 0x38: 325b018dcd1SHidetoshi Shimokawa desc = "command_set_spec_ID"; 326b018dcd1SHidetoshi Shimokawa break; 327b018dcd1SHidetoshi Shimokawa case 0x39: 328b018dcd1SHidetoshi Shimokawa desc = "command_set"; 329b018dcd1SHidetoshi Shimokawa break; 330b018dcd1SHidetoshi Shimokawa case 0x3a: 331b018dcd1SHidetoshi Shimokawa desc = "unit_characteristics"; 332b018dcd1SHidetoshi Shimokawa break; 333b018dcd1SHidetoshi Shimokawa case 0x3b: 334b018dcd1SHidetoshi Shimokawa desc = "command_set_revision"; 335b018dcd1SHidetoshi Shimokawa break; 336b018dcd1SHidetoshi Shimokawa case 0x3c: 337b018dcd1SHidetoshi Shimokawa desc = "firmware_revision"; 338b018dcd1SHidetoshi Shimokawa break; 339b018dcd1SHidetoshi Shimokawa case 0x3d: 340b018dcd1SHidetoshi Shimokawa desc = "reconnect_timeout"; 341b018dcd1SHidetoshi Shimokawa break; 342b018dcd1SHidetoshi Shimokawa case 0x54: 343b018dcd1SHidetoshi Shimokawa desc = "management_agent"; 344b018dcd1SHidetoshi Shimokawa break; 345b018dcd1SHidetoshi Shimokawa case 0x81: 346b018dcd1SHidetoshi Shimokawa desc = "text_leaf"; 34777ee030bSHidetoshi Shimokawa crom_parse_text(cc, buf + strlen(buf), len); 348b018dcd1SHidetoshi Shimokawa break; 349b018dcd1SHidetoshi Shimokawa case 0xd1: 350b018dcd1SHidetoshi Shimokawa desc = "unit_directory"; 351b018dcd1SHidetoshi Shimokawa break; 352b018dcd1SHidetoshi Shimokawa case 0xd4: 353b018dcd1SHidetoshi Shimokawa desc = "logical_unit_directory"; 354b018dcd1SHidetoshi Shimokawa break; 355b018dcd1SHidetoshi Shimokawa default: 356b018dcd1SHidetoshi Shimokawa desc = "unknown"; 357b018dcd1SHidetoshi Shimokawa } 358b018dcd1SHidetoshi Shimokawa return desc; 359b018dcd1SHidetoshi Shimokawa } 360b018dcd1SHidetoshi Shimokawa #endif 36177ee030bSHidetoshi Shimokawa 36277ee030bSHidetoshi Shimokawa #if defined(_KERNEL) || defined(TEST) 36377ee030bSHidetoshi Shimokawa 36477ee030bSHidetoshi Shimokawa int 36577ee030bSHidetoshi Shimokawa crom_add_quad(struct crom_chunk *chunk, u_int32_t entry) 36677ee030bSHidetoshi Shimokawa { 36777ee030bSHidetoshi Shimokawa int index; 36877ee030bSHidetoshi Shimokawa 36977ee030bSHidetoshi Shimokawa index = chunk->data.crc_len; 37077ee030bSHidetoshi Shimokawa if (index >= CROM_MAX_CHUNK_LEN - 1) { 37177ee030bSHidetoshi Shimokawa printf("too large chunk %d\n", index); 37277ee030bSHidetoshi Shimokawa return(-1); 37377ee030bSHidetoshi Shimokawa } 37477ee030bSHidetoshi Shimokawa chunk->data.buf[index] = entry; 37577ee030bSHidetoshi Shimokawa chunk->data.crc_len++; 37677ee030bSHidetoshi Shimokawa return(index); 37777ee030bSHidetoshi Shimokawa } 37877ee030bSHidetoshi Shimokawa 37977ee030bSHidetoshi Shimokawa int 38077ee030bSHidetoshi Shimokawa crom_add_entry(struct crom_chunk *chunk, int key, int val) 38177ee030bSHidetoshi Shimokawa { 38277ee030bSHidetoshi Shimokawa struct csrreg *reg; 38377ee030bSHidetoshi Shimokawa u_int32_t i; 38477ee030bSHidetoshi Shimokawa 38577ee030bSHidetoshi Shimokawa reg = (struct csrreg *)&i; 38677ee030bSHidetoshi Shimokawa reg->key = key; 38777ee030bSHidetoshi Shimokawa reg->val = val; 38877ee030bSHidetoshi Shimokawa return(crom_add_quad(chunk, (u_int32_t) i)); 38977ee030bSHidetoshi Shimokawa } 39077ee030bSHidetoshi Shimokawa 39177ee030bSHidetoshi Shimokawa int 39277ee030bSHidetoshi Shimokawa crom_add_chunk(struct crom_src *src, struct crom_chunk *parent, 39377ee030bSHidetoshi Shimokawa struct crom_chunk *child, int key) 39477ee030bSHidetoshi Shimokawa { 39577ee030bSHidetoshi Shimokawa int index; 39677ee030bSHidetoshi Shimokawa 39777ee030bSHidetoshi Shimokawa if (parent == NULL) { 39877ee030bSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 39977ee030bSHidetoshi Shimokawa return(0); 40077ee030bSHidetoshi Shimokawa } 40177ee030bSHidetoshi Shimokawa 40277ee030bSHidetoshi Shimokawa index = crom_add_entry(parent, key, 0); 40377ee030bSHidetoshi Shimokawa if (index < 0) { 40477ee030bSHidetoshi Shimokawa return(-1); 40577ee030bSHidetoshi Shimokawa } 40677ee030bSHidetoshi Shimokawa child->ref_chunk = parent; 40777ee030bSHidetoshi Shimokawa child->ref_index = index; 40877ee030bSHidetoshi Shimokawa STAILQ_INSERT_TAIL(&src->chunk_list, child, link); 40977ee030bSHidetoshi Shimokawa return(index); 41077ee030bSHidetoshi Shimokawa } 41177ee030bSHidetoshi Shimokawa 41277ee030bSHidetoshi Shimokawa int 41377ee030bSHidetoshi Shimokawa crom_add_simple_text(struct crom_src *src, struct crom_chunk *parent, 41477ee030bSHidetoshi Shimokawa struct crom_chunk *chunk, char *buf) 41577ee030bSHidetoshi Shimokawa { 41677ee030bSHidetoshi Shimokawa struct csrtext *tl; 41777ee030bSHidetoshi Shimokawa u_int32_t *p; 41877ee030bSHidetoshi Shimokawa int len, i; 41977ee030bSHidetoshi Shimokawa 42077ee030bSHidetoshi Shimokawa len = strlen(buf); 42177ee030bSHidetoshi Shimokawa #define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext)) 42277ee030bSHidetoshi Shimokawa if (len > MAX_TEXT) { 42377ee030bSHidetoshi Shimokawa #if __FreeBSD_version < 500000 42477ee030bSHidetoshi Shimokawa printf("text(%d) trancated to %d.\n", len, MAX_TEXT); 42577ee030bSHidetoshi Shimokawa #else 42677ee030bSHidetoshi Shimokawa printf("text(%d) trancated to %td.\n", len, MAX_TEXT); 42777ee030bSHidetoshi Shimokawa #endif 42877ee030bSHidetoshi Shimokawa len = MAX_TEXT; 42977ee030bSHidetoshi Shimokawa } 43077ee030bSHidetoshi Shimokawa 43177ee030bSHidetoshi Shimokawa tl = (struct csrtext *) &chunk->data; 43277ee030bSHidetoshi Shimokawa tl->crc_len = howmany(sizeof(struct csrtext) + len, sizeof(u_int32_t)); 43377ee030bSHidetoshi Shimokawa tl->spec_id = 0; 43477ee030bSHidetoshi Shimokawa tl->spec_type = 0; 43577ee030bSHidetoshi Shimokawa tl->lang_id = 0; 43677ee030bSHidetoshi Shimokawa p = (u_int32_t *) buf; 437b83977f0SHidetoshi Shimokawa for (i = 0; i < howmany(len, sizeof(u_int32_t)); i ++) 43877ee030bSHidetoshi Shimokawa tl->text[i] = ntohl(*p++); 43977ee030bSHidetoshi Shimokawa return (crom_add_chunk(src, parent, chunk, CROM_TEXTLEAF)); 44077ee030bSHidetoshi Shimokawa } 44177ee030bSHidetoshi Shimokawa 44277ee030bSHidetoshi Shimokawa static int 44377ee030bSHidetoshi Shimokawa crom_copy(u_int32_t *src, u_int32_t *dst, int *offset, int len, int maxlen) 44477ee030bSHidetoshi Shimokawa { 44577ee030bSHidetoshi Shimokawa if (*offset + len > maxlen) { 44677ee030bSHidetoshi Shimokawa printf("Config. ROM is too large for the buffer\n"); 44777ee030bSHidetoshi Shimokawa return(-1); 44877ee030bSHidetoshi Shimokawa } 44977ee030bSHidetoshi Shimokawa bcopy(src, (char *)(dst + *offset), len * sizeof(u_int32_t)); 45077ee030bSHidetoshi Shimokawa *offset += len; 45177ee030bSHidetoshi Shimokawa return(0); 45277ee030bSHidetoshi Shimokawa } 45377ee030bSHidetoshi Shimokawa 45477ee030bSHidetoshi Shimokawa int 45577ee030bSHidetoshi Shimokawa crom_load(struct crom_src *src, u_int32_t *buf, int maxlen) 45677ee030bSHidetoshi Shimokawa { 45777ee030bSHidetoshi Shimokawa struct crom_chunk *chunk, *parent; 45877ee030bSHidetoshi Shimokawa struct csrhdr *hdr; 459b83977f0SHidetoshi Shimokawa #ifdef _KERNEL 46077ee030bSHidetoshi Shimokawa u_int32_t *ptr; 461b83977f0SHidetoshi Shimokawa int i; 46277ee030bSHidetoshi Shimokawa #endif 46377ee030bSHidetoshi Shimokawa int count, offset; 46477ee030bSHidetoshi Shimokawa int len; 46577ee030bSHidetoshi Shimokawa 46677ee030bSHidetoshi Shimokawa offset = 0; 46777ee030bSHidetoshi Shimokawa /* Determine offset */ 46877ee030bSHidetoshi Shimokawa STAILQ_FOREACH(chunk, &src->chunk_list, link) { 46977ee030bSHidetoshi Shimokawa chunk->offset = offset; 47077ee030bSHidetoshi Shimokawa /* Assume the offset of the parent is already known */ 47177ee030bSHidetoshi Shimokawa parent = chunk->ref_chunk; 47277ee030bSHidetoshi Shimokawa if (parent != NULL) { 47377ee030bSHidetoshi Shimokawa struct csrreg *reg; 47477ee030bSHidetoshi Shimokawa reg = (struct csrreg *) 47577ee030bSHidetoshi Shimokawa &parent->data.buf[chunk->ref_index]; 47677ee030bSHidetoshi Shimokawa reg->val = offset - 47777ee030bSHidetoshi Shimokawa (parent->offset + 1 + chunk->ref_index); 47877ee030bSHidetoshi Shimokawa } 47977ee030bSHidetoshi Shimokawa offset += 1 + chunk->data.crc_len; 48077ee030bSHidetoshi Shimokawa } 48177ee030bSHidetoshi Shimokawa 48277ee030bSHidetoshi Shimokawa /* Calculate CRC and dump to the buffer */ 48377ee030bSHidetoshi Shimokawa len = 1 + src->hdr.info_len; 48477ee030bSHidetoshi Shimokawa count = 0; 48577ee030bSHidetoshi Shimokawa if (crom_copy((u_int32_t *)&src->hdr, buf, &count, len, maxlen) < 0) 48677ee030bSHidetoshi Shimokawa return(-1); 48777ee030bSHidetoshi Shimokawa STAILQ_FOREACH(chunk, &src->chunk_list, link) { 48877ee030bSHidetoshi Shimokawa chunk->data.crc = 48977ee030bSHidetoshi Shimokawa crom_crc(&chunk->data.buf[0], chunk->data.crc_len); 49077ee030bSHidetoshi Shimokawa 49177ee030bSHidetoshi Shimokawa len = 1 + chunk->data.crc_len; 49277ee030bSHidetoshi Shimokawa if (crom_copy((u_int32_t *)&chunk->data, buf, 49377ee030bSHidetoshi Shimokawa &count, len, maxlen) < 0) 49477ee030bSHidetoshi Shimokawa return(-1); 49577ee030bSHidetoshi Shimokawa } 49677ee030bSHidetoshi Shimokawa hdr = (struct csrhdr *)buf; 49777ee030bSHidetoshi Shimokawa hdr->crc_len = count - 1; 498b83977f0SHidetoshi Shimokawa hdr->crc = crom_crc(&buf[1], hdr->crc_len); 49977ee030bSHidetoshi Shimokawa 500b83977f0SHidetoshi Shimokawa #ifdef _KERNEL 50177ee030bSHidetoshi Shimokawa /* byte swap */ 50277ee030bSHidetoshi Shimokawa ptr = buf; 50377ee030bSHidetoshi Shimokawa for (i = 0; i < count; i ++) { 50477ee030bSHidetoshi Shimokawa *ptr = htonl(*ptr); 50577ee030bSHidetoshi Shimokawa ptr++; 50677ee030bSHidetoshi Shimokawa } 50777ee030bSHidetoshi Shimokawa #endif 50877ee030bSHidetoshi Shimokawa 50977ee030bSHidetoshi Shimokawa return(count); 51077ee030bSHidetoshi Shimokawa } 51177ee030bSHidetoshi Shimokawa #endif 51277ee030bSHidetoshi Shimokawa 51377ee030bSHidetoshi Shimokawa #ifdef TEST 51477ee030bSHidetoshi Shimokawa int 51577ee030bSHidetoshi Shimokawa main () { 51677ee030bSHidetoshi Shimokawa struct crom_src src; 51777ee030bSHidetoshi Shimokawa struct crom_chunk root,unit1,unit2,unit3; 51877ee030bSHidetoshi Shimokawa struct crom_chunk text1,text2,text3,text4,text5,text6,text7; 51977ee030bSHidetoshi Shimokawa u_int32_t buf[256], *p; 52077ee030bSHidetoshi Shimokawa int i; 52177ee030bSHidetoshi Shimokawa 52277ee030bSHidetoshi Shimokawa bzero(&src, sizeof(src)); 52377ee030bSHidetoshi Shimokawa bzero(&root, sizeof(root)); 52477ee030bSHidetoshi Shimokawa bzero(&unit1, sizeof(unit1)); 52577ee030bSHidetoshi Shimokawa bzero(&unit2, sizeof(unit2)); 52677ee030bSHidetoshi Shimokawa bzero(&unit3, sizeof(unit3)); 52777ee030bSHidetoshi Shimokawa bzero(&text1, sizeof(text1)); 52877ee030bSHidetoshi Shimokawa bzero(&text2, sizeof(text2)); 52977ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text3)); 53077ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text4)); 53177ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text5)); 53277ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text6)); 53377ee030bSHidetoshi Shimokawa bzero(&text3, sizeof(text7)); 53477ee030bSHidetoshi Shimokawa bzero(buf, sizeof(buf)); 53577ee030bSHidetoshi Shimokawa 53677ee030bSHidetoshi Shimokawa /* BUS info sample */ 53777ee030bSHidetoshi Shimokawa src.hdr.info_len = 4; 53877ee030bSHidetoshi Shimokawa src.businfo.bus_name = CSR_BUS_NAME_IEEE1394; 53977ee030bSHidetoshi Shimokawa src.businfo.eui64.hi = 0x11223344; 54077ee030bSHidetoshi Shimokawa src.businfo.eui64.lo = 0x55667788; 54177ee030bSHidetoshi Shimokawa src.businfo.link_spd = FWSPD_S400; 54277ee030bSHidetoshi Shimokawa src.businfo.generation = 0; 54377ee030bSHidetoshi Shimokawa src.businfo.max_rom = MAXROM_4; 54477ee030bSHidetoshi Shimokawa src.businfo.max_rec = 10; 54577ee030bSHidetoshi Shimokawa src.businfo.cyc_clk_acc = 100; 54677ee030bSHidetoshi Shimokawa src.businfo.pmc = 0; 54777ee030bSHidetoshi Shimokawa src.businfo.bmc = 1; 54877ee030bSHidetoshi Shimokawa src.businfo.isc = 1; 54977ee030bSHidetoshi Shimokawa src.businfo.cmc = 1; 55077ee030bSHidetoshi Shimokawa src.businfo.irmc = 1; 55177ee030bSHidetoshi Shimokawa STAILQ_INIT(&src.chunk_list); 55277ee030bSHidetoshi Shimokawa 55377ee030bSHidetoshi Shimokawa /* Root directory */ 55477ee030bSHidetoshi Shimokawa crom_add_chunk(&src, NULL, &root, 0); 55577ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_NCAP, 0x123456); 55677ee030bSHidetoshi Shimokawa /* private company_id */ 55777ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_VENDOR, 0xacde48); 55877ee030bSHidetoshi Shimokawa 55977ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text1, "FreeBSD"); 56077ee030bSHidetoshi Shimokawa crom_add_entry(&root, CSRKEY_HW, __FreeBSD_version); 56177ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &root, &text2, "FreeBSD-5"); 56277ee030bSHidetoshi Shimokawa 56377ee030bSHidetoshi Shimokawa /* SBP unit directory */ 56477ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit1, CROM_UDIR); 56577ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_SPEC, CSRVAL_ANSIT10); 56677ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_VER, CSRVAL_T10SBP2); 56777ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_COM_SPEC, CSRVAL_ANSIT10); 56877ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_COM_SET, CSRVAL_SCSI); 56977ee030bSHidetoshi Shimokawa /* management_agent */ 57077ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CROM_MGM, 0x1000); 57177ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_UNIT_CH, (10<<8) | 8); 57277ee030bSHidetoshi Shimokawa /* Device type and LUN */ 57377ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CROM_LUN, 0); 57477ee030bSHidetoshi Shimokawa crom_add_entry(&unit1, CSRKEY_MODEL, 1); 57577ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit1, &text3, "scsi_target"); 57677ee030bSHidetoshi Shimokawa 57777ee030bSHidetoshi Shimokawa /* RFC2734 IPv4 over IEEE1394 */ 57877ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit2, CROM_UDIR); 57977ee030bSHidetoshi Shimokawa crom_add_entry(&unit2, CSRKEY_SPEC, CSRVAL_IETF); 58077ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit2, &text4, "IANA"); 58177ee030bSHidetoshi Shimokawa crom_add_entry(&unit2, CSRKEY_VER, 1); 58277ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit2, &text5, "IPv4"); 58377ee030bSHidetoshi Shimokawa 58477ee030bSHidetoshi Shimokawa /* RFC3146 IPv6 over IEEE1394 */ 58577ee030bSHidetoshi Shimokawa crom_add_chunk(&src, &root, &unit3, CROM_UDIR); 58677ee030bSHidetoshi Shimokawa crom_add_entry(&unit3, CSRKEY_SPEC, CSRVAL_IETF); 58777ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit3, &text6, "IANA"); 58877ee030bSHidetoshi Shimokawa crom_add_entry(&unit3, CSRKEY_VER, 2); 58977ee030bSHidetoshi Shimokawa crom_add_simple_text(&src, &unit3, &text7, "IPv6"); 59077ee030bSHidetoshi Shimokawa 59177ee030bSHidetoshi Shimokawa crom_load(&src, buf, 256); 59277ee030bSHidetoshi Shimokawa p = buf; 59377ee030bSHidetoshi Shimokawa #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n" 59477ee030bSHidetoshi Shimokawa for (i = 0; i < 256/8; i ++) { 59577ee030bSHidetoshi Shimokawa printf(DUMP_FORMAT, 59677ee030bSHidetoshi Shimokawa p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); 59777ee030bSHidetoshi Shimokawa p += 8; 59877ee030bSHidetoshi Shimokawa } 59977ee030bSHidetoshi Shimokawa return(0); 60077ee030bSHidetoshi Shimokawa } 60177ee030bSHidetoshi Shimokawa #endif 602