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 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
29 * 1394 Services Layer Hotplug Routines
30 * This file contains routines that walk the old and topology
31 * trees, at bus reset time, creating devinfo's for new nodes and offlining
32 * nodes that are removed.
36 #include <sys/sysmacros.h>
38 #include <sys/sunddi.h>
39 #include <sys/sunndi.h>
40 #include <sys/modctl.h>
41 #include <sys/sunddi.h>
42 #include <sys/ddi_impldefs.h>
43 #include <sys/types.h>
45 #include <sys/tnf_probe.h>
47 #include <sys/1394/t1394.h>
48 #include <sys/1394/s1394.h>
49 #include <sys/1394/h1394.h>
50 #include <sys/1394/ieee1394.h>
52 static void s1394_send_remove_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
53 t1394_localinfo_t
*localinfo
);
54 static void s1394_send_insert_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
55 t1394_localinfo_t
*localinfo
);
56 static dev_info_t
*s1394_create_devinfo(s1394_hal_t
*hal
, s1394_node_t
*node
,
57 uint32_t *unit_dir
, int nunit
);
58 static void s1394_update_unit_dir_location(s1394_hal_t
*hal
, dev_info_t
*tdip
,
62 * s1394_send_remove_event()
63 * Invokes any "remove event" callback registered for dip. Passes
64 * t1394_localinfo_t as impl_data for the callback.
67 s1394_send_remove_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
68 t1394_localinfo_t
*localinfo
)
71 ddi_eventcookie_t cookie
;
73 (void) sprintf(name
, "%s%d", ddi_driver_name(dip
),
74 ddi_get_instance(dip
));
76 TNF_PROBE_1_DEBUG(s1394_send_remove_event_enter
,
77 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_string
, device
,
80 if (ndi_event_retrieve_cookie(hal
->hal_ndi_event_hdl
, dip
,
81 DDI_DEVI_REMOVE_EVENT
, &cookie
, NDI_EVENT_NOPASS
)
83 (void) ndi_event_run_callbacks(hal
->hal_ndi_event_hdl
, dip
,
86 TNF_PROBE_0_DEBUG(s1394_send_remove_event_exit
,
87 S1394_TNF_SL_HOTPLUG_STACK
, "");
91 * s1394_send_insert_event()
92 * Invokes any "insert event" callback registered for dip. Passes
93 * t1394_localinfo_t as impl_data for the callback.
96 s1394_send_insert_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
97 t1394_localinfo_t
*localinfo
)
100 ddi_eventcookie_t cookie
;
102 (void) sprintf(name
, "%s%d", ddi_driver_name(dip
),
103 ddi_get_instance(dip
));
105 TNF_PROBE_1_DEBUG(s1394_send_insert_event_enter
,
106 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_string
, device
,
109 if (ndi_event_retrieve_cookie(hal
->hal_ndi_event_hdl
, dip
,
110 DDI_DEVI_INSERT_EVENT
, &cookie
, NDI_EVENT_NOPASS
) ==
112 (void) ndi_event_run_callbacks(hal
->hal_ndi_event_hdl
, dip
,
115 TNF_PROBE_0_DEBUG(s1394_send_insert_event_exit
,
116 S1394_TNF_SL_HOTPLUG_STACK
, "");
120 * s1394_create_devinfo()
121 * This routine creates a devinfo corresponding to the unit_dir passed in.
122 * It adds "hp-node", "reg", "compatible" properties to the devinfo
123 * (formats for "reg" and "compatible" properties are specified by 1275
124 * binding for IEEE1394). If unable to create the devinfo and/or add the
125 * the properties, returns NULL, otherwise, returns the devinfo created.
127 * NOTE: All ndi_* routines are interrupt callable (and thus won't sleep).
128 * So, we don't drop topology_mutex across ndi calls.
131 s1394_create_devinfo(s1394_hal_t
*hal
, s1394_node_t
*node
, uint32_t *unit_dir
,
136 dev_info_t
*target_dip
;
139 int result
, i
, j
, spec_id
, sw_version
;
140 int mod_ven
, mod_hw
, mod_spec
, mod_sw
;
141 int node_ven
, node_hw
, node_spec
, node_sw
;
143 /*LINTED type is unused*/
144 uint32_t type __unused
, key
, value
;
145 uint32_t unit_spec_id
, unit_sw_version
;
146 uint32_t node_spec_id
, node_sw_version
;
147 uint32_t node_vendor_id
, node_hw_version
;
148 uint32_t module_spec_id
, module_sw_version
;
149 uint32_t module_vendor_id
, module_hw_version
;
151 char *fmt
= "firewire%06x,%06x";
153 char *buf
[5], data
[5][24];
156 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
158 TNF_PROBE_2_DEBUG(s1394_create_devinfo_enter
,
159 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_uint
, guid_hi
,
160 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
);
162 hal_dip
= hal
->halinfo
.dip
;
164 /* Allocate and init a new device node instance. */
165 result
= ndi_devi_alloc(hal_dip
, "unit", (pnode_t
)DEVI_SID_NODEID
,
168 if (result
!= NDI_SUCCESS
) {
169 cmn_err(CE_NOTE
, "!Unable to create devinfo"
170 " (node's GUID %08x%08x)", node
->node_guid_hi
,
172 TNF_PROBE_2(s1394_create_devinfo_fail_alloc
,
173 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
, guid_hi
,
174 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
);
175 TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit
,
176 S1394_TNF_SL_HOTPLUG_STACK
, "");
180 /* Add "hp-node" property */
181 result
= ndi_prop_update_int(DDI_DEV_T_NONE
, target_dip
, "hp-node", 0);
182 if (result
!= NDI_SUCCESS
) {
183 cmn_err(CE_NOTE
, "!Unable to add \"hp-node\" property"
184 " (node's GUID %08x%08x)", node
->node_guid_hi
,
187 cmn_err(CE_CONT
, "!Error code %d", result
);
189 TNF_PROBE_3(s1394_create_devinfo_hp_node
,
190 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
, guid_hi
,
191 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
,
192 tnf_int
, error
, result
);
193 ndi_prop_remove_all(target_dip
);
194 (void) ndi_devi_free(target_dip
);
195 TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit
,
196 S1394_TNF_SL_HOTPLUG_STACK
, "");
200 spec_id
= sw_version
= mod_ven
= mod_hw
= mod_spec
= mod_sw
=
201 node_ven
= node_hw
= node_spec
= node_sw
= 0;
202 unit_sw_version
= node_sw_version
= node_hw_version
=
203 module_sw_version
= module_hw_version
= 0;
206 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
207 root_dir_len
= CFGROM_DIR_LEN(root_dir
);
209 for (i
= 0; i
< root_dir_len
; i
++) {
211 CFGROM_TYPE_KEY_VALUE(root_dir
[i
+ 1], type
, key
, value
);
214 case IEEE1212_MODULE_VENDOR_ID
:
215 module_vendor_id
= value
;
218 case IEEE1212_MODULE_HW_VERSION
:
219 module_hw_version
= value
;
222 case IEEE1212_MODULE_SPEC_ID
:
223 module_spec_id
= value
;
226 case IEEE1212_MODULE_SW_VERSION
:
227 module_sw_version
= value
;
230 case IEEE1212_NODE_VENDOR_ID
:
231 node_vendor_id
= value
;
234 case IEEE1212_NODE_UNIQUE_ID
: {
235 uint32_t *node_unique_leaf
=
236 &root_dir
[i
+ 1] + value
;
237 node_vendor_id
= (node_unique_leaf
[1] >> 8);
241 case IEEE1212_NODE_HW_VERSION
:
242 node_hw_version
= value
;
245 case IEEE1212_NODE_SPEC_ID
:
246 node_spec_id
= value
;
249 case IEEE1212_NODE_SW_VERSION
:
250 node_sw_version
= value
;
255 if (mod_ven
&& mod_hw
&& mod_spec
&& mod_sw
&& node_ven
&&
256 node_hw
&& node_spec
&& node_sw
) {
262 * Search for unit spec and version
264 for (i
= 0; i
< CFGROM_DIR_LEN(unit_dir
); i
++) {
266 CFGROM_TYPE_KEY_VALUE(unit_dir
[i
+ 1], type
, key
, value
);
267 if (key
== IEEE1212_UNIT_SPEC_ID
) {
269 unit_spec_id
= value
;
271 } else if (key
== IEEE1212_UNIT_SW_VERSION
) {
273 unit_sw_version
= value
;
276 if (spec_id
&& sw_version
)
281 * Refer to IEEE1212 (pages 90-92) for information regarding various
282 * id's. Module_Vendor_Id is required. Node_Vendor_Id is optional and
283 * if not implemented, its assumed value is Module_Vendor_Id.
284 * Module_Spec_Id is optional and if not implemented, its assumed value
285 * is Module_Vendor_Id. Node_Spec_Id is optional, and if not
286 * implemented, its assumed value is Node_Vendor_Id. Unit_Spec_Id is
287 * optional, and if not implemented, its assumed value is
291 node_vendor_id
= module_vendor_id
;
295 if (node_spec
== 0) {
296 node_spec_id
= node_vendor_id
;
301 module_spec_id
= module_vendor_id
;
306 unit_spec_id
= node_vendor_id
;
311 if (sw_version
!= 0) {
313 (void) sprintf(data
[i
++], fmt
, unit_spec_id
, unit_sw_version
);
317 (void) sprintf(data
[i
++], fmt
, node_spec_id
, node_sw_version
);
321 (void) sprintf(data
[i
++], fmt
, node_vendor_id
, node_hw_version
);
325 (void) sprintf(data
[i
++], fmt
, module_spec_id
,
330 (void) sprintf(data
[i
++], fmt
, module_vendor_id
,
334 result
= ndi_prop_update_string_array(DDI_DEV_T_NONE
, target_dip
,
335 "compatible", (char **)&buf
, i
);
336 if (result
!= NDI_SUCCESS
) {
337 cmn_err(CE_NOTE
, "!Unable to add \"compatible\" property"
338 " (node's GUID %08x%08x)", node
->node_guid_hi
,
341 cmn_err(CE_CONT
, "!Error code %d; nelements %d", result
, i
);
342 for (j
= 0; j
< i
; j
++) {
343 cmn_err(CE_CONT
, "!buf[%d]: %s", j
, buf
[j
]);
346 ndi_prop_remove_all(target_dip
);
347 (void) ndi_devi_free(target_dip
);
348 TNF_PROBE_4(s1394_create_devinfo_fail_compat
,
349 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
, guid_hi
,
350 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
,
351 tnf_int
, error
, result
, tnf_int
, nelements
, i
);
352 TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit
,
353 S1394_TNF_SL_HOTPLUG_STACK
, "");
357 for (j
= 0; j
< i
; j
++) {
358 TNF_PROBE_2_DEBUG(s1394_create_devinfo_props
,
359 S1394_TNF_SL_HOTPLUG_STACK
, "",
360 tnf_int
, compat_index
, j
,
361 tnf_string
, compat_prop
, buf
[j
]);
365 reg
[0] = node
->node_guid_hi
;
366 reg
[1] = node
->node_guid_lo
;
367 s1394_cfgrom_parse_unit_dir(unit_dir
, ®
[2], ®
[3], ®
[4],
372 result
= ndi_prop_update_int_array(DDI_DEV_T_NONE
, target_dip
, "reg",
374 if (result
!= NDI_SUCCESS
) {
375 cmn_err(CE_NOTE
, "!Unable to add \"reg\" property");
377 cmn_err(CE_CONT
, "!Error code %d", result
);
378 for (j
= 0; j
< 6; j
++) {
379 cmn_err(CE_CONT
, "!reg[%d]: 0x%08x", j
, reg
[j
]);
382 ndi_prop_remove_all(target_dip
);
383 (void) ndi_devi_free(target_dip
);
384 TNF_PROBE_3(s1394_create_devinfo_fail_reg
,
385 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
, guid_hi
,
386 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
,
387 tnf_int
, error
, result
);
388 TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit
,
389 S1394_TNF_SL_HOTPLUG_STACK
, "");
393 TNF_PROBE_1_DEBUG(s1394_create_devinfo_exit
,
394 S1394_TNF_SL_HOTPLUG_STACK
, "",
395 tnf_opaque
, target_dip
, target_dip
);
402 * Searches all children of pdip for a match of name@caddr. Builds the
403 * name and address of each child node by looking up the reg property on
404 * the node and compares the built name@addr with the name@addr passed in.
405 * Returns the child dip if a match is found, otherwise, returns NULL.
407 * This routine is decidedly non-ddi. We had to use this one since
408 * ndi_devi_find() can find only nodes that have valid addr field
409 * set and that won't happen unless the node goes through INITCHILD
410 * (at which time nx1394.c calls ddi_set_name_addr()). If, in future,
411 * the ndi_devi_find() provides a way of looking up nodes using criteria
412 * other than addr, we can get rid of this routine.
416 s1394_devi_find(dev_info_t
*pdip
, char *name
, char *caddr
)
421 dev_info_t
*cdip
= NULL
;
423 ASSERT((name
!= NULL
) && (caddr
!= NULL
));
425 TNF_PROBE_1_DEBUG(s1394_devi_find_enter
, S1394_TNF_SL_HOTPLUG_STACK
,
426 "", tnf_string
, addr
, caddr
);
429 * for each child of this parent, find name and addr and match with
430 * name and caddr passed in.
432 for (cdip
= (dev_info_t
*)DEVI(pdip
)->devi_child
; cdip
!= NULL
;
433 cdip
= (dev_info_t
*)DEVI(cdip
)->devi_sibling
) {
435 i
= ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, cdip
,
436 DDI_PROP_DONTPASS
, "reg", (int **)®ptr
,
439 if (i
!= DDI_PROP_SUCCESS
)
443 * Construct addr from the reg property (addr is of the format
444 * GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where GGGGGGGGGGGGGGGG is
445 * the address and AAAAAAAAAAAA is the optional unit address)
447 if (regptr
[2] != NULL
|| regptr
[3] != NULL
) {
448 (void) sprintf(addr
, "%08x%08x,%04x%08x", regptr
[0],
449 regptr
[1], regptr
[2], regptr
[3]);
451 (void) sprintf(addr
, "%08x%08x", regptr
[0], regptr
[1]);
453 ddi_prop_free(regptr
);
455 if (strcmp(caddr
, addr
) == 0) {
456 ASSERT(strcmp(ddi_node_name(cdip
), name
) == 0);
462 TNF_PROBE_1(s1394_devi_find_no_match
,
463 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
, addr
, caddr
);
466 TNF_PROBE_0_DEBUG(s1394_devi_find_exit
, S1394_TNF_SL_HOTPLUG_STACK
, "");
472 * s1394_update_devinfo_tree()
473 * Parses the config rom for the passed in node and creates/updates devinfo's
474 * for each unit directory found. If the devinfo corresponding to a unit
475 * already exists, any insert event callbacks registered for that devinfo
476 * are called (topology tree is unlocked and relocked around these
477 * callbacks). Returns DDI_SUCCESS if everything went fine and DDI_FAILURE
478 * if unable to reacquire the lock after callbacks (relock fails because of
479 * an intervening bus reset or if the services layer kills the bus reset
480 * thread). The node is marked as parsed before returning.
483 s1394_update_devinfo_tree(s1394_hal_t
*hal
, s1394_node_t
*node
)
486 int j
, units
, d
, lockfail
= 0;
487 s1394_target_t
*target
, *t
;
488 uint32_t hi
, lo
, size_hi
, size_lo
, type
, key
, value
;
489 uint32_t *ptr
, *root_dir
, dir_len
;
490 t1394_localinfo_t linfo
;
492 uint32_t *unit_dir_ptrs
[32];
493 dev_info_t
*devinfo_ptrs
[32];
494 uint32_t new_devinfo
= 0; /* to keep track of new allocations */
498 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
500 ASSERT(CFGROM_PARSED(node
) == B_FALSE
);
501 ASSERT(node
->cfgrom
!= NULL
);
503 TNF_PROBE_2_DEBUG(s1394_update_devinfo_tree_enter
,
504 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
, node_num
,
505 node
->node_num
, tnf_opaque
, cfgrom
, node
->cfgrom
);
507 /* scan through config rom looking for unit dirs */
508 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
510 if (node
->cfgrom_valid_size
< CFGROM_DIR_LEN(root_dir
))
511 dir_len
= node
->cfgrom_valid_size
;
513 dir_len
= CFGROM_DIR_LEN(root_dir
);
515 CFGROM_TYPE_KEY_VALUE(root_dir
[0], type
, key
, value
);
516 if (s1394_valid_dir(hal
, node
, key
, root_dir
) == B_FALSE
) {
518 "!Bad root directory in config rom (node's GUID %08x%08x)",
519 node
->node_guid_hi
, node
->node_guid_lo
);
521 TNF_PROBE_1_DEBUG(s1394_update_devinfo_tree_exit
,
522 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_string
, msg
,
525 SET_CFGROM_PARSED(node
);
526 CLEAR_CFGROM_GEN_CHANGED(node
); /* if set */
527 CLEAR_CFGROM_NEW_ALLOC(node
);
529 return (DDI_SUCCESS
);
532 for (units
= 0, j
= 1; j
<= dir_len
; j
++) {
533 CFGROM_TYPE_KEY_VALUE(root_dir
[j
], type
, key
, value
);
534 if (key
== IEEE1212_UNIT_DIRECTORY
&& type
==
535 IEEE1212_DIRECTORY_TYPE
) {
536 ptr
= &root_dir
[j
] + value
;
537 if (s1394_valid_dir(hal
, node
, key
, ptr
) == B_TRUE
) {
538 unit_dir_ptrs
[units
++] = ptr
;
540 cmn_err(CE_NOTE
, "!Bad unit directory in config"
541 " rom (node's GUID %08x%08x)",
542 node
->node_guid_hi
, node
->node_guid_lo
);
543 TNF_PROBE_2(s1394_update_devinfo_tree_bad_dir
,
544 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
,
545 guid_hi
, node
->node_guid_hi
, tnf_uint
,
546 guid_lo
, node
->node_guid_lo
);
551 for (d
= 0, j
= 0; j
< units
; j
++) {
553 s1394_cfgrom_parse_unit_dir(unit_dir_ptrs
[j
],
554 &hi
, &lo
, &size_hi
, &size_lo
);
559 (void) sprintf(caddr
, "%08x%08x,%04x%08x",
560 node
->node_guid_hi
, node
->node_guid_lo
, hi
, lo
);
562 (void) sprintf(caddr
, "%08x%08x",
563 node
->node_guid_hi
, node
->node_guid_lo
);
566 tdip
= s1394_devi_find(hal
->halinfo
.dip
, "unit", caddr
);
569 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
570 target
= s1394_target_from_dip_locked(hal
, tdip
);
571 if (target
!= NULL
) {
572 target
->target_sibling
= NULL
;
573 target
->on_node
= node
;
574 target
->target_state
&= ~S1394_TARG_GONE
;
575 target
->unit_dir
= unit_dir_ptrs
[j
] - root_dir
;
577 if ((t
= node
->target_list
) != NULL
) {
579 while (t
->target_sibling
!= NULL
) {
580 t
= t
->target_sibling
;
583 t
->target_sibling
= target
;
585 node
->target_list
= target
;
588 target
->target_list
= node
->target_list
;
590 rw_exit(&hal
->target_list_rwlock
);
592 s1394_update_unit_dir_location(hal
, tdip
,
593 unit_dir_ptrs
[j
] - root_dir
);
596 /* create devinfo for unit@caddr */
597 tdip
= s1394_create_devinfo(hal
, node
,
598 unit_dir_ptrs
[j
], j
);
600 new_devinfo
|= (1 << d
);
601 s1394_update_unit_dir_location(hal
, tdip
,
602 unit_dir_ptrs
[j
] - root_dir
);
606 devinfo_ptrs
[d
++] = tdip
;
609 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
610 /* Online all valid units */
611 for (j
= 0; j
< d
; j
++) {
612 if ((new_devinfo
& (1 << j
)) == 0) {
613 linfo
.bus_generation
= hal
->generation_count
;
614 linfo
.local_nodeID
= hal
->node_id
;
616 /* don't need to drop topology_tree_mutex across ndi calls */
617 (void) ndi_devi_online_async(devinfo_ptrs
[j
], 0);
618 if ((new_devinfo
& (1 << j
)) == 0) {
620 * send an insert event if this an existing devinfo.
621 * drop and reacquire topology_tree_mutex across
624 s1394_unlock_tree(hal
);
625 s1394_send_insert_event(hal
, devinfo_ptrs
[j
], &linfo
);
626 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
627 TNF_PROBE_4(s1394_update_devinfo_tree_lock_fail
,
628 S1394_TNF_SL_HOTPLUG_ERROR
, "",
629 tnf_int
, node_num
, node
->node_num
,
630 tnf_opaque
, cfgrom
, node
->cfgrom
,
632 tnf_opaque
, devinfo
, devinfo_ptrs
[j
]);
640 TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit
,
641 S1394_TNF_SL_HOTPLUG_ERROR
, "");
642 return (DDI_FAILURE
);
645 SET_CFGROM_PARSED(node
);
646 CLEAR_CFGROM_GEN_CHANGED(node
); /* if set */
647 CLEAR_CFGROM_NEW_ALLOC(node
);
649 TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit
,
650 S1394_TNF_SL_HOTPLUG_STACK
, "");
652 return (DDI_SUCCESS
);
656 * s1394_offline_node()
657 * Offlines a node. This involves marking all targets attached to the
658 * node as gone, invoking any remove event callbacks and calling
659 * ndi_devi_offline to mark the devinfo as OFFLINE (for each unit
660 * directory on the node). The tree is unlocked and relocked around
661 * the callbacks. If unable to relock the tree, DDI_FAILURE, else
662 * returns DDI_SUCCESS.
665 s1394_offline_node(s1394_hal_t
*hal
, s1394_node_t
*node
)
670 uint32_t *unit_dir_ptrs
[32];
671 dev_info_t
*devinfo_ptrs
[32];
672 t1394_localinfo_t linfo
;
674 uint32_t *ptr
, *root_dir
, dir_len
;
675 uint32_t hi
, lo
, size_hi
, size_lo
, type
, key
, value
;
678 node_num
= node
->node_num
;
680 TNF_PROBE_1_DEBUG(s1394_offline_node_enter
, S1394_TNF_SL_HOTPLUG_STACK
,
681 "", tnf_uint
, node_num
, node_num
);
683 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
686 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
687 t
= node
->target_list
;
689 TNF_PROBE_2(s1394_process_old_tree_mark
,
690 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
, node_num
, node_num
,
691 tnf_opaque
, target
, t
);
692 t
->target_state
|= S1394_TARG_GONE
;
694 t
= t
->target_sibling
;
696 rw_exit(&hal
->target_list_rwlock
);
698 /* scan through config rom looking for unit dirs */
699 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
701 if (node
->cfgrom_valid_size
< CFGROM_DIR_LEN(root_dir
))
702 dir_len
= node
->cfgrom_valid_size
;
704 dir_len
= CFGROM_DIR_LEN(root_dir
);
706 CFGROM_TYPE_KEY_VALUE(root_dir
[0], type
, key
, value
);
708 for (units
= 0, j
= 1; j
<= dir_len
; j
++) {
709 CFGROM_TYPE_KEY_VALUE(root_dir
[j
], type
, key
, value
);
710 if (key
== IEEE1212_UNIT_DIRECTORY
&& type
==
711 IEEE1212_DIRECTORY_TYPE
) {
712 ptr
= &root_dir
[j
] + value
;
713 if (s1394_valid_dir(hal
, node
, key
, ptr
) == B_TRUE
) {
714 unit_dir_ptrs
[units
++] = ptr
;
719 for (d
= 0, j
= 0; j
< units
; j
++) {
721 s1394_cfgrom_parse_unit_dir(unit_dir_ptrs
[j
],
722 &hi
, &lo
, &size_hi
, &size_lo
);
727 (void) sprintf(caddr
, "%08x%08x,%04x%08x",
728 node
->node_guid_hi
, node
->node_guid_lo
, hi
, lo
);
730 (void) sprintf(caddr
, "%08x%08x",
731 node
->node_guid_hi
, node
->node_guid_lo
);
734 if ((tdip
= s1394_devi_find(hal
->halinfo
.dip
, "unit", caddr
)) !=
736 devinfo_ptrs
[d
++] = tdip
;
739 node
->old_node
= NULL
;
741 linfo
.bus_generation
= hal
->generation_count
;
742 linfo
.local_nodeID
= hal
->node_id
;
744 for (j
= 0; j
< d
; j
++) {
745 s1394_unlock_tree(hal
);
747 TNF_PROBE_2(s1394_offline_node
,
748 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
, node_num
, node_num
,
749 tnf_opaque
, devinfo
, devinfo_ptrs
[j
]);
751 s1394_send_remove_event(hal
, devinfo_ptrs
[j
], &linfo
);
752 (void) ndi_devi_offline(devinfo_ptrs
[j
], NDI_DEVI_REMOVE
);
753 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
754 TNF_PROBE_2(s1394_offline_node
,
755 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
, msg
,
756 "unlock to relock tree", tnf_uint
, node_num
,
758 TNF_PROBE_0_DEBUG(s1394_offline_node_exit
,
759 S1394_TNF_SL_HOTPLUG_STACK
, "");
760 return (DDI_FAILURE
);
764 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
765 TNF_PROBE_0_DEBUG(s1394_offline_node_exit
, S1394_TNF_SL_HOTPLUG_STACK
,
767 return (DDI_SUCCESS
);
771 * s1394_process_topology_tree()
772 * Walks the topology tree, processing each node. If node that has
773 * already been parsed, updates the generation property on all devinfos
774 * for the node. Also, if the node exists in both old & new trees, ASSERTS
775 * that both point to the same config rom. If the node has valid config
776 * rom but hasn't been parsed yet, calls s1394_update_devinfo_tree()
777 * to parse and create devinfos for the node. Kicks off further config
778 * rom reading if only the bus info block for the node is read.
779 * Returns DDI_SUCCESS if everything went fine, else returns DDI_FAILURE
780 * (for eg. unable to reacquire the tree lock etc). wait_for_cbs argument
781 * tells the caller if some completions can be expected. wait_gen tells
782 * the generation the commands were issued at.
785 s1394_process_topology_tree(s1394_hal_t
*hal
, int *wait_for_cbs
,
789 uint_t hal_node_num
, number_of_nodes
;
790 s1394_node_t
*node
, *onode
;
791 s1394_status_t status
;
793 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
795 TNF_PROBE_0_DEBUG(s1394_process_topology_tree_enter
,
796 S1394_TNF_SL_HOTPLUG_STACK
, "");
798 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
799 TNF_PROBE_0(s1394_process_topology_tree_lock_failed
,
800 S1394_TNF_SL_HOTPLUG_ERROR
, "");
801 TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit
,
802 S1394_TNF_SL_HOTPLUG_STACK
, "");
803 return (DDI_FAILURE
);
806 hal_node_num
= IEEE1394_NODE_NUM(hal
->node_id
);
807 hal
->cfgroms_being_read
= 0;
808 number_of_nodes
= hal
->number_of_nodes
;
809 s1394_unlock_tree(hal
);
811 for (i
= 0; i
< number_of_nodes
; i
++) {
813 if (i
== hal_node_num
)
815 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
816 return (DDI_FAILURE
);
818 node
= &hal
->topology_tree
[i
];
820 TNF_PROBE_4_DEBUG(s1394_process_topology_tree
,
821 S1394_TNF_SL_HOTPLUG_STACK
, "",
822 tnf_int
, node_num
, i
,
823 tnf_int
, parsed
, CFGROM_PARSED(node
),
824 tnf_int
, matched
, NODE_MATCHED(node
),
825 tnf_int
, visited
, NODE_VISITED(node
));
827 if (LINK_ACTIVE(node
) == B_FALSE
) {
828 s1394_unlock_tree(hal
);
831 if (node
->cfgrom
== NULL
) {
832 s1394_unlock_tree(hal
);
836 onode
= node
->old_node
;
838 if (onode
!= NULL
&& onode
->cfgrom
!= NULL
&& node
->cfgrom
!=
841 * onode->cfgrom != node->cfgrom should have been
842 * handled by s1394_match_GUID()!!!
844 if (onode
->cfgrom
!= node
->cfgrom
)
845 TNF_PROBE_5(s1394_process_topology_tree_err
,
846 S1394_TNF_SL_HOTPLUG_ERROR
, "",
847 tnf_int
, node_num
, i
, tnf_int
, gen_changed
,
848 CFGROM_GEN_CHANGED(node
), tnf_int
, parsed
,
849 CFGROM_PARSED(node
), tnf_opaque
, old_cfgrom
,
850 onode
->cfgrom
, tnf_opaque
, new_cfgrom
,
852 ASSERT(onode
->cfgrom
== node
->cfgrom
);
855 if (CFGROM_PARSED(node
) == B_FALSE
&& CFGROM_ALL_READ(node
) ==
857 ASSERT((node
->cfgrom_size
<
858 IEEE1394_CONFIG_ROM_QUAD_SZ
) ||
859 NODE_MATCHED(node
) == B_TRUE
);
860 rw_enter(&hal
->target_list_rwlock
, RW_READER
);
861 ASSERT(node
->target_list
== NULL
);
862 rw_exit(&hal
->target_list_rwlock
);
863 if (s1394_update_devinfo_tree(hal
, node
) ==
865 ASSERT(MUTEX_NOT_HELD(
866 &hal
->topology_tree_mutex
));
867 TNF_PROBE_1(s1394_process_topology_tree
,
868 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
,
869 msg
, "failure from update devinfo");
871 s1394_process_topology_tree_exit
,
872 S1394_TNF_SL_HOTPLUG_STACK
, "");
873 return (DDI_FAILURE
);
875 } else if (CFGROM_PARSED(node
) == B_FALSE
&& CFGROM_BIB_READ(
877 if (s1394_read_rest_of_cfgrom(hal
, node
, &status
) !=
879 TNF_PROBE_1(s1394_process_topology_tree
,
880 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
,
881 msg
, "failure reading rest of cfgrom");
882 if ((status
& S1394_LOCK_FAILED
) == 0) {
883 ASSERT(MUTEX_HELD(&hal
->
884 topology_tree_mutex
));
886 s1394_unlock_tree(hal
);
889 s1394_process_topology_tree_exit
,
890 S1394_TNF_SL_HOTPLUG_STACK
, "");
891 return (DDI_FAILURE
);
894 *wait_gen
= hal
->br_cfgrom_read_gen
;
898 s1394_unlock_tree(hal
);
902 * flag the tree as processed; if a single bus reset happens after
903 * this, we will use tree matching.
905 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
906 TNF_PROBE_1(s1394_process_topology_tree
,
907 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
,
908 msg
, "relock failed while marking tree processed");
909 TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit
,
910 S1394_TNF_SL_HOTPLUG_STACK
, "");
911 return (DDI_FAILURE
);
913 hal
->topology_tree_processed
= B_TRUE
;
914 s1394_unlock_tree(hal
);
916 TNF_PROBE_1_DEBUG(s1394_process_topology_tree_exit
,
917 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
, hal_instance
,
918 ddi_get_instance(hal
->halinfo
.dip
));
920 return (DDI_SUCCESS
);
924 * s1394_process_old_tree()
925 * Walks through the old tree and offlines nodes that are removed. Nodes
926 * with an active link in the old tree but link powered off in the current
927 * generation are also offlined, as well as nodes with invalid config
928 * rom in current generation.
929 * The topology tree is locked/unlocked while walking through all the nodes;
930 * if the locking fails at any stage, stops further walking and returns
931 * DDI_FAILURE. Returns DDI_SUCCESS if everything went fine.
934 s1394_process_old_tree(s1394_hal_t
*hal
)
937 uint_t hal_node_num_old
, old_number_of_nodes
;
940 TNF_PROBE_0_DEBUG(s1394_process_old_tree_enter
,
941 S1394_TNF_SL_HOTPLUG_STACK
, "");
944 * NODE_MATCHED(onode) == 0 indicates this node doesn't exist
947 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
949 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
950 TNF_PROBE_0(s1394_process_old_tree_lock_failed
,
951 S1394_TNF_SL_HOTPLUG_ERROR
, "");
952 TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit
,
953 S1394_TNF_SL_HOTPLUG_STACK
, "");
954 return (DDI_FAILURE
);
956 hal_node_num_old
= IEEE1394_NODE_NUM(hal
->old_node_id
);
957 old_number_of_nodes
= hal
->old_number_of_nodes
;
958 s1394_unlock_tree(hal
);
960 for (i
= 0; i
< old_number_of_nodes
; i
++) {
962 if (i
== hal_node_num_old
)
964 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
965 TNF_PROBE_2(s1394_process_old_tree
,
966 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
, msg
,
967 "lock failed while processing node", tnf_uint
,
969 TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit
,
970 S1394_TNF_SL_HOTPLUG_STACK
, "");
971 return (DDI_FAILURE
);
974 onode
= &hal
->old_tree
[i
];
976 if (onode
->cfgrom
== NULL
) {
977 CLEAR_CFGROM_STATE(onode
);
978 s1394_unlock_tree(hal
);
982 TNF_PROBE_1_DEBUG(s1394_process_old_tree
,
983 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_opaque
,
984 cfgrom
, onode
->cfgrom
);
986 TNF_PROBE_5_DEBUG(s1394_process_old_tree
,
987 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
,
988 node_num
, i
, tnf_int
, parsed
, CFGROM_PARSED(onode
), tnf_int
,
989 matched
, NODE_MATCHED(onode
), tnf_int
, visited
,
990 NODE_VISITED(onode
), tnf_int
, generation_changed
,
991 CFGROM_GEN_CHANGED(onode
));
994 * onode->cur_node == NULL iff we couldn't read cfgrom in the
995 * current generation in non-tree matching case (and thus
996 * match_GUIDs couldn't set cur_node).
998 if (NODE_MATCHED(onode
) == B_FALSE
|| (onode
->cur_node
==
999 NULL
|| ((CFGROM_VALID(onode
) == B_TRUE
&&
1000 CFGROM_VALID(onode
->cur_node
) == B_FALSE
) ||
1001 (LINK_ACTIVE(onode
) == B_TRUE
&& LINK_ACTIVE(onode
->
1002 cur_node
) == B_FALSE
)))) {
1004 if (onode
->cur_node
!= NULL
&& CFGROM_VALID(onode
) ==
1006 CFGROM_VALID(onode
->cur_node
) == B_FALSE
) {
1008 s1394_process_old_tree_invalid_cfgrom
,
1009 S1394_TNF_SL_HOTPLUG_STACK
, "",
1010 tnf_int
, node_num
, i
);
1012 if (onode
->cur_node
!= NULL
&& LINK_ACTIVE(onode
) ==
1013 B_TRUE
&& LINK_ACTIVE(onode
->cur_node
) == B_FALSE
) {
1015 s1394_process_old_tree_link_off
,
1016 S1394_TNF_SL_HOTPLUG_STACK
,
1017 "", tnf_int
, node_num
, i
);
1019 if (s1394_offline_node(hal
, onode
) != DDI_SUCCESS
) {
1020 TNF_PROBE_2(s1394_process_old_tree
,
1021 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
,
1022 msg
, "failure from offline node", tnf_uint
,
1024 TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit
,
1025 S1394_TNF_SL_HOTPLUG_STACK
, "");
1026 return (DDI_FAILURE
);
1028 s1394_free_cfgrom(hal
, onode
, S1394_FREE_CFGROM_OLD
);
1031 s1394_unlock_tree(hal
);
1034 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
1036 TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit
,
1037 S1394_TNF_SL_HOTPLUG_STACK
, "");
1039 return (DDI_SUCCESS
);
1043 * s1394_update_unit_dir_location()
1044 * Updates the unit-dir-offset property on the devinfo.
1045 * NOTE: ndi_prop_update_int() is interrupt callable (and thus won't block);
1046 * so, the caller doesn't drop topology_tree_mutex when calling this routine.
1050 s1394_update_unit_dir_location(s1394_hal_t
*hal
, dev_info_t
*tdip
,
1053 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
1054 ASSERT(tdip
!= NULL
);
1056 TNF_PROBE_1_DEBUG(s1394_update_unit_dir_location_enter
,
1057 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_uint
, offset
, offset
);
1058 (void) ndi_prop_update_int(DDI_DEV_T_NONE
, tdip
, "unit-dir-offset",
1060 TNF_PROBE_0_DEBUG(s1394_update_unit_dir_location_exit
,
1061 S1394_TNF_SL_HOTPLUG_STACK
, "");
1065 * s1394_add_target_to_node()
1066 * adds target to the list of targets hanging off the node. Figures out
1067 * the node by searching the topology tree for the GUID corresponding
1068 * to the target. Points on_node field of target structure at the node.
1071 s1394_add_target_to_node(s1394_target_t
*target
)
1078 char name
[MAXNAMELEN
];
1081 TNF_PROBE_0_DEBUG(s1394_add_target_to_node_enter
,
1082 S1394_TNF_SL_HOTPLUG_STACK
, "");
1084 hal
= target
->on_hal
;
1085 ASSERT(hal
!= NULL
);
1087 /* Topology tree must be locked when it gets here! */
1088 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
1090 /* target_list_rwlock should be held in write mode */
1091 ASSERT(rw_read_locked(&target
->on_hal
->target_list_rwlock
) == 0);
1093 if ((ptr
= ddi_get_name_addr(target
->target_dip
)) == NULL
) {
1094 TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit_no_name
,
1095 S1394_TNF_SL_HOTPLUG_STACK
, "");
1099 (void) sprintf(name
, ptr
);
1100 /* Drop the ,<ADDR> part, if present */
1101 if ((ptr
= strchr(name
, ',')) != NULL
)
1105 guid_hi
= s1394_stoi(ptr
, 8, 16);
1106 guid_lo
= s1394_stoi(ptr
+ 8, 8, 16);
1108 /* Search the HAL's node list for this GUID */
1109 for (i
= 0; i
< hal
->number_of_nodes
; i
++) {
1110 if (CFGROM_VALID(&hal
->topology_tree
[i
]) == B_TRUE
) {
1111 ASSERT(hal
->topology_tree
[i
].cfgrom
!= NULL
);
1113 if ((hal
->topology_tree
[i
].node_guid_hi
== guid_hi
) &&
1114 (hal
->topology_tree
[i
].node_guid_lo
== guid_lo
)) {
1115 target
->on_node
= &hal
->topology_tree
[i
];
1116 if ((t
= hal
->topology_tree
[i
].target_list
) !=
1118 ASSERT(t
!= target
);
1119 while (t
->target_sibling
!= NULL
) {
1120 t
= t
->target_sibling
;
1121 ASSERT(t
!= target
);
1123 t
->target_sibling
= target
;
1125 hal
->topology_tree
[i
].target_list
=
1130 * update target_list in all targets on the
1133 t
= hal
->topology_tree
[i
].target_list
;
1136 hal
->topology_tree
[i
].target_list
;
1137 t
= t
->target_sibling
;
1144 TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit
,
1145 S1394_TNF_SL_HOTPLUG_STACK
, "");
1149 * s1394_remove_target_from_node()
1150 * Removes target from the corresponding node's target_list.
1153 s1394_remove_target_from_node(s1394_target_t
*target
)
1155 s1394_target_t
*t
, *t1
;
1158 TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_enter
,
1159 S1394_TNF_SL_HOTPLUG_STACK
, "");
1161 hal
= target
->on_hal
;
1162 ASSERT(hal
!= NULL
);
1164 /* Topology tree must be locked when it gets here! */
1165 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
1167 /* target_list_rwlock should be held in write mode */
1168 ASSERT(rw_read_locked(&target
->on_hal
->target_list_rwlock
) == 0);
1170 if (target
->on_node
== NULL
) {
1171 TNF_PROBE_1_DEBUG(s1394_remove_target_from_node_NULL
,
1172 S1394_TNF_SL_HOTPLUG_STACK
, "",
1173 tnf_uint
, target_state
, target
->target_state
);
1176 t
= target
->target_list
;
1181 target
->target_list
= t
->target_sibling
;
1183 t1
->target_sibling
= t
->target_sibling
;
1188 t
= t
->target_sibling
;
1190 /* Update the target_list pointer in all the targets */
1191 if (target
->on_node
!= NULL
)
1192 target
->on_node
->target_list
= target
->target_list
;
1194 t
= t1
= target
->target_list
;
1196 t
->target_list
= t1
;
1197 t
= t
->target_sibling
;
1200 target
->on_node
= NULL
;
1201 target
->target_sibling
= NULL
;
1203 TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_exit
,
1204 S1394_TNF_SL_HOTPLUG_STACK
, "");