4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * SBP2 config ROM routines
33 #include <sys/types.h>
35 #include <sys/sunddi.h>
37 #include <sys/1394/ieee1212.h>
38 #include <sys/sbp2/impl.h>
40 static int sbp2_cfgrom_rq(sbp2_tgt_t
*, void *, uint64_t, uint32_t *);
41 static int sbp2_cfgrom_parse_dir(sbp2_tgt_t
*, void *,
42 sbp2_cfgrom_parse_arg_t
*);
43 static int sbp2_cfgrom_read_leaf(sbp2_tgt_t
*, void *,
45 static int sbp2_cfgrom_read_bib(sbp2_tgt_t
*, void *, sbp2_cfgrom_bib_t
*);
46 static void sbp2_cfgrom_free_bib(sbp2_tgt_t
*, sbp2_cfgrom_bib_t
*);
47 static void sbp2_cfgrom_dir_grow(sbp2_cfgrom_dir_t
*, int);
48 static sbp2_cfgrom_ent_t
*sbp2_cfgrom_dir_new_ent(sbp2_cfgrom_dir_t
*);
49 static int sbp2_cfgrom_walk_impl(sbp2_cfgrom_ent_t
*,
50 int (*)(void *, sbp2_cfgrom_ent_t
*, int), void *, int);
51 static int sbp2_cfgrom_ent_by_key_walker(void *, sbp2_cfgrom_ent_t
*,
53 static void sbp2_cfgrom_walk_free(sbp2_cfgrom_ent_t
*);
55 static hrtime_t sbp2_cfgrom_read_delay
= 20 * 1000000; /* in ns */
57 /* imitate throwing an exception when read fails */
58 #define SBP2_CFGROM_RQ(tp, cmd, addr, q) \
59 if ((ret = sbp2_cfgrom_rq(tp, cmd, addr, q)) != 0) { \
64 sbp2_cfgrom_rq(sbp2_tgt_t
*tp
, void *cmd
, uint64_t addr
, uint32_t *q
)
66 hrtime_t tm
; /* time since last read */
70 tm
= gethrtime() - tp
->t_last_cfgrd
;
71 if (tm
< sbp2_cfgrom_read_delay
) {
72 delay(drv_usectohz((sbp2_cfgrom_read_delay
- tm
) / 1000));
74 ret
= SBP2_RQ(tp
, cmd
, addr
, q
, &berr
);
76 tp
->t_last_cfgrd
= gethrtime();
81 sbp2_cfgrom_parse(sbp2_tgt_t
*tp
, sbp2_cfgrom_t
*crp
)
83 sbp2_cfgrom_ent_t
*root_dir
= &crp
->cr_root
;
84 sbp2_cfgrom_bib_t
*bib
= &crp
->cr_bib
;
87 sbp2_cfgrom_parse_arg_t pa
;
89 if ((ret
= SBP2_ALLOC_CMD(tp
, &cmd
, 0)) != SBP2_SUCCESS
) {
93 if ((ret
= sbp2_cfgrom_read_bib(tp
, cmd
, bib
)) != SBP2_SUCCESS
) {
94 SBP2_FREE_CMD(tp
, cmd
);
98 /* parse root directory and everything underneath */
99 bzero(root_dir
, sizeof (sbp2_cfgrom_ent_t
));
100 root_dir
->ce_kt
= IEEE1212_DIRECTORY_TYPE
;
101 root_dir
->ce_offset
= SBP2_CFGROM_ADDR(tp
) + 4 + bib
->cb_len
* 4;
102 pa
.pa_dir
= root_dir
;
107 if ((ret
= sbp2_cfgrom_parse_dir(tp
, cmd
, &pa
)) != SBP2_SUCCESS
) {
108 sbp2_cfgrom_free(tp
, crp
);
111 SBP2_FREE_CMD(tp
, cmd
);
117 * Caller must initialize pa and pa->pa_dir.
120 sbp2_cfgrom_parse_dir(sbp2_tgt_t
*tp
, void *cmd
, sbp2_cfgrom_parse_arg_t
*pa
)
122 sbp2_cfgrom_ent_t
*dir
= pa
->pa_dir
; /* directory being parsed */
123 sbp2_cfgrom_ent_t
*cep
; /* current entry structure */
124 sbp2_cfgrom_ent_t
*pcep
= NULL
; /* previous entry structure */
125 sbp2_cfgrom_parse_arg_t this_pa
; /* parse args */
126 uint64_t addr
; /* current address */
127 uint32_t entry
; /* current entry */
128 uint8_t t
, k
; /* key type and value */
129 uint32_t v
; /* entry value */
133 this_pa
.pa_pdir
= dir
;
134 this_pa
.pa_ref
= pa
->pa_ref
;
135 this_pa
.pa_depth
= pa
->pa_depth
+ 1;
137 /* read directory entry and initialize the structure */
138 SBP2_CFGROM_RQ(tp
, cmd
, dir
->ce_offset
, &entry
);
139 dir
->ce_len
= IEEE1212_DIR_LEN(entry
);
140 sbp2_cfgrom_dir_grow(&dir
->ce_data
.dir
, dir
->ce_len
);
142 /* walk directory entries */
143 addr
= dir
->ce_offset
+ 4;
144 for (i
= 0; i
< dir
->ce_len
; i
++, addr
+= 4) {
145 SBP2_CFGROM_RQ(tp
, cmd
, addr
, &entry
);
146 CFGROM_TYPE_KEY_VALUE(entry
, t
, k
, v
);
148 cep
= sbp2_cfgrom_dir_new_ent(&dir
->ce_data
.dir
);
152 case IEEE1212_IMMEDIATE_TYPE
:
154 cep
->ce_offset
= addr
;
155 cep
->ce_data
.imm
= v
;
157 case IEEE1212_CSR_OFFSET_TYPE
:
159 cep
->ce_offset
= addr
;
160 cep
->ce_data
.offset
= v
;
162 case IEEE1212_LEAF_TYPE
:
163 cep
->ce_offset
= addr
+ 4 * v
;
164 if (dir
->ce_kv
!= IEEE1212_TEXTUAL_DESCRIPTOR
) {
165 /* text leaf describes preceding entry */
168 /* text directory describes preceding entry */
169 cep
->ce_ref
= this_pa
.pa_ref
;
171 ret
= sbp2_cfgrom_read_leaf(tp
, cmd
, cep
);
173 case IEEE1212_DIRECTORY_TYPE
:
174 cep
->ce_offset
= addr
+ 4 * v
;
175 this_pa
.pa_dir
= cep
;
176 this_pa
.pa_ref
= pcep
;
177 if (this_pa
.pa_depth
< SBP2_CFGROM_MAX_DEPTH
) {
178 ret
= sbp2_cfgrom_parse_dir(tp
, cmd
, &this_pa
);
193 sbp2_cfgrom_read_leaf(sbp2_tgt_t
*tp
, void *cmd
, sbp2_cfgrom_ent_t
*cep
)
198 uint64_t addr
= cep
->ce_offset
;
201 SBP2_CFGROM_RQ(tp
, cmd
, addr
, &val
);
204 /* verify data length */
205 cep
->ce_len
= (val
>> 16);
206 if (cep
->ce_len
< 1) {
209 cep
->ce_data
.leaf
= kmem_zalloc(cep
->ce_len
* 4, KM_SLEEP
);
212 for (i
= 0; i
< cep
->ce_len
; i
++, addr
+= 4) {
213 SBP2_CFGROM_RQ(tp
, cmd
, addr
, &cep
->ce_data
.leaf
[i
]);
219 if (cep
->ce_data
.leaf
) {
220 kmem_free(cep
->ce_data
.leaf
, cep
->ce_len
* 4);
227 sbp2_cfgrom_read_bib(sbp2_tgt_t
*tp
, void *cmd
, sbp2_cfgrom_bib_t
*cbp
)
232 uint64_t addr
= SBP2_CFGROM_ADDR(tp
);
235 SBP2_CFGROM_RQ(tp
, cmd
, addr
, &val
);
238 /* verify data length */
239 cbp
->cb_len
= (val
>> 24);
240 if (cbp
->cb_len
< 1) {
243 cbp
->cb_buf
= kmem_zalloc(cbp
->cb_len
* 4, KM_SLEEP
);
246 for (i
= 0; i
< cbp
->cb_len
; i
++, addr
+= 4) {
247 SBP2_CFGROM_RQ(tp
, cmd
, addr
, &cbp
->cb_buf
[i
]);
251 sbp2_cfgrom_free_bib(tp
, cbp
);
258 sbp2_cfgrom_free_bib(sbp2_tgt_t
*tp
, sbp2_cfgrom_bib_t
*cbp
)
260 if ((cbp
->cb_buf
!= NULL
) && (cbp
->cb_len
> 0)) {
261 kmem_free(cbp
->cb_buf
, cbp
->cb_len
* 4);
267 sbp2_cfgrom_dir_grow(sbp2_cfgrom_dir_t
*dir
, int incr
)
269 int new_size
, old_size
;
274 new_size
= (dir
->cd_size
+ incr
) * sizeof (sbp2_cfgrom_ent_t
);
275 new_ent
= kmem_zalloc(new_size
, KM_SLEEP
);
276 if (dir
->cd_size
> 0) {
277 old_size
= dir
->cd_size
* sizeof (sbp2_cfgrom_ent_t
);
278 bcopy(dir
->cd_ent
, new_ent
, old_size
);
279 kmem_free(dir
->cd_ent
, old_size
);
281 dir
->cd_ent
= new_ent
;
282 dir
->cd_size
+= incr
;
285 static sbp2_cfgrom_ent_t
*
286 sbp2_cfgrom_dir_new_ent(sbp2_cfgrom_dir_t
*dir
)
288 /* grow if out of entries */
289 if (dir
->cd_cnt
>= dir
->cd_size
) {
290 ASSERT(dir
->cd_cnt
== dir
->cd_size
);
291 sbp2_cfgrom_dir_grow(dir
, SBP2_CFGROM_GROW_INCR
);
294 return (&dir
->cd_ent
[dir
->cd_cnt
++]);
298 * walk Config ROM entries calling the specified function for each
301 sbp2_cfgrom_walk(sbp2_cfgrom_ent_t
*dir
,
302 int (*func
)(void *, sbp2_cfgrom_ent_t
*, int), void *arg
)
304 ASSERT(dir
->ce_kt
== IEEE1212_DIRECTORY_TYPE
);
305 (void) sbp2_cfgrom_walk_impl(dir
, func
, arg
, 0);
309 sbp2_cfgrom_walk_impl(sbp2_cfgrom_ent_t
*dir
,
310 int (*func
)(void *, sbp2_cfgrom_ent_t
*, int), void *arg
, int level
)
313 sbp2_cfgrom_ent_t
*ent
;
315 for (i
= 0; i
< dir
->ce_data
.dir
.cd_cnt
; i
++) {
316 ent
= &dir
->ce_data
.dir
.cd_ent
[i
];
317 if (func(arg
, ent
, level
) == SBP2_WALK_STOP
) {
318 return (SBP2_WALK_STOP
);
320 if (ent
->ce_kt
== IEEE1212_DIRECTORY_TYPE
) {
321 if (sbp2_cfgrom_walk_impl(ent
, func
, arg
, level
+ 1) ==
323 return (SBP2_WALK_STOP
);
327 return (SBP2_WALK_CONTINUE
);
332 sbp2_cfgrom_ent_by_key(sbp2_cfgrom_ent_t
*dir
, int8_t kt
, int8_t kv
, int num
)
334 sbp2_cfgrom_ent_by_key_t ebk
;
341 sbp2_cfgrom_walk(dir
, sbp2_cfgrom_ent_by_key_walker
, &ebk
);
348 sbp2_cfgrom_ent_by_key_walker(void *arg
, sbp2_cfgrom_ent_t
*ent
, int level
)
350 sbp2_cfgrom_ent_by_key_t
*ebk
= arg
;
352 if ((ent
->ce_kt
== ebk
->kt
) && (ent
->ce_kv
== ebk
->kv
)) {
353 if (ebk
->cnt
== ebk
->num
) {
355 return (SBP2_WALK_STOP
);
359 return (SBP2_WALK_CONTINUE
);
364 sbp2_cfgrom_free(sbp2_tgt_t
*tp
, sbp2_cfgrom_t
*crp
)
366 sbp2_cfgrom_free_bib(tp
, &crp
->cr_bib
);
367 sbp2_cfgrom_walk_free(&crp
->cr_root
);
371 sbp2_cfgrom_walk_free(sbp2_cfgrom_ent_t
*dir
)
374 sbp2_cfgrom_dir_t
*cdp
= &dir
->ce_data
.dir
;
375 sbp2_cfgrom_ent_t
*ent
= cdp
->cd_ent
;
377 for (i
= 0; i
< cdp
->cd_cnt
; i
++) {
378 if (ent
[i
].ce_kt
== IEEE1212_DIRECTORY_TYPE
) {
379 sbp2_cfgrom_walk_free(&ent
[i
]);
380 } else if ((ent
[i
].ce_kt
== IEEE1212_LEAF_TYPE
) &&
381 (ent
[i
].ce_data
.leaf
!= NULL
)) {
382 kmem_free(ent
[i
].ce_data
.leaf
, ent
[i
].ce_len
* 4);
386 kmem_free(ent
, cdp
->cd_size
* sizeof (sbp2_cfgrom_ent_t
));