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 if (ndi_event_retrieve_cookie(hal
->hal_ndi_event_hdl
, dip
,
77 DDI_DEVI_REMOVE_EVENT
, &cookie
, NDI_EVENT_NOPASS
)
79 (void) ndi_event_run_callbacks(hal
->hal_ndi_event_hdl
, dip
,
85 * s1394_send_insert_event()
86 * Invokes any "insert event" callback registered for dip. Passes
87 * t1394_localinfo_t as impl_data for the callback.
90 s1394_send_insert_event(s1394_hal_t
*hal
, dev_info_t
*dip
,
91 t1394_localinfo_t
*localinfo
)
94 ddi_eventcookie_t cookie
;
96 (void) sprintf(name
, "%s%d", ddi_driver_name(dip
),
97 ddi_get_instance(dip
));
99 if (ndi_event_retrieve_cookie(hal
->hal_ndi_event_hdl
, dip
,
100 DDI_DEVI_INSERT_EVENT
, &cookie
, NDI_EVENT_NOPASS
) ==
102 (void) ndi_event_run_callbacks(hal
->hal_ndi_event_hdl
, dip
,
107 * s1394_create_devinfo()
108 * This routine creates a devinfo corresponding to the unit_dir passed in.
109 * It adds "hp-node", "reg", "compatible" properties to the devinfo
110 * (formats for "reg" and "compatible" properties are specified by 1275
111 * binding for IEEE1394). If unable to create the devinfo and/or add the
112 * the properties, returns NULL, otherwise, returns the devinfo created.
114 * NOTE: All ndi_* routines are interrupt callable (and thus won't sleep).
115 * So, we don't drop topology_mutex across ndi calls.
118 s1394_create_devinfo(s1394_hal_t
*hal
, s1394_node_t
*node
, uint32_t *unit_dir
,
123 dev_info_t
*target_dip
;
126 int result
, i
, j
, spec_id
, sw_version
;
127 int mod_ven
, mod_hw
, mod_spec
, mod_sw
;
128 int node_ven
, node_hw
, node_spec
, node_sw
;
130 /*LINTED type is unused*/
131 uint32_t type __unused
, key
, value
;
132 uint32_t unit_spec_id
, unit_sw_version
;
133 uint32_t node_spec_id
, node_sw_version
;
134 uint32_t node_vendor_id
, node_hw_version
;
135 uint32_t module_spec_id
, module_sw_version
;
136 uint32_t module_vendor_id
, module_hw_version
;
138 char *fmt
= "firewire%06x,%06x";
140 char *buf
[5], data
[5][24];
143 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
145 hal_dip
= hal
->halinfo
.dip
;
147 /* Allocate and init a new device node instance. */
148 result
= ndi_devi_alloc(hal_dip
, "unit", (pnode_t
)DEVI_SID_NODEID
,
151 if (result
!= NDI_SUCCESS
) {
152 cmn_err(CE_NOTE
, "!Unable to create devinfo"
153 " (node's GUID %08x%08x)", node
->node_guid_hi
,
158 /* Add "hp-node" property */
159 result
= ndi_prop_update_int(DDI_DEV_T_NONE
, target_dip
, "hp-node", 0);
160 if (result
!= NDI_SUCCESS
) {
161 cmn_err(CE_NOTE
, "!Unable to add \"hp-node\" property"
162 " (node's GUID %08x%08x)", node
->node_guid_hi
,
165 cmn_err(CE_CONT
, "!Error code %d", result
);
167 ndi_prop_remove_all(target_dip
);
168 (void) ndi_devi_free(target_dip
);
172 spec_id
= sw_version
= mod_ven
= mod_hw
= mod_spec
= mod_sw
=
173 node_ven
= node_hw
= node_spec
= node_sw
= 0;
174 unit_sw_version
= node_sw_version
= node_hw_version
=
175 module_sw_version
= module_hw_version
= 0;
178 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
179 root_dir_len
= CFGROM_DIR_LEN(root_dir
);
181 for (i
= 0; i
< root_dir_len
; i
++) {
183 CFGROM_TYPE_KEY_VALUE(root_dir
[i
+ 1], type
, key
, value
);
186 case IEEE1212_MODULE_VENDOR_ID
:
187 module_vendor_id
= value
;
190 case IEEE1212_MODULE_HW_VERSION
:
191 module_hw_version
= value
;
194 case IEEE1212_MODULE_SPEC_ID
:
195 module_spec_id
= value
;
198 case IEEE1212_MODULE_SW_VERSION
:
199 module_sw_version
= value
;
202 case IEEE1212_NODE_VENDOR_ID
:
203 node_vendor_id
= value
;
206 case IEEE1212_NODE_UNIQUE_ID
: {
207 uint32_t *node_unique_leaf
=
208 &root_dir
[i
+ 1] + value
;
209 node_vendor_id
= (node_unique_leaf
[1] >> 8);
213 case IEEE1212_NODE_HW_VERSION
:
214 node_hw_version
= value
;
217 case IEEE1212_NODE_SPEC_ID
:
218 node_spec_id
= value
;
221 case IEEE1212_NODE_SW_VERSION
:
222 node_sw_version
= value
;
227 if (mod_ven
&& mod_hw
&& mod_spec
&& mod_sw
&& node_ven
&&
228 node_hw
&& node_spec
&& node_sw
) {
234 * Search for unit spec and version
236 for (i
= 0; i
< CFGROM_DIR_LEN(unit_dir
); i
++) {
238 CFGROM_TYPE_KEY_VALUE(unit_dir
[i
+ 1], type
, key
, value
);
239 if (key
== IEEE1212_UNIT_SPEC_ID
) {
241 unit_spec_id
= value
;
243 } else if (key
== IEEE1212_UNIT_SW_VERSION
) {
245 unit_sw_version
= value
;
248 if (spec_id
&& sw_version
)
253 * Refer to IEEE1212 (pages 90-92) for information regarding various
254 * id's. Module_Vendor_Id is required. Node_Vendor_Id is optional and
255 * if not implemented, its assumed value is Module_Vendor_Id.
256 * Module_Spec_Id is optional and if not implemented, its assumed value
257 * is Module_Vendor_Id. Node_Spec_Id is optional, and if not
258 * implemented, its assumed value is Node_Vendor_Id. Unit_Spec_Id is
259 * optional, and if not implemented, its assumed value is
263 node_vendor_id
= module_vendor_id
;
267 if (node_spec
== 0) {
268 node_spec_id
= node_vendor_id
;
273 module_spec_id
= module_vendor_id
;
278 unit_spec_id
= node_vendor_id
;
283 if (sw_version
!= 0) {
285 (void) sprintf(data
[i
++], fmt
, unit_spec_id
, unit_sw_version
);
289 (void) sprintf(data
[i
++], fmt
, node_spec_id
, node_sw_version
);
293 (void) sprintf(data
[i
++], fmt
, node_vendor_id
, node_hw_version
);
297 (void) sprintf(data
[i
++], fmt
, module_spec_id
,
302 (void) sprintf(data
[i
++], fmt
, module_vendor_id
,
306 result
= ndi_prop_update_string_array(DDI_DEV_T_NONE
, target_dip
,
307 "compatible", (char **)&buf
, i
);
308 if (result
!= NDI_SUCCESS
) {
309 cmn_err(CE_NOTE
, "!Unable to add \"compatible\" property"
310 " (node's GUID %08x%08x)", node
->node_guid_hi
,
313 cmn_err(CE_CONT
, "!Error code %d; nelements %d", result
, i
);
314 for (j
= 0; j
< i
; j
++) {
315 cmn_err(CE_CONT
, "!buf[%d]: %s", j
, buf
[j
]);
318 ndi_prop_remove_all(target_dip
);
319 (void) ndi_devi_free(target_dip
);
324 reg
[0] = node
->node_guid_hi
;
325 reg
[1] = node
->node_guid_lo
;
326 s1394_cfgrom_parse_unit_dir(unit_dir
, ®
[2], ®
[3], ®
[4],
331 result
= ndi_prop_update_int_array(DDI_DEV_T_NONE
, target_dip
, "reg",
333 if (result
!= NDI_SUCCESS
) {
334 cmn_err(CE_NOTE
, "!Unable to add \"reg\" property");
336 cmn_err(CE_CONT
, "!Error code %d", result
);
337 for (j
= 0; j
< 6; j
++) {
338 cmn_err(CE_CONT
, "!reg[%d]: 0x%08x", j
, reg
[j
]);
341 ndi_prop_remove_all(target_dip
);
342 (void) ndi_devi_free(target_dip
);
351 * Searches all children of pdip for a match of name@caddr. Builds the
352 * name and address of each child node by looking up the reg property on
353 * the node and compares the built name@addr with the name@addr passed in.
354 * Returns the child dip if a match is found, otherwise, returns NULL.
356 * This routine is decidedly non-ddi. We had to use this one since
357 * ndi_devi_find() can find only nodes that have valid addr field
358 * set and that won't happen unless the node goes through INITCHILD
359 * (at which time nx1394.c calls ddi_set_name_addr()). If, in future,
360 * the ndi_devi_find() provides a way of looking up nodes using criteria
361 * other than addr, we can get rid of this routine.
365 s1394_devi_find(dev_info_t
*pdip
, char *name
, char *caddr
)
370 dev_info_t
*cdip
= NULL
;
372 ASSERT((name
!= NULL
) && (caddr
!= NULL
));
375 * for each child of this parent, find name and addr and match with
376 * name and caddr passed in.
378 for (cdip
= (dev_info_t
*)DEVI(pdip
)->devi_child
; cdip
!= NULL
;
379 cdip
= (dev_info_t
*)DEVI(cdip
)->devi_sibling
) {
381 i
= ddi_prop_lookup_int_array(DDI_DEV_T_ANY
, cdip
,
382 DDI_PROP_DONTPASS
, "reg", (int **)®ptr
,
385 if (i
!= DDI_PROP_SUCCESS
)
389 * Construct addr from the reg property (addr is of the format
390 * GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where GGGGGGGGGGGGGGGG is
391 * the address and AAAAAAAAAAAA is the optional unit address)
393 if (regptr
[2] != (uintptr_t)NULL
||
394 regptr
[3] != (uintptr_t)NULL
) {
395 (void) sprintf(addr
, "%08x%08x,%04x%08x", regptr
[0],
396 regptr
[1], regptr
[2], regptr
[3]);
398 (void) sprintf(addr
, "%08x%08x", regptr
[0], regptr
[1]);
400 ddi_prop_free(regptr
);
402 if (strcmp(caddr
, addr
) == 0) {
403 ASSERT(strcmp(ddi_node_name(cdip
), name
) == 0);
412 * s1394_update_devinfo_tree()
413 * Parses the config rom for the passed in node and creates/updates devinfo's
414 * for each unit directory found. If the devinfo corresponding to a unit
415 * already exists, any insert event callbacks registered for that devinfo
416 * are called (topology tree is unlocked and relocked around these
417 * callbacks). Returns DDI_SUCCESS if everything went fine and DDI_FAILURE
418 * if unable to reacquire the lock after callbacks (relock fails because of
419 * an intervening bus reset or if the services layer kills the bus reset
420 * thread). The node is marked as parsed before returning.
423 s1394_update_devinfo_tree(s1394_hal_t
*hal
, s1394_node_t
*node
)
426 int j
, units
, d
, lockfail
= 0;
427 s1394_target_t
*target
, *t
;
428 uint32_t hi
, lo
, size_hi
, size_lo
, type
, key
, value
;
429 uint32_t *ptr
, *root_dir
, dir_len
;
430 t1394_localinfo_t linfo
;
432 uint32_t *unit_dir_ptrs
[32];
433 dev_info_t
*devinfo_ptrs
[32];
434 uint32_t new_devinfo
= 0; /* to keep track of new allocations */
438 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
440 ASSERT(CFGROM_PARSED(node
) == B_FALSE
);
441 ASSERT(node
->cfgrom
!= NULL
);
443 /* scan through config rom looking for unit dirs */
444 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
446 if (node
->cfgrom_valid_size
< CFGROM_DIR_LEN(root_dir
))
447 dir_len
= node
->cfgrom_valid_size
;
449 dir_len
= CFGROM_DIR_LEN(root_dir
);
451 CFGROM_TYPE_KEY_VALUE(root_dir
[0], type
, key
, value
);
452 if (s1394_valid_dir(hal
, node
, key
, root_dir
) == B_FALSE
) {
454 "!Bad root directory in config rom (node's GUID %08x%08x)",
455 node
->node_guid_hi
, node
->node_guid_lo
);
457 SET_CFGROM_PARSED(node
);
458 CLEAR_CFGROM_GEN_CHANGED(node
); /* if set */
459 CLEAR_CFGROM_NEW_ALLOC(node
);
461 return (DDI_SUCCESS
);
464 for (units
= 0, j
= 1; j
<= dir_len
; j
++) {
465 CFGROM_TYPE_KEY_VALUE(root_dir
[j
], type
, key
, value
);
466 if (key
== IEEE1212_UNIT_DIRECTORY
&& type
==
467 IEEE1212_DIRECTORY_TYPE
) {
468 ptr
= &root_dir
[j
] + value
;
469 if (s1394_valid_dir(hal
, node
, key
, ptr
) == B_TRUE
) {
470 unit_dir_ptrs
[units
++] = ptr
;
472 cmn_err(CE_NOTE
, "!Bad unit directory in config"
473 " rom (node's GUID %08x%08x)",
474 node
->node_guid_hi
, node
->node_guid_lo
);
479 for (d
= 0, j
= 0; j
< units
; j
++) {
481 s1394_cfgrom_parse_unit_dir(unit_dir_ptrs
[j
],
482 &hi
, &lo
, &size_hi
, &size_lo
);
487 (void) sprintf(caddr
, "%08x%08x,%04x%08x",
488 node
->node_guid_hi
, node
->node_guid_lo
, hi
, lo
);
490 (void) sprintf(caddr
, "%08x%08x",
491 node
->node_guid_hi
, node
->node_guid_lo
);
494 tdip
= s1394_devi_find(hal
->halinfo
.dip
, "unit", caddr
);
497 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
498 target
= s1394_target_from_dip_locked(hal
, tdip
);
499 if (target
!= NULL
) {
500 target
->target_sibling
= NULL
;
501 target
->on_node
= node
;
502 target
->target_state
&= ~S1394_TARG_GONE
;
503 target
->unit_dir
= unit_dir_ptrs
[j
] - root_dir
;
505 if ((t
= node
->target_list
) != NULL
) {
507 while (t
->target_sibling
!= NULL
) {
508 t
= t
->target_sibling
;
511 t
->target_sibling
= target
;
513 node
->target_list
= target
;
516 target
->target_list
= node
->target_list
;
518 rw_exit(&hal
->target_list_rwlock
);
520 s1394_update_unit_dir_location(hal
, tdip
,
521 unit_dir_ptrs
[j
] - root_dir
);
524 /* create devinfo for unit@caddr */
525 tdip
= s1394_create_devinfo(hal
, node
,
526 unit_dir_ptrs
[j
], j
);
528 new_devinfo
|= (1 << d
);
529 s1394_update_unit_dir_location(hal
, tdip
,
530 unit_dir_ptrs
[j
] - root_dir
);
534 devinfo_ptrs
[d
++] = tdip
;
537 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
538 /* Online all valid units */
539 for (j
= 0; j
< d
; j
++) {
540 if ((new_devinfo
& (1 << j
)) == 0) {
541 linfo
.bus_generation
= hal
->generation_count
;
542 linfo
.local_nodeID
= hal
->node_id
;
544 /* don't need to drop topology_tree_mutex across ndi calls */
545 (void) ndi_devi_online_async(devinfo_ptrs
[j
], 0);
546 if ((new_devinfo
& (1 << j
)) == 0) {
548 * send an insert event if this an existing devinfo.
549 * drop and reacquire topology_tree_mutex across
552 s1394_unlock_tree(hal
);
553 s1394_send_insert_event(hal
, devinfo_ptrs
[j
], &linfo
);
554 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
562 return (DDI_FAILURE
);
565 SET_CFGROM_PARSED(node
);
566 CLEAR_CFGROM_GEN_CHANGED(node
); /* if set */
567 CLEAR_CFGROM_NEW_ALLOC(node
);
569 return (DDI_SUCCESS
);
573 * s1394_offline_node()
574 * Offlines a node. This involves marking all targets attached to the
575 * node as gone, invoking any remove event callbacks and calling
576 * ndi_devi_offline to mark the devinfo as OFFLINE (for each unit
577 * directory on the node). The tree is unlocked and relocked around
578 * the callbacks. If unable to relock the tree, DDI_FAILURE, else
579 * returns DDI_SUCCESS.
582 s1394_offline_node(s1394_hal_t
*hal
, s1394_node_t
*node
)
587 uint32_t *unit_dir_ptrs
[32];
588 dev_info_t
*devinfo_ptrs
[32];
589 t1394_localinfo_t linfo
;
591 uint32_t *ptr
, *root_dir
, dir_len
;
592 uint32_t hi
, lo
, size_hi
, size_lo
, type
, key
, value
;
595 node_num
= node
->node_num
;
597 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
600 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
601 t
= node
->target_list
;
603 t
->target_state
|= S1394_TARG_GONE
;
605 t
= t
->target_sibling
;
607 rw_exit(&hal
->target_list_rwlock
);
609 /* scan through config rom looking for unit dirs */
610 root_dir
= CFGROM_ROOT_DIR(node
->cfgrom
);
612 if (node
->cfgrom_valid_size
< CFGROM_DIR_LEN(root_dir
))
613 dir_len
= node
->cfgrom_valid_size
;
615 dir_len
= CFGROM_DIR_LEN(root_dir
);
617 CFGROM_TYPE_KEY_VALUE(root_dir
[0], type
, key
, value
);
619 for (units
= 0, j
= 1; j
<= dir_len
; j
++) {
620 CFGROM_TYPE_KEY_VALUE(root_dir
[j
], type
, key
, value
);
621 if (key
== IEEE1212_UNIT_DIRECTORY
&& type
==
622 IEEE1212_DIRECTORY_TYPE
) {
623 ptr
= &root_dir
[j
] + value
;
624 if (s1394_valid_dir(hal
, node
, key
, ptr
) == B_TRUE
) {
625 unit_dir_ptrs
[units
++] = ptr
;
630 for (d
= 0, j
= 0; j
< units
; j
++) {
632 s1394_cfgrom_parse_unit_dir(unit_dir_ptrs
[j
],
633 &hi
, &lo
, &size_hi
, &size_lo
);
638 (void) sprintf(caddr
, "%08x%08x,%04x%08x",
639 node
->node_guid_hi
, node
->node_guid_lo
, hi
, lo
);
641 (void) sprintf(caddr
, "%08x%08x",
642 node
->node_guid_hi
, node
->node_guid_lo
);
645 if ((tdip
= s1394_devi_find(hal
->halinfo
.dip
, "unit", caddr
)) !=
647 devinfo_ptrs
[d
++] = tdip
;
650 node
->old_node
= NULL
;
652 linfo
.bus_generation
= hal
->generation_count
;
653 linfo
.local_nodeID
= hal
->node_id
;
655 for (j
= 0; j
< d
; j
++) {
656 s1394_unlock_tree(hal
);
658 s1394_send_remove_event(hal
, devinfo_ptrs
[j
], &linfo
);
659 (void) ndi_devi_offline(devinfo_ptrs
[j
], NDI_DEVI_REMOVE
);
660 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
661 return (DDI_FAILURE
);
665 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
666 return (DDI_SUCCESS
);
670 * s1394_process_topology_tree()
671 * Walks the topology tree, processing each node. If node that has
672 * already been parsed, updates the generation property on all devinfos
673 * for the node. Also, if the node exists in both old & new trees, ASSERTS
674 * that both point to the same config rom. If the node has valid config
675 * rom but hasn't been parsed yet, calls s1394_update_devinfo_tree()
676 * to parse and create devinfos for the node. Kicks off further config
677 * rom reading if only the bus info block for the node is read.
678 * Returns DDI_SUCCESS if everything went fine, else returns DDI_FAILURE
679 * (for eg. unable to reacquire the tree lock etc). wait_for_cbs argument
680 * tells the caller if some completions can be expected. wait_gen tells
681 * the generation the commands were issued at.
684 s1394_process_topology_tree(s1394_hal_t
*hal
, int *wait_for_cbs
,
688 uint_t hal_node_num
, number_of_nodes
;
689 s1394_node_t
*node
, *onode
;
690 s1394_status_t status
;
692 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
694 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
695 return (DDI_FAILURE
);
698 hal_node_num
= IEEE1394_NODE_NUM(hal
->node_id
);
699 hal
->cfgroms_being_read
= 0;
700 number_of_nodes
= hal
->number_of_nodes
;
701 s1394_unlock_tree(hal
);
703 for (i
= 0; i
< number_of_nodes
; i
++) {
705 if (i
== hal_node_num
)
707 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
708 return (DDI_FAILURE
);
710 node
= &hal
->topology_tree
[i
];
712 if (LINK_ACTIVE(node
) == B_FALSE
) {
713 s1394_unlock_tree(hal
);
716 if (node
->cfgrom
== NULL
) {
717 s1394_unlock_tree(hal
);
721 onode
= node
->old_node
;
723 if (onode
!= NULL
&& onode
->cfgrom
!= NULL
&& node
->cfgrom
!=
726 * onode->cfgrom != node->cfgrom should have been
727 * handled by s1394_match_GUID()!!!
729 ASSERT(onode
->cfgrom
== node
->cfgrom
);
732 if (CFGROM_PARSED(node
) == B_FALSE
&& CFGROM_ALL_READ(node
) ==
734 ASSERT((node
->cfgrom_size
<
735 IEEE1394_CONFIG_ROM_QUAD_SZ
) ||
736 NODE_MATCHED(node
) == B_TRUE
);
737 rw_enter(&hal
->target_list_rwlock
, RW_READER
);
738 ASSERT(node
->target_list
== NULL
);
739 rw_exit(&hal
->target_list_rwlock
);
740 if (s1394_update_devinfo_tree(hal
, node
) ==
742 ASSERT(MUTEX_NOT_HELD(
743 &hal
->topology_tree_mutex
));
744 return (DDI_FAILURE
);
746 } else if (CFGROM_PARSED(node
) == B_FALSE
&& CFGROM_BIB_READ(
748 if (s1394_read_rest_of_cfgrom(hal
, node
, &status
) !=
750 if ((status
& S1394_LOCK_FAILED
) == 0) {
751 ASSERT(MUTEX_HELD(&hal
->
752 topology_tree_mutex
));
754 s1394_unlock_tree(hal
);
756 return (DDI_FAILURE
);
759 *wait_gen
= hal
->br_cfgrom_read_gen
;
763 s1394_unlock_tree(hal
);
767 * flag the tree as processed; if a single bus reset happens after
768 * this, we will use tree matching.
770 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
771 return (DDI_FAILURE
);
773 hal
->topology_tree_processed
= B_TRUE
;
774 s1394_unlock_tree(hal
);
776 return (DDI_SUCCESS
);
780 * s1394_process_old_tree()
781 * Walks through the old tree and offlines nodes that are removed. Nodes
782 * with an active link in the old tree but link powered off in the current
783 * generation are also offlined, as well as nodes with invalid config
784 * rom in current generation.
785 * The topology tree is locked/unlocked while walking through all the nodes;
786 * if the locking fails at any stage, stops further walking and returns
787 * DDI_FAILURE. Returns DDI_SUCCESS if everything went fine.
790 s1394_process_old_tree(s1394_hal_t
*hal
)
793 uint_t hal_node_num_old
, old_number_of_nodes
;
797 * NODE_MATCHED(onode) == 0 indicates this node doesn't exist
800 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
802 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
803 return (DDI_FAILURE
);
805 hal_node_num_old
= IEEE1394_NODE_NUM(hal
->old_node_id
);
806 old_number_of_nodes
= hal
->old_number_of_nodes
;
807 s1394_unlock_tree(hal
);
809 for (i
= 0; i
< old_number_of_nodes
; i
++) {
811 if (i
== hal_node_num_old
)
813 if (s1394_lock_tree(hal
) != DDI_SUCCESS
) {
814 return (DDI_FAILURE
);
817 onode
= &hal
->old_tree
[i
];
819 if (onode
->cfgrom
== NULL
) {
820 CLEAR_CFGROM_STATE(onode
);
821 s1394_unlock_tree(hal
);
826 * onode->cur_node == NULL iff we couldn't read cfgrom in the
827 * current generation in non-tree matching case (and thus
828 * match_GUIDs couldn't set cur_node).
830 if (NODE_MATCHED(onode
) == B_FALSE
|| (onode
->cur_node
==
831 NULL
|| ((CFGROM_VALID(onode
) == B_TRUE
&&
832 CFGROM_VALID(onode
->cur_node
) == B_FALSE
) ||
833 (LINK_ACTIVE(onode
) == B_TRUE
&& LINK_ACTIVE(onode
->
834 cur_node
) == B_FALSE
)))) {
835 if (s1394_offline_node(hal
, onode
) != DDI_SUCCESS
)
836 return (DDI_FAILURE
);
837 s1394_free_cfgrom(hal
, onode
, S1394_FREE_CFGROM_OLD
);
840 s1394_unlock_tree(hal
);
843 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
845 return (DDI_SUCCESS
);
849 * s1394_update_unit_dir_location()
850 * Updates the unit-dir-offset property on the devinfo.
851 * NOTE: ndi_prop_update_int() is interrupt callable (and thus won't block);
852 * so, the caller doesn't drop topology_tree_mutex when calling this routine.
856 s1394_update_unit_dir_location(s1394_hal_t
*hal
, dev_info_t
*tdip
,
859 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
860 ASSERT(tdip
!= NULL
);
862 (void) ndi_prop_update_int(DDI_DEV_T_NONE
, tdip
, "unit-dir-offset",
867 * s1394_add_target_to_node()
868 * adds target to the list of targets hanging off the node. Figures out
869 * the node by searching the topology tree for the GUID corresponding
870 * to the target. Points on_node field of target structure at the node.
873 s1394_add_target_to_node(s1394_target_t
*target
)
880 char name
[MAXNAMELEN
];
883 hal
= target
->on_hal
;
886 /* Topology tree must be locked when it gets here! */
887 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
889 /* target_list_rwlock should be held in write mode */
890 ASSERT(rw_read_locked(&target
->on_hal
->target_list_rwlock
) == 0);
892 if ((ptr
= ddi_get_name_addr(target
->target_dip
)) == NULL
) {
896 (void) sprintf(name
, ptr
);
897 /* Drop the ,<ADDR> part, if present */
898 if ((ptr
= strchr(name
, ',')) != NULL
)
902 guid_hi
= s1394_stoi(ptr
, 8, 16);
903 guid_lo
= s1394_stoi(ptr
+ 8, 8, 16);
905 /* Search the HAL's node list for this GUID */
906 for (i
= 0; i
< hal
->number_of_nodes
; i
++) {
907 if (CFGROM_VALID(&hal
->topology_tree
[i
]) == B_TRUE
) {
908 ASSERT(hal
->topology_tree
[i
].cfgrom
!= NULL
);
910 if ((hal
->topology_tree
[i
].node_guid_hi
== guid_hi
) &&
911 (hal
->topology_tree
[i
].node_guid_lo
== guid_lo
)) {
912 target
->on_node
= &hal
->topology_tree
[i
];
913 if ((t
= hal
->topology_tree
[i
].target_list
) !=
916 while (t
->target_sibling
!= NULL
) {
917 t
= t
->target_sibling
;
920 t
->target_sibling
= target
;
922 hal
->topology_tree
[i
].target_list
=
927 * update target_list in all targets on the
930 t
= hal
->topology_tree
[i
].target_list
;
933 hal
->topology_tree
[i
].target_list
;
934 t
= t
->target_sibling
;
943 * s1394_remove_target_from_node()
944 * Removes target from the corresponding node's target_list.
947 s1394_remove_target_from_node(s1394_target_t
*target
)
949 s1394_target_t
*t
, *t1
;
952 hal
= target
->on_hal
;
955 /* Topology tree must be locked when it gets here! */
956 ASSERT(MUTEX_HELD(&hal
->topology_tree_mutex
));
958 /* target_list_rwlock should be held in write mode */
959 ASSERT(rw_read_locked(&target
->on_hal
->target_list_rwlock
) == 0);
961 t
= target
->target_list
;
966 target
->target_list
= t
->target_sibling
;
968 t1
->target_sibling
= t
->target_sibling
;
973 t
= t
->target_sibling
;
975 /* Update the target_list pointer in all the targets */
976 if (target
->on_node
!= NULL
)
977 target
->on_node
->target_list
= target
->target_list
;
979 t
= t1
= target
->target_list
;
982 t
= t
->target_sibling
;
985 target
->on_node
= NULL
;
986 target
->target_sibling
= NULL
;