1 /* $NetBSD: fwcrom.c,v 1.9 2009/03/18 17:06:49 cegger Exp $ */
3 * Copyright (c) 2002-2003
4 * Hidetoshi Shimokawa. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
17 * This product includes software developed by Hidetoshi Shimokawa.
19 * 4. Neither the name of the author nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: fwcrom.c,v 1.9 2009/03/18 17:06:49 cegger Exp $");
39 __FBSDID("$FreeBSD: /repoman/r/ncvs/src/sys/dev/firewire/fwcrom.c,v 1.14 2006/02/04 21:37:39 imp Exp $");
42 #if defined(__FreeBSD__)
43 #include <sys/param.h>
47 #include <bootstrap.h>
49 #if defined(_KERNEL) || defined(TEST)
50 #include <sys/queue.h>
53 #include <sys/systm.h>
54 #include <sys/kernel.h>
56 #include <netinet/in.h>
70 #include <dev/firewire/fw_port.h>
71 #include <dev/firewire/firewire.h>
72 #include <dev/firewire/iec13213.h>
74 #elif defined(__NetBSD__)
75 #include <sys/param.h>
77 #include <sys/device.h>
78 #include <sys/errno.h>
79 #include <sys/systm.h>
84 #include <dev/ieee1394/fw_port.h>
85 #include <dev/ieee1394/firewire.h>
86 #include <dev/ieee1394/iec13213.h>
89 #define MAX_ROM (1024 - sizeof(uint32_t) * 5)
90 #define CROM_END(cc) ((char *)(cc)->stack[0].dir + MAX_ROM - 1)
93 crom_init_context(struct crom_context
*cc
, uint32_t *p
)
97 hdr
= (struct csrhdr
*)p
;
98 if (hdr
->info_len
<= 1) {
99 /* minimum or invalid ROM */
103 p
+= 1 + hdr
->info_len
;
105 /* check size of root directory */
106 if (((struct csrdirectory
*)p
)->crc_len
== 0) {
111 cc
->stack
[0].dir
= (struct csrdirectory
*)p
;
112 cc
->stack
[0].index
= 0;
116 crom_get(struct crom_context
*cc
)
118 struct crom_ptr
*ptr
;
120 ptr
= &cc
->stack
[cc
->depth
];
121 return (&ptr
->dir
->entry
[ptr
->index
]);
125 crom_next(struct crom_context
*cc
)
127 struct crom_ptr
*ptr
;
133 if ((reg
->key
& CSRTYPE_MASK
) == CSRTYPE_D
) {
134 if (cc
->depth
>= CROM_MAX_DEPTH
) {
135 printf("crom_next: too deep\n");
140 ptr
= &cc
->stack
[cc
->depth
];
141 ptr
->dir
= (struct csrdirectory
*) (reg
+ reg
->val
);
146 ptr
= &cc
->stack
[cc
->depth
];
149 if (ptr
->index
< ptr
->dir
->crc_len
&&
150 (char *)crom_get(cc
) <= CROM_END(cc
))
153 if (ptr
->index
< ptr
->dir
->crc_len
)
154 printf("crom_next: bound check failed\n");
166 crom_search_key(struct crom_context
*cc
, uint8_t key
)
170 while(cc
->depth
>= 0) {
180 crom_has_specver(uint32_t *p
, uint32_t spec
, uint32_t ver
)
183 struct crom_context c
, *cc
;
187 crom_init_context(cc
, p
);
188 while(cc
->depth
>= 0) {
191 if (reg
->key
== CSRKEY_SPEC
&& reg
->val
== spec
)
196 if (reg
->key
== CSRKEY_VER
&& reg
->val
== ver
)
207 crom_parse_text(struct crom_context
*cc
, char *buf
, int len
)
210 struct csrtext
*textleaf
;
213 static char *nullstr
= (char *)&"(null)";
219 if (reg
->key
!= CROM_TEXTLEAF
||
220 (char *)(reg
+ reg
->val
) > CROM_END(cc
)) {
221 strncpy(buf
, nullstr
, len
);
224 textleaf
= (struct csrtext
*)(reg
+ reg
->val
);
226 if ((char *)textleaf
+ textleaf
->crc_len
> CROM_END(cc
)) {
227 strncpy(buf
, nullstr
, len
);
231 /* XXX should check spec and type */
233 bp
= (uint32_t *)&buf
[0];
234 qlen
= textleaf
->crc_len
- 2;
237 for (i
= 0; i
< qlen
; i
++)
238 *bp
++ = ntohl(textleaf
->text
[i
]);
239 /* make sure to terminate the string */
247 crom_crc(uint32_t *ptr
, int len
)
250 uint32_t data
, sum
, crc
= 0;
252 for (i
= 0; i
< len
; i
++) {
254 for (shift
= 28; shift
>= 0; shift
-= 4) {
255 sum
= ((crc
>> 12) ^ (data
>> shift
)) & 0xf;
256 crc
= (crc
<< 4) ^ (sum
<< 12) ^ (sum
<< 5) ^ sum
;
260 return((uint16_t) crc
);
263 #if !defined(_KERNEL) && !defined(_BOOT)
265 crom_desc_specver(uint32_t spec
, uint32_t ver
, char *buf
, int len
)
267 const char *s
= NULL
;
269 if (spec
== CSRVAL_ANSIT10
|| spec
== 0) {
276 s
= "unknown ANSIT10";
279 if (spec
== CSRVAL_1394TA
|| spec
== 0) {
303 s
= "1394 Direct print";
306 s
= "Industrial & Instrument";
310 s
= "unknown 1394TA";
314 snprintf(buf
, len
, "%s", s
);
318 crom_desc(struct crom_context
*cc
, char *buf
, int len
)
321 struct csrdirectory
*dir
;
326 switch (reg
->key
& CSRTYPE_MASK
) {
329 len
-= snprintf(buf
, len
, "%d", reg
->val
);
336 len
-= snprintf(buf
, len
, "offset=0x%04x(%d)",
341 /* XXX fall through */
343 dir
= (struct csrdirectory
*) (reg
+ reg
->val
);
344 crc
= crom_crc((uint32_t *)&dir
->entry
[0], dir
->crc_len
);
345 len
-= snprintf(buf
, len
, "len=%d crc=0x%04x(%s) ",
346 dir
->crc_len
, dir
->crc
,
347 (crc
== dir
->crc
) ? "OK" : "NG");
352 desc
= "module_vendor_ID";
355 desc
= "hardware_version";
358 desc
= "node_capabilities";
361 desc
= "unit_spec_ID";
364 desc
= "unit_sw_version";
365 crom_desc_specver(0, reg
->val
, buf
, len
);
368 desc
= "logical_unit_number";
374 desc
= "command_set_spec_ID";
377 desc
= "command_set";
380 desc
= "unit_characteristics";
383 desc
= "command_set_revision";
386 desc
= "firmware_revision";
389 desc
= "reconnect_timeout";
392 desc
= "management_agent";
396 crom_parse_text(cc
, buf
+ strlen(buf
), len
);
399 desc
= "unit_directory";
402 desc
= "logical_unit_directory";
411 #if defined(_KERNEL) || defined(_BOOT) || defined(TEST)
414 crom_add_quad(struct crom_chunk
*chunk
, uint32_t entry
)
418 index
= chunk
->data
.crc_len
;
419 if (index
>= CROM_MAX_CHUNK_LEN
- 1) {
420 printf("too large chunk %d\n", index
);
423 chunk
->data
.buf
[index
] = entry
;
424 chunk
->data
.crc_len
++;
429 crom_add_entry(struct crom_chunk
*chunk
, int key
, int val
)
439 return(crom_add_quad(chunk
, foo
.i
));
443 crom_add_chunk(struct crom_src
*src
, struct crom_chunk
*parent
,
444 struct crom_chunk
*child
, int key
)
448 if (parent
== NULL
) {
449 STAILQ_INSERT_TAIL(&src
->chunk_list
, child
, link
);
453 index
= crom_add_entry(parent
, key
, 0);
457 child
->ref_chunk
= parent
;
458 child
->ref_index
= index
;
459 STAILQ_INSERT_TAIL(&src
->chunk_list
, child
, link
);
463 #if defined(__FreeBSD__)
464 #define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
465 #elif defined(__NetBSD__)
466 #define MAX_TEXT (int)((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
469 crom_add_simple_text(struct crom_src
*src
, struct crom_chunk
*parent
,
470 struct crom_chunk
*chunk
, const char *buf
)
478 if (len
> MAX_TEXT
) {
479 #if defined(__DragonFly__) || __FreeBSD_version < 500000 || defined(__NetBSD__)
480 printf("text(%d) trancated to %d.\n", len
, MAX_TEXT
);
482 printf("text(%d) trancated to %td.\n", len
, MAX_TEXT
);
487 tl
= (struct csrtext
*) &chunk
->data
;
488 tl
->crc_len
= howmany(sizeof(struct csrtext
) + len
, sizeof(uint32_t));
492 memset(&t
[0], 0, roundup2(len
, sizeof(uint32_t)));
493 memcpy(&t
[0], buf
, len
);
494 p
= (uint32_t *)&t
[0];
495 for (i
= 0; i
< howmany(len
, sizeof(uint32_t)); i
++)
496 tl
->text
[i
] = ntohl(*p
++);
497 return (crom_add_chunk(src
, parent
, chunk
, CROM_TEXTLEAF
));
501 crom_copy(uint32_t *src
, uint32_t *dst
, int *offset
, int len
, int maxlen
)
503 if (*offset
+ len
> maxlen
) {
504 printf("Config. ROM is too large for the buffer\n");
507 memcpy((char *)(dst
+ *offset
), src
, len
* sizeof(uint32_t));
513 crom_load(struct crom_src
*src
, uint32_t *buf
, int maxlen
)
515 struct crom_chunk
*chunk
, *parent
;
517 #if defined(_KERNEL) || defined(_BOOT)
525 /* Determine offset */
526 STAILQ_FOREACH(chunk
, &src
->chunk_list
, link
) {
527 chunk
->offset
= offset
;
528 /* Assume the offset of the parent is already known */
529 parent
= chunk
->ref_chunk
;
530 if (parent
!= NULL
) {
532 reg
= (struct csrreg
*)
533 &parent
->data
.buf
[chunk
->ref_index
];
535 (parent
->offset
+ 1 + chunk
->ref_index
);
537 offset
+= 1 + chunk
->data
.crc_len
;
540 /* Calculate CRC and dump to the buffer */
541 len
= 1 + src
->hdr
.info_len
;
543 if (crom_copy((uint32_t *)&src
->hdr
, buf
, &count
, len
, maxlen
) < 0)
545 STAILQ_FOREACH(chunk
, &src
->chunk_list
, link
) {
547 crom_crc(&chunk
->data
.buf
[0], chunk
->data
.crc_len
);
549 len
= 1 + chunk
->data
.crc_len
;
550 if (crom_copy((uint32_t *)&chunk
->data
, buf
,
551 &count
, len
, maxlen
) < 0)
554 hdr
= (struct csrhdr
*)buf
;
555 hdr
->crc_len
= count
- 1;
556 hdr
->crc
= crom_crc(&buf
[1], hdr
->crc_len
);
558 #if defined(_KERNEL) || defined(_BOOT)
561 for (i
= 0; i
< count
; i
++) {
575 struct crom_chunk root
,unit1
,unit2
,unit3
;
576 struct crom_chunk text1
,text2
,text3
,text4
,text5
,text6
,text7
;
577 uint32_t buf
[256], *p
;
580 memset(&src
, 0, sizeof(src
));
581 memset(&root
, 0, sizeof(root
));
582 memset(&unit1
, 0, sizeof(unit1
));
583 memset(&unit2
, 0, sizeof(unit2
));
584 memset(&unit3
, 0, sizeof(unit3
));
585 memset(&text1
, 0, sizeof(text1
));
586 memset(&text2
, 0, sizeof(text2
));
587 memset(&text3
, 0, sizeof(text3
));
588 memset(&text3
, 0, sizeof(text4
));
589 memset(&text3
, 0, sizeof(text5
));
590 memset(&text3
, 0, sizeof(text6
));
591 memset(&text3
, 0, sizeof(text7
));
592 memset(buf
, 0, sizeof(buf
));
594 /* BUS info sample */
595 src
.hdr
.info_len
= 4;
596 src
.businfo
.bus_name
= CSR_BUS_NAME_IEEE1394
;
597 src
.businfo
.eui64
.hi
= 0x11223344;
598 src
.businfo
.eui64
.lo
= 0x55667788;
599 src
.businfo
.link_spd
= FWSPD_S400
;
600 src
.businfo
.generation
= 0;
601 src
.businfo
.max_rom
= MAXROM_4
;
602 src
.businfo
.max_rec
= 10;
603 src
.businfo
.cyc_clk_acc
= 100;
608 src
.businfo
.irmc
= 1;
609 STAILQ_INIT(&src
.chunk_list
);
612 crom_add_chunk(&src
, NULL
, &root
, 0);
613 crom_add_entry(&root
, CSRKEY_NCAP
, 0x123456);
614 /* private company_id */
615 crom_add_entry(&root
, CSRKEY_VENDOR
, 0xacde48);
617 crom_add_simple_text(&src
, &root
, &text1
, OS_STR
);
618 crom_add_entry(&root
, CSRKEY_HW
, OS_VER
);
619 crom_add_simple_text(&src
, &root
, &text2
, OS_VER_STR
);
621 /* SBP unit directory */
622 crom_add_chunk(&src
, &root
, &unit1
, CROM_UDIR
);
623 crom_add_entry(&unit1
, CSRKEY_SPEC
, CSRVAL_ANSIT10
);
624 crom_add_entry(&unit1
, CSRKEY_VER
, CSRVAL_T10SBP2
);
625 crom_add_entry(&unit1
, CSRKEY_COM_SPEC
, CSRVAL_ANSIT10
);
626 crom_add_entry(&unit1
, CSRKEY_COM_SET
, CSRVAL_SCSI
);
627 /* management_agent */
628 crom_add_entry(&unit1
, CROM_MGM
, 0x1000);
629 crom_add_entry(&unit1
, CSRKEY_UNIT_CH
, (10<<8) | 8);
630 /* Device type and LUN */
631 crom_add_entry(&unit1
, CROM_LUN
, 0);
632 crom_add_entry(&unit1
, CSRKEY_MODEL
, 1);
633 crom_add_simple_text(&src
, &unit1
, &text3
, "scsi_target");
635 /* RFC2734 IPv4 over IEEE1394 */
636 crom_add_chunk(&src
, &root
, &unit2
, CROM_UDIR
);
637 crom_add_entry(&unit2
, CSRKEY_SPEC
, CSRVAL_IETF
);
638 crom_add_simple_text(&src
, &unit2
, &text4
, "IANA");
639 crom_add_entry(&unit2
, CSRKEY_VER
, 1);
640 crom_add_simple_text(&src
, &unit2
, &text5
, "IPv4");
642 /* RFC3146 IPv6 over IEEE1394 */
643 crom_add_chunk(&src
, &root
, &unit3
, CROM_UDIR
);
644 crom_add_entry(&unit3
, CSRKEY_SPEC
, CSRVAL_IETF
);
645 crom_add_simple_text(&src
, &unit3
, &text6
, "IANA");
646 crom_add_entry(&unit3
, CSRKEY_VER
, 2);
647 crom_add_simple_text(&src
, &unit3
, &text7
, "IPv6");
649 crom_load(&src
, buf
, 256);
651 #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
652 for (i
= 0; i
< 256/8; i
++) {
654 p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);