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 * $FreeBSD: src/sys/dev/firewire/fwcrom.c,v 1.9 2003/10/02 04:06:55 simokawa Exp $
37 #include <sys/param.h>
38 #if defined(_KERNEL) || defined(TEST)
39 #include <sys/queue.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
45 #include <netinet/in.h>
51 #define ksnprintf snprintf /* sigh. used by fwcontrol */
52 #define kprintf printf
55 #include <bus/firewire/firewire.h>
56 #include <bus/firewire/iec13213.h>
58 #define MAX_ROM (1024 - sizeof(u_int32_t) * 5)
59 #define CROM_END(cc) ((vm_offset_t)(cc)->stack[0].dir + MAX_ROM - 1)
62 crom_init_context(struct crom_context
*cc
, u_int32_t
*p
)
66 hdr
= (struct csrhdr
*)p
;
67 if (hdr
->info_len
== 0) {
69 * This isn't supposed to happen but it does. The problem
70 * is possibly related to fw_attach_dev()'s going from an
71 * FWDEVINIT to a FWDEVATTACHED state, or in a host<->host
72 * situation where one host gets the root directory for
73 * another before the other has actually initialized it.
75 kprintf("crom_init_context: WARNING, info_len is 0\n");
79 if (hdr
->info_len
== 1) {
83 p
+= 1 + hdr
->info_len
;
85 /* check size of root directory */
86 if (((struct csrdirectory
*)p
)->crc_len
== 0) {
91 cc
->stack
[0].dir
= (struct csrdirectory
*)p
;
92 cc
->stack
[0].index
= 0;
96 crom_get(struct crom_context
*cc
)
100 ptr
= &cc
->stack
[cc
->depth
];
101 return (&ptr
->dir
->entry
[ptr
->index
]);
105 crom_next(struct crom_context
*cc
)
107 struct crom_ptr
*ptr
;
113 if ((reg
->key
& CSRTYPE_MASK
) == CSRTYPE_D
) {
114 if (cc
->depth
>= CROM_MAX_DEPTH
) {
115 kprintf("crom_next: too deep\n");
120 ptr
= &cc
->stack
[cc
->depth
];
121 ptr
->dir
= (struct csrdirectory
*) (reg
+ reg
->val
);
126 ptr
= &cc
->stack
[cc
->depth
];
129 if (ptr
->index
< ptr
->dir
->crc_len
&&
130 (vm_offset_t
)crom_get(cc
) <= CROM_END(cc
))
133 if (ptr
->index
< ptr
->dir
->crc_len
)
134 kprintf("crom_next: bound check failed\n");
146 crom_search_key(struct crom_context
*cc
, u_int8_t key
)
150 while(cc
->depth
>= 0) {
160 crom_has_specver(u_int32_t
*p
, u_int32_t spec
, u_int32_t ver
)
163 struct crom_context c
, *cc
;
167 crom_init_context(cc
, p
);
168 while(cc
->depth
>= 0) {
171 if (reg
->key
== CSRKEY_SPEC
&& reg
->val
== spec
)
176 if (reg
->key
== CSRKEY_VER
&& reg
->val
== ver
)
187 crom_parse_text(struct crom_context
*cc
, char *buf
, int len
)
190 struct csrtext
*textleaf
;
193 static const char *nullstr
= "(null)";
199 if (reg
->key
!= CROM_TEXTLEAF
||
200 (vm_offset_t
)(reg
+ reg
->val
) > CROM_END(cc
)) {
201 strncpy(buf
, nullstr
, len
);
204 textleaf
= (struct csrtext
*)(reg
+ reg
->val
);
206 if ((vm_offset_t
)textleaf
+ textleaf
->crc_len
> CROM_END(cc
)) {
207 strncpy(buf
, nullstr
, len
);
211 /* XXX should check spec and type */
213 bp
= (u_int32_t
*)&buf
[0];
214 qlen
= textleaf
->crc_len
- 2;
217 for (i
= 0; i
< qlen
; i
++)
218 *bp
++ = ntohl(textleaf
->text
[i
]);
219 /* make sure to terminate the string */
227 crom_crc(u_int32_t
*ptr
, int len
)
230 u_int32_t data
, sum
, crc
= 0;
232 for (i
= 0; i
< len
; i
++) {
234 for (shift
= 28; shift
>= 0; shift
-= 4) {
235 sum
= ((crc
>> 12) ^ (data
>> shift
)) & 0xf;
236 crc
= (crc
<< 4) ^ (sum
<< 12) ^ (sum
<< 5) ^ sum
;
240 return((u_int16_t
) crc
);
245 crom_desc_specver(u_int32_t spec
, u_int32_t ver
, char *buf
, int len
)
247 const char *s
= NULL
;
249 if (spec
== CSRVAL_ANSIT10
|| spec
== 0) {
256 s
= "unknown ANSIT10";
259 if (spec
== CSRVAL_1394TA
|| spec
== 0) {
283 s
= "1394 Direct print";
286 s
= "Industrial & Instrument";
290 s
= "unknown 1394TA";
294 ksnprintf(buf
, len
, "%s", s
);
298 crom_desc(struct crom_context
*cc
, char *buf
, int len
)
301 struct csrdirectory
*dir
;
306 switch (reg
->key
& CSRTYPE_MASK
) {
309 len
-= ksnprintf(buf
, len
, "%d", reg
->val
);
316 len
-= ksnprintf(buf
, len
, "offset=0x%04x(%d)",
321 /* XXX fall through */
323 dir
= (struct csrdirectory
*) (reg
+ reg
->val
);
324 crc
= crom_crc((u_int32_t
*)&dir
->entry
[0], dir
->crc_len
);
325 len
-= ksnprintf(buf
, len
, "len=%d crc=0x%04x(%s) ",
326 dir
->crc_len
, dir
->crc
,
327 (crc
== dir
->crc
) ? "OK" : "NG");
332 desc
= "module_vendor_ID";
335 desc
= "hardware_version";
338 desc
= "node_capabilities";
341 desc
= "unit_spec_ID";
344 desc
= "unit_sw_version";
345 crom_desc_specver(0, reg
->val
, buf
, len
);
348 desc
= "logical_unit_number";
354 desc
= "command_set_spec_ID";
357 desc
= "command_set";
360 desc
= "unit_characteristics";
363 desc
= "command_set_revision";
366 desc
= "firmware_revision";
369 desc
= "reconnect_timeout";
372 desc
= "management_agent";
376 crom_parse_text(cc
, buf
+ strlen(buf
), len
);
379 desc
= "unit_directory";
382 desc
= "logical_unit_directory";
391 #if defined(_KERNEL) || defined(TEST)
394 crom_add_quad(struct crom_chunk
*chunk
, u_int32_t entry
)
398 index
= chunk
->data
.crc_len
;
399 if (index
>= CROM_MAX_CHUNK_LEN
- 1) {
400 kprintf("too large chunk %d\n", index
);
403 chunk
->data
.buf
[index
] = entry
;
404 chunk
->data
.crc_len
++;
409 crom_add_entry(struct crom_chunk
*chunk
, int key
, int val
)
414 reg
= (struct csrreg
*)(void *)&i
;
417 return(crom_add_quad(chunk
, i
));
421 crom_add_chunk(struct crom_src
*src
, struct crom_chunk
*parent
,
422 struct crom_chunk
*child
, int key
)
426 if (parent
== NULL
) {
427 STAILQ_INSERT_TAIL(&src
->chunk_list
, child
, link
);
431 index
= crom_add_entry(parent
, key
, 0);
435 child
->ref_chunk
= parent
;
436 child
->ref_index
= index
;
437 STAILQ_INSERT_TAIL(&src
->chunk_list
, child
, link
);
441 #define MAX_TEXT ((CROM_MAX_CHUNK_LEN + 1) * 4 - sizeof(struct csrtext))
443 crom_add_simple_text(struct crom_src
*src
, struct crom_chunk
*parent
,
444 struct crom_chunk
*chunk
, char *buf
)
452 if (len
> MAX_TEXT
) {
453 kprintf("text(%d) truncated to %lu.\n", len
, (u_long
)MAX_TEXT
);
457 tl
= (struct csrtext
*)(void *)&chunk
->data
;
458 tl
->crc_len
= howmany(sizeof(struct csrtext
) + len
, sizeof(u_int32_t
));
462 bzero(&t
[0], roundup2(len
, sizeof(u_int32_t
)));
463 bcopy(buf
, &t
[0], len
);
464 p
= (u_int32_t
*)&t
[0];
465 for (i
= 0; i
< howmany(len
, sizeof(u_int32_t
)); i
++)
466 tl
->text
[i
] = ntohl(*p
++);
467 return (crom_add_chunk(src
, parent
, chunk
, CROM_TEXTLEAF
));
471 crom_copy(u_int32_t
*src
, u_int32_t
*dst
, int *offset
, int len
, int maxlen
)
473 if (*offset
+ len
> maxlen
) {
474 kprintf("Config. ROM is too large for the buffer\n");
477 bcopy(src
, (char *)(dst
+ *offset
), len
* sizeof(u_int32_t
));
483 crom_load(struct crom_src
*src
, u_int32_t
*buf
, int maxlen
)
485 struct crom_chunk
*chunk
, *parent
;
495 /* Determine offset */
496 STAILQ_FOREACH(chunk
, &src
->chunk_list
, link
) {
497 chunk
->offset
= offset
;
498 /* Assume the offset of the parent is already known */
499 parent
= chunk
->ref_chunk
;
500 if (parent
!= NULL
) {
502 reg
= (struct csrreg
*)
503 &parent
->data
.buf
[chunk
->ref_index
];
505 (parent
->offset
+ 1 + chunk
->ref_index
);
507 offset
+= 1 + chunk
->data
.crc_len
;
510 /* Calculate CRC and dump to the buffer */
511 len
= 1 + src
->hdr
.info_len
;
513 if (crom_copy((u_int32_t
*)(void *)&src
->hdr
, buf
, &count
, len
, maxlen
) < 0)
515 STAILQ_FOREACH(chunk
, &src
->chunk_list
, link
) {
517 crom_crc(&chunk
->data
.buf
[0], chunk
->data
.crc_len
);
519 len
= 1 + chunk
->data
.crc_len
;
520 if (crom_copy((u_int32_t
*)&chunk
->data
, buf
,
521 &count
, len
, maxlen
) < 0)
524 hdr
= (struct csrhdr
*)buf
;
525 hdr
->crc_len
= count
- 1;
526 hdr
->crc
= crom_crc(&buf
[1], hdr
->crc_len
);
531 for (i
= 0; i
< count
; i
++) {
543 main(int argc
, char *argv
[])
546 struct crom_chunk root
,unit1
,unit2
,unit3
;
547 struct crom_chunk text1
,text2
,text3
,text4
,text5
,text6
,text7
;
548 u_int32_t buf
[256], *p
;
551 bzero(&src
, sizeof(src
));
552 bzero(&root
, sizeof(root
));
553 bzero(&unit1
, sizeof(unit1
));
554 bzero(&unit2
, sizeof(unit2
));
555 bzero(&unit3
, sizeof(unit3
));
556 bzero(&text1
, sizeof(text1
));
557 bzero(&text2
, sizeof(text2
));
558 bzero(&text3
, sizeof(text3
));
559 bzero(&text3
, sizeof(text4
));
560 bzero(&text3
, sizeof(text5
));
561 bzero(&text3
, sizeof(text6
));
562 bzero(&text3
, sizeof(text7
));
563 bzero(buf
, sizeof(buf
));
565 /* BUS info sample */
566 src
.hdr
.info_len
= 4;
567 src
.businfo
.bus_name
= CSR_BUS_NAME_IEEE1394
;
568 src
.businfo
.eui64
.hi
= 0x11223344;
569 src
.businfo
.eui64
.lo
= 0x55667788;
570 src
.businfo
.link_spd
= FWSPD_S400
;
571 src
.businfo
.generation
= 0;
572 src
.businfo
.max_rom
= MAXROM_4
;
573 src
.businfo
.max_rec
= 10;
574 src
.businfo
.cyc_clk_acc
= 100;
579 src
.businfo
.irmc
= 1;
580 STAILQ_INIT(&src
.chunk_list
);
583 crom_add_chunk(&src
, NULL
, &root
, 0);
584 crom_add_entry(&root
, CSRKEY_NCAP
, 0x123456);
585 /* private company_id */
586 crom_add_entry(&root
, CSRKEY_VENDOR
, 0xacde48);
588 crom_add_simple_text(&src
, &root
, &text1
, "DragonFly");
589 crom_add_entry(&root
, CSRKEY_HW
, __DragonFly_version
);
590 crom_add_simple_text(&src
, &root
, &text2
, "DragonFly-1");
592 /* SBP unit directory */
593 crom_add_chunk(&src
, &root
, &unit1
, CROM_UDIR
);
594 crom_add_entry(&unit1
, CSRKEY_SPEC
, CSRVAL_ANSIT10
);
595 crom_add_entry(&unit1
, CSRKEY_VER
, CSRVAL_T10SBP2
);
596 crom_add_entry(&unit1
, CSRKEY_COM_SPEC
, CSRVAL_ANSIT10
);
597 crom_add_entry(&unit1
, CSRKEY_COM_SET
, CSRVAL_SCSI
);
598 /* management_agent */
599 crom_add_entry(&unit1
, CROM_MGM
, 0x1000);
600 crom_add_entry(&unit1
, CSRKEY_UNIT_CH
, (10<<8) | 8);
601 /* Device type and LUN */
602 crom_add_entry(&unit1
, CROM_LUN
, 0);
603 crom_add_entry(&unit1
, CSRKEY_MODEL
, 1);
604 crom_add_simple_text(&src
, &unit1
, &text3
, "scsi_target");
606 /* RFC2734 IPv4 over IEEE1394 */
607 crom_add_chunk(&src
, &root
, &unit2
, CROM_UDIR
);
608 crom_add_entry(&unit2
, CSRKEY_SPEC
, CSRVAL_IETF
);
609 crom_add_simple_text(&src
, &unit2
, &text4
, "IANA");
610 crom_add_entry(&unit2
, CSRKEY_VER
, 1);
611 crom_add_simple_text(&src
, &unit2
, &text5
, "IPv4");
613 /* RFC3146 IPv6 over IEEE1394 */
614 crom_add_chunk(&src
, &root
, &unit3
, CROM_UDIR
);
615 crom_add_entry(&unit3
, CSRKEY_SPEC
, CSRVAL_IETF
);
616 crom_add_simple_text(&src
, &unit3
, &text6
, "IANA");
617 crom_add_entry(&unit3
, CSRKEY_VER
, 2);
618 crom_add_simple_text(&src
, &unit3
, &text7
, "IPv6");
620 crom_load(&src
, buf
, 256);
622 #define DUMP_FORMAT "%08x %08x %08x %08x %08x %08x %08x %08x\n"
623 for (i
= 0; i
< 256/8; i
++) {
625 p
[0], p
[1], p
[2], p
[3], p
[4], p
[5], p
[6], p
[7]);