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.
27 #pragma ident "%Z%%M% %I% %E% SMI"
31 * 1394 Services Layer Hotplug Routines
32 * This file contains routines that walk the old and topology
33 * trees, at bus reset time, creating devinfo's for new nodes and offlining
34 * nodes that are removed.
38 #include <sys/sysmacros.h>
40 #include <sys/sunddi.h>
41 #include <sys/sunndi.h>
42 #include <sys/modctl.h>
43 #include <sys/sunddi.h>
44 #include <sys/ddi_impldefs.h>
45 #include <sys/types.h>
47 #include <sys/tnf_probe.h>
49 #include <sys/1394/t1394.h>
50 #include <sys/1394/s1394.h>
51 #include <sys/1394/h1394.h>
52 #include <sys/1394/ieee1394.h>
54 static void s1394_send_remove_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
55 t1394_localinfo_t
*localinfo
);
56 static void s1394_send_insert_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
57 t1394_localinfo_t
*localinfo
);
58 static dev_info_t
*s1394_create_devinfo(s1394_hal_t
*hal
, s1394_node_t
*node
,
59 uint32_t *unit_dir
, int nunit
);
60 static void s1394_update_unit_dir_location(s1394_hal_t
*hal
, dev_info_t
*tdip
,
64 * s1394_send_remove_event()
65 * Invokes any "remove event" callback registered for dip. Passes
66 * t1394_localinfo_t as impl_data for the callback.
69 s1394_send_remove_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
70 t1394_localinfo_t
*localinfo
)
73 ddi_eventcookie_t cookie
;
75 (void) sprintf(name
, "%s%d", ddi_driver_name(dip
),
76 ddi_get_instance(dip
));
78 TNF_PROBE_1_DEBUG(s1394_send_remove_event_enter
,
79 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_string
, device
,
82 if (ndi_event_retrieve_cookie(hal
->hal_ndi_event_hdl
, dip
,
83 DDI_DEVI_REMOVE_EVENT
, &cookie
, NDI_EVENT_NOPASS
)
85 (void) ndi_event_run_callbacks(hal
->hal_ndi_event_hdl
, dip
,
88 TNF_PROBE_0_DEBUG(s1394_send_remove_event_exit
,
89 S1394_TNF_SL_HOTPLUG_STACK
, "");
93 * s1394_send_insert_event()
94 * Invokes any "insert event" callback registered for dip. Passes
95 * t1394_localinfo_t as impl_data for the callback.
98 s1394_send_insert_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
99 t1394_localinfo_t
*localinfo
)
102 ddi_eventcookie_t cookie
;
104 (void) sprintf(name
, "%s%d", ddi_driver_name(dip
),
105 ddi_get_instance(dip
));
107 TNF_PROBE_1_DEBUG(s1394_send_insert_event_enter
,
108 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_string
, device
,
111 if (ndi_event_retrieve_cookie(hal
->hal_ndi_event_hdl
, dip
,
112 DDI_DEVI_INSERT_EVENT
, &cookie
, NDI_EVENT_NOPASS
) ==
114 (void) ndi_event_run_callbacks(hal
->hal_ndi_event_hdl
, dip
,
117 TNF_PROBE_0_DEBUG(s1394_send_insert_event_exit
,
118 S1394_TNF_SL_HOTPLUG_STACK
, "");
122 * s1394_create_devinfo()
123 * This routine creates a devinfo corresponding to the unit_dir passed in.
124 * It adds "hp-node", "reg", "compatible" properties to the devinfo
125 * (formats for "reg" and "compatible" properties are specified by 1275
126 * binding for IEEE1394). If unable to create the devinfo and/or add the
127 * the properties, returns NULL, otherwise, returns the devinfo created.
129 * NOTE: All ndi_* routines are interrupt callable (and thus won't sleep).
130 * So, we don't drop topology_mutex across ndi calls.
133 s1394_create_devinfo(s1394_hal_t
*hal
, s1394_node_t
*node
, uint32_t *unit_dir
,
138 dev_info_t
*target_dip
;
141 int result
, i
, j
, spec_id
, sw_version
;
142 int mod_ven
, mod_hw
, mod_spec
, mod_sw
;
143 int node_ven
, node_hw
, node_spec
, node_sw
;
145 /*LINTED type is unused*/
146 uint32_t type
, key
, value
;
147 uint32_t unit_spec_id
, unit_sw_version
;
148 uint32_t node_spec_id
, node_sw_version
;
149 uint32_t node_vendor_id
, node_hw_version
;
150 uint32_t module_spec_id
, module_sw_version
;
151 uint32_t module_vendor_id
, module_hw_version
;
153 char *fmt
= "firewire%06x,%06x";
155 char *buf
[5], data
[5][24];
158 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
160 TNF_PROBE_2_DEBUG(s1394_create_devinfo_enter
,
161 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_uint
, guid_hi
,
162 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
);
164 hal_dip
= hal
->halinfo
.dip
;
166 /* Allocate and init a new device node instance. */
167 result
= ndi_devi_alloc(hal_dip
, "unit", (pnode_t
)DEVI_SID_NODEID
,
170 if (result
!= NDI_SUCCESS
) {
171 cmn_err(CE_NOTE
, "!Unable to create devinfo"
172 " (node's GUID %08x%08x)", node
->node_guid_hi
,
174 TNF_PROBE_2(s1394_create_devinfo_fail_alloc
,
175 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
, guid_hi
,
176 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
);
177 TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit
,
178 S1394_TNF_SL_HOTPLUG_STACK
, "");
182 /* Add "hp-node" property */
183 result
= ndi_prop_update_int(DDI_DEV_T_NONE
, target_dip
, "hp-node", 0);
184 if (result
!= NDI_SUCCESS
) {
185 cmn_err(CE_NOTE
, "!Unable to add \"hp-node\" property"
186 " (node's GUID %08x%08x)", node
->node_guid_hi
,
189 cmn_err(CE_CONT
, "!Error code %d", result
);
191 TNF_PROBE_3(s1394_create_devinfo_hp_node
,
192 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
, guid_hi
,
193 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
,
194 tnf_int
, error
, result
);
195 ndi_prop_remove_all(target_dip
);
196 (void) ndi_devi_free(target_dip
);
197 TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit
,
198 S1394_TNF_SL_HOTPLUG_STACK
, "");
202 spec_id
= sw_version
= mod_ven
= mod_hw
= mod_spec
= mod_sw
=
203 node_ven
= node_hw
= node_spec
= node_sw
= 0;
204 unit_sw_version
= node_sw_version
= node_hw_version
=
205 module_sw_version
= module_hw_version
= 0;
208 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
209 root_dir_len
= CFGROM_DIR_LEN(root_dir
);
211 for (i
= 0; i
< root_dir_len
; i
++) {
213 CFGROM_TYPE_KEY_VALUE(root_dir
[i
+ 1], type
, key
, value
);
216 case IEEE1212_MODULE_VENDOR_ID
:
217 module_vendor_id
= value
;
220 case IEEE1212_MODULE_HW_VERSION
:
221 module_hw_version
= value
;
224 case IEEE1212_MODULE_SPEC_ID
:
225 module_spec_id
= value
;
228 case IEEE1212_MODULE_SW_VERSION
:
229 module_sw_version
= value
;
232 case IEEE1212_NODE_VENDOR_ID
:
233 node_vendor_id
= value
;
236 case IEEE1212_NODE_UNIQUE_ID
: {
237 uint32_t *node_unique_leaf
=
238 &root_dir
[i
+ 1] + value
;
239 node_vendor_id
= (node_unique_leaf
[1] >> 8);
243 case IEEE1212_NODE_HW_VERSION
:
244 node_hw_version
= value
;
247 case IEEE1212_NODE_SPEC_ID
:
248 node_spec_id
= value
;
251 case IEEE1212_NODE_SW_VERSION
:
252 node_sw_version
= value
;
257 if (mod_ven
&& mod_hw
&& mod_spec
&& mod_sw
&& node_ven
&&
258 node_hw
&& node_spec
&& node_sw
) {
264 * Search for unit spec and version
266 for (i
= 0; i
< CFGROM_DIR_LEN(unit_dir
); i
++) {
268 CFGROM_TYPE_KEY_VALUE(unit_dir
[i
+ 1], type
, key
, value
);
269 if (key
== IEEE1212_UNIT_SPEC_ID
) {
271 unit_spec_id
= value
;
273 } else if (key
== IEEE1212_UNIT_SW_VERSION
) {
275 unit_sw_version
= value
;
278 if (spec_id
&& sw_version
)
283 * Refer to IEEE1212 (pages 90-92) for information regarding various
284 * id's. Module_Vendor_Id is required. Node_Vendor_Id is optional and
285 * if not implemented, its assumed value is Module_Vendor_Id.
286 * Module_Spec_Id is optional and if not implemented, its assumed value
287 * is Module_Vendor_Id. Node_Spec_Id is optional, and if not
288 * implemented, its assumed value is Node_Vendor_Id. Unit_Spec_Id is
289 * optional, and if not implemented, its assumed value is
293 node_vendor_id
= module_vendor_id
;
297 if (node_spec
== 0) {
298 node_spec_id
= node_vendor_id
;
303 module_spec_id
= module_vendor_id
;
308 unit_spec_id
= node_vendor_id
;
313 if (sw_version
!= 0) {
315 (void) sprintf(data
[i
++], fmt
, unit_spec_id
, unit_sw_version
);
319 (void) sprintf(data
[i
++], fmt
, node_spec_id
, node_sw_version
);
323 (void) sprintf(data
[i
++], fmt
, node_vendor_id
, node_hw_version
);
327 (void) sprintf(data
[i
++], fmt
, module_spec_id
,
332 (void) sprintf(data
[i
++], fmt
, module_vendor_id
,
336 result
= ndi_prop_update_string_array(DDI_DEV_T_NONE
, target_dip
,
337 "compatible", (char **)&buf
, i
);
338 if (result
!= NDI_SUCCESS
) {
339 cmn_err(CE_NOTE
, "!Unable to add \"compatible\" property"
340 " (node's GUID %08x%08x)", node
->node_guid_hi
,
343 cmn_err(CE_CONT
, "!Error code %d; nelements %d", result
, i
);
344 for (j
= 0; j
< i
; j
++) {
345 cmn_err(CE_CONT
, "!buf[%d]: %s", j
, buf
[j
]);
348 ndi_prop_remove_all(target_dip
);
349 (void) ndi_devi_free(target_dip
);
350 TNF_PROBE_4(s1394_create_devinfo_fail_compat
,
351 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
, guid_hi
,
352 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
,
353 tnf_int
, error
, result
, tnf_int
, nelements
, i
);
354 TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit
,
355 S1394_TNF_SL_HOTPLUG_STACK
, "");
359 for (j
= 0; j
< i
; j
++) {
360 TNF_PROBE_2_DEBUG(s1394_create_devinfo_props
,
361 S1394_TNF_SL_HOTPLUG_STACK
, "",
362 tnf_int
, compat_index
, j
,
363 tnf_string
, compat_prop
, buf
[j
]);
367 reg
[0] = node
->node_guid_hi
;
368 reg
[1] = node
->node_guid_lo
;
369 s1394_cfgrom_parse_unit_dir(unit_dir
, ®
[2], ®
[3], ®
[4],
374 result
= ndi_prop_update_int_array(DDI_DEV_T_NONE
, target_dip
, "reg",
376 if (result
!= NDI_SUCCESS
) {
377 cmn_err(CE_NOTE
, "!Unable to add \"reg\" property");
379 cmn_err(CE_CONT
, "!Error code %d", result
);
380 for (j
= 0; j
< 6; j
++) {
381 cmn_err(CE_CONT
, "!reg[%d]: 0x%08x", j
, reg
[j
]);
384 ndi_prop_remove_all(target_dip
);
385 (void) ndi_devi_free(target_dip
);
386 TNF_PROBE_3(s1394_create_devinfo_fail_reg
,
387 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
, guid_hi
,
388 node
->node_guid_hi
, tnf_uint
, guid_lo
, node
->node_guid_lo
,
389 tnf_int
, error
, result
);
390 TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit
,
391 S1394_TNF_SL_HOTPLUG_STACK
, "");
395 TNF_PROBE_1_DEBUG(s1394_create_devinfo_exit
,
396 S1394_TNF_SL_HOTPLUG_STACK
, "",
397 tnf_opaque
, target_dip
, target_dip
);
404 * Searches all children of pdip for a match of name@caddr. Builds the
405 * name and address of each child node by looking up the reg property on
406 * the node and compares the built name@addr with the name@addr passed in.
407 * Returns the child dip if a match is found, otherwise, returns NULL.
409 * This routine is decidedly non-ddi. We had to use this one since
410 * ndi_devi_find() can find only nodes that have valid addr field
411 * set and that won't happen unless the node goes through INITCHILD
412 * (at which time nx1394.c calls ddi_set_name_addr()). If, in future,
413 * the ndi_devi_find() provides a way of looking up nodes using criteria
414 * other than addr, we can get rid of this routine.
418 s1394_devi_find(dev_info_t
*pdip
, char *name
, char *caddr
)
423 dev_info_t
*cdip
= NULL
;
425 ASSERT((name
!= NULL
) && (caddr
!= NULL
));
427 TNF_PROBE_1_DEBUG(s1394_devi_find_enter
, S1394_TNF_SL_HOTPLUG_STACK
,
428 "", tnf_string
, addr
, caddr
);
431 * for each child of this parent, find name and addr and match with
432 * name and caddr passed in.
434 for (cdip
= (dev_info_t
*)DEVI(pdip
)->devi_child
; cdip
!= NULL
;
435 cdip
= (dev_info_t
*)DEVI(cdip
)->devi_sibling
) {
437 i
= ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, cdip
,
438 DDI_PROP_DONTPASS
, "reg", (int **)®ptr
,
441 if (i
!= DDI_PROP_SUCCESS
)
445 * Construct addr from the reg property (addr is of the format
446 * GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where GGGGGGGGGGGGGGGG is
447 * the address and AAAAAAAAAAAA is the optional unit address)
449 if (regptr
[2] != NULL
|| regptr
[3] != NULL
) {
450 (void) sprintf(addr
, "%08x%08x,%04x%08x", regptr
[0],
451 regptr
[1], regptr
[2], regptr
[3]);
453 (void) sprintf(addr
, "%08x%08x", regptr
[0], regptr
[1]);
455 ddi_prop_free(regptr
);
457 if (strcmp(caddr
, addr
) == 0) {
458 ASSERT(strcmp(ddi_node_name(cdip
), name
) == 0);
464 TNF_PROBE_1(s1394_devi_find_no_match
,
465 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
, addr
, caddr
);
468 TNF_PROBE_0_DEBUG(s1394_devi_find_exit
, S1394_TNF_SL_HOTPLUG_STACK
, "");
474 * s1394_update_devinfo_tree()
475 * Parses the config rom for the passed in node and creates/updates devinfo's
476 * for each unit directory found. If the devinfo corresponding to a unit
477 * already exists, any insert event callbacks registered for that devinfo
478 * are called (topology tree is unlocked and relocked around these
479 * callbacks). Returns DDI_SUCCESS if everything went fine and DDI_FAILURE
480 * if unable to reacquire the lock after callbacks (relock fails because of
481 * an intervening bus reset or if the services layer kills the bus reset
482 * thread). The node is marked as parsed before returning.
485 s1394_update_devinfo_tree(s1394_hal_t
*hal
, s1394_node_t
*node
)
488 int j
, units
, d
, lockfail
= 0;
489 s1394_target_t
*target
, *t
;
490 uint32_t hi
, lo
, size_hi
, size_lo
, type
, key
, value
;
491 uint32_t *ptr
, *root_dir
, dir_len
;
492 t1394_localinfo_t linfo
;
494 uint32_t *unit_dir_ptrs
[32];
495 dev_info_t
*devinfo_ptrs
[32];
496 uint32_t new_devinfo
= 0; /* to keep track of new allocations */
500 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
502 ASSERT(CFGROM_PARSED(node
) == B_FALSE
);
503 ASSERT(node
->cfgrom
!= NULL
);
505 TNF_PROBE_2_DEBUG(s1394_update_devinfo_tree_enter
,
506 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
, node_num
,
507 node
->node_num
, tnf_opaque
, cfgrom
, node
->cfgrom
);
509 /* scan through config rom looking for unit dirs */
510 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
512 if (node
->cfgrom_valid_size
< CFGROM_DIR_LEN(root_dir
))
513 dir_len
= node
->cfgrom_valid_size
;
515 dir_len
= CFGROM_DIR_LEN(root_dir
);
517 CFGROM_TYPE_KEY_VALUE(root_dir
[0], type
, key
, value
);
518 if (s1394_valid_dir(hal
, node
, key
, root_dir
) == B_FALSE
) {
520 "!Bad root directory in config rom (node's GUID %08x%08x)",
521 node
->node_guid_hi
, node
->node_guid_lo
);
523 TNF_PROBE_1_DEBUG(s1394_update_devinfo_tree_exit
,
524 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_string
, msg
,
527 SET_CFGROM_PARSED(node
);
528 CLEAR_CFGROM_GEN_CHANGED(node
); /* if set */
529 CLEAR_CFGROM_NEW_ALLOC(node
);
531 return (DDI_SUCCESS
);
534 for (units
= 0, j
= 1; j
<= dir_len
; j
++) {
535 CFGROM_TYPE_KEY_VALUE(root_dir
[j
], type
, key
, value
);
536 if (key
== IEEE1212_UNIT_DIRECTORY
&& type
==
537 IEEE1212_DIRECTORY_TYPE
) {
538 ptr
= &root_dir
[j
] + value
;
539 if (s1394_valid_dir(hal
, node
, key
, ptr
) == B_TRUE
) {
540 unit_dir_ptrs
[units
++] = ptr
;
542 cmn_err(CE_NOTE
, "!Bad unit directory in config"
543 " rom (node's GUID %08x%08x)",
544 node
->node_guid_hi
, node
->node_guid_lo
);
545 TNF_PROBE_2(s1394_update_devinfo_tree_bad_dir
,
546 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_uint
,
547 guid_hi
, node
->node_guid_hi
, tnf_uint
,
548 guid_lo
, node
->node_guid_lo
);
553 for (d
= 0, j
= 0; j
< units
; j
++) {
555 s1394_cfgrom_parse_unit_dir(unit_dir_ptrs
[j
],
556 &hi
, &lo
, &size_hi
, &size_lo
);
561 (void) sprintf(caddr
, "%08x%08x,%04x%08x",
562 node
->node_guid_hi
, node
->node_guid_lo
, hi
, lo
);
564 (void) sprintf(caddr
, "%08x%08x",
565 node
->node_guid_hi
, node
->node_guid_lo
);
568 tdip
= s1394_devi_find(hal
->halinfo
.dip
, "unit", caddr
);
571 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
572 target
= s1394_target_from_dip_locked(hal
, tdip
);
573 if (target
!= NULL
) {
574 target
->target_sibling
= NULL
;
575 target
->on_node
= node
;
576 target
->target_state
&= ~S1394_TARG_GONE
;
577 target
->unit_dir
= unit_dir_ptrs
[j
] - root_dir
;
579 if ((t
= node
->target_list
) != NULL
) {
581 while (t
->target_sibling
!= NULL
) {
582 t
= t
->target_sibling
;
585 t
->target_sibling
= target
;
587 node
->target_list
= target
;
590 target
->target_list
= node
->target_list
;
592 rw_exit(&hal
->target_list_rwlock
);
594 s1394_update_unit_dir_location(hal
, tdip
,
595 unit_dir_ptrs
[j
] - root_dir
);
598 /* create devinfo for unit@caddr */
599 tdip
= s1394_create_devinfo(hal
, node
,
600 unit_dir_ptrs
[j
], j
);
602 new_devinfo
|= (1 << d
);
603 s1394_update_unit_dir_location(hal
, tdip
,
604 unit_dir_ptrs
[j
] - root_dir
);
608 devinfo_ptrs
[d
++] = tdip
;
611 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
612 /* Online all valid units */
613 for (j
= 0; j
< d
; j
++) {
614 if ((new_devinfo
& (1 << j
)) == 0) {
615 linfo
.bus_generation
= hal
->generation_count
;
616 linfo
.local_nodeID
= hal
->node_id
;
618 /* don't need to drop topology_tree_mutex across ndi calls */
619 (void) ndi_devi_online_async(devinfo_ptrs
[j
], 0);
620 if ((new_devinfo
& (1 << j
)) == 0) {
622 * send an insert event if this an existing devinfo.
623 * drop and reacquire topology_tree_mutex across
626 s1394_unlock_tree(hal
);
627 s1394_send_insert_event(hal
, devinfo_ptrs
[j
], &linfo
);
628 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
629 TNF_PROBE_4(s1394_update_devinfo_tree_lock_fail
,
630 S1394_TNF_SL_HOTPLUG_ERROR
, "",
631 tnf_int
, node_num
, node
->node_num
,
632 tnf_opaque
, cfgrom
, node
->cfgrom
,
634 tnf_opaque
, devinfo
, devinfo_ptrs
[j
]);
642 TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit
,
643 S1394_TNF_SL_HOTPLUG_ERROR
, "");
644 return (DDI_FAILURE
);
647 SET_CFGROM_PARSED(node
);
648 CLEAR_CFGROM_GEN_CHANGED(node
); /* if set */
649 CLEAR_CFGROM_NEW_ALLOC(node
);
651 TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit
,
652 S1394_TNF_SL_HOTPLUG_STACK
, "");
654 return (DDI_SUCCESS
);
658 * s1394_offline_node()
659 * Offlines a node. This involves marking all targets attached to the
660 * node as gone, invoking any remove event callbacks and calling
661 * ndi_devi_offline to mark the devinfo as OFFLINE (for each unit
662 * directory on the node). The tree is unlocked and relocked around
663 * the callbacks. If unable to relock the tree, DDI_FAILURE, else
664 * returns DDI_SUCCESS.
667 s1394_offline_node(s1394_hal_t
*hal
, s1394_node_t
*node
)
672 uint32_t *unit_dir_ptrs
[32];
673 dev_info_t
*devinfo_ptrs
[32];
674 t1394_localinfo_t linfo
;
676 uint32_t *ptr
, *root_dir
, dir_len
;
677 uint32_t hi
, lo
, size_hi
, size_lo
, type
, key
, value
;
680 node_num
= node
->node_num
;
682 TNF_PROBE_1_DEBUG(s1394_offline_node_enter
, S1394_TNF_SL_HOTPLUG_STACK
,
683 "", tnf_uint
, node_num
, node_num
);
685 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
688 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
689 t
= node
->target_list
;
691 TNF_PROBE_2(s1394_process_old_tree_mark
,
692 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
, node_num
, node_num
,
693 tnf_opaque
, target
, t
);
694 t
->target_state
|= S1394_TARG_GONE
;
696 t
= t
->target_sibling
;
698 rw_exit(&hal
->target_list_rwlock
);
700 /* scan through config rom looking for unit dirs */
701 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
703 if (node
->cfgrom_valid_size
< CFGROM_DIR_LEN(root_dir
))
704 dir_len
= node
->cfgrom_valid_size
;
706 dir_len
= CFGROM_DIR_LEN(root_dir
);
708 CFGROM_TYPE_KEY_VALUE(root_dir
[0], type
, key
, value
);
710 for (units
= 0, j
= 1; j
<= dir_len
; j
++) {
711 CFGROM_TYPE_KEY_VALUE(root_dir
[j
], type
, key
, value
);
712 if (key
== IEEE1212_UNIT_DIRECTORY
&& type
==
713 IEEE1212_DIRECTORY_TYPE
) {
714 ptr
= &root_dir
[j
] + value
;
715 if (s1394_valid_dir(hal
, node
, key
, ptr
) == B_TRUE
) {
716 unit_dir_ptrs
[units
++] = ptr
;
721 for (d
= 0, j
= 0; j
< units
; j
++) {
723 s1394_cfgrom_parse_unit_dir(unit_dir_ptrs
[j
],
724 &hi
, &lo
, &size_hi
, &size_lo
);
729 (void) sprintf(caddr
, "%08x%08x,%04x%08x",
730 node
->node_guid_hi
, node
->node_guid_lo
, hi
, lo
);
732 (void) sprintf(caddr
, "%08x%08x",
733 node
->node_guid_hi
, node
->node_guid_lo
);
736 if ((tdip
= s1394_devi_find(hal
->halinfo
.dip
, "unit", caddr
)) !=
738 devinfo_ptrs
[d
++] = tdip
;
741 node
->old_node
= NULL
;
743 linfo
.bus_generation
= hal
->generation_count
;
744 linfo
.local_nodeID
= hal
->node_id
;
746 for (j
= 0; j
< d
; j
++) {
747 s1394_unlock_tree(hal
);
749 TNF_PROBE_2(s1394_offline_node
,
750 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
, node_num
, node_num
,
751 tnf_opaque
, devinfo
, devinfo_ptrs
[j
]);
753 s1394_send_remove_event(hal
, devinfo_ptrs
[j
], &linfo
);
754 (void) ndi_devi_offline(devinfo_ptrs
[j
], NDI_DEVI_REMOVE
);
755 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
756 TNF_PROBE_2(s1394_offline_node
,
757 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
, msg
,
758 "unlock to relock tree", tnf_uint
, node_num
,
760 TNF_PROBE_0_DEBUG(s1394_offline_node_exit
,
761 S1394_TNF_SL_HOTPLUG_STACK
, "");
762 return (DDI_FAILURE
);
766 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
767 TNF_PROBE_0_DEBUG(s1394_offline_node_exit
, S1394_TNF_SL_HOTPLUG_STACK
,
769 return (DDI_SUCCESS
);
773 * s1394_process_topology_tree()
774 * Walks the topology tree, processing each node. If node that has
775 * already been parsed, updates the generation property on all devinfos
776 * for the node. Also, if the node exists in both old & new trees, ASSERTS
777 * that both point to the same config rom. If the node has valid config
778 * rom but hasn't been parsed yet, calls s1394_update_devinfo_tree()
779 * to parse and create devinfos for the node. Kicks off further config
780 * rom reading if only the bus info block for the node is read.
781 * Returns DDI_SUCCESS if everything went fine, else returns DDI_FAILURE
782 * (for eg. unable to reacquire the tree lock etc). wait_for_cbs argument
783 * tells the caller if some completions can be expected. wait_gen tells
784 * the generation the commands were issued at.
787 s1394_process_topology_tree(s1394_hal_t
*hal
, int *wait_for_cbs
,
791 uint_t hal_node_num
, number_of_nodes
;
792 s1394_node_t
*node
, *onode
;
793 s1394_status_t status
;
795 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
797 TNF_PROBE_0_DEBUG(s1394_process_topology_tree_enter
,
798 S1394_TNF_SL_HOTPLUG_STACK
, "");
800 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
801 TNF_PROBE_0(s1394_process_topology_tree_lock_failed
,
802 S1394_TNF_SL_HOTPLUG_ERROR
, "");
803 TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit
,
804 S1394_TNF_SL_HOTPLUG_STACK
, "");
805 return (DDI_FAILURE
);
808 hal_node_num
= IEEE1394_NODE_NUM(hal
->node_id
);
809 hal
->cfgroms_being_read
= 0;
810 number_of_nodes
= hal
->number_of_nodes
;
811 s1394_unlock_tree(hal
);
813 for (i
= 0; i
< number_of_nodes
; i
++) {
815 if (i
== hal_node_num
)
817 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
818 return (DDI_FAILURE
);
820 node
= &hal
->topology_tree
[i
];
822 TNF_PROBE_4_DEBUG(s1394_process_topology_tree
,
823 S1394_TNF_SL_HOTPLUG_STACK
, "",
824 tnf_int
, node_num
, i
,
825 tnf_int
, parsed
, CFGROM_PARSED(node
),
826 tnf_int
, matched
, NODE_MATCHED(node
),
827 tnf_int
, visited
, NODE_VISITED(node
));
829 if (LINK_ACTIVE(node
) == B_FALSE
) {
830 s1394_unlock_tree(hal
);
833 if (node
->cfgrom
== NULL
) {
834 s1394_unlock_tree(hal
);
838 onode
= node
->old_node
;
840 if (onode
!= NULL
&& onode
->cfgrom
!= NULL
&& node
->cfgrom
!=
843 * onode->cfgrom != node->cfgrom should have been
844 * handled by s1394_match_GUID()!!!
846 if (onode
->cfgrom
!= node
->cfgrom
)
847 TNF_PROBE_5(s1394_process_topology_tree_err
,
848 S1394_TNF_SL_HOTPLUG_ERROR
, "",
849 tnf_int
, node_num
, i
, tnf_int
, gen_changed
,
850 CFGROM_GEN_CHANGED(node
), tnf_int
, parsed
,
851 CFGROM_PARSED(node
), tnf_opaque
, old_cfgrom
,
852 onode
->cfgrom
, tnf_opaque
, new_cfgrom
,
854 ASSERT(onode
->cfgrom
== node
->cfgrom
);
857 if (CFGROM_PARSED(node
) == B_FALSE
&& CFGROM_ALL_READ(node
) ==
859 ASSERT((node
->cfgrom_size
<
860 IEEE1394_CONFIG_ROM_QUAD_SZ
) ||
861 NODE_MATCHED(node
) == B_TRUE
);
862 rw_enter(&hal
->target_list_rwlock
, RW_READER
);
863 ASSERT(node
->target_list
== NULL
);
864 rw_exit(&hal
->target_list_rwlock
);
865 if (s1394_update_devinfo_tree(hal
, node
) ==
867 ASSERT(MUTEX_NOT_HELD(
868 &hal
->topology_tree_mutex
));
869 TNF_PROBE_1(s1394_process_topology_tree
,
870 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
,
871 msg
, "failure from update devinfo");
873 s1394_process_topology_tree_exit
,
874 S1394_TNF_SL_HOTPLUG_STACK
, "");
875 return (DDI_FAILURE
);
877 } else if (CFGROM_PARSED(node
) == B_FALSE
&& CFGROM_BIB_READ(
879 if (s1394_read_rest_of_cfgrom(hal
, node
, &status
) !=
881 TNF_PROBE_1(s1394_process_topology_tree
,
882 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
,
883 msg
, "failure reading rest of cfgrom");
884 if ((status
& S1394_LOCK_FAILED
) == 0) {
885 ASSERT(MUTEX_HELD(&hal
->
886 topology_tree_mutex
));
888 s1394_unlock_tree(hal
);
891 s1394_process_topology_tree_exit
,
892 S1394_TNF_SL_HOTPLUG_STACK
, "");
893 return (DDI_FAILURE
);
896 *wait_gen
= hal
->br_cfgrom_read_gen
;
900 s1394_unlock_tree(hal
);
904 * flag the tree as processed; if a single bus reset happens after
905 * this, we will use tree matching.
907 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
908 TNF_PROBE_1(s1394_process_topology_tree
,
909 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
,
910 msg
, "relock failed while marking tree processed");
911 TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit
,
912 S1394_TNF_SL_HOTPLUG_STACK
, "");
913 return (DDI_FAILURE
);
915 hal
->topology_tree_processed
= B_TRUE
;
916 s1394_unlock_tree(hal
);
918 TNF_PROBE_1_DEBUG(s1394_process_topology_tree_exit
,
919 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
, hal_instance
,
920 ddi_get_instance(hal
->halinfo
.dip
));
922 return (DDI_SUCCESS
);
926 * s1394_process_old_tree()
927 * Walks through the old tree and offlines nodes that are removed. Nodes
928 * with an active link in the old tree but link powered off in the current
929 * generation are also offlined, as well as nodes with invalid config
930 * rom in current generation.
931 * The topology tree is locked/unlocked while walking through all the nodes;
932 * if the locking fails at any stage, stops further walking and returns
933 * DDI_FAILURE. Returns DDI_SUCCESS if everything went fine.
936 s1394_process_old_tree(s1394_hal_t
*hal
)
939 uint_t hal_node_num_old
, old_number_of_nodes
;
942 TNF_PROBE_0_DEBUG(s1394_process_old_tree_enter
,
943 S1394_TNF_SL_HOTPLUG_STACK
, "");
946 * NODE_MATCHED(onode) == 0 indicates this node doesn't exist
949 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
951 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
952 TNF_PROBE_0(s1394_process_old_tree_lock_failed
,
953 S1394_TNF_SL_HOTPLUG_ERROR
, "");
954 TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit
,
955 S1394_TNF_SL_HOTPLUG_STACK
, "");
956 return (DDI_FAILURE
);
958 hal_node_num_old
= IEEE1394_NODE_NUM(hal
->old_node_id
);
959 old_number_of_nodes
= hal
->old_number_of_nodes
;
960 s1394_unlock_tree(hal
);
962 for (i
= 0; i
< old_number_of_nodes
; i
++) {
964 if (i
== hal_node_num_old
)
966 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
967 TNF_PROBE_2(s1394_process_old_tree
,
968 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
, msg
,
969 "lock failed while processing node", tnf_uint
,
971 TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit
,
972 S1394_TNF_SL_HOTPLUG_STACK
, "");
973 return (DDI_FAILURE
);
976 onode
= &hal
->old_tree
[i
];
978 if (onode
->cfgrom
== NULL
) {
979 CLEAR_CFGROM_STATE(onode
);
980 s1394_unlock_tree(hal
);
984 TNF_PROBE_1_DEBUG(s1394_process_old_tree
,
985 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_opaque
,
986 cfgrom
, onode
->cfgrom
);
988 TNF_PROBE_5_DEBUG(s1394_process_old_tree
,
989 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_int
,
990 node_num
, i
, tnf_int
, parsed
, CFGROM_PARSED(onode
), tnf_int
,
991 matched
, NODE_MATCHED(onode
), tnf_int
, visited
,
992 NODE_VISITED(onode
), tnf_int
, generation_changed
,
993 CFGROM_GEN_CHANGED(onode
));
996 * onode->cur_node == NULL iff we couldn't read cfgrom in the
997 * current generation in non-tree matching case (and thus
998 * match_GUIDs couldn't set cur_node).
1000 if (NODE_MATCHED(onode
) == B_FALSE
|| (onode
->cur_node
==
1001 NULL
|| ((CFGROM_VALID(onode
) == B_TRUE
&&
1002 CFGROM_VALID(onode
->cur_node
) == B_FALSE
) ||
1003 (LINK_ACTIVE(onode
) == B_TRUE
&& LINK_ACTIVE(onode
->
1004 cur_node
) == B_FALSE
)))) {
1006 if (onode
->cur_node
!= NULL
&& CFGROM_VALID(onode
) ==
1007 B_TRUE
&& CFGROM_VALID(onode
->cur_node
) == B_FALSE
)
1009 (s1394_process_old_tree_invalid_cfgrom
,
1010 S1394_TNF_SL_HOTPLUG_STACK
, "",
1011 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
);
1018 if (s1394_offline_node(hal
, onode
) != DDI_SUCCESS
) {
1019 TNF_PROBE_2(s1394_process_old_tree
,
1020 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
,
1021 msg
, "failure from offline node", tnf_uint
,
1023 TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit
,
1024 S1394_TNF_SL_HOTPLUG_STACK
, "");
1025 return (DDI_FAILURE
);
1027 s1394_free_cfgrom(hal
, onode
, S1394_FREE_CFGROM_OLD
);
1030 s1394_unlock_tree(hal
);
1033 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
1035 TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit
,
1036 S1394_TNF_SL_HOTPLUG_STACK
, "");
1038 return (DDI_SUCCESS
);
1042 * s1394_update_unit_dir_location()
1043 * Updates the unit-dir-offset property on the devinfo.
1044 * NOTE: ndi_prop_update_int() is interrupt callable (and thus won't block);
1045 * so, the caller doesn't drop topology_tree_mutex when calling this routine.
1049 s1394_update_unit_dir_location(s1394_hal_t
*hal
, dev_info_t
*tdip
,
1052 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
1053 ASSERT(tdip
!= NULL
);
1055 TNF_PROBE_1_DEBUG(s1394_update_unit_dir_location_enter
,
1056 S1394_TNF_SL_HOTPLUG_STACK
, "", tnf_uint
, offset
, offset
);
1057 (void) ndi_prop_update_int(DDI_DEV_T_NONE
, tdip
, "unit-dir-offset",
1059 TNF_PROBE_0_DEBUG(s1394_update_unit_dir_location_exit
,
1060 S1394_TNF_SL_HOTPLUG_STACK
, "");
1064 * s1394_add_target_to_node()
1065 * adds target to the list of targets hanging off the node. Figures out
1066 * the node by searching the topology tree for the GUID corresponding
1067 * to the target. Points on_node field of target structure at the node.
1070 s1394_add_target_to_node(s1394_target_t
*target
)
1077 char name
[MAXNAMELEN
];
1080 TNF_PROBE_0_DEBUG(s1394_add_target_to_node_enter
,
1081 S1394_TNF_SL_HOTPLUG_STACK
, "");
1083 hal
= target
->on_hal
;
1084 ASSERT(hal
!= NULL
);
1086 /* Topology tree must be locked when it gets here! */
1087 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
1089 /* target_list_rwlock should be held in write mode */
1090 ASSERT(rw_read_locked(&target
->on_hal
->target_list_rwlock
) == 0);
1092 if ((ptr
= ddi_get_name_addr(target
->target_dip
)) == NULL
) {
1093 TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit_no_name
,
1094 S1394_TNF_SL_HOTPLUG_STACK
, "");
1098 (void) sprintf(name
, ptr
);
1099 /* Drop the ,<ADDR> part, if present */
1100 if ((ptr
= strchr(name
, ',')) != NULL
)
1104 guid_hi
= s1394_stoi(ptr
, 8, 16);
1105 guid_lo
= s1394_stoi(ptr
+ 8, 8, 16);
1107 /* Search the HAL's node list for this GUID */
1108 for (i
= 0; i
< hal
->number_of_nodes
; i
++) {
1109 if (CFGROM_VALID(&hal
->topology_tree
[i
]) == B_TRUE
) {
1110 ASSERT(hal
->topology_tree
[i
].cfgrom
!= NULL
);
1112 if ((hal
->topology_tree
[i
].node_guid_hi
== guid_hi
) &&
1113 (hal
->topology_tree
[i
].node_guid_lo
== guid_lo
)) {
1114 target
->on_node
= &hal
->topology_tree
[i
];
1115 if ((t
= hal
->topology_tree
[i
].target_list
) !=
1117 ASSERT(t
!= target
);
1118 while (t
->target_sibling
!= NULL
) {
1119 t
= t
->target_sibling
;
1120 ASSERT(t
!= target
);
1122 t
->target_sibling
= target
;
1124 hal
->topology_tree
[i
].target_list
=
1129 * update target_list in all targets on the
1132 t
= hal
->topology_tree
[i
].target_list
;
1135 hal
->topology_tree
[i
].target_list
;
1136 t
= t
->target_sibling
;
1143 TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit
,
1144 S1394_TNF_SL_HOTPLUG_STACK
, "");
1148 * s1394_remove_target_from_node()
1149 * Removes target from the corresponding node's target_list.
1152 s1394_remove_target_from_node(s1394_target_t
*target
)
1154 s1394_target_t
*t
, *t1
;
1157 TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_enter
,
1158 S1394_TNF_SL_HOTPLUG_STACK
, "");
1160 hal
= target
->on_hal
;
1161 ASSERT(hal
!= NULL
);
1163 /* Topology tree must be locked when it gets here! */
1164 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
1166 /* target_list_rwlock should be held in write mode */
1167 ASSERT(rw_read_locked(&target
->on_hal
->target_list_rwlock
) == 0);
1169 if (target
->on_node
== NULL
) {
1170 TNF_PROBE_1_DEBUG(s1394_remove_target_from_node_NULL
,
1171 S1394_TNF_SL_HOTPLUG_STACK
, "",
1172 tnf_uint
, target_state
, target
->target_state
);
1175 t
= target
->target_list
;
1180 target
->target_list
= t
->target_sibling
;
1182 t1
->target_sibling
= t
->target_sibling
;
1187 t
= t
->target_sibling
;
1189 /* Update the target_list pointer in all the targets */
1190 if (target
->on_node
!= NULL
)
1191 target
->on_node
->target_list
= target
->target_list
;
1193 t
= t1
= target
->target_list
;
1195 t
->target_list
= t1
;
1196 t
= t
->target_sibling
;
1199 target
->on_node
= NULL
;
1200 target
->target_sibling
= NULL
;
1202 TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_exit
,
1203 S1394_TNF_SL_HOTPLUG_STACK
, "");