2 * Copyright (c) 2002-2003
3 * Hidetoshi Shimokawa. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
16 * This product includes software developed by Hidetoshi Shimokawa.
18 * 4. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $DragonFly: src/sys/bus/firewire/fwcrom.c,v 1.10 2007/05/13 18:33:56 swildner Exp $
38 #include <sys/cdefs.h>
39 __FBSDID("$FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.9 2003/10/02 04:06:55 simokawa Exp $");
42 #include <sys/param.h>
43 #if defined(_KERNEL) || defined(TEST)
44 #include <sys/queue.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
50 #include <netinet/in.h>
56 #define ksnprintf snprintf /* sigh. used by fwcontrol */
57 #define kprintf printf
64 #include <dev/firewire/firewire.h>
65 #include <dev/firewire/iec13213.h>
68 #define MAX_ROM (1024 - sizeof(u_int32_t) * 5)
69 #define CROM_END(cc) ((vm_offset_t)(cc)->stack[0].dir + MAX_ROM - 1)
72 crom_init_context(struct crom_context
*cc
, u_int32_t
*p
)
76 hdr
= (struct csrhdr
*)p
;
77 if (hdr
->info_len
== 0) {
79 * This isn't supposed to happen but it does. The problem
80 * is possibly related to fw_attach_dev()'s going from an
81 * FWDEVINIT to a FWDEVATTACHED state, or in a host<->host
82 * situation where one host gets the root directory for
83 * another before the other has actually initialized it.
85 kprintf("crom_init_context: WARNING, info_len is 0\n");
89 if (hdr
->info_len
== 1) {
93 p
+= 1 + hdr
->info_len
;
95 /* check size of root directory */
96 if (((struct csrdirectory
*)p
)->crc_len
== 0) {
101 cc
->stack
[0].dir
= (struct csrdirectory
*)p
;
102 cc
->stack
[0].index
= 0;
106 crom_get(struct crom_context
*cc
)
108 struct crom_ptr
*ptr
;
110 ptr
= &cc
->stack
[cc
->depth
];
111 return (&ptr
->dir
->entry
[ptr
->index
]);
115 crom_next(struct crom_context
*cc
)
117 struct crom_ptr
*ptr
;
123 if ((reg
->key
& CSRTYPE_MASK
) == CSRTYPE_D
) {
124 if (cc
->depth
>= CROM_MAX_DEPTH
) {
125 kprintf("crom_next: too deep\n");
130 ptr
= &cc
->stack
[cc
->depth
];
131 ptr
->dir
= (struct csrdirectory
*) (reg
+ reg
->val
);
136 ptr
= &cc
->stack
[cc
->depth
];
139 if (ptr
->index
< ptr
->dir
->crc_len
&&
140 (vm_offset_t
)crom_get(cc
) <= CROM_END(cc
))
143 if (ptr
->index
< ptr
->dir
->crc_len
)
144 kprintf("crom_next: bound check failed\n");
156 crom_search_key(struct crom_context
*cc
, u_int8_t key
)
160 while(cc
->depth
>= 0) {
170 crom_has_specver(u_int32_t
*p
, u_int32_t spec
, u_int32_t ver
)
173 struct crom_context c
, *cc
;
177 crom_init_context(cc
, p
);
178 while(cc
->depth
>= 0) {
181 if (reg
->key
== CSRKEY_SPEC
&& reg
->val
== spec
)
186 if (reg
->key
== CSRKEY_VER
&& reg
->val
== ver
)
197 crom_parse_text(struct crom_context
*cc
, char *buf
, int len
)
200 struct csrtext
*textleaf
;
203 static char *nullstr
= "(null)";
209 if (reg
->key
!= CROM_TEXTLEAF
||
210 (vm_offset_t
)(reg
+ reg
->val
) > CROM_END(cc
)) {
211 strncpy(buf
, nullstr
, len
);
214 textleaf
= (struct csrtext
*)(reg
+ reg
->val
);
216 if ((vm_offset_t
)textleaf
+ textleaf
->crc_len
> CROM_END(cc
)) {
217 strncpy(buf
, nullstr
, len
);
221 /* XXX should check spec and type */
223 bp
= (u_int32_t
*)&buf
[0];
224 qlen
= textleaf
->crc_len
- 2;
227 for (i
= 0; i
< qlen
; i
++)
228 *bp
++ = ntohl(textleaf
->text
[i
]);
229 /* make sure to terminate the string */
237 crom_crc(u_int32_t
*ptr
, int len
)
240 u_int32_t data
, sum
, crc
= 0;
242 for (i
= 0; i
< len
; i
++) {
244 for (shift
= 28; shift
>= 0; shift
-= 4) {
245 sum
= ((crc
>> 12) ^ (data
>> shift
)) & 0xf;
246 crc
= (crc
<< 4) ^ (sum
<< 12) ^ (sum
<< 5) ^ sum
;
250 return((u_int16_t
) crc
);
255 crom_desc_specver(u_int32_t spec
, u_int32_t ver
, char *buf
, int len
)
259 if (spec
== CSRVAL_ANSIT10
|| spec
== 0) {
266 s
= "unknown ANSIT10";
269 if (spec
== CSRVAL_1394TA
|| spec
== 0) {
293 s
= "1394 Direct print";
296 s
= "Industrial & Instrument";
300 s
= "unknown 1394TA";
304 ksnprintf(buf
, len
, "%s", s
);
308 crom_desc(struct crom_context
*cc
, char *buf
, int len
)
311 struct csrdirectory
*dir
;
316 switch (reg
->key
& CSRTYPE_MASK
) {
319 len
-= ksnprintf(buf
, len
, "%d", reg
->val
);
326 len
-= ksnprintf(buf
, len
, "offset=0x%04x(%d)",
331 /* XXX fall through */
333 dir
= (struct csrdirectory
*) (reg
+ reg
->val
);
334 crc
= crom_crc((u_int32_t
*)&dir
->entry
[0], dir
->crc_len
);
335 len
-= ksnprintf(buf
, len
, "len=%d crc=0x%04x(%s) ",
336 dir
->crc_len
, dir
->crc
,
337 (crc
== dir
->crc
) ? "OK" : "NG");
342 desc
= "module_vendor_ID";
345 desc
= "hardware_version";
348 desc
= "node_capabilities";
351 desc
= "unit_spec_ID";
354 desc
= "unit_sw_version";
355 crom_desc_specver(0, reg
->val
, buf
, len
);
358 desc
= "logical_unit_number";
364 desc
= "command_set_spec_ID";
367 desc
= "command_set";
370 desc
= "unit_characteristics";
373 desc
= "command_set_revision";
376 desc
= "firmware_revision";
379 desc
= "reconnect_timeout";
382 desc
= "management_agent";
386 crom_parse_text(cc
, buf
+ strlen(buf
), len
);
389 desc
= "unit_directory";
392 desc
= "logical_unit_directory";
401 #if defined(_KERNEL) || defined(TEST)
404 crom_add_quad(struct crom_chunk
*chunk
, u_int32_t entry
)
408 index
= chunk
->data
.crc_len
;
409 if (index
>= CROM_MAX_CHUNK_LEN
- 1) {
410 kprintf("too large chunk %d\n", index
);
413 chunk
->data
.buf
[index
] = entry
;
414 chunk
->data
.crc_len
++;
419 crom_add_entry(struct crom_chunk
*chunk
, int key
, int val
)
424 reg
= (struct csrreg
*)&i
;
427 return(crom_add_quad(chunk
, (u_int32_t
) i
));
431 crom_add_chunk(struct crom_src
*src
, struct crom_chunk
*parent
,
432 struct crom_chunk
*child
, int key
)
436 if (parent
== NULL
) {
437 STAILQ_INSERT_TAIL(&src
->chunk_list
, child
, link
);
441 index
= crom_add_entry(parent
, key
, 0);
445 child
->ref_chunk
= parent
;
446 child
->ref_index
= index
;
447 STAILQ_INSERT_TAIL(&src
->chunk_list
, child
, link
);
451 #define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
453 crom_add_simple_text(struct crom_src
*src
, struct crom_chunk
*parent
,
454 struct crom_chunk
*chunk
, char *buf
)
462 if (len
> MAX_TEXT
) {
463 #if defined(__DragonFly__) || __FreeBSD_version < 500000
464 kprintf("text(%d) truncated to %lu.\n", len
, (u_long
)MAX_TEXT
);
466 kprintf("text(%d) truncated to %td.\n", len
, MAX_TEXT
);
471 tl
= (struct csrtext
*) &chunk
->data
;
472 tl
->crc_len
= howmany(sizeof(struct csrtext
) + len
, sizeof(u_int32_t
));
476 bzero(&t
[0], roundup2(len
, sizeof(u_int32_t
)));
477 bcopy(buf
, &t
[0], len
);
478 p
= (u_int32_t
*)&t
[0];
479 for (i
= 0; i
< howmany(len
, sizeof(u_int32_t
)); i
++)
480 tl
->text
[i
] = ntohl(*p
++);
481 return (crom_add_chunk(src
, parent
, chunk
, CROM_TEXTLEAF
));
485 crom_copy(u_int32_t
*src
, u_int32_t
*dst
, int *offset
, int len
, int maxlen
)
487 if (*offset
+ len
> maxlen
) {
488 kprintf("Config. ROM is too large for the buffer\n");
491 bcopy(src
, (char *)(dst
+ *offset
), len
* sizeof(u_int32_t
));
497 crom_load(struct crom_src
*src
, u_int32_t
*buf
, int maxlen
)
499 struct crom_chunk
*chunk
, *parent
;
509 /* Determine offset */
510 STAILQ_FOREACH(chunk
, &src
->chunk_list
, link
) {
511 chunk
->offset
= offset
;
512 /* Assume the offset of the parent is already known */
513 parent
= chunk
->ref_chunk
;
514 if (parent
!= NULL
) {
516 reg
= (struct csrreg
*)
517 &parent
->data
.buf
[chunk
->ref_index
];
519 (parent
->offset
+ 1 + chunk
->ref_index
);
521 offset
+= 1 + chunk
->data
.crc_len
;
524 /* Calculate CRC and dump to the buffer */
525 len
= 1 + src
->hdr
.info_len
;
527 if (crom_copy((u_int32_t
*)&src
->hdr
, buf
, &count
, len
, maxlen
) < 0)
529 STAILQ_FOREACH(chunk
, &src
->chunk_list
, link
) {
531 crom_crc(&chunk
->data
.buf
[0], chunk
->data
.crc_len
);
533 len
= 1 + chunk
->data
.crc_len
;
534 if (crom_copy((u_int32_t
*)&chunk
->data
, buf
,
535 &count
, len
, maxlen
) < 0)
538 hdr
= (struct csrhdr
*)buf
;
539 hdr
->crc_len
= count
- 1;
540 hdr
->crc
= crom_crc(&buf
[1], hdr
->crc_len
);
545 for (i
= 0; i
< count
; i
++) {
557 main(int argc
, char *argv
[])
560 struct crom_chunk root
,unit1
,unit2
,unit3
;
561 struct crom_chunk text1
,text2
,text3
,text4
,text5
,text6
,text7
;
562 u_int32_t buf
[256], *p
;
565 bzero(&src
, sizeof(src
));
566 bzero(&root
, sizeof(root
));
567 bzero(&unit1
, sizeof(unit1
));
568 bzero(&unit2
, sizeof(unit2
));
569 bzero(&unit3
, sizeof(unit3
));
570 bzero(&text1
, sizeof(text1
));
571 bzero(&text2
, sizeof(text2
));
572 bzero(&text3
, sizeof(text3
));
573 bzero(&text3
, sizeof(text4
));
574 bzero(&text3
, sizeof(text5
));
575 bzero(&text3
, sizeof(text6
));
576 bzero(&text3
, sizeof(text7
));
577 bzero(buf
, sizeof(buf
));
579 /* BUS info sample */
580 src
.hdr
.info_len
= 4;
581 src
.businfo
.bus_name
= CSR_BUS_NAME_IEEE1394
;
582 src
.businfo
.eui64
.hi
= 0x11223344;
583 src
.businfo
.eui64
.lo
= 0x55667788;
584 src
.businfo
.link_spd
= FWSPD_S400
;
585 src
.businfo
.generation
= 0;
586 src
.businfo
.max_rom
= MAXROM_4
;
587 src
.businfo
.max_rec
= 10;
588 src
.businfo
.cyc_clk_acc
= 100;
593 src
.businfo
.irmc
= 1;
594 STAILQ_INIT(&src
.chunk_list
);
597 crom_add_chunk(&src
, NULL
, &root
, 0);
598 crom_add_entry(&root
, CSRKEY_NCAP
, 0x123456);
599 /* private company_id */
600 crom_add_entry(&root
, CSRKEY_VENDOR
, 0xacde48);
603 crom_add_simple_text(&src
, &root
, &text1
, "DragonFly");
604 crom_add_entry(&root
, CSRKEY_HW
, __DragonFly_cc_version
);
605 crom_add_simple_text(&src
, &root
, &text2
, "DragonFly-1");
607 crom_add_simple_text(&src
, &root
, &text1
, "FreeBSD");
608 crom_add_entry(&root
, CSRKEY_HW
, __FreeBSD_version
);
609 crom_add_simple_text(&src
, &root
, &text2
, "FreeBSD-5");
612 /* SBP unit directory */
613 crom_add_chunk(&src
, &root
, &unit1
, CROM_UDIR
);
614 crom_add_entry(&unit1
, CSRKEY_SPEC
, CSRVAL_ANSIT10
);
615 crom_add_entry(&unit1
, CSRKEY_VER
, CSRVAL_T10SBP2
);
616 crom_add_entry(&unit1
, CSRKEY_COM_SPEC
, CSRVAL_ANSIT10
);
617 crom_add_entry(&unit1
, CSRKEY_COM_SET
, CSRVAL_SCSI
);
618 /* management_agent */
619 crom_add_entry(&unit1
, CROM_MGM
, 0x1000);
620 crom_add_entry(&unit1
, CSRKEY_UNIT_CH
, (10<<8) | 8);
621 /* Device type and LUN */
622 crom_add_entry(&unit1
, CROM_LUN
, 0);
623 crom_add_entry(&unit1
, CSRKEY_MODEL
, 1);
624 crom_add_simple_text(&src
, &unit1
, &text3
, "scsi_target");
626 /* RFC2734 IPv4 over IEEE1394 */
627 crom_add_chunk(&src
, &root
, &unit2
, CROM_UDIR
);
628 crom_add_entry(&unit2
, CSRKEY_SPEC
, CSRVAL_IETF
);
629 crom_add_simple_text(&src
, &unit2
, &text4
, "IANA");
630 crom_add_entry(&unit2
, CSRKEY_VER
, 1);
631 crom_add_simple_text(&src
, &unit2
, &text5
, "IPv4");
633 /* RFC3146 IPv6 over IEEE1394 */
634 crom_add_chunk(&src
, &root
, &unit3
, CROM_UDIR
);
635 crom_add_entry(&unit3
, CSRKEY_SPEC
, CSRVAL_IETF
);
636 crom_add_simple_text(&src
, &unit3
, &text6
, "IANA");
637 crom_add_entry(&unit3
, CSRKEY_VER
, 2);
638 crom_add_simple_text(&src
, &unit3
, &text7
, "IPv6");
640 crom_load(&src
, buf
, 256);
642 #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
643 for (i
= 0; i
< 256/8; i
++) {
645 p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);