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 /*
23fa9e4066Sahrens  * 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 /*
287c478bd9Sstevel@tonic-gate  * s1394_hotplug.c
297c478bd9Sstevel@tonic-gate  *    1394 Services Layer Hotplug Routines
307c478bd9Sstevel@tonic-gate  *    This file contains routines that walk the old and topology
317c478bd9Sstevel@tonic-gate  *    trees, at bus reset time, creating devinfo's for new nodes and offlining
327c478bd9Sstevel@tonic-gate  *    nodes that are removed.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/conf.h>
367c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
377c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
407c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
417c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
437c478bd9Sstevel@tonic-gate #include <sys/types.h>
447c478bd9Sstevel@tonic-gate #include <sys/1394/t1394.h>
457c478bd9Sstevel@tonic-gate #include <sys/1394/s1394.h>
467c478bd9Sstevel@tonic-gate #include <sys/1394/h1394.h>
477c478bd9Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate static void s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
507c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo);
517c478bd9Sstevel@tonic-gate static void s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
527c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo);
537c478bd9Sstevel@tonic-gate static dev_info_t *s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node,
547c478bd9Sstevel@tonic-gate     uint32_t *unit_dir, int nunit);
557c478bd9Sstevel@tonic-gate static void s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
567c478bd9Sstevel@tonic-gate     uint_t offset);
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate  * s1394_send_remove_event()
607c478bd9Sstevel@tonic-gate  *    Invokes any "remove event" callback registered for dip. Passes
617c478bd9Sstevel@tonic-gate  *    t1394_localinfo_t as impl_data for the callback.
627c478bd9Sstevel@tonic-gate  */
637c478bd9Sstevel@tonic-gate static void
s1394_send_remove_event(s1394_hal_t * hal,dev_info_t * dip,t1394_localinfo_t * localinfo)647c478bd9Sstevel@tonic-gate s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
657c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo)
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate 	char name[128];
687c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "%s%d", ddi_driver_name(dip),
717c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
747c478bd9Sstevel@tonic-gate 	    DDI_DEVI_REMOVE_EVENT, &cookie, NDI_EVENT_NOPASS)
757c478bd9Sstevel@tonic-gate 	    == NDI_SUCCESS) {
767c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
777c478bd9Sstevel@tonic-gate 		    cookie, localinfo);
787c478bd9Sstevel@tonic-gate 	}
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * s1394_send_insert_event()
837c478bd9Sstevel@tonic-gate  *    Invokes any "insert event" callback registered for dip. Passes
847c478bd9Sstevel@tonic-gate  *    t1394_localinfo_t as impl_data for the callback.
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate static void
s1394_send_insert_event(s1394_hal_t * hal,dev_info_t * dip,t1394_localinfo_t * localinfo)877c478bd9Sstevel@tonic-gate s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
887c478bd9Sstevel@tonic-gate     t1394_localinfo_t *localinfo)
897c478bd9Sstevel@tonic-gate {
907c478bd9Sstevel@tonic-gate 	char name[128];
917c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t cookie;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "%s%d", ddi_driver_name(dip),
947c478bd9Sstevel@tonic-gate 	    ddi_get_instance(dip));
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
977c478bd9Sstevel@tonic-gate 	    DDI_DEVI_INSERT_EVENT, &cookie, NDI_EVENT_NOPASS) ==
987c478bd9Sstevel@tonic-gate 	    NDI_SUCCESS)
997c478bd9Sstevel@tonic-gate 		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
1007c478bd9Sstevel@tonic-gate 		    cookie, localinfo);
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * s1394_create_devinfo()
1057c478bd9Sstevel@tonic-gate  *    This routine creates a devinfo corresponding to the unit_dir passed in.
1067c478bd9Sstevel@tonic-gate  *    It adds "hp-node", "reg", "compatible" properties to the devinfo
1077c478bd9Sstevel@tonic-gate  *    (formats for "reg" and "compatible" properties are specified by 1275
1087c478bd9Sstevel@tonic-gate  *    binding for IEEE1394). If unable to create the devinfo and/or add the
1097c478bd9Sstevel@tonic-gate  *    the properties, returns NULL, otherwise, returns the devinfo created.
1107c478bd9Sstevel@tonic-gate  *
1117c478bd9Sstevel@tonic-gate  *    NOTE: All ndi_* routines are interrupt callable (and thus won't sleep).
1127c478bd9Sstevel@tonic-gate  *    So, we don't drop topology_mutex across ndi calls.
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate static dev_info_t *
s1394_create_devinfo(s1394_hal_t * hal,s1394_node_t * node,uint32_t * unit_dir,int nunit)1157c478bd9Sstevel@tonic-gate s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node, uint32_t *unit_dir,
1167c478bd9Sstevel@tonic-gate     int nunit)
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate 	dev_info_t *hal_dip;
1197c478bd9Sstevel@tonic-gate 	uint32_t *root_dir;
1207c478bd9Sstevel@tonic-gate 	dev_info_t *target_dip;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	int root_dir_len;
1237c478bd9Sstevel@tonic-gate 	int result, i, j, spec_id, sw_version;
1247c478bd9Sstevel@tonic-gate 	int mod_ven, mod_hw, mod_spec, mod_sw;
1257c478bd9Sstevel@tonic-gate 	int node_ven, node_hw, node_spec, node_sw;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	/*LINTED type is unused*/
1287373b68aSToomas Soome 	uint32_t type __unused, key, value;
1297c478bd9Sstevel@tonic-gate 	uint32_t unit_spec_id, unit_sw_version;
1307c478bd9Sstevel@tonic-gate 	uint32_t node_spec_id, node_sw_version;
1317c478bd9Sstevel@tonic-gate 	uint32_t node_vendor_id, node_hw_version;
1327c478bd9Sstevel@tonic-gate 	uint32_t module_spec_id, module_sw_version;
1337c478bd9Sstevel@tonic-gate 	uint32_t module_vendor_id, module_hw_version;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	char *fmt = "firewire%06x,%06x";
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	char *buf[5], data[5][24];
1387c478bd9Sstevel@tonic-gate 	uint32_t reg[6];
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	hal_dip = hal->halinfo.dip;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	/* Allocate and init a new device node instance. */
145fa9e4066Sahrens 	result = ndi_devi_alloc(hal_dip, "unit", (pnode_t)DEVI_SID_NODEID,
1467c478bd9Sstevel@tonic-gate 	    &target_dip);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	if (result != NDI_SUCCESS) {
1497c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!Unable to create devinfo"
1507c478bd9Sstevel@tonic-gate 		    " (node's GUID %08x%08x)", node->node_guid_hi,
1517c478bd9Sstevel@tonic-gate 		    node->node_guid_lo);
1527c478bd9Sstevel@tonic-gate 		return (NULL);
1537c478bd9Sstevel@tonic-gate 	}
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* Add "hp-node" property */
1567c478bd9Sstevel@tonic-gate 	result = ndi_prop_update_int(DDI_DEV_T_NONE, target_dip, "hp-node", 0);
1577c478bd9Sstevel@tonic-gate 	if (result != NDI_SUCCESS) {
1587c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!Unable to add \"hp-node\" property"
1597c478bd9Sstevel@tonic-gate 		    " (node's GUID %08x%08x)", node->node_guid_hi,
1607c478bd9Sstevel@tonic-gate 		    node->node_guid_lo);
1617c478bd9Sstevel@tonic-gate #if defined(DEBUG)
1627c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "!Error code %d", result);
1637c478bd9Sstevel@tonic-gate #endif
1647c478bd9Sstevel@tonic-gate 		ndi_prop_remove_all(target_dip);
1657c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(target_dip);
1667c478bd9Sstevel@tonic-gate 		return (NULL);
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	spec_id = sw_version = mod_ven = mod_hw = mod_spec = mod_sw =
1707c478bd9Sstevel@tonic-gate 	    node_ven = node_hw = node_spec = node_sw = 0;
1717c478bd9Sstevel@tonic-gate 	unit_sw_version = node_sw_version = node_hw_version =
1727c478bd9Sstevel@tonic-gate 	    module_sw_version = module_hw_version = 0;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
1767c478bd9Sstevel@tonic-gate 	root_dir_len = CFGROM_DIR_LEN(root_dir);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	for (i = 0; i < root_dir_len; i++) {
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 		CFGROM_TYPE_KEY_VALUE(root_dir[i + 1], type, key, value);
1817c478bd9Sstevel@tonic-gate 		switch (key) {
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 		case IEEE1212_MODULE_VENDOR_ID:
1847c478bd9Sstevel@tonic-gate 			module_vendor_id = value;
1857c478bd9Sstevel@tonic-gate 			mod_ven++;
1867c478bd9Sstevel@tonic-gate 			break;
1877c478bd9Sstevel@tonic-gate 		case IEEE1212_MODULE_HW_VERSION:
1887c478bd9Sstevel@tonic-gate 			module_hw_version = value;
1897c478bd9Sstevel@tonic-gate 			mod_hw++;
1907c478bd9Sstevel@tonic-gate 			break;
1917c478bd9Sstevel@tonic-gate 		case IEEE1212_MODULE_SPEC_ID:
1927c478bd9Sstevel@tonic-gate 			module_spec_id = value;
1937c478bd9Sstevel@tonic-gate 			mod_spec++;
1947c478bd9Sstevel@tonic-gate 			break;
1957c478bd9Sstevel@tonic-gate 		case IEEE1212_MODULE_SW_VERSION:
1967c478bd9Sstevel@tonic-gate 			module_sw_version = value;
1977c478bd9Sstevel@tonic-gate 			mod_sw++;
1987c478bd9Sstevel@tonic-gate 			break;
1997c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_VENDOR_ID:
2007c478bd9Sstevel@tonic-gate 			node_vendor_id = value;
2017c478bd9Sstevel@tonic-gate 			node_ven++;
2027c478bd9Sstevel@tonic-gate 			break;
2037c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_UNIQUE_ID: {
2047c478bd9Sstevel@tonic-gate 				uint32_t *node_unique_leaf =
2057c478bd9Sstevel@tonic-gate 				    &root_dir[i + 1] + value;
2067c478bd9Sstevel@tonic-gate 				node_vendor_id = (node_unique_leaf[1] >> 8);
2077c478bd9Sstevel@tonic-gate 				node_ven++;
2087c478bd9Sstevel@tonic-gate 			}
2097c478bd9Sstevel@tonic-gate 			break;
2107c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_HW_VERSION:
2117c478bd9Sstevel@tonic-gate 			node_hw_version = value;
2127c478bd9Sstevel@tonic-gate 			node_hw++;
2137c478bd9Sstevel@tonic-gate 			break;
2147c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_SPEC_ID:
2157c478bd9Sstevel@tonic-gate 			node_spec_id = value;
2167c478bd9Sstevel@tonic-gate 			node_spec++;
2177c478bd9Sstevel@tonic-gate 			break;
2187c478bd9Sstevel@tonic-gate 		case IEEE1212_NODE_SW_VERSION:
2197c478bd9Sstevel@tonic-gate 			node_sw_version = value;
2207c478bd9Sstevel@tonic-gate 			node_sw++;
2217c478bd9Sstevel@tonic-gate 			break;
2227c478bd9Sstevel@tonic-gate 		}
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 		if (mod_ven && mod_hw && mod_spec && mod_sw && node_ven &&
2257c478bd9Sstevel@tonic-gate 		    node_hw && node_spec && node_sw) {
2267c478bd9Sstevel@tonic-gate 			break;
2277c478bd9Sstevel@tonic-gate 		}
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	/*
2317c478bd9Sstevel@tonic-gate 	 * Search for unit spec and version
2327c478bd9Sstevel@tonic-gate 	 */
2337c478bd9Sstevel@tonic-gate 	for (i = 0; i < CFGROM_DIR_LEN(unit_dir); i++) {
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 		CFGROM_TYPE_KEY_VALUE(unit_dir[i + 1], type, key, value);
2367c478bd9Sstevel@tonic-gate 		if (key == IEEE1212_UNIT_SPEC_ID) {
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 			unit_spec_id = value;
2397c478bd9Sstevel@tonic-gate 			spec_id++;
2407c478bd9Sstevel@tonic-gate 		} else if (key == IEEE1212_UNIT_SW_VERSION) {
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 			unit_sw_version = value;
2437c478bd9Sstevel@tonic-gate 			sw_version++;
2447c478bd9Sstevel@tonic-gate 		}
2457c478bd9Sstevel@tonic-gate 		if (spec_id && sw_version)
2467c478bd9Sstevel@tonic-gate 			break;
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	/*
2507c478bd9Sstevel@tonic-gate 	 * Refer to IEEE1212 (pages 90-92) for information regarding various
2517c478bd9Sstevel@tonic-gate 	 * id's. Module_Vendor_Id is required. Node_Vendor_Id is optional and
2527c478bd9Sstevel@tonic-gate 	 * if not implemented, its assumed value is Module_Vendor_Id.
2537c478bd9Sstevel@tonic-gate 	 * Module_Spec_Id is optional and if not implemented, its assumed value
2547c478bd9Sstevel@tonic-gate 	 * is Module_Vendor_Id. Node_Spec_Id is optional, and if not
2557c478bd9Sstevel@tonic-gate 	 * implemented, its assumed value is Node_Vendor_Id. Unit_Spec_Id is
2567c478bd9Sstevel@tonic-gate 	 * optional, and if not implemented, its assumed value is
2577c478bd9Sstevel@tonic-gate 	 * Node_Vendor_Id.
2587c478bd9Sstevel@tonic-gate 	 */
2597c478bd9Sstevel@tonic-gate 	if (node_ven == 0) {
2607c478bd9Sstevel@tonic-gate 		node_vendor_id = module_vendor_id;
2617c478bd9Sstevel@tonic-gate 		node_ven++;
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	if (node_spec == 0) {
2657c478bd9Sstevel@tonic-gate 		node_spec_id = node_vendor_id;
2667c478bd9Sstevel@tonic-gate 		node_spec++;
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	if (mod_spec == 0) {
2707c478bd9Sstevel@tonic-gate 		module_spec_id = module_vendor_id;
2717c478bd9Sstevel@tonic-gate 		mod_spec++;
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	if (spec_id == 0) {
2757c478bd9Sstevel@tonic-gate 		unit_spec_id = node_vendor_id;
2767c478bd9Sstevel@tonic-gate 		spec_id++;
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	i = 0;
2807c478bd9Sstevel@tonic-gate 	if (sw_version != 0) {
2817c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
2827c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, unit_spec_id, unit_sw_version);
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 	if (node_sw != 0) {
2857c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
2867c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, node_spec_id, node_sw_version);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 	if (node_hw != 0) {
2897c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
2907c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, node_vendor_id, node_hw_version);
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 	if (mod_sw != 0) {
2937c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
2947c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, module_spec_id,
2957c478bd9Sstevel@tonic-gate 		    module_sw_version);
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 	if (mod_hw != 0) {
2987c478bd9Sstevel@tonic-gate 		buf[i] = data[i];
2997c478bd9Sstevel@tonic-gate 		(void) sprintf(data[i++], fmt, module_vendor_id,
3007c478bd9Sstevel@tonic-gate 		    module_hw_version);
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	result = ndi_prop_update_string_array(DDI_DEV_T_NONE, target_dip,
3047c478bd9Sstevel@tonic-gate 	    "compatible", (char **)&buf, i);
3057c478bd9Sstevel@tonic-gate 	if (result != NDI_SUCCESS) {
3067c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!Unable to add \"compatible\" property"
3077c478bd9Sstevel@tonic-gate 		    " (node's GUID %08x%08x)", node->node_guid_hi,
3087c478bd9Sstevel@tonic-gate 		    node->node_guid_lo);
3097c478bd9Sstevel@tonic-gate #if defined(DEBUG)
3107c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "!Error code %d; nelements %d", result, i);
3117c478bd9Sstevel@tonic-gate 		for (j = 0; j < i; j++) {
3127c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "!buf[%d]: %s", j, buf[j]);
3137c478bd9Sstevel@tonic-gate 		}
3147c478bd9Sstevel@tonic-gate #endif
3157c478bd9Sstevel@tonic-gate 		ndi_prop_remove_all(target_dip);
3167c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(target_dip);
3177c478bd9Sstevel@tonic-gate 		return (NULL);
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate 	/* GUID,ADDR */
3217c478bd9Sstevel@tonic-gate 	reg[0] = node->node_guid_hi;
3227c478bd9Sstevel@tonic-gate 	reg[1] = node->node_guid_lo;
3237c478bd9Sstevel@tonic-gate 	s1394_cfgrom_parse_unit_dir(unit_dir, &reg[2], &reg[3], &reg[4],
3247c478bd9Sstevel@tonic-gate 	    &reg[5]);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	reg[3] = nunit;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	result = ndi_prop_update_int_array(DDI_DEV_T_NONE, target_dip, "reg",
3297c478bd9Sstevel@tonic-gate 	    (int *)reg, 6);
3307c478bd9Sstevel@tonic-gate 	if (result != NDI_SUCCESS) {
3317c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!Unable to add \"reg\" property");
3327c478bd9Sstevel@tonic-gate #if defined(DEBUG)
3337c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "!Error code %d", result);
3347c478bd9Sstevel@tonic-gate 		for (j = 0; j < 6; j++) {
3357c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, "!reg[%d]: 0x%08x", j, reg[j]);
3367c478bd9Sstevel@tonic-gate 		}
3377c478bd9Sstevel@tonic-gate #endif
3387c478bd9Sstevel@tonic-gate 		ndi_prop_remove_all(target_dip);
3397c478bd9Sstevel@tonic-gate 		(void) ndi_devi_free(target_dip);
3407c478bd9Sstevel@tonic-gate 		return (NULL);
3417c478bd9Sstevel@tonic-gate 	}
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	return (target_dip);
3447c478bd9Sstevel@tonic-gate }
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate /*
3477c478bd9Sstevel@tonic-gate  * s1394_devi_find()
3487c478bd9Sstevel@tonic-gate  *    Searches all children of pdip for a match of name@caddr. Builds the
3497c478bd9Sstevel@tonic-gate  *    name and address of each child node by looking up the reg property on
3507c478bd9Sstevel@tonic-gate  *    the node and compares the built name@addr with the name@addr passed in.
3517c478bd9Sstevel@tonic-gate  *    Returns the child dip if a match is found, otherwise, returns NULL.
3527c478bd9Sstevel@tonic-gate  *    NOTE:
3537c478bd9Sstevel@tonic-gate  *    This routine is decidedly non-ddi. We had to use this one since
3547c478bd9Sstevel@tonic-gate  *    ndi_devi_find() can find only nodes that have valid addr field
3557c478bd9Sstevel@tonic-gate  *    set and that won't happen unless the node goes through INITCHILD
3567c478bd9Sstevel@tonic-gate  *    (at which time nx1394.c calls ddi_set_name_addr()). If, in future,
3577c478bd9Sstevel@tonic-gate  *    the ndi_devi_find() provides a way of looking up nodes using criteria
3587c478bd9Sstevel@tonic-gate  *    other than addr, we can get rid of this routine.
3597c478bd9Sstevel@tonic-gate  */
3607c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3617c478bd9Sstevel@tonic-gate dev_info_t *
s1394_devi_find(dev_info_t * pdip,char * name,char * caddr)3627c478bd9Sstevel@tonic-gate s1394_devi_find(dev_info_t *pdip, char *name, char *caddr)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	int i, reglen;
3657c478bd9Sstevel@tonic-gate 	char addr[32];
3667c478bd9Sstevel@tonic-gate 	uint32_t *regptr;
3677c478bd9Sstevel@tonic-gate 	dev_info_t *cdip = NULL;
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	ASSERT((name != NULL) && (caddr != NULL));
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	/*
3727c478bd9Sstevel@tonic-gate 	 * for each child of this parent, find name and addr and match with
3737c478bd9Sstevel@tonic-gate 	 * name and caddr passed in.
3747c478bd9Sstevel@tonic-gate 	 */
3757c478bd9Sstevel@tonic-gate 	for (cdip = (dev_info_t *)DEVI(pdip)->devi_child; cdip != NULL;
3767c478bd9Sstevel@tonic-gate 	    cdip = (dev_info_t *)DEVI(cdip)->devi_sibling) {
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 		i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
3797c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg", (int **)&regptr,
3807c478bd9Sstevel@tonic-gate 		    (uint_t *)&reglen);
3817c478bd9Sstevel@tonic-gate 
3827c478bd9Sstevel@tonic-gate 		if (i != DDI_PROP_SUCCESS)
3837c478bd9Sstevel@tonic-gate 			continue;
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		/*
3867c478bd9Sstevel@tonic-gate 		 * Construct addr from the reg property (addr is of the format
3877c478bd9Sstevel@tonic-gate 		 * GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where GGGGGGGGGGGGGGGG is
3887c478bd9Sstevel@tonic-gate 		 * the address and AAAAAAAAAAAA is the optional unit address)
3897c478bd9Sstevel@tonic-gate 		 */
3901a182508SToomas Soome 		if (regptr[2] != 0 || regptr[3] != 0) {
3917c478bd9Sstevel@tonic-gate 			(void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
3927c478bd9Sstevel@tonic-gate 			    regptr[1], regptr[2], regptr[3]);
3937c478bd9Sstevel@tonic-gate 		} else {
3947c478bd9Sstevel@tonic-gate 			(void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
3957c478bd9Sstevel@tonic-gate 		}
3967c478bd9Sstevel@tonic-gate 		ddi_prop_free(regptr);
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 		if (strcmp(caddr, addr) == 0) {
3997c478bd9Sstevel@tonic-gate 			ASSERT(strcmp(ddi_node_name(cdip), name) == 0);
4007c478bd9Sstevel@tonic-gate 			break;
4017c478bd9Sstevel@tonic-gate 		}
4027c478bd9Sstevel@tonic-gate 	}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	return (cdip);
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate  * s1394_update_devinfo_tree()
4097c478bd9Sstevel@tonic-gate  *    Parses the config rom for the passed in node and creates/updates devinfo's
4107c478bd9Sstevel@tonic-gate  *    for each unit directory found. If the devinfo corresponding to a unit
4117c478bd9Sstevel@tonic-gate  *    already exists, any insert event callbacks registered for that devinfo
4127c478bd9Sstevel@tonic-gate  *    are called (topology tree is unlocked and relocked around these
4137c478bd9Sstevel@tonic-gate  *    callbacks). Returns DDI_SUCCESS if everything went fine and DDI_FAILURE
4147c478bd9Sstevel@tonic-gate  *    if unable to reacquire the lock after callbacks (relock fails because of
4157c478bd9Sstevel@tonic-gate  *    an intervening bus reset or if the services layer kills the bus reset
4167c478bd9Sstevel@tonic-gate  *    thread). The node is marked as parsed before returning.
4177c478bd9Sstevel@tonic-gate  */
4187c478bd9Sstevel@tonic-gate int
s1394_update_devinfo_tree(s1394_hal_t * hal,s1394_node_t * node)4197c478bd9Sstevel@tonic-gate s1394_update_devinfo_tree(s1394_hal_t *hal, s1394_node_t *node)
4207c478bd9Sstevel@tonic-gate {
4217c478bd9Sstevel@tonic-gate 	dev_info_t *tdip;
4227c478bd9Sstevel@tonic-gate 	int j, units, d, lockfail = 0;
4237c478bd9Sstevel@tonic-gate 	s1394_target_t *target, *t;
4247c478bd9Sstevel@tonic-gate 	uint32_t hi, lo, size_hi, size_lo, type, key, value;
4257c478bd9Sstevel@tonic-gate 	uint32_t *ptr, *root_dir, dir_len;
4267c478bd9Sstevel@tonic-gate 	t1394_localinfo_t linfo;
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	uint32_t *unit_dir_ptrs[32];
4297c478bd9Sstevel@tonic-gate 	dev_info_t *devinfo_ptrs[32];
4307c478bd9Sstevel@tonic-gate 	uint32_t new_devinfo = 0;	/* to keep track of new allocations */
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	char caddr[32];
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	ASSERT(CFGROM_PARSED(node) == B_FALSE);
4377c478bd9Sstevel@tonic-gate 	ASSERT(node->cfgrom != NULL);
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/* scan through config rom looking for unit dirs */
4407c478bd9Sstevel@tonic-gate 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
4437c478bd9Sstevel@tonic-gate 		dir_len = node->cfgrom_valid_size;
4447c478bd9Sstevel@tonic-gate 	else
4457c478bd9Sstevel@tonic-gate 		dir_len = CFGROM_DIR_LEN(root_dir);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
4487c478bd9Sstevel@tonic-gate 	if (s1394_valid_dir(hal, node, key, root_dir) == B_FALSE) {
4497c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
4507c478bd9Sstevel@tonic-gate 		    "!Bad root directory in config rom (node's GUID %08x%08x)",
4517c478bd9Sstevel@tonic-gate 		    node->node_guid_hi, node->node_guid_lo);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 		SET_CFGROM_PARSED(node);
4547c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_GEN_CHANGED(node);	/* if set */
4557c478bd9Sstevel@tonic-gate 		CLEAR_CFGROM_NEW_ALLOC(node);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
4587c478bd9Sstevel@tonic-gate 	}
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	for (units = 0, j = 1; j <= dir_len; j++) {
4617c478bd9Sstevel@tonic-gate 		CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
4627c478bd9Sstevel@tonic-gate 		if (key == IEEE1212_UNIT_DIRECTORY && type ==
4637c478bd9Sstevel@tonic-gate 		    IEEE1212_DIRECTORY_TYPE) {
4647c478bd9Sstevel@tonic-gate 			ptr = &root_dir[j] + value;
4657c478bd9Sstevel@tonic-gate 			if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
4667c478bd9Sstevel@tonic-gate 				unit_dir_ptrs[units++] = ptr;
4677c478bd9Sstevel@tonic-gate 			} else {
4687c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "!Bad unit directory in config"
4697c478bd9Sstevel@tonic-gate 				    " rom (node's GUID %08x%08x)",
4707c478bd9Sstevel@tonic-gate 				    node->node_guid_hi, node->node_guid_lo);
4717c478bd9Sstevel@tonic-gate 			}
4727c478bd9Sstevel@tonic-gate 		}
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	for (d = 0, j = 0; j < units; j++) {
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 		s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
4787c478bd9Sstevel@tonic-gate 		    &hi, &lo, &size_hi, &size_lo);
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 		lo = j;
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 		if (hi || lo) {
4837c478bd9Sstevel@tonic-gate 			(void) sprintf(caddr, "%08x%08x,%04x%08x",
4847c478bd9Sstevel@tonic-gate 			    node->node_guid_hi, node->node_guid_lo, hi, lo);
4857c478bd9Sstevel@tonic-gate 		} else {
4867c478bd9Sstevel@tonic-gate 			(void) sprintf(caddr, "%08x%08x",
4877c478bd9Sstevel@tonic-gate 			    node->node_guid_hi, node->node_guid_lo);
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 		tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr);
4917c478bd9Sstevel@tonic-gate 		if (tdip != NULL) {
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 			rw_enter(&hal->target_list_rwlock, RW_WRITER);
4947c478bd9Sstevel@tonic-gate 			target = s1394_target_from_dip_locked(hal, tdip);
4957c478bd9Sstevel@tonic-gate 			if (target != NULL) {
4967c478bd9Sstevel@tonic-gate 				target->target_sibling = NULL;
4977c478bd9Sstevel@tonic-gate 				target->on_node = node;
4987c478bd9Sstevel@tonic-gate 				target->target_state &= ~S1394_TARG_GONE;
4997c478bd9Sstevel@tonic-gate 				target->unit_dir = unit_dir_ptrs[j] - root_dir;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 				if ((t = node->target_list) != NULL) {
5027c478bd9Sstevel@tonic-gate 					ASSERT(t != target);
5037c478bd9Sstevel@tonic-gate 					while (t->target_sibling != NULL) {
5047c478bd9Sstevel@tonic-gate 						t = t->target_sibling;
5057c478bd9Sstevel@tonic-gate 						ASSERT(t != target);
5067c478bd9Sstevel@tonic-gate 					}
5077c478bd9Sstevel@tonic-gate 					t->target_sibling = target;
5087c478bd9Sstevel@tonic-gate 				} else {
5097c478bd9Sstevel@tonic-gate 					node->target_list = target;
5107c478bd9Sstevel@tonic-gate 				}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 				target->target_list = node->target_list;
5137c478bd9Sstevel@tonic-gate 			}
5147c478bd9Sstevel@tonic-gate 			rw_exit(&hal->target_list_rwlock);
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 			s1394_update_unit_dir_location(hal, tdip,
5177c478bd9Sstevel@tonic-gate 			    unit_dir_ptrs[j] - root_dir);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 		} else {
5207c478bd9Sstevel@tonic-gate 			/* create devinfo for unit@caddr */
5217c478bd9Sstevel@tonic-gate 			tdip = s1394_create_devinfo(hal, node,
5227c478bd9Sstevel@tonic-gate 			    unit_dir_ptrs[j], j);
5237c478bd9Sstevel@tonic-gate 			if (tdip != NULL) {
5247c478bd9Sstevel@tonic-gate 				new_devinfo |= (1 << d);
5257c478bd9Sstevel@tonic-gate 				s1394_update_unit_dir_location(hal, tdip,
5267c478bd9Sstevel@tonic-gate 				    unit_dir_ptrs[j] - root_dir);
5277c478bd9Sstevel@tonic-gate 			}
5287c478bd9Sstevel@tonic-gate 		}
5297c478bd9Sstevel@tonic-gate 		if (tdip != NULL)
5307c478bd9Sstevel@tonic-gate 			devinfo_ptrs[d++] = tdip;
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
5347c478bd9Sstevel@tonic-gate 	/* Online all valid units */
5357c478bd9Sstevel@tonic-gate 	for (j = 0; j < d; j++) {
5367c478bd9Sstevel@tonic-gate 		if ((new_devinfo & (1 << j)) == 0) {
5377c478bd9Sstevel@tonic-gate 			linfo.bus_generation = hal->generation_count;
5387c478bd9Sstevel@tonic-gate 			linfo.local_nodeID = hal->node_id;
5397c478bd9Sstevel@tonic-gate 		}
5407c478bd9Sstevel@tonic-gate 		/* don't need to drop topology_tree_mutex across ndi calls */
5417c478bd9Sstevel@tonic-gate 		(void) ndi_devi_online_async(devinfo_ptrs[j], 0);
5427c478bd9Sstevel@tonic-gate 		if ((new_devinfo & (1 << j)) == 0) {
5437c478bd9Sstevel@tonic-gate 			/*
5447c478bd9Sstevel@tonic-gate 			 * send an insert event if this an existing devinfo.
5457c478bd9Sstevel@tonic-gate 			 * drop and reacquire topology_tree_mutex across
5467c478bd9Sstevel@tonic-gate 			 * the event calls
5477c478bd9Sstevel@tonic-gate 			 */
5487c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
5497c478bd9Sstevel@tonic-gate 			s1394_send_insert_event(hal, devinfo_ptrs[j], &linfo);
5507c478bd9Sstevel@tonic-gate 			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
5517c478bd9Sstevel@tonic-gate 				lockfail = 1;
5527c478bd9Sstevel@tonic-gate 				break;
5537c478bd9Sstevel@tonic-gate 			}
5547c478bd9Sstevel@tonic-gate 		}
5557c478bd9Sstevel@tonic-gate 	}
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate 	if (lockfail) {
5587c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5597c478bd9Sstevel@tonic-gate 	}
5607c478bd9Sstevel@tonic-gate 
5617c478bd9Sstevel@tonic-gate 	SET_CFGROM_PARSED(node);
5627c478bd9Sstevel@tonic-gate 	CLEAR_CFGROM_GEN_CHANGED(node);	/* if set */
5637c478bd9Sstevel@tonic-gate 	CLEAR_CFGROM_NEW_ALLOC(node);
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5667c478bd9Sstevel@tonic-gate }
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate /*
5697c478bd9Sstevel@tonic-gate  * s1394_offline_node()
5707c478bd9Sstevel@tonic-gate  *    Offlines a node. This involves marking all targets attached to the
5717c478bd9Sstevel@tonic-gate  *    node as gone, invoking any remove event callbacks and calling
5727c478bd9Sstevel@tonic-gate  *    ndi_devi_offline to mark the devinfo as OFFLINE (for each unit
5737c478bd9Sstevel@tonic-gate  *    directory on the node). The tree is unlocked and relocked around
5747c478bd9Sstevel@tonic-gate  *    the callbacks. If unable to relock the tree, DDI_FAILURE, else
5757c478bd9Sstevel@tonic-gate  *    returns DDI_SUCCESS.
5767c478bd9Sstevel@tonic-gate  */
5777c478bd9Sstevel@tonic-gate int
s1394_offline_node(s1394_hal_t * hal,s1394_node_t * node)5787c478bd9Sstevel@tonic-gate s1394_offline_node(s1394_hal_t *hal, s1394_node_t *node)
5797c478bd9Sstevel@tonic-gate {
5807c478bd9Sstevel@tonic-gate 	s1394_target_t *t;
5817c478bd9Sstevel@tonic-gate 	dev_info_t *tdip;
5827c478bd9Sstevel@tonic-gate 	int j, d, units;
5837c478bd9Sstevel@tonic-gate 	uint32_t *unit_dir_ptrs[32];
5847c478bd9Sstevel@tonic-gate 	dev_info_t *devinfo_ptrs[32];
5857c478bd9Sstevel@tonic-gate 	t1394_localinfo_t linfo;
5867c478bd9Sstevel@tonic-gate 	uint32_t *ptr, *root_dir, dir_len;
5877c478bd9Sstevel@tonic-gate 	uint32_t hi, lo, size_hi, size_lo, type, key, value;
5887c478bd9Sstevel@tonic-gate 	char caddr[32];
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	d = 0;
5937c478bd9Sstevel@tonic-gate 	rw_enter(&hal->target_list_rwlock, RW_WRITER);
5947c478bd9Sstevel@tonic-gate 	t = node->target_list;
5957c478bd9Sstevel@tonic-gate 	while (t != NULL) {
5967c478bd9Sstevel@tonic-gate 		t->target_state |= S1394_TARG_GONE;
5977c478bd9Sstevel@tonic-gate 		t->on_node = NULL;
5987c478bd9Sstevel@tonic-gate 		t = t->target_sibling;
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 	rw_exit(&hal->target_list_rwlock);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	/* scan through config rom looking for unit dirs */
6037c478bd9Sstevel@tonic-gate 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate 	if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
6067c478bd9Sstevel@tonic-gate 		dir_len = node->cfgrom_valid_size;
6077c478bd9Sstevel@tonic-gate 	else
6087c478bd9Sstevel@tonic-gate 		dir_len = CFGROM_DIR_LEN(root_dir);
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	for (units = 0, j = 1; j <= dir_len; j++) {
6137c478bd9Sstevel@tonic-gate 		CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
6147c478bd9Sstevel@tonic-gate 		if (key == IEEE1212_UNIT_DIRECTORY && type ==
615*2570281cSToomas Soome 				IEEE1212_DIRECTORY_TYPE) {
6167c478bd9Sstevel@tonic-gate 			ptr = &root_dir[j] + value;
6177c478bd9Sstevel@tonic-gate 			if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
6187c478bd9Sstevel@tonic-gate 				unit_dir_ptrs[units++] = ptr;
6197c478bd9Sstevel@tonic-gate 			}
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 	}
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	for (d = 0, j = 0; j < units; j++) {
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
626*2570281cSToomas Soome 				&hi, &lo, &size_hi, &size_lo);
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 		lo = j;
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 		if (hi || lo) {
6317c478bd9Sstevel@tonic-gate 			(void) sprintf(caddr, "%08x%08x,%04x%08x",
632*2570281cSToomas Soome 					node->node_guid_hi, node->node_guid_lo, hi, lo);
6337c478bd9Sstevel@tonic-gate 		} else {
6347c478bd9Sstevel@tonic-gate 			(void) sprintf(caddr, "%08x%08x",
635*2570281cSToomas Soome 					node->node_guid_hi, node->node_guid_lo);
6367c478bd9Sstevel@tonic-gate 		}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 		if ((tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr)) !=
639*2570281cSToomas Soome 				NULL)
6407c478bd9Sstevel@tonic-gate 			devinfo_ptrs[d++] = tdip;
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	node->old_node = NULL;
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	linfo.bus_generation = hal->generation_count;
6467c478bd9Sstevel@tonic-gate 	linfo.local_nodeID = hal->node_id;
6477c478bd9Sstevel@tonic-gate 
6487c478bd9Sstevel@tonic-gate 	for (j = 0; j < d; j++) {
6497c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 		s1394_send_remove_event(hal, devinfo_ptrs[j], &linfo);
6527c478bd9Sstevel@tonic-gate 		(void) ndi_devi_offline(devinfo_ptrs[j], NDI_DEVI_REMOVE);
6537c478bd9Sstevel@tonic-gate 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
6547c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
6597c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate /*
6637c478bd9Sstevel@tonic-gate  * s1394_process_topology_tree()
6647c478bd9Sstevel@tonic-gate  *    Walks the topology tree, processing each node. If node that has
6657c478bd9Sstevel@tonic-gate  *    already been parsed, updates the generation property on all devinfos
6667c478bd9Sstevel@tonic-gate  *    for the node. Also, if the node exists in both old & new trees, ASSERTS
6677c478bd9Sstevel@tonic-gate  *    that both point to the same config rom. If the node has valid config
6687c478bd9Sstevel@tonic-gate  *    rom but hasn't been parsed yet, calls s1394_update_devinfo_tree()
6697c478bd9Sstevel@tonic-gate  *    to parse and create devinfos for the node. Kicks off further config
6707c478bd9Sstevel@tonic-gate  *    rom reading if only the bus info block for the node is read.
6717c478bd9Sstevel@tonic-gate  *    Returns DDI_SUCCESS if everything went fine, else returns DDI_FAILURE
6727c478bd9Sstevel@tonic-gate  *    (for eg. unable to reacquire the tree lock etc). wait_for_cbs argument
6737c478bd9Sstevel@tonic-gate  *    tells the caller if some completions can be expected. wait_gen tells
6747c478bd9Sstevel@tonic-gate  *    the generation the commands were issued at.
6757c478bd9Sstevel@tonic-gate  */
6767c478bd9Sstevel@tonic-gate int
s1394_process_topology_tree(s1394_hal_t * hal,int * wait_for_cbs,uint_t * wait_gen)6777c478bd9Sstevel@tonic-gate s1394_process_topology_tree(s1394_hal_t *hal, int *wait_for_cbs,
6787c478bd9Sstevel@tonic-gate     uint_t *wait_gen)
6797c478bd9Sstevel@tonic-gate {
6807c478bd9Sstevel@tonic-gate 	int i;
6817c478bd9Sstevel@tonic-gate 	uint_t hal_node_num, number_of_nodes;
6827c478bd9Sstevel@tonic-gate 	s1394_node_t *node, *onode;
6837c478bd9Sstevel@tonic-gate 	s1394_status_t status;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
6887c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
6927c478bd9Sstevel@tonic-gate 	hal->cfgroms_being_read = 0;
6937c478bd9Sstevel@tonic-gate 	number_of_nodes = hal->number_of_nodes;
6947c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	for (i = 0; i < number_of_nodes; i++) {
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 		if (i == hal_node_num)
6997c478bd9Sstevel@tonic-gate 			continue;
7007c478bd9Sstevel@tonic-gate 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
7017c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7027c478bd9Sstevel@tonic-gate 		}
7037c478bd9Sstevel@tonic-gate 		node = &hal->topology_tree[i];
7047c478bd9Sstevel@tonic-gate 
7057c478bd9Sstevel@tonic-gate 		if (LINK_ACTIVE(node) == B_FALSE) {
7067c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
7077c478bd9Sstevel@tonic-gate 			continue;
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 		if (node->cfgrom == NULL) {
7107c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
7117c478bd9Sstevel@tonic-gate 			continue;
7127c478bd9Sstevel@tonic-gate 		}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 		onode = node->old_node;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		if (onode != NULL && onode->cfgrom != NULL && node->cfgrom !=
7177c478bd9Sstevel@tonic-gate 		    NULL) {
7187c478bd9Sstevel@tonic-gate 			/*
7197c478bd9Sstevel@tonic-gate 			 * onode->cfgrom != node->cfgrom should have been
7207c478bd9Sstevel@tonic-gate 			 * handled by s1394_match_GUID()!!!
7217c478bd9Sstevel@tonic-gate 			 */
7227c478bd9Sstevel@tonic-gate 			ASSERT(onode->cfgrom == node->cfgrom);
7237c478bd9Sstevel@tonic-gate 		}
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 		if (CFGROM_PARSED(node) == B_FALSE && CFGROM_ALL_READ(node) ==
7267c478bd9Sstevel@tonic-gate 		    B_TRUE) {
7277c478bd9Sstevel@tonic-gate 			ASSERT((node->cfgrom_size <
7287c478bd9Sstevel@tonic-gate 			    IEEE1394_CONFIG_ROM_QUAD_SZ) ||
7297c478bd9Sstevel@tonic-gate 			    NODE_MATCHED(node) == B_TRUE);
7307c478bd9Sstevel@tonic-gate 			rw_enter(&hal->target_list_rwlock, RW_READER);
7317c478bd9Sstevel@tonic-gate 			ASSERT(node->target_list == NULL);
7327c478bd9Sstevel@tonic-gate 			rw_exit(&hal->target_list_rwlock);
7337c478bd9Sstevel@tonic-gate 			if (s1394_update_devinfo_tree(hal, node) ==
7347c478bd9Sstevel@tonic-gate 			    DDI_FAILURE) {
7357c478bd9Sstevel@tonic-gate 				ASSERT(MUTEX_NOT_HELD(
7367c478bd9Sstevel@tonic-gate 				    &hal->topology_tree_mutex));
7377c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
7387c478bd9Sstevel@tonic-gate 			}
7397c478bd9Sstevel@tonic-gate 		} else if (CFGROM_PARSED(node) == B_FALSE && CFGROM_BIB_READ(
7407c478bd9Sstevel@tonic-gate 		    node) == B_TRUE) {
7417c478bd9Sstevel@tonic-gate 			if (s1394_read_rest_of_cfgrom(hal, node, &status) !=
7427c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
7437c478bd9Sstevel@tonic-gate 				if ((status & S1394_LOCK_FAILED) == 0) {
7447c478bd9Sstevel@tonic-gate 					ASSERT(MUTEX_HELD(&hal->
7457c478bd9Sstevel@tonic-gate 					    topology_tree_mutex));
7467c478bd9Sstevel@tonic-gate 					*wait_for_cbs = 0;
7477c478bd9Sstevel@tonic-gate 					s1394_unlock_tree(hal);
7487c478bd9Sstevel@tonic-gate 				}
7497c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
7507c478bd9Sstevel@tonic-gate 			} else {
7517c478bd9Sstevel@tonic-gate 				*wait_for_cbs = 1;
7527c478bd9Sstevel@tonic-gate 				*wait_gen = hal->br_cfgrom_read_gen;
7537c478bd9Sstevel@tonic-gate 			}
7547c478bd9Sstevel@tonic-gate 		}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	/*
7607c478bd9Sstevel@tonic-gate 	 * flag the tree as processed; if a single bus reset happens after
7617c478bd9Sstevel@tonic-gate 	 * this, we will use tree matching.
7627c478bd9Sstevel@tonic-gate 	 */
7637c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
7647c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7657c478bd9Sstevel@tonic-gate 	}
7667c478bd9Sstevel@tonic-gate 	hal->topology_tree_processed = B_TRUE;
7677c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7707c478bd9Sstevel@tonic-gate }
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate /*
7737c478bd9Sstevel@tonic-gate  * s1394_process_old_tree()
7747c478bd9Sstevel@tonic-gate  *    Walks through the old tree and offlines nodes that are removed. Nodes
7757c478bd9Sstevel@tonic-gate  *    with an active link in the old tree but link powered off in the current
7767c478bd9Sstevel@tonic-gate  *    generation are also offlined, as well as nodes with invalid config
7777c478bd9Sstevel@tonic-gate  *    rom in current generation.
7787c478bd9Sstevel@tonic-gate  *    The topology tree is locked/unlocked while walking through all the nodes;
7797c478bd9Sstevel@tonic-gate  *    if the locking fails at any stage, stops further walking and returns
7807c478bd9Sstevel@tonic-gate  *    DDI_FAILURE. Returns DDI_SUCCESS if everything went fine.
7817c478bd9Sstevel@tonic-gate  */
7827c478bd9Sstevel@tonic-gate int
s1394_process_old_tree(s1394_hal_t * hal)7837c478bd9Sstevel@tonic-gate s1394_process_old_tree(s1394_hal_t *hal)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate 	int i;
7867c478bd9Sstevel@tonic-gate 	uint_t hal_node_num_old, old_number_of_nodes;
7877c478bd9Sstevel@tonic-gate 	s1394_node_t *onode;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	/*
7907c478bd9Sstevel@tonic-gate 	 * NODE_MATCHED(onode) == 0 indicates this node doesn't exist
7917c478bd9Sstevel@tonic-gate 	 * any more.
7927c478bd9Sstevel@tonic-gate 	 */
7937c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
7967c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7977c478bd9Sstevel@tonic-gate 	}
7987c478bd9Sstevel@tonic-gate 	hal_node_num_old = IEEE1394_NODE_NUM(hal->old_node_id);
7997c478bd9Sstevel@tonic-gate 	old_number_of_nodes = hal->old_number_of_nodes;
8007c478bd9Sstevel@tonic-gate 	s1394_unlock_tree(hal);
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	for (i = 0; i < old_number_of_nodes; i++) {
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 		if (i == hal_node_num_old)
8057c478bd9Sstevel@tonic-gate 			continue;
8067c478bd9Sstevel@tonic-gate 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
8077c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
8087c478bd9Sstevel@tonic-gate 		}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 		onode = &hal->old_tree[i];
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 		if (onode->cfgrom == NULL) {
8137c478bd9Sstevel@tonic-gate 			CLEAR_CFGROM_STATE(onode);
8147c478bd9Sstevel@tonic-gate 			s1394_unlock_tree(hal);
8157c478bd9Sstevel@tonic-gate 			continue;
8167c478bd9Sstevel@tonic-gate 		}
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		/*
8197c478bd9Sstevel@tonic-gate 		 * onode->cur_node == NULL iff we couldn't read cfgrom in the
8207c478bd9Sstevel@tonic-gate 		 * current generation in non-tree matching case (and thus
8217c478bd9Sstevel@tonic-gate 		 * match_GUIDs couldn't set cur_node).
8227c478bd9Sstevel@tonic-gate 		 */
8237c478bd9Sstevel@tonic-gate 		if (NODE_MATCHED(onode) == B_FALSE || (onode->cur_node ==
8247c478bd9Sstevel@tonic-gate 		    NULL || ((CFGROM_VALID(onode) == B_TRUE &&
8257c478bd9Sstevel@tonic-gate 		    CFGROM_VALID(onode->cur_node) == B_FALSE) ||
8267c478bd9Sstevel@tonic-gate 		    (LINK_ACTIVE(onode) == B_TRUE && LINK_ACTIVE(onode->
8277c478bd9Sstevel@tonic-gate 		    cur_node) == B_FALSE)))) {
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate 			if (s1394_offline_node(hal, onode) != DDI_SUCCESS) {
8307c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
8317c478bd9Sstevel@tonic-gate 			}
8327c478bd9Sstevel@tonic-gate 			s1394_free_cfgrom(hal, onode, S1394_FREE_CFGROM_OLD);
8337c478bd9Sstevel@tonic-gate 		}
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 		s1394_unlock_tree(hal);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate 
8437c478bd9Sstevel@tonic-gate /*
8447c478bd9Sstevel@tonic-gate  * s1394_update_unit_dir_location()
8457c478bd9Sstevel@tonic-gate  *    Updates the unit-dir-offset property on the devinfo.
8467c478bd9Sstevel@tonic-gate  *    NOTE: ndi_prop_update_int() is interrupt callable (and thus won't block);
8477c478bd9Sstevel@tonic-gate  *    so, the caller doesn't drop topology_tree_mutex when calling this routine.
8487c478bd9Sstevel@tonic-gate  */
8497c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8507c478bd9Sstevel@tonic-gate static void
s1394_update_unit_dir_location(s1394_hal_t * hal,dev_info_t * tdip,uint_t offset)8517c478bd9Sstevel@tonic-gate s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
8527c478bd9Sstevel@tonic-gate     uint_t offset)
8537c478bd9Sstevel@tonic-gate {
8547c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
8557c478bd9Sstevel@tonic-gate 	ASSERT(tdip != NULL);
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, tdip, "unit-dir-offset",
8587c478bd9Sstevel@tonic-gate 	    offset);
8597c478bd9Sstevel@tonic-gate }
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate /*
8627c478bd9Sstevel@tonic-gate  * s1394_add_target_to_node()
8637c478bd9Sstevel@tonic-gate  *    adds target to the list of targets hanging off the node. Figures out
8647c478bd9Sstevel@tonic-gate  *    the node by searching the topology tree for the GUID corresponding
8657c478bd9Sstevel@tonic-gate  *    to the target. Points on_node field of target structure at the node.
8667c478bd9Sstevel@tonic-gate  */
8677c478bd9Sstevel@tonic-gate void
s1394_add_target_to_node(s1394_target_t * target)8687c478bd9Sstevel@tonic-gate s1394_add_target_to_node(s1394_target_t *target)
8697c478bd9Sstevel@tonic-gate {
8707c478bd9Sstevel@tonic-gate 	s1394_target_t *t;
8717c478bd9Sstevel@tonic-gate 	s1394_hal_t *hal;
8727c478bd9Sstevel@tonic-gate 	uint32_t guid_hi;
8737c478bd9Sstevel@tonic-gate 	uint32_t guid_lo;
8747c478bd9Sstevel@tonic-gate 	int i;
8757c478bd9Sstevel@tonic-gate 	char name[MAXNAMELEN];
8767c478bd9Sstevel@tonic-gate 	char *ptr;
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
8797c478bd9Sstevel@tonic-gate 	ASSERT(hal != NULL);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	/* Topology tree must be locked when it gets here! */
8827c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	/* target_list_rwlock should be held in write mode */
8857c478bd9Sstevel@tonic-gate 	ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	if ((ptr = ddi_get_name_addr(target->target_dip)) == NULL) {
8887c478bd9Sstevel@tonic-gate 		return;
8897c478bd9Sstevel@tonic-gate 	}
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	(void) sprintf(name, ptr);
8927c478bd9Sstevel@tonic-gate 	/* Drop the ,<ADDR> part, if present */
8937c478bd9Sstevel@tonic-gate 	if ((ptr = strchr(name, ',')) != NULL)
8947c478bd9Sstevel@tonic-gate 		*ptr = '\0';
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	ptr = name;
8977c478bd9Sstevel@tonic-gate 	guid_hi = s1394_stoi(ptr, 8, 16);
8987c478bd9Sstevel@tonic-gate 	guid_lo = s1394_stoi(ptr + 8, 8, 16);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	/* Search the HAL's node list for this GUID */
9017c478bd9Sstevel@tonic-gate 	for (i = 0; i < hal->number_of_nodes; i++) {
9027c478bd9Sstevel@tonic-gate 		if (CFGROM_VALID(&hal->topology_tree[i]) == B_TRUE) {
9037c478bd9Sstevel@tonic-gate 			ASSERT(hal->topology_tree[i].cfgrom != NULL);
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 			if ((hal->topology_tree[i].node_guid_hi == guid_hi) &&
9067c478bd9Sstevel@tonic-gate 			    (hal->topology_tree[i].node_guid_lo == guid_lo)) {
9077c478bd9Sstevel@tonic-gate 				target->on_node = &hal->topology_tree[i];
9087c478bd9Sstevel@tonic-gate 				if ((t = hal->topology_tree[i].target_list) !=
9097c478bd9Sstevel@tonic-gate 				    NULL) {
9107c478bd9Sstevel@tonic-gate 					ASSERT(t != target);
9117c478bd9Sstevel@tonic-gate 					while (t->target_sibling != NULL) {
9127c478bd9Sstevel@tonic-gate 						t = t->target_sibling;
9137c478bd9Sstevel@tonic-gate 						ASSERT(t != target);
9147c478bd9Sstevel@tonic-gate 					}
9157c478bd9Sstevel@tonic-gate 					t->target_sibling = target;
9167c478bd9Sstevel@tonic-gate 				} else {
9177c478bd9Sstevel@tonic-gate 					hal->topology_tree[i].target_list =
9187c478bd9Sstevel@tonic-gate 					    target;
9197c478bd9Sstevel@tonic-gate 				}
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 				/*
9227c478bd9Sstevel@tonic-gate 				 * update target_list in all targets on the
9237c478bd9Sstevel@tonic-gate 				 * node
9247c478bd9Sstevel@tonic-gate 				 */
9257c478bd9Sstevel@tonic-gate 				t = hal->topology_tree[i].target_list;
9267c478bd9Sstevel@tonic-gate 				while (t != NULL) {
9277c478bd9Sstevel@tonic-gate 					t->target_list =
9287c478bd9Sstevel@tonic-gate 					    hal->topology_tree[i].target_list;
9297c478bd9Sstevel@tonic-gate 					t = t->target_sibling;
9307c478bd9Sstevel@tonic-gate 				}
9317c478bd9Sstevel@tonic-gate 				break;
9327c478bd9Sstevel@tonic-gate 			}
9337c478bd9Sstevel@tonic-gate 		}
9347c478bd9Sstevel@tonic-gate 	}
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate /*
9387c478bd9Sstevel@tonic-gate  * s1394_remove_target_from_node()
9397c478bd9Sstevel@tonic-gate  *    Removes target from the corresponding node's target_list.
9407c478bd9Sstevel@tonic-gate  */
9417c478bd9Sstevel@tonic-gate void
s1394_remove_target_from_node(s1394_target_t * target)9427c478bd9Sstevel@tonic-gate s1394_remove_target_from_node(s1394_target_t *target)
9437c478bd9Sstevel@tonic-gate {
9447c478bd9Sstevel@tonic-gate 	s1394_target_t *t, *t1;
9457c478bd9Sstevel@tonic-gate 	s1394_hal_t *hal;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	hal = target->on_hal;
9487c478bd9Sstevel@tonic-gate 	ASSERT(hal != NULL);
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	/* Topology tree must be locked when it gets here! */
9517c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	/* target_list_rwlock should be held in write mode */
9547c478bd9Sstevel@tonic-gate 	ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	t = target->target_list;
9577c478bd9Sstevel@tonic-gate 	t1 = NULL;
9587c478bd9Sstevel@tonic-gate 	while (t != NULL) {
9597c478bd9Sstevel@tonic-gate 		if (t == target) {
9607c478bd9Sstevel@tonic-gate 			if (t1 == NULL) {
9617c478bd9Sstevel@tonic-gate 				target->target_list = t->target_sibling;
9627c478bd9Sstevel@tonic-gate 			} else {
9637c478bd9Sstevel@tonic-gate 				t1->target_sibling = t->target_sibling;
9647c478bd9Sstevel@tonic-gate 			}
9657c478bd9Sstevel@tonic-gate 			break;
9667c478bd9Sstevel@tonic-gate 		}
9677c478bd9Sstevel@tonic-gate 		t1 = t;
9687c478bd9Sstevel@tonic-gate 		t = t->target_sibling;
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 	/* Update the target_list pointer in all the targets */
9717c478bd9Sstevel@tonic-gate 	if (target->on_node != NULL)
9727c478bd9Sstevel@tonic-gate 		target->on_node->target_list = target->target_list;
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	t = t1 = target->target_list;
9757c478bd9Sstevel@tonic-gate 	while (t != NULL) {
9767c478bd9Sstevel@tonic-gate 		t->target_list = t1;
9777c478bd9Sstevel@tonic-gate 		t = t->target_sibling;
9787c478bd9Sstevel@tonic-gate 	}
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 	target->on_node = NULL;
9817c478bd9Sstevel@tonic-gate 	target->target_sibling = NULL;
9827c478bd9Sstevel@tonic-gate }
983