xref: /titanic_44/usr/src/uts/common/io/1394/s1394_hotplug.c (revision fa9e4066f08beec538e775443c5be79dd423fcab)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*fa9e4066Sahrens  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * s1394_hotplug.c
317c478bd9Sstevel@tonic-gate  *    1394 Services Layer Hotplug Routines
327c478bd9Sstevel@tonic-gate  *    This file contains routines that walk the old and topology
337c478bd9Sstevel@tonic-gate  *    trees, at bus reset time, creating devinfo's for new nodes and offlining
347c478bd9Sstevel@tonic-gate  *    nodes that are removed.
357c478bd9Sstevel@tonic-gate  */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <sys/conf.h>
387c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
397c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
407c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
417c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
427c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
437c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
447c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate #include <sys/tnf_probe.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate #include <sys/1394/t1394.h>
507c478bd9Sstevel@tonic-gate #include <sys/1394/s1394.h>
517c478bd9Sstevel@tonic-gate #include <sys/1394/h1394.h>
527c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate static void s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
557c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo);
567c478bd9Sstevel@tonic-gate static void s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
577c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo);
587c478bd9Sstevel@tonic-gate static dev_info_t *s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node,
597c478bd9Sstevel@tonic-gate     uint32_t *unit_dir, int nunit);
607c478bd9Sstevel@tonic-gate static void s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
617c478bd9Sstevel@tonic-gate     uint_t offset);
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  * s1394_send_remove_event()
657c478bd9Sstevel@tonic-gate  *    Invokes any "remove event" callback registered for dip. Passes
667c478bd9Sstevel@tonic-gate  *    t1394_localinfo_t as impl_data for the callback.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate static void
s1394_send_remove_event(s1394_hal_t * hal,dev_info_t * dip,t1394_localinfo_t * localinfo)697c478bd9Sstevel@tonic-gate s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
707c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo)
717c478bd9Sstevel@tonic-gate {
727c478bd9Sstevel@tonic-gate 	char name[128];
737c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "%s%d", ddi_driver_name(dip),
767c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(s1394_send_remove_event_enter,
797c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, device,
807c478bd9Sstevel@tonic-gate 	    name);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
837c478bd9Sstevel@tonic-gate 	    DDI_DEVI_REMOVE_EVENT, &cookie, NDI_EVENT_NOPASS)
847c478bd9Sstevel@tonic-gate 	    == NDI_SUCCESS) {
857c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
867c478bd9Sstevel@tonic-gate 		    cookie, localinfo);
877c478bd9Sstevel@tonic-gate 	}
887c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_send_remove_event_exit,
897c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
907c478bd9Sstevel@tonic-gate }
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * s1394_send_insert_event()
947c478bd9Sstevel@tonic-gate  *    Invokes any "insert event" callback registered for dip. Passes
957c478bd9Sstevel@tonic-gate  *    t1394_localinfo_t as impl_data for the callback.
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate static void
s1394_send_insert_event(s1394_hal_t * hal,dev_info_t * dip,t1394_localinfo_t * localinfo)987c478bd9Sstevel@tonic-gate s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
997c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	char name[128];
1027c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "%s%d", ddi_driver_name(dip),
1057c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(s1394_send_insert_event_enter,
1087c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, device,
1097c478bd9Sstevel@tonic-gate 	    name);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
1127c478bd9Sstevel@tonic-gate 	    DDI_DEVI_INSERT_EVENT, &cookie, NDI_EVENT_NOPASS) ==
1137c478bd9Sstevel@tonic-gate 	    NDI_SUCCESS)
1147c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
1157c478bd9Sstevel@tonic-gate 		    cookie, localinfo);
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_send_insert_event_exit,
1187c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
1197c478bd9Sstevel@tonic-gate }
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * s1394_create_devinfo()
1237c478bd9Sstevel@tonic-gate  *    This routine creates a devinfo corresponding to the unit_dir passed in.
1247c478bd9Sstevel@tonic-gate  *    It adds "hp-node", "reg", "compatible" properties to the devinfo
1257c478bd9Sstevel@tonic-gate  *    (formats for "reg" and "compatible" properties are specified by 1275
1267c478bd9Sstevel@tonic-gate  *    binding for IEEE1394). If unable to create the devinfo and/or add the
1277c478bd9Sstevel@tonic-gate  *    the properties, returns NULL, otherwise, returns the devinfo created.
1287c478bd9Sstevel@tonic-gate  *
1297c478bd9Sstevel@tonic-gate  *    NOTE: All ndi_* routines are interrupt callable (and thus won't sleep).
1307c478bd9Sstevel@tonic-gate  *    So, we don't drop topology_mutex across ndi calls.
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate static dev_info_t *
s1394_create_devinfo(s1394_hal_t * hal,s1394_node_t * node,uint32_t * unit_dir,int nunit)1337c478bd9Sstevel@tonic-gate s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node, uint32_t *unit_dir,
1347c478bd9Sstevel@tonic-gate     int nunit)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	dev_info_t *hal_dip;
1377c478bd9Sstevel@tonic-gate 	uint32_t *root_dir;
1387c478bd9Sstevel@tonic-gate 	dev_info_t *target_dip;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	int root_dir_len;
1417c478bd9Sstevel@tonic-gate 	int result, i, j, spec_id, sw_version;
1427c478bd9Sstevel@tonic-gate 	int mod_ven, mod_hw, mod_spec, mod_sw;
1437c478bd9Sstevel@tonic-gate 	int node_ven, node_hw, node_spec, node_sw;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	/*LINTED type is unused*/
1467c478bd9Sstevel@tonic-gate 	uint32_t type, key, value;
1477c478bd9Sstevel@tonic-gate 	uint32_t unit_spec_id, unit_sw_version;
1487c478bd9Sstevel@tonic-gate 	uint32_t node_spec_id, node_sw_version;
1497c478bd9Sstevel@tonic-gate 	uint32_t node_vendor_id, node_hw_version;
1507c478bd9Sstevel@tonic-gate 	uint32_t module_spec_id, module_sw_version;
1517c478bd9Sstevel@tonic-gate 	uint32_t module_vendor_id, module_hw_version;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	char *fmt = "firewire%06x,%06x";
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	char *buf[5], data[5][24];
1567c478bd9Sstevel@tonic-gate 	uint32_t reg[6];
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	TNF_PROBE_2_DEBUG(s1394_create_devinfo_enter,
1617c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, guid_hi,
1627c478bd9Sstevel@tonic-gate 	    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	hal_dip = hal->halinfo.dip;
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	/* Allocate and init a new device node instance. */
167*fa9e4066Sahrens 	result = ndi_devi_alloc(hal_dip, "unit", (pnode_t)DEVI_SID_NODEID,
1687c478bd9Sstevel@tonic-gate 	    &target_dip);
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if (result != NDI_SUCCESS) {
1717c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!Unable to create devinfo"
1727c478bd9Sstevel@tonic-gate 		    " (node's GUID %08x%08x)", node->node_guid_hi,
1737c478bd9Sstevel@tonic-gate 		    node->node_guid_lo);
1747c478bd9Sstevel@tonic-gate 		TNF_PROBE_2(s1394_create_devinfo_fail_alloc,
1757c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
1767c478bd9Sstevel@tonic-gate 		    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo);
1777c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
1787c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
1797c478bd9Sstevel@tonic-gate 		return (NULL);
1807c478bd9Sstevel@tonic-gate 	}
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	/* Add "hp-node" property */
1837c478bd9Sstevel@tonic-gate 	result = ndi_prop_update_int(DDI_DEV_T_NONE, target_dip, "hp-node", 0);
1847c478bd9Sstevel@tonic-gate 	if (result != NDI_SUCCESS) {
1857c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!Unable to add \"hp-node\" property"
1867c478bd9Sstevel@tonic-gate 		    " (node's GUID %08x%08x)", node->node_guid_hi,
1877c478bd9Sstevel@tonic-gate 		    node->node_guid_lo);
1887c478bd9Sstevel@tonic-gate #if defined(DEBUG)
1897c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "!Error code %d", result);
1907c478bd9Sstevel@tonic-gate #endif
1917c478bd9Sstevel@tonic-gate 		TNF_PROBE_3(s1394_create_devinfo_hp_node,
1927c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
1937c478bd9Sstevel@tonic-gate 		    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
1947c478bd9Sstevel@tonic-gate 		    tnf_int, error, result);
1957c478bd9Sstevel@tonic-gate 		ndi_prop_remove_all(target_dip);
1967c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(target_dip);
1977c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
1987c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
1997c478bd9Sstevel@tonic-gate 		return (NULL);
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	spec_id = sw_version = mod_ven = mod_hw = mod_spec = mod_sw =
2037c478bd9Sstevel@tonic-gate 	    node_ven = node_hw = node_spec = node_sw = 0;
2047c478bd9Sstevel@tonic-gate 	unit_sw_version = node_sw_version = node_hw_version =
2057c478bd9Sstevel@tonic-gate 	    module_sw_version = module_hw_version = 0;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
2097c478bd9Sstevel@tonic-gate 	root_dir_len = CFGROM_DIR_LEN(root_dir);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	for (i = 0; i < root_dir_len; i++) {
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 		CFGROM_TYPE_KEY_VALUE(root_dir[i + 1], type, key, value);
2147c478bd9Sstevel@tonic-gate 		switch (key) {
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 		case IEEE1212_MODULE_VENDOR_ID:
2177c478bd9Sstevel@tonic-gate 			module_vendor_id = value;
2187c478bd9Sstevel@tonic-gate 			mod_ven++;
2197c478bd9Sstevel@tonic-gate 			break;
2207c478bd9Sstevel@tonic-gate 		case IEEE1212_MODULE_HW_VERSION:
2217c478bd9Sstevel@tonic-gate 			module_hw_version = value;
2227c478bd9Sstevel@tonic-gate 			mod_hw++;
2237c478bd9Sstevel@tonic-gate 			break;
2247c478bd9Sstevel@tonic-gate 		case IEEE1212_MODULE_SPEC_ID:
2257c478bd9Sstevel@tonic-gate 			module_spec_id = value;
2267c478bd9Sstevel@tonic-gate 			mod_spec++;
2277c478bd9Sstevel@tonic-gate 			break;
2287c478bd9Sstevel@tonic-gate 		case IEEE1212_MODULE_SW_VERSION:
2297c478bd9Sstevel@tonic-gate 			module_sw_version = value;
2307c478bd9Sstevel@tonic-gate 			mod_sw++;
2317c478bd9Sstevel@tonic-gate 			break;
2327c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_VENDOR_ID:
2337c478bd9Sstevel@tonic-gate 			node_vendor_id = value;
2347c478bd9Sstevel@tonic-gate 			node_ven++;
2357c478bd9Sstevel@tonic-gate 			break;
2367c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_UNIQUE_ID: {
2377c478bd9Sstevel@tonic-gate 				uint32_t *node_unique_leaf =
2387c478bd9Sstevel@tonic-gate 				    &root_dir[i + 1] + value;
2397c478bd9Sstevel@tonic-gate 				node_vendor_id = (node_unique_leaf[1] >> 8);
2407c478bd9Sstevel@tonic-gate 				node_ven++;
2417c478bd9Sstevel@tonic-gate 			}
2427c478bd9Sstevel@tonic-gate 			break;
2437c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_HW_VERSION:
2447c478bd9Sstevel@tonic-gate 			node_hw_version = value;
2457c478bd9Sstevel@tonic-gate 			node_hw++;
2467c478bd9Sstevel@tonic-gate 			break;
2477c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_SPEC_ID:
2487c478bd9Sstevel@tonic-gate 			node_spec_id = value;
2497c478bd9Sstevel@tonic-gate 			node_spec++;
2507c478bd9Sstevel@tonic-gate 			break;
2517c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_SW_VERSION:
2527c478bd9Sstevel@tonic-gate 			node_sw_version = value;
2537c478bd9Sstevel@tonic-gate 			node_sw++;
2547c478bd9Sstevel@tonic-gate 			break;
2557c478bd9Sstevel@tonic-gate 		}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 		if (mod_ven && mod_hw && mod_spec && mod_sw && node_ven &&
2587c478bd9Sstevel@tonic-gate 		    node_hw && node_spec && node_sw) {
2597c478bd9Sstevel@tonic-gate 			break;
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	/*
2647c478bd9Sstevel@tonic-gate 	 * Search for unit spec and version
2657c478bd9Sstevel@tonic-gate 	 */
2667c478bd9Sstevel@tonic-gate 	for (i = 0; i < CFGROM_DIR_LEN(unit_dir); i++) {
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		CFGROM_TYPE_KEY_VALUE(unit_dir[i + 1], type, key, value);
2697c478bd9Sstevel@tonic-gate 		if (key == IEEE1212_UNIT_SPEC_ID) {
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 			unit_spec_id = value;
2727c478bd9Sstevel@tonic-gate 			spec_id++;
2737c478bd9Sstevel@tonic-gate 		} else if (key == IEEE1212_UNIT_SW_VERSION) {
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 			unit_sw_version = value;
2767c478bd9Sstevel@tonic-gate 			sw_version++;
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 		if (spec_id && sw_version)
2797c478bd9Sstevel@tonic-gate 			break;
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	/*
2837c478bd9Sstevel@tonic-gate 	 * Refer to IEEE1212 (pages 90-92) for information regarding various
2847c478bd9Sstevel@tonic-gate 	 * id's. Module_Vendor_Id is required. Node_Vendor_Id is optional and
2857c478bd9Sstevel@tonic-gate 	 * if not implemented, its assumed value is Module_Vendor_Id.
2867c478bd9Sstevel@tonic-gate 	 * Module_Spec_Id is optional and if not implemented, its assumed value
2877c478bd9Sstevel@tonic-gate 	 * is Module_Vendor_Id. Node_Spec_Id is optional, and if not
2887c478bd9Sstevel@tonic-gate 	 * implemented, its assumed value is Node_Vendor_Id. Unit_Spec_Id is
2897c478bd9Sstevel@tonic-gate 	 * optional, and if not implemented, its assumed value is
2907c478bd9Sstevel@tonic-gate 	 * Node_Vendor_Id.
2917c478bd9Sstevel@tonic-gate 	 */
2927c478bd9Sstevel@tonic-gate 	if (node_ven == 0) {
2937c478bd9Sstevel@tonic-gate 		node_vendor_id = module_vendor_id;
2947c478bd9Sstevel@tonic-gate 		node_ven++;
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	if (node_spec == 0) {
2987c478bd9Sstevel@tonic-gate 		node_spec_id = node_vendor_id;
2997c478bd9Sstevel@tonic-gate 		node_spec++;
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	if (mod_spec == 0) {
3037c478bd9Sstevel@tonic-gate 		module_spec_id = module_vendor_id;
3047c478bd9Sstevel@tonic-gate 		mod_spec++;
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (spec_id == 0) {
3087c478bd9Sstevel@tonic-gate 		unit_spec_id = node_vendor_id;
3097c478bd9Sstevel@tonic-gate 		spec_id++;
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	i = 0;
3137c478bd9Sstevel@tonic-gate 	if (sw_version != 0) {
3147c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
3157c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, unit_spec_id, unit_sw_version);
3167c478bd9Sstevel@tonic-gate 	}
3177c478bd9Sstevel@tonic-gate 	if (node_sw != 0) {
3187c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
3197c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, node_spec_id, node_sw_version);
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 	if (node_hw != 0) {
3227c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
3237c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, node_vendor_id, node_hw_version);
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 	if (mod_sw != 0) {
3267c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
3277c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, module_spec_id,
3287c478bd9Sstevel@tonic-gate 		    module_sw_version);
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 	if (mod_hw != 0) {
3317c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
3327c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, module_vendor_id,
3337c478bd9Sstevel@tonic-gate 		    module_hw_version);
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	result = ndi_prop_update_string_array(DDI_DEV_T_NONE, target_dip,
3377c478bd9Sstevel@tonic-gate 	    "compatible", (char **)&buf, i);
3387c478bd9Sstevel@tonic-gate 	if (result != NDI_SUCCESS) {
3397c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!Unable to add \"compatible\" property"
3407c478bd9Sstevel@tonic-gate 		    " (node's GUID %08x%08x)", node->node_guid_hi,
3417c478bd9Sstevel@tonic-gate 		    node->node_guid_lo);
3427c478bd9Sstevel@tonic-gate #if defined(DEBUG)
3437c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "!Error code %d; nelements %d", result, i);
3447c478bd9Sstevel@tonic-gate 		for (j = 0; j < i; j++) {
3457c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "!buf[%d]: %s", j, buf[j]);
3467c478bd9Sstevel@tonic-gate 		}
3477c478bd9Sstevel@tonic-gate #endif
3487c478bd9Sstevel@tonic-gate 		ndi_prop_remove_all(target_dip);
3497c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(target_dip);
3507c478bd9Sstevel@tonic-gate 		TNF_PROBE_4(s1394_create_devinfo_fail_compat,
3517c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
3527c478bd9Sstevel@tonic-gate 		    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
3537c478bd9Sstevel@tonic-gate 		    tnf_int, error, result, tnf_int, nelements, i);
3547c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
3557c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
3567c478bd9Sstevel@tonic-gate 		return (NULL);
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	for (j = 0; j < i; j++) {
3607c478bd9Sstevel@tonic-gate 		TNF_PROBE_2_DEBUG(s1394_create_devinfo_props,
3617c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "",
3627c478bd9Sstevel@tonic-gate 		    tnf_int, compat_index, j,
3637c478bd9Sstevel@tonic-gate 		    tnf_string, compat_prop, buf[j]);
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/* GUID,ADDR */
3677c478bd9Sstevel@tonic-gate 	reg[0] = node->node_guid_hi;
3687c478bd9Sstevel@tonic-gate 	reg[1] = node->node_guid_lo;
3697c478bd9Sstevel@tonic-gate 	s1394_cfgrom_parse_unit_dir(unit_dir, &reg[2], &reg[3], &reg[4],
3707c478bd9Sstevel@tonic-gate 	    &reg[5]);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	reg[3] = nunit;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	result = ndi_prop_update_int_array(DDI_DEV_T_NONE, target_dip, "reg",
3757c478bd9Sstevel@tonic-gate 	    (int *)reg, 6);
3767c478bd9Sstevel@tonic-gate 	if (result != NDI_SUCCESS) {
3777c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!Unable to add \"reg\" property");
3787c478bd9Sstevel@tonic-gate #if defined(DEBUG)
3797c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "!Error code %d", result);
3807c478bd9Sstevel@tonic-gate 		for (j = 0; j < 6; j++) {
3817c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "!reg[%d]: 0x%08x", j, reg[j]);
3827c478bd9Sstevel@tonic-gate 		}
3837c478bd9Sstevel@tonic-gate #endif
3847c478bd9Sstevel@tonic-gate 		ndi_prop_remove_all(target_dip);
3857c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(target_dip);
3867c478bd9Sstevel@tonic-gate 		TNF_PROBE_3(s1394_create_devinfo_fail_reg,
3877c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
3887c478bd9Sstevel@tonic-gate 		    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
3897c478bd9Sstevel@tonic-gate 		    tnf_int, error, result);
3907c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
3917c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
3927c478bd9Sstevel@tonic-gate 		return (NULL);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(s1394_create_devinfo_exit,
3967c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "",
3977c478bd9Sstevel@tonic-gate 	    tnf_opaque, target_dip, target_dip);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	return (target_dip);
4007c478bd9Sstevel@tonic-gate }
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate /*
4037c478bd9Sstevel@tonic-gate  * s1394_devi_find()
4047c478bd9Sstevel@tonic-gate  *    Searches all children of pdip for a match of name@caddr. Builds the
4057c478bd9Sstevel@tonic-gate  *    name and address of each child node by looking up the reg property on
4067c478bd9Sstevel@tonic-gate  *    the node and compares the built name@addr with the name@addr passed in.
4077c478bd9Sstevel@tonic-gate  *    Returns the child dip if a match is found, otherwise, returns NULL.
4087c478bd9Sstevel@tonic-gate  *    NOTE:
4097c478bd9Sstevel@tonic-gate  *    This routine is decidedly non-ddi. We had to use this one since
4107c478bd9Sstevel@tonic-gate  *    ndi_devi_find() can find only nodes that have valid addr field
4117c478bd9Sstevel@tonic-gate  *    set and that won't happen unless the node goes through INITCHILD
4127c478bd9Sstevel@tonic-gate  *    (at which time nx1394.c calls ddi_set_name_addr()). If, in future,
4137c478bd9Sstevel@tonic-gate  *    the ndi_devi_find() provides a way of looking up nodes using criteria
4147c478bd9Sstevel@tonic-gate  *    other than addr, we can get rid of this routine.
4157c478bd9Sstevel@tonic-gate  */
4167c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4177c478bd9Sstevel@tonic-gate dev_info_t *
s1394_devi_find(dev_info_t * pdip,char * name,char * caddr)4187c478bd9Sstevel@tonic-gate s1394_devi_find(dev_info_t *pdip, char *name, char *caddr)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate 	int i, reglen;
4217c478bd9Sstevel@tonic-gate 	char addr[32];
4227c478bd9Sstevel@tonic-gate 	uint32_t *regptr;
4237c478bd9Sstevel@tonic-gate 	dev_info_t *cdip = NULL;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	ASSERT((name != NULL) && (caddr != NULL));
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(s1394_devi_find_enter, S1394_TNF_SL_HOTPLUG_STACK,
4287c478bd9Sstevel@tonic-gate 	    "", tnf_string, addr, caddr);
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	/*
4317c478bd9Sstevel@tonic-gate 	 * for each child of this parent, find name and addr and match with
4327c478bd9Sstevel@tonic-gate 	 * name and caddr passed in.
4337c478bd9Sstevel@tonic-gate 	 */
4347c478bd9Sstevel@tonic-gate 	for (cdip = (dev_info_t *)DEVI(pdip)->devi_child; cdip != NULL;
4357c478bd9Sstevel@tonic-gate 	    cdip = (dev_info_t *)DEVI(cdip)->devi_sibling) {
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 		i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
4387c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg", (int **)&regptr,
4397c478bd9Sstevel@tonic-gate 		    (uint_t *)&reglen);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		if (i != DDI_PROP_SUCCESS)
4427c478bd9Sstevel@tonic-gate 			continue;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 		/*
4457c478bd9Sstevel@tonic-gate 		 * Construct addr from the reg property (addr is of the format
4467c478bd9Sstevel@tonic-gate 		 * GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where GGGGGGGGGGGGGGGG is
4477c478bd9Sstevel@tonic-gate 		 * the address and AAAAAAAAAAAA is the optional unit address)
4487c478bd9Sstevel@tonic-gate 		 */
4497c478bd9Sstevel@tonic-gate 		if (regptr[2] != NULL || regptr[3] != NULL) {
4507c478bd9Sstevel@tonic-gate 			(void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
4517c478bd9Sstevel@tonic-gate 			    regptr[1], regptr[2], regptr[3]);
4527c478bd9Sstevel@tonic-gate 		} else {
4537c478bd9Sstevel@tonic-gate 			(void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
4547c478bd9Sstevel@tonic-gate 		}
4557c478bd9Sstevel@tonic-gate 		ddi_prop_free(regptr);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 		if (strcmp(caddr, addr) == 0) {
4587c478bd9Sstevel@tonic-gate 			ASSERT(strcmp(ddi_node_name(cdip), name) == 0);
4597c478bd9Sstevel@tonic-gate 			break;
4607c478bd9Sstevel@tonic-gate 		}
4617c478bd9Sstevel@tonic-gate 	}
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	if (cdip == NULL) {
4647c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(s1394_devi_find_no_match,
4657c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, addr, caddr);
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 
4687c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_devi_find_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	return (cdip);
4717c478bd9Sstevel@tonic-gate }
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate /*
4747c478bd9Sstevel@tonic-gate  * s1394_update_devinfo_tree()
4757c478bd9Sstevel@tonic-gate  *    Parses the config rom for the passed in node and creates/updates devinfo's
4767c478bd9Sstevel@tonic-gate  *    for each unit directory found. If the devinfo corresponding to a unit
4777c478bd9Sstevel@tonic-gate  *    already exists, any insert event callbacks registered for that devinfo
4787c478bd9Sstevel@tonic-gate  *    are called (topology tree is unlocked and relocked around these
4797c478bd9Sstevel@tonic-gate  *    callbacks). Returns DDI_SUCCESS if everything went fine and DDI_FAILURE
4807c478bd9Sstevel@tonic-gate  *    if unable to reacquire the lock after callbacks (relock fails because of
4817c478bd9Sstevel@tonic-gate  *    an intervening bus reset or if the services layer kills the bus reset
4827c478bd9Sstevel@tonic-gate  *    thread). The node is marked as parsed before returning.
4837c478bd9Sstevel@tonic-gate  */
4847c478bd9Sstevel@tonic-gate int
s1394_update_devinfo_tree(s1394_hal_t * hal,s1394_node_t * node)4857c478bd9Sstevel@tonic-gate s1394_update_devinfo_tree(s1394_hal_t *hal, s1394_node_t *node)
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	dev_info_t *tdip;
4887c478bd9Sstevel@tonic-gate 	int j, units, d, lockfail = 0;
4897c478bd9Sstevel@tonic-gate 	s1394_target_t *target, *t;
4907c478bd9Sstevel@tonic-gate 	uint32_t hi, lo, size_hi, size_lo, type, key, value;
4917c478bd9Sstevel@tonic-gate 	uint32_t *ptr, *root_dir, dir_len;
4927c478bd9Sstevel@tonic-gate 	t1394_localinfo_t linfo;
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	uint32_t *unit_dir_ptrs[32];
4957c478bd9Sstevel@tonic-gate 	dev_info_t *devinfo_ptrs[32];
4967c478bd9Sstevel@tonic-gate 	uint32_t new_devinfo = 0;	/* to keep track of new allocations */
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	char caddr[32];
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	ASSERT(CFGROM_PARSED(node) == B_FALSE);
5037c478bd9Sstevel@tonic-gate 	ASSERT(node->cfgrom != NULL);
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	TNF_PROBE_2_DEBUG(s1394_update_devinfo_tree_enter,
5067c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num,
5077c478bd9Sstevel@tonic-gate 	    node->node_num, tnf_opaque, cfgrom, node->cfgrom);
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	/* scan through config rom looking for unit dirs */
5107c478bd9Sstevel@tonic-gate 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
5137c478bd9Sstevel@tonic-gate 		dir_len = node->cfgrom_valid_size;
5147c478bd9Sstevel@tonic-gate 	else
5157c478bd9Sstevel@tonic-gate 		dir_len = CFGROM_DIR_LEN(root_dir);
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
5187c478bd9Sstevel@tonic-gate 	if (s1394_valid_dir(hal, node, key, root_dir) == B_FALSE) {
5197c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
5207c478bd9Sstevel@tonic-gate 		    "!Bad root directory in config rom (node's GUID %08x%08x)",
5217c478bd9Sstevel@tonic-gate 		    node->node_guid_hi, node->node_guid_lo);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(s1394_update_devinfo_tree_exit,
5247c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
5257c478bd9Sstevel@tonic-gate 		    "bad directory");
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 		SET_CFGROM_PARSED(node);
5287c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_GEN_CHANGED(node);	/* if set */
5297c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_NEW_ALLOC(node);
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5327c478bd9Sstevel@tonic-gate 	}
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	for (units = 0, j = 1; j <= dir_len; j++) {
5357c478bd9Sstevel@tonic-gate 		CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
5367c478bd9Sstevel@tonic-gate 		if (key == IEEE1212_UNIT_DIRECTORY && type ==
5377c478bd9Sstevel@tonic-gate 		    IEEE1212_DIRECTORY_TYPE) {
5387c478bd9Sstevel@tonic-gate 			ptr = &root_dir[j] + value;
5397c478bd9Sstevel@tonic-gate 			if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
5407c478bd9Sstevel@tonic-gate 				unit_dir_ptrs[units++] = ptr;
5417c478bd9Sstevel@tonic-gate 			} else {
5427c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "!Bad unit directory in config"
5437c478bd9Sstevel@tonic-gate 				    " rom (node's GUID %08x%08x)",
5447c478bd9Sstevel@tonic-gate 				    node->node_guid_hi, node->node_guid_lo);
5457c478bd9Sstevel@tonic-gate 				TNF_PROBE_2(s1394_update_devinfo_tree_bad_dir,
5467c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint,
5477c478bd9Sstevel@tonic-gate 				    guid_hi, node->node_guid_hi, tnf_uint,
5487c478bd9Sstevel@tonic-gate 				    guid_lo, node->node_guid_lo);
5497c478bd9Sstevel@tonic-gate 			}
5507c478bd9Sstevel@tonic-gate 		}
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	for (d = 0, j = 0; j < units; j++) {
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 		s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
5567c478bd9Sstevel@tonic-gate 		    &hi, &lo, &size_hi, &size_lo);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 		lo = j;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		if (hi || lo) {
5617c478bd9Sstevel@tonic-gate 			(void) sprintf(caddr, "%08x%08x,%04x%08x",
5627c478bd9Sstevel@tonic-gate 			    node->node_guid_hi, node->node_guid_lo, hi, lo);
5637c478bd9Sstevel@tonic-gate 		} else {
5647c478bd9Sstevel@tonic-gate 			(void) sprintf(caddr, "%08x%08x",
5657c478bd9Sstevel@tonic-gate 			    node->node_guid_hi, node->node_guid_lo);
5667c478bd9Sstevel@tonic-gate 		}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 		tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr);
5697c478bd9Sstevel@tonic-gate 		if (tdip != NULL) {
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 			rw_enter(&hal->target_list_rwlock, RW_WRITER);
5727c478bd9Sstevel@tonic-gate 			target = s1394_target_from_dip_locked(hal, tdip);
5737c478bd9Sstevel@tonic-gate 			if (target != NULL) {
5747c478bd9Sstevel@tonic-gate 				target->target_sibling = NULL;
5757c478bd9Sstevel@tonic-gate 				target->on_node = node;
5767c478bd9Sstevel@tonic-gate 				target->target_state &= ~S1394_TARG_GONE;
5777c478bd9Sstevel@tonic-gate 				target->unit_dir = unit_dir_ptrs[j] - root_dir;
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 				if ((t = node->target_list) != NULL) {
5807c478bd9Sstevel@tonic-gate 					ASSERT(t != target);
5817c478bd9Sstevel@tonic-gate 					while (t->target_sibling != NULL) {
5827c478bd9Sstevel@tonic-gate 						t = t->target_sibling;
5837c478bd9Sstevel@tonic-gate 						ASSERT(t != target);
5847c478bd9Sstevel@tonic-gate 					}
5857c478bd9Sstevel@tonic-gate 					t->target_sibling = target;
5867c478bd9Sstevel@tonic-gate 				} else {
5877c478bd9Sstevel@tonic-gate 					node->target_list = target;
5887c478bd9Sstevel@tonic-gate 				}
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 				target->target_list = node->target_list;
5917c478bd9Sstevel@tonic-gate 			}
5927c478bd9Sstevel@tonic-gate 			rw_exit(&hal->target_list_rwlock);
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 			s1394_update_unit_dir_location(hal, tdip,
5957c478bd9Sstevel@tonic-gate 			    unit_dir_ptrs[j] - root_dir);
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 		} else {
5987c478bd9Sstevel@tonic-gate 			/* create devinfo for unit@caddr */
5997c478bd9Sstevel@tonic-gate 			tdip = s1394_create_devinfo(hal, node,
6007c478bd9Sstevel@tonic-gate 			    unit_dir_ptrs[j], j);
6017c478bd9Sstevel@tonic-gate 			if (tdip != NULL) {
6027c478bd9Sstevel@tonic-gate 				new_devinfo |= (1 << d);
6037c478bd9Sstevel@tonic-gate 				s1394_update_unit_dir_location(hal, tdip,
6047c478bd9Sstevel@tonic-gate 				    unit_dir_ptrs[j] - root_dir);
6057c478bd9Sstevel@tonic-gate 			}
6067c478bd9Sstevel@tonic-gate 		}
6077c478bd9Sstevel@tonic-gate 		if (tdip != NULL)
6087c478bd9Sstevel@tonic-gate 			devinfo_ptrs[d++] = tdip;
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
6127c478bd9Sstevel@tonic-gate 	/* Online all valid units */
6137c478bd9Sstevel@tonic-gate 	for (j = 0; j < d; j++) {
6147c478bd9Sstevel@tonic-gate 		if ((new_devinfo & (1 << j)) == 0) {
6157c478bd9Sstevel@tonic-gate 			linfo.bus_generation = hal->generation_count;
6167c478bd9Sstevel@tonic-gate 			linfo.local_nodeID = hal->node_id;
6177c478bd9Sstevel@tonic-gate 		}
6187c478bd9Sstevel@tonic-gate 		/* don't need to drop topology_tree_mutex across ndi calls */
6197c478bd9Sstevel@tonic-gate 		(void) ndi_devi_online_async(devinfo_ptrs[j], 0);
6207c478bd9Sstevel@tonic-gate 		if ((new_devinfo & (1 << j)) == 0) {
6217c478bd9Sstevel@tonic-gate 			/*
6227c478bd9Sstevel@tonic-gate 			 * send an insert event if this an existing devinfo.
6237c478bd9Sstevel@tonic-gate 			 * drop and reacquire topology_tree_mutex across
6247c478bd9Sstevel@tonic-gate 			 * the event calls
6257c478bd9Sstevel@tonic-gate 			 */
6267c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
6277c478bd9Sstevel@tonic-gate 			s1394_send_insert_event(hal, devinfo_ptrs[j], &linfo);
6287c478bd9Sstevel@tonic-gate 			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
6297c478bd9Sstevel@tonic-gate 				TNF_PROBE_4(s1394_update_devinfo_tree_lock_fail,
6307c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_ERROR, "",
6317c478bd9Sstevel@tonic-gate 				    tnf_int, node_num, node->node_num,
6327c478bd9Sstevel@tonic-gate 				    tnf_opaque, cfgrom, node->cfgrom,
6337c478bd9Sstevel@tonic-gate 				    tnf_int, unit, j,
6347c478bd9Sstevel@tonic-gate 				    tnf_opaque, devinfo, devinfo_ptrs[j]);
6357c478bd9Sstevel@tonic-gate 				lockfail = 1;
6367c478bd9Sstevel@tonic-gate 				break;
6377c478bd9Sstevel@tonic-gate 			}
6387c478bd9Sstevel@tonic-gate 		}
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	if (lockfail) {
6427c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit,
6437c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "");
6447c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	SET_CFGROM_PARSED(node);
6487c478bd9Sstevel@tonic-gate 	CLEAR_CFGROM_GEN_CHANGED(node);	/* if set */
6497c478bd9Sstevel@tonic-gate 	CLEAR_CFGROM_NEW_ALLOC(node);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit,
6527c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
6537c478bd9Sstevel@tonic-gate 
6547c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate /*
6587c478bd9Sstevel@tonic-gate  * s1394_offline_node()
6597c478bd9Sstevel@tonic-gate  *    Offlines a node. This involves marking all targets attached to the
6607c478bd9Sstevel@tonic-gate  *    node as gone, invoking any remove event callbacks and calling
6617c478bd9Sstevel@tonic-gate  *    ndi_devi_offline to mark the devinfo as OFFLINE (for each unit
6627c478bd9Sstevel@tonic-gate  *    directory on the node). The tree is unlocked and relocked around
6637c478bd9Sstevel@tonic-gate  *    the callbacks. If unable to relock the tree, DDI_FAILURE, else
6647c478bd9Sstevel@tonic-gate  *    returns DDI_SUCCESS.
6657c478bd9Sstevel@tonic-gate  */
6667c478bd9Sstevel@tonic-gate int
s1394_offline_node(s1394_hal_t * hal,s1394_node_t * node)6677c478bd9Sstevel@tonic-gate s1394_offline_node(s1394_hal_t *hal, s1394_node_t *node)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate 	s1394_target_t *t;
6707c478bd9Sstevel@tonic-gate 	dev_info_t *tdip;
6717c478bd9Sstevel@tonic-gate 	int j, d, units;
6727c478bd9Sstevel@tonic-gate 	uint32_t *unit_dir_ptrs[32];
6737c478bd9Sstevel@tonic-gate 	dev_info_t *devinfo_ptrs[32];
6747c478bd9Sstevel@tonic-gate 	t1394_localinfo_t linfo;
6757c478bd9Sstevel@tonic-gate 	uint_t node_num;
6767c478bd9Sstevel@tonic-gate 	uint32_t *ptr, *root_dir, dir_len;
6777c478bd9Sstevel@tonic-gate 	uint32_t hi, lo, size_hi, size_lo, type, key, value;
6787c478bd9Sstevel@tonic-gate 	char caddr[32];
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	node_num = node->node_num;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(s1394_offline_node_enter, S1394_TNF_SL_HOTPLUG_STACK,
6837c478bd9Sstevel@tonic-gate 	    "", tnf_uint, node_num, node_num);
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	d = 0;
6887c478bd9Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_WRITER);
6897c478bd9Sstevel@tonic-gate 	t = node->target_list;
6907c478bd9Sstevel@tonic-gate 	while (t != NULL) {
6917c478bd9Sstevel@tonic-gate 		TNF_PROBE_2(s1394_process_old_tree_mark,
6927c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num, node_num,
6937c478bd9Sstevel@tonic-gate 			tnf_opaque, target, t);
6947c478bd9Sstevel@tonic-gate 		t->target_state |= S1394_TARG_GONE;
6957c478bd9Sstevel@tonic-gate 		t->on_node = NULL;
6967c478bd9Sstevel@tonic-gate 		t = t->target_sibling;
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	/* scan through config rom looking for unit dirs */
7017c478bd9Sstevel@tonic-gate 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
7047c478bd9Sstevel@tonic-gate 		dir_len = node->cfgrom_valid_size;
7057c478bd9Sstevel@tonic-gate 	else
7067c478bd9Sstevel@tonic-gate 		dir_len = CFGROM_DIR_LEN(root_dir);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	for (units = 0, j = 1; j <= dir_len; j++) {
7117c478bd9Sstevel@tonic-gate 		CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
7127c478bd9Sstevel@tonic-gate 		if (key == IEEE1212_UNIT_DIRECTORY && type ==
7137c478bd9Sstevel@tonic-gate 		    IEEE1212_DIRECTORY_TYPE) {
7147c478bd9Sstevel@tonic-gate 			ptr = &root_dir[j] + value;
7157c478bd9Sstevel@tonic-gate 			if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
7167c478bd9Sstevel@tonic-gate 				unit_dir_ptrs[units++] = ptr;
7177c478bd9Sstevel@tonic-gate 			}
7187c478bd9Sstevel@tonic-gate 		}
7197c478bd9Sstevel@tonic-gate 	}
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	for (d = 0, j = 0; j < units; j++) {
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 		s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
7247c478bd9Sstevel@tonic-gate 		    &hi, &lo, &size_hi, &size_lo);
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 		lo = j;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 		if (hi || lo) {
7297c478bd9Sstevel@tonic-gate 			(void) sprintf(caddr, "%08x%08x,%04x%08x",
7307c478bd9Sstevel@tonic-gate 			    node->node_guid_hi, node->node_guid_lo, hi, lo);
7317c478bd9Sstevel@tonic-gate 		} else {
7327c478bd9Sstevel@tonic-gate 			(void) sprintf(caddr, "%08x%08x",
7337c478bd9Sstevel@tonic-gate 			    node->node_guid_hi, node->node_guid_lo);
7347c478bd9Sstevel@tonic-gate 		}
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 		if ((tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr)) !=
7377c478bd9Sstevel@tonic-gate 		    NULL)
7387c478bd9Sstevel@tonic-gate 			devinfo_ptrs[d++] = tdip;
7397c478bd9Sstevel@tonic-gate 	}
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	node->old_node = NULL;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	linfo.bus_generation = hal->generation_count;
7447c478bd9Sstevel@tonic-gate 	linfo.local_nodeID = hal->node_id;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	for (j = 0; j < d; j++) {
7477c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 		TNF_PROBE_2(s1394_offline_node,
7507c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num, node_num,
7517c478bd9Sstevel@tonic-gate 		    tnf_opaque, devinfo, devinfo_ptrs[j]);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 		s1394_send_remove_event(hal, devinfo_ptrs[j], &linfo);
7547c478bd9Sstevel@tonic-gate 		(void) ndi_devi_offline(devinfo_ptrs[j], NDI_DEVI_REMOVE);
7557c478bd9Sstevel@tonic-gate 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
7567c478bd9Sstevel@tonic-gate 			TNF_PROBE_2(s1394_offline_node,
7577c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
7587c478bd9Sstevel@tonic-gate 			    "unlock to relock tree", tnf_uint, node_num,
7597c478bd9Sstevel@tonic-gate 			    node_num);
7607c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(s1394_offline_node_exit,
7617c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_HOTPLUG_STACK, "");
7627c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
7677c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_offline_node_exit, S1394_TNF_SL_HOTPLUG_STACK,
7687c478bd9Sstevel@tonic-gate 	    "");
7697c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate /*
7737c478bd9Sstevel@tonic-gate  * s1394_process_topology_tree()
7747c478bd9Sstevel@tonic-gate  *    Walks the topology tree, processing each node. If node that has
7757c478bd9Sstevel@tonic-gate  *    already been parsed, updates the generation property on all devinfos
7767c478bd9Sstevel@tonic-gate  *    for the node. Also, if the node exists in both old & new trees, ASSERTS
7777c478bd9Sstevel@tonic-gate  *    that both point to the same config rom. If the node has valid config
7787c478bd9Sstevel@tonic-gate  *    rom but hasn't been parsed yet, calls s1394_update_devinfo_tree()
7797c478bd9Sstevel@tonic-gate  *    to parse and create devinfos for the node. Kicks off further config
7807c478bd9Sstevel@tonic-gate  *    rom reading if only the bus info block for the node is read.
7817c478bd9Sstevel@tonic-gate  *    Returns DDI_SUCCESS if everything went fine, else returns DDI_FAILURE
7827c478bd9Sstevel@tonic-gate  *    (for eg. unable to reacquire the tree lock etc). wait_for_cbs argument
7837c478bd9Sstevel@tonic-gate  *    tells the caller if some completions can be expected. wait_gen tells
7847c478bd9Sstevel@tonic-gate  *    the generation the commands were issued at.
7857c478bd9Sstevel@tonic-gate  */
7867c478bd9Sstevel@tonic-gate int
s1394_process_topology_tree(s1394_hal_t * hal,int * wait_for_cbs,uint_t * wait_gen)7877c478bd9Sstevel@tonic-gate s1394_process_topology_tree(s1394_hal_t *hal, int *wait_for_cbs,
7887c478bd9Sstevel@tonic-gate     uint_t *wait_gen)
7897c478bd9Sstevel@tonic-gate {
7907c478bd9Sstevel@tonic-gate 	int i;
7917c478bd9Sstevel@tonic-gate 	uint_t hal_node_num, number_of_nodes;
7927c478bd9Sstevel@tonic-gate 	s1394_node_t *node, *onode;
7937c478bd9Sstevel@tonic-gate 	s1394_status_t status;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_process_topology_tree_enter,
7987c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
8017c478bd9Sstevel@tonic-gate 		TNF_PROBE_0(s1394_process_topology_tree_lock_failed,
8027c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "");
8037c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit,
8047c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
8057c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
8097c478bd9Sstevel@tonic-gate 	hal->cfgroms_being_read = 0;
8107c478bd9Sstevel@tonic-gate 	number_of_nodes = hal->number_of_nodes;
8117c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	for (i = 0; i < number_of_nodes; i++) {
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 		if (i == hal_node_num)
8167c478bd9Sstevel@tonic-gate 			continue;
8177c478bd9Sstevel@tonic-gate 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
8187c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8197c478bd9Sstevel@tonic-gate 		}
8207c478bd9Sstevel@tonic-gate 		node = &hal->topology_tree[i];
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 		TNF_PROBE_4_DEBUG(s1394_process_topology_tree,
8237c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "",
8247c478bd9Sstevel@tonic-gate 		    tnf_int, node_num, i,
8257c478bd9Sstevel@tonic-gate 		    tnf_int, parsed, CFGROM_PARSED(node),
8267c478bd9Sstevel@tonic-gate 		    tnf_int, matched, NODE_MATCHED(node),
8277c478bd9Sstevel@tonic-gate 		    tnf_int, visited, NODE_VISITED(node));
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 		if (LINK_ACTIVE(node) == B_FALSE) {
8307c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
8317c478bd9Sstevel@tonic-gate 			continue;
8327c478bd9Sstevel@tonic-gate 		}
8337c478bd9Sstevel@tonic-gate 		if (node->cfgrom == NULL) {
8347c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
8357c478bd9Sstevel@tonic-gate 			continue;
8367c478bd9Sstevel@tonic-gate 		}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 		onode = node->old_node;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 		if (onode != NULL && onode->cfgrom != NULL && node->cfgrom !=
8417c478bd9Sstevel@tonic-gate 		    NULL) {
8427c478bd9Sstevel@tonic-gate 			/*
8437c478bd9Sstevel@tonic-gate 			 * onode->cfgrom != node->cfgrom should have been
8447c478bd9Sstevel@tonic-gate 			 * handled by s1394_match_GUID()!!!
8457c478bd9Sstevel@tonic-gate 			 */
8467c478bd9Sstevel@tonic-gate 			if (onode->cfgrom != node->cfgrom)
8477c478bd9Sstevel@tonic-gate 				TNF_PROBE_5(s1394_process_topology_tree_err,
8487c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_ERROR, "",
8497c478bd9Sstevel@tonic-gate 				    tnf_int, node_num, i, tnf_int, gen_changed,
8507c478bd9Sstevel@tonic-gate 				    CFGROM_GEN_CHANGED(node), tnf_int, parsed,
8517c478bd9Sstevel@tonic-gate 				    CFGROM_PARSED(node), tnf_opaque, old_cfgrom,
8527c478bd9Sstevel@tonic-gate 				    onode->cfgrom, tnf_opaque, new_cfgrom,
8537c478bd9Sstevel@tonic-gate 				    node->cfgrom);
8547c478bd9Sstevel@tonic-gate 			ASSERT(onode->cfgrom == node->cfgrom);
8557c478bd9Sstevel@tonic-gate 		}
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 		if (CFGROM_PARSED(node) == B_FALSE && CFGROM_ALL_READ(node) ==
8587c478bd9Sstevel@tonic-gate 		    B_TRUE) {
8597c478bd9Sstevel@tonic-gate 			ASSERT((node->cfgrom_size <
8607c478bd9Sstevel@tonic-gate 			    IEEE1394_CONFIG_ROM_QUAD_SZ) ||
8617c478bd9Sstevel@tonic-gate 			    NODE_MATCHED(node) == B_TRUE);
8627c478bd9Sstevel@tonic-gate 			rw_enter(&hal->target_list_rwlock, RW_READER);
8637c478bd9Sstevel@tonic-gate 			ASSERT(node->target_list == NULL);
8647c478bd9Sstevel@tonic-gate 			rw_exit(&hal->target_list_rwlock);
8657c478bd9Sstevel@tonic-gate 			if (s1394_update_devinfo_tree(hal, node) ==
8667c478bd9Sstevel@tonic-gate 			    DDI_FAILURE) {
8677c478bd9Sstevel@tonic-gate 				ASSERT(MUTEX_NOT_HELD(
8687c478bd9Sstevel@tonic-gate 				    &hal->topology_tree_mutex));
8697c478bd9Sstevel@tonic-gate 				TNF_PROBE_1(s1394_process_topology_tree,
8707c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
8717c478bd9Sstevel@tonic-gate 				    msg, "failure from update devinfo");
8727c478bd9Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(
8737c478bd9Sstevel@tonic-gate 				    s1394_process_topology_tree_exit,
8747c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_STACK, "");
8757c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
8767c478bd9Sstevel@tonic-gate 			}
8777c478bd9Sstevel@tonic-gate 		} else if (CFGROM_PARSED(node) == B_FALSE && CFGROM_BIB_READ(
8787c478bd9Sstevel@tonic-gate 		    node) == B_TRUE) {
8797c478bd9Sstevel@tonic-gate 			if (s1394_read_rest_of_cfgrom(hal, node, &status) !=
8807c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
8817c478bd9Sstevel@tonic-gate 				TNF_PROBE_1(s1394_process_topology_tree,
8827c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
8837c478bd9Sstevel@tonic-gate 				    msg, "failure reading rest of cfgrom");
8847c478bd9Sstevel@tonic-gate 				if ((status & S1394_LOCK_FAILED) == 0) {
8857c478bd9Sstevel@tonic-gate 					ASSERT(MUTEX_HELD(&hal->
8867c478bd9Sstevel@tonic-gate 					    topology_tree_mutex));
8877c478bd9Sstevel@tonic-gate 					*wait_for_cbs = 0;
8887c478bd9Sstevel@tonic-gate 					s1394_unlock_tree(hal);
8897c478bd9Sstevel@tonic-gate 				}
8907c478bd9Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(
8917c478bd9Sstevel@tonic-gate 				    s1394_process_topology_tree_exit,
8927c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_STACK, "");
8937c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
8947c478bd9Sstevel@tonic-gate 			} else {
8957c478bd9Sstevel@tonic-gate 				*wait_for_cbs = 1;
8967c478bd9Sstevel@tonic-gate 				*wait_gen = hal->br_cfgrom_read_gen;
8977c478bd9Sstevel@tonic-gate 			}
8987c478bd9Sstevel@tonic-gate 		}
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
9017c478bd9Sstevel@tonic-gate 	}
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	/*
9047c478bd9Sstevel@tonic-gate 	 * flag the tree as processed; if a single bus reset happens after
9057c478bd9Sstevel@tonic-gate 	 * this, we will use tree matching.
9067c478bd9Sstevel@tonic-gate 	 */
9077c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
9087c478bd9Sstevel@tonic-gate 		TNF_PROBE_1(s1394_process_topology_tree,
9097c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
9107c478bd9Sstevel@tonic-gate 		    msg, "relock failed while marking tree processed");
9117c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit,
9127c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
9137c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9147c478bd9Sstevel@tonic-gate 	}
9157c478bd9Sstevel@tonic-gate 	hal->topology_tree_processed = B_TRUE;
9167c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(s1394_process_topology_tree_exit,
9197c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, hal_instance,
9207c478bd9Sstevel@tonic-gate 	    ddi_get_instance(hal->halinfo.dip));
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9237c478bd9Sstevel@tonic-gate }
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate /*
9267c478bd9Sstevel@tonic-gate  * s1394_process_old_tree()
9277c478bd9Sstevel@tonic-gate  *    Walks through the old tree and offlines nodes that are removed. Nodes
9287c478bd9Sstevel@tonic-gate  *    with an active link in the old tree but link powered off in the current
9297c478bd9Sstevel@tonic-gate  *    generation are also offlined, as well as nodes with invalid config
9307c478bd9Sstevel@tonic-gate  *    rom in current generation.
9317c478bd9Sstevel@tonic-gate  *    The topology tree is locked/unlocked while walking through all the nodes;
9327c478bd9Sstevel@tonic-gate  *    if the locking fails at any stage, stops further walking and returns
9337c478bd9Sstevel@tonic-gate  *    DDI_FAILURE. Returns DDI_SUCCESS if everything went fine.
9347c478bd9Sstevel@tonic-gate  */
9357c478bd9Sstevel@tonic-gate int
s1394_process_old_tree(s1394_hal_t * hal)9367c478bd9Sstevel@tonic-gate s1394_process_old_tree(s1394_hal_t *hal)
9377c478bd9Sstevel@tonic-gate {
9387c478bd9Sstevel@tonic-gate 	int i;
9397c478bd9Sstevel@tonic-gate 	uint_t hal_node_num_old, old_number_of_nodes;
9407c478bd9Sstevel@tonic-gate 	s1394_node_t *onode;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_process_old_tree_enter,
9437c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate 	/*
9467c478bd9Sstevel@tonic-gate 	 * NODE_MATCHED(onode) == 0 indicates this node doesn't exist
9477c478bd9Sstevel@tonic-gate 	 * any more.
9487c478bd9Sstevel@tonic-gate 	 */
9497c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
9527c478bd9Sstevel@tonic-gate 		TNF_PROBE_0(s1394_process_old_tree_lock_failed,
9537c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_ERROR, "");
9547c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
9557c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
9567c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9577c478bd9Sstevel@tonic-gate 	}
9587c478bd9Sstevel@tonic-gate 	hal_node_num_old = IEEE1394_NODE_NUM(hal->old_node_id);
9597c478bd9Sstevel@tonic-gate 	old_number_of_nodes = hal->old_number_of_nodes;
9607c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	for (i = 0; i < old_number_of_nodes; i++) {
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 		if (i == hal_node_num_old)
9657c478bd9Sstevel@tonic-gate 			continue;
9667c478bd9Sstevel@tonic-gate 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
9677c478bd9Sstevel@tonic-gate 			TNF_PROBE_2(s1394_process_old_tree,
9687c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
9697c478bd9Sstevel@tonic-gate 			    "lock failed while processing node", tnf_uint,
9707c478bd9Sstevel@tonic-gate 			    node_num, i);
9717c478bd9Sstevel@tonic-gate 			TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
9727c478bd9Sstevel@tonic-gate 			    S1394_TNF_SL_HOTPLUG_STACK, "");
9737c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
9747c478bd9Sstevel@tonic-gate 		}
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 		onode = &hal->old_tree[i];
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		if (onode->cfgrom == NULL) {
9797c478bd9Sstevel@tonic-gate 			CLEAR_CFGROM_STATE(onode);
9807c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
9817c478bd9Sstevel@tonic-gate 			continue;
9827c478bd9Sstevel@tonic-gate 		}
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(s1394_process_old_tree,
9857c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque,
9867c478bd9Sstevel@tonic-gate 		    cfgrom, onode->cfgrom);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		TNF_PROBE_5_DEBUG(s1394_process_old_tree,
9897c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int,
9907c478bd9Sstevel@tonic-gate 		    node_num, i, tnf_int, parsed, CFGROM_PARSED(onode), tnf_int,
9917c478bd9Sstevel@tonic-gate 		    matched, NODE_MATCHED(onode), tnf_int, visited,
9927c478bd9Sstevel@tonic-gate 		    NODE_VISITED(onode), tnf_int, generation_changed,
9937c478bd9Sstevel@tonic-gate 		    CFGROM_GEN_CHANGED(onode));
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 		/*
9967c478bd9Sstevel@tonic-gate 		 * onode->cur_node == NULL iff we couldn't read cfgrom in the
9977c478bd9Sstevel@tonic-gate 		 * current generation in non-tree matching case (and thus
9987c478bd9Sstevel@tonic-gate 		 * match_GUIDs couldn't set cur_node).
9997c478bd9Sstevel@tonic-gate 		 */
10007c478bd9Sstevel@tonic-gate 		if (NODE_MATCHED(onode) == B_FALSE || (onode->cur_node ==
10017c478bd9Sstevel@tonic-gate 		    NULL || ((CFGROM_VALID(onode) == B_TRUE &&
10027c478bd9Sstevel@tonic-gate 		    CFGROM_VALID(onode->cur_node) == B_FALSE) ||
10037c478bd9Sstevel@tonic-gate 		    (LINK_ACTIVE(onode) == B_TRUE && LINK_ACTIVE(onode->
10047c478bd9Sstevel@tonic-gate 		    cur_node) == B_FALSE)))) {
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 			if (onode->cur_node != NULL && CFGROM_VALID(onode) ==
10077c478bd9Sstevel@tonic-gate 			    B_TRUE && CFGROM_VALID(onode->cur_node) == B_FALSE)
10087c478bd9Sstevel@tonic-gate 				TNF_PROBE_1_DEBUG
10097c478bd9Sstevel@tonic-gate 				    (s1394_process_old_tree_invalid_cfgrom,
10107c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_STACK, "",
10117c478bd9Sstevel@tonic-gate 				    tnf_int, node_num, i);
10127c478bd9Sstevel@tonic-gate 			if (onode->cur_node != NULL && LINK_ACTIVE(onode) ==
10137c478bd9Sstevel@tonic-gate 			    B_TRUE && LINK_ACTIVE(onode->cur_node) == B_FALSE)
10147c478bd9Sstevel@tonic-gate 				TNF_PROBE_1_DEBUG
10157c478bd9Sstevel@tonic-gate 				    (s1394_process_old_tree_link_off,
10167c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_STACK,
10177c478bd9Sstevel@tonic-gate 				    "", tnf_int, node_num, i);
10187c478bd9Sstevel@tonic-gate 			if (s1394_offline_node(hal, onode) != DDI_SUCCESS) {
10197c478bd9Sstevel@tonic-gate 				TNF_PROBE_2(s1394_process_old_tree,
10207c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
10217c478bd9Sstevel@tonic-gate 				    msg, "failure from offline node", tnf_uint,
10227c478bd9Sstevel@tonic-gate 				    node_num, i);
10237c478bd9Sstevel@tonic-gate 				TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
10247c478bd9Sstevel@tonic-gate 				    S1394_TNF_SL_HOTPLUG_STACK, "");
10257c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
10267c478bd9Sstevel@tonic-gate 			}
10277c478bd9Sstevel@tonic-gate 			s1394_free_cfgrom(hal, onode, S1394_FREE_CFGROM_OLD);
10287c478bd9Sstevel@tonic-gate 		}
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
10367c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10397c478bd9Sstevel@tonic-gate }
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate /*
10427c478bd9Sstevel@tonic-gate  * s1394_update_unit_dir_location()
10437c478bd9Sstevel@tonic-gate  *    Updates the unit-dir-offset property on the devinfo.
10447c478bd9Sstevel@tonic-gate  *    NOTE: ndi_prop_update_int() is interrupt callable (and thus won't block);
10457c478bd9Sstevel@tonic-gate  *    so, the caller doesn't drop topology_tree_mutex when calling this routine.
10467c478bd9Sstevel@tonic-gate  */
10477c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10487c478bd9Sstevel@tonic-gate static void
s1394_update_unit_dir_location(s1394_hal_t * hal,dev_info_t * tdip,uint_t offset)10497c478bd9Sstevel@tonic-gate s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
10507c478bd9Sstevel@tonic-gate     uint_t offset)
10517c478bd9Sstevel@tonic-gate {
10527c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
10537c478bd9Sstevel@tonic-gate 	ASSERT(tdip != NULL);
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	TNF_PROBE_1_DEBUG(s1394_update_unit_dir_location_enter,
10567c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, offset, offset);
10577c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, tdip, "unit-dir-offset",
10587c478bd9Sstevel@tonic-gate 	    offset);
10597c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_update_unit_dir_location_exit,
10607c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
10617c478bd9Sstevel@tonic-gate }
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate /*
10647c478bd9Sstevel@tonic-gate  * s1394_add_target_to_node()
10657c478bd9Sstevel@tonic-gate  *    adds target to the list of targets hanging off the node. Figures out
10667c478bd9Sstevel@tonic-gate  *    the node by searching the topology tree for the GUID corresponding
10677c478bd9Sstevel@tonic-gate  *    to the target. Points on_node field of target structure at the node.
10687c478bd9Sstevel@tonic-gate  */
10697c478bd9Sstevel@tonic-gate void
s1394_add_target_to_node(s1394_target_t * target)10707c478bd9Sstevel@tonic-gate s1394_add_target_to_node(s1394_target_t *target)
10717c478bd9Sstevel@tonic-gate {
10727c478bd9Sstevel@tonic-gate 	s1394_target_t *t;
10737c478bd9Sstevel@tonic-gate 	s1394_hal_t *hal;
10747c478bd9Sstevel@tonic-gate 	uint32_t guid_hi;
10757c478bd9Sstevel@tonic-gate 	uint32_t guid_lo;
10767c478bd9Sstevel@tonic-gate 	int i;
10777c478bd9Sstevel@tonic-gate 	char name[MAXNAMELEN];
10787c478bd9Sstevel@tonic-gate 	char *ptr;
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_add_target_to_node_enter,
10817c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
10847c478bd9Sstevel@tonic-gate 	ASSERT(hal != NULL);
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	/* Topology tree must be locked when it gets here! */
10877c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	/* target_list_rwlock should be held in write mode */
10907c478bd9Sstevel@tonic-gate 	ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	if ((ptr = ddi_get_name_addr(target->target_dip)) == NULL) {
10937c478bd9Sstevel@tonic-gate 		TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit_no_name,
10947c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "");
10957c478bd9Sstevel@tonic-gate 		return;
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	(void) sprintf(name, ptr);
10997c478bd9Sstevel@tonic-gate 	/* Drop the ,<ADDR> part, if present */
11007c478bd9Sstevel@tonic-gate 	if ((ptr = strchr(name, ',')) != NULL)
11017c478bd9Sstevel@tonic-gate 		*ptr = '\0';
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	ptr = name;
11047c478bd9Sstevel@tonic-gate 	guid_hi = s1394_stoi(ptr, 8, 16);
11057c478bd9Sstevel@tonic-gate 	guid_lo = s1394_stoi(ptr + 8, 8, 16);
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	/* Search the HAL's node list for this GUID */
11087c478bd9Sstevel@tonic-gate 	for (i = 0; i < hal->number_of_nodes; i++) {
11097c478bd9Sstevel@tonic-gate 		if (CFGROM_VALID(&hal->topology_tree[i]) == B_TRUE) {
11107c478bd9Sstevel@tonic-gate 			ASSERT(hal->topology_tree[i].cfgrom != NULL);
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 			if ((hal->topology_tree[i].node_guid_hi == guid_hi) &&
11137c478bd9Sstevel@tonic-gate 			    (hal->topology_tree[i].node_guid_lo == guid_lo)) {
11147c478bd9Sstevel@tonic-gate 				target->on_node = &hal->topology_tree[i];
11157c478bd9Sstevel@tonic-gate 				if ((t = hal->topology_tree[i].target_list) !=
11167c478bd9Sstevel@tonic-gate 				    NULL) {
11177c478bd9Sstevel@tonic-gate 					ASSERT(t != target);
11187c478bd9Sstevel@tonic-gate 					while (t->target_sibling != NULL) {
11197c478bd9Sstevel@tonic-gate 						t = t->target_sibling;
11207c478bd9Sstevel@tonic-gate 						ASSERT(t != target);
11217c478bd9Sstevel@tonic-gate 					}
11227c478bd9Sstevel@tonic-gate 					t->target_sibling = target;
11237c478bd9Sstevel@tonic-gate 				} else {
11247c478bd9Sstevel@tonic-gate 					hal->topology_tree[i].target_list =
11257c478bd9Sstevel@tonic-gate 					    target;
11267c478bd9Sstevel@tonic-gate 				}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 				/*
11297c478bd9Sstevel@tonic-gate 				 * update target_list in all targets on the
11307c478bd9Sstevel@tonic-gate 				 * node
11317c478bd9Sstevel@tonic-gate 				 */
11327c478bd9Sstevel@tonic-gate 				t = hal->topology_tree[i].target_list;
11337c478bd9Sstevel@tonic-gate 				while (t != NULL) {
11347c478bd9Sstevel@tonic-gate 					t->target_list =
11357c478bd9Sstevel@tonic-gate 					    hal->topology_tree[i].target_list;
11367c478bd9Sstevel@tonic-gate 					t = t->target_sibling;
11377c478bd9Sstevel@tonic-gate 				}
11387c478bd9Sstevel@tonic-gate 				break;
11397c478bd9Sstevel@tonic-gate 			}
11407c478bd9Sstevel@tonic-gate 		}
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit,
11447c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
11457c478bd9Sstevel@tonic-gate }
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate /*
11487c478bd9Sstevel@tonic-gate  * s1394_remove_target_from_node()
11497c478bd9Sstevel@tonic-gate  *    Removes target from the corresponding node's target_list.
11507c478bd9Sstevel@tonic-gate  */
11517c478bd9Sstevel@tonic-gate void
s1394_remove_target_from_node(s1394_target_t * target)11527c478bd9Sstevel@tonic-gate s1394_remove_target_from_node(s1394_target_t *target)
11537c478bd9Sstevel@tonic-gate {
11547c478bd9Sstevel@tonic-gate 	s1394_target_t *t, *t1;
11557c478bd9Sstevel@tonic-gate 	s1394_hal_t *hal;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_enter,
11587c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
11617c478bd9Sstevel@tonic-gate 	ASSERT(hal != NULL);
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 	/* Topology tree must be locked when it gets here! */
11647c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	/* target_list_rwlock should be held in write mode */
11677c478bd9Sstevel@tonic-gate 	ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	if (target->on_node == NULL) {
11707c478bd9Sstevel@tonic-gate 		TNF_PROBE_1_DEBUG(s1394_remove_target_from_node_NULL,
11717c478bd9Sstevel@tonic-gate 		    S1394_TNF_SL_HOTPLUG_STACK, "",
11727c478bd9Sstevel@tonic-gate 		    tnf_uint, target_state, target->target_state);
11737c478bd9Sstevel@tonic-gate 	}
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	t = target->target_list;
11767c478bd9Sstevel@tonic-gate 	t1 = NULL;
11777c478bd9Sstevel@tonic-gate 	while (t != NULL) {
11787c478bd9Sstevel@tonic-gate 		if (t == target) {
11797c478bd9Sstevel@tonic-gate 			if (t1 == NULL) {
11807c478bd9Sstevel@tonic-gate 				target->target_list = t->target_sibling;
11817c478bd9Sstevel@tonic-gate 			} else {
11827c478bd9Sstevel@tonic-gate 				t1->target_sibling = t->target_sibling;
11837c478bd9Sstevel@tonic-gate 			}
11847c478bd9Sstevel@tonic-gate 			break;
11857c478bd9Sstevel@tonic-gate 		}
11867c478bd9Sstevel@tonic-gate 		t1 = t;
11877c478bd9Sstevel@tonic-gate 		t = t->target_sibling;
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 	/* Update the target_list pointer in all the targets */
11907c478bd9Sstevel@tonic-gate 	if (target->on_node != NULL)
11917c478bd9Sstevel@tonic-gate 		target->on_node->target_list = target->target_list;
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	t = t1 = target->target_list;
11947c478bd9Sstevel@tonic-gate 	while (t != NULL) {
11957c478bd9Sstevel@tonic-gate 		t->target_list = t1;
11967c478bd9Sstevel@tonic-gate 		t = t->target_sibling;
11977c478bd9Sstevel@tonic-gate 	}
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	target->on_node = NULL;
12007c478bd9Sstevel@tonic-gate 	target->target_sibling = NULL;
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_exit,
12037c478bd9Sstevel@tonic-gate 	    S1394_TNF_SL_HOTPLUG_STACK, "");
12047c478bd9Sstevel@tonic-gate }
1205