10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
23*789Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * s1394_hotplug.c
310Sstevel@tonic-gate * 1394 Services Layer Hotplug Routines
320Sstevel@tonic-gate * This file contains routines that walk the old and topology
330Sstevel@tonic-gate * trees, at bus reset time, creating devinfo's for new nodes and offlining
340Sstevel@tonic-gate * nodes that are removed.
350Sstevel@tonic-gate */
360Sstevel@tonic-gate
370Sstevel@tonic-gate #include <sys/conf.h>
380Sstevel@tonic-gate #include <sys/sysmacros.h>
390Sstevel@tonic-gate #include <sys/ddi.h>
400Sstevel@tonic-gate #include <sys/sunddi.h>
410Sstevel@tonic-gate #include <sys/sunndi.h>
420Sstevel@tonic-gate #include <sys/modctl.h>
430Sstevel@tonic-gate #include <sys/sunddi.h>
440Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
450Sstevel@tonic-gate #include <sys/types.h>
460Sstevel@tonic-gate
470Sstevel@tonic-gate #include <sys/tnf_probe.h>
480Sstevel@tonic-gate
490Sstevel@tonic-gate #include <sys/1394/t1394.h>
500Sstevel@tonic-gate #include <sys/1394/s1394.h>
510Sstevel@tonic-gate #include <sys/1394/h1394.h>
520Sstevel@tonic-gate #include <sys/1394/ieee1394.h>
530Sstevel@tonic-gate
540Sstevel@tonic-gate static void s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
550Sstevel@tonic-gate t1394_localinfo_t *localinfo);
560Sstevel@tonic-gate static void s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
570Sstevel@tonic-gate t1394_localinfo_t *localinfo);
580Sstevel@tonic-gate static dev_info_t *s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node,
590Sstevel@tonic-gate uint32_t *unit_dir, int nunit);
600Sstevel@tonic-gate static void s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
610Sstevel@tonic-gate uint_t offset);
620Sstevel@tonic-gate
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate * s1394_send_remove_event()
650Sstevel@tonic-gate * Invokes any "remove event" callback registered for dip. Passes
660Sstevel@tonic-gate * t1394_localinfo_t as impl_data for the callback.
670Sstevel@tonic-gate */
680Sstevel@tonic-gate static void
s1394_send_remove_event(s1394_hal_t * hal,dev_info_t * dip,t1394_localinfo_t * localinfo)690Sstevel@tonic-gate s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
700Sstevel@tonic-gate t1394_localinfo_t *localinfo)
710Sstevel@tonic-gate {
720Sstevel@tonic-gate char name[128];
730Sstevel@tonic-gate ddi_eventcookie_t cookie;
740Sstevel@tonic-gate
750Sstevel@tonic-gate (void) sprintf(name, "%s%d", ddi_driver_name(dip),
760Sstevel@tonic-gate ddi_get_instance(dip));
770Sstevel@tonic-gate
780Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_send_remove_event_enter,
790Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, device,
800Sstevel@tonic-gate name);
810Sstevel@tonic-gate
820Sstevel@tonic-gate if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
830Sstevel@tonic-gate DDI_DEVI_REMOVE_EVENT, &cookie, NDI_EVENT_NOPASS)
840Sstevel@tonic-gate == NDI_SUCCESS) {
850Sstevel@tonic-gate (void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
860Sstevel@tonic-gate cookie, localinfo);
870Sstevel@tonic-gate }
880Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_send_remove_event_exit,
890Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
900Sstevel@tonic-gate }
910Sstevel@tonic-gate
920Sstevel@tonic-gate /*
930Sstevel@tonic-gate * s1394_send_insert_event()
940Sstevel@tonic-gate * Invokes any "insert event" callback registered for dip. Passes
950Sstevel@tonic-gate * t1394_localinfo_t as impl_data for the callback.
960Sstevel@tonic-gate */
970Sstevel@tonic-gate static void
s1394_send_insert_event(s1394_hal_t * hal,dev_info_t * dip,t1394_localinfo_t * localinfo)980Sstevel@tonic-gate s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
990Sstevel@tonic-gate t1394_localinfo_t *localinfo)
1000Sstevel@tonic-gate {
1010Sstevel@tonic-gate char name[128];
1020Sstevel@tonic-gate ddi_eventcookie_t cookie;
1030Sstevel@tonic-gate
1040Sstevel@tonic-gate (void) sprintf(name, "%s%d", ddi_driver_name(dip),
1050Sstevel@tonic-gate ddi_get_instance(dip));
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_send_insert_event_enter,
1080Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, device,
1090Sstevel@tonic-gate name);
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
1120Sstevel@tonic-gate DDI_DEVI_INSERT_EVENT, &cookie, NDI_EVENT_NOPASS) ==
1130Sstevel@tonic-gate NDI_SUCCESS)
1140Sstevel@tonic-gate (void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
1150Sstevel@tonic-gate cookie, localinfo);
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_send_insert_event_exit,
1180Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate * s1394_create_devinfo()
1230Sstevel@tonic-gate * This routine creates a devinfo corresponding to the unit_dir passed in.
1240Sstevel@tonic-gate * It adds "hp-node", "reg", "compatible" properties to the devinfo
1250Sstevel@tonic-gate * (formats for "reg" and "compatible" properties are specified by 1275
1260Sstevel@tonic-gate * binding for IEEE1394). If unable to create the devinfo and/or add the
1270Sstevel@tonic-gate * the properties, returns NULL, otherwise, returns the devinfo created.
1280Sstevel@tonic-gate *
1290Sstevel@tonic-gate * NOTE: All ndi_* routines are interrupt callable (and thus won't sleep).
1300Sstevel@tonic-gate * So, we don't drop topology_mutex across ndi calls.
1310Sstevel@tonic-gate */
1320Sstevel@tonic-gate static dev_info_t *
s1394_create_devinfo(s1394_hal_t * hal,s1394_node_t * node,uint32_t * unit_dir,int nunit)1330Sstevel@tonic-gate s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node, uint32_t *unit_dir,
1340Sstevel@tonic-gate int nunit)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate dev_info_t *hal_dip;
1370Sstevel@tonic-gate uint32_t *root_dir;
1380Sstevel@tonic-gate dev_info_t *target_dip;
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate int root_dir_len;
1410Sstevel@tonic-gate int result, i, j, spec_id, sw_version;
1420Sstevel@tonic-gate int mod_ven, mod_hw, mod_spec, mod_sw;
1430Sstevel@tonic-gate int node_ven, node_hw, node_spec, node_sw;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate /*LINTED type is unused*/
1460Sstevel@tonic-gate uint32_t type, key, value;
1470Sstevel@tonic-gate uint32_t unit_spec_id, unit_sw_version;
1480Sstevel@tonic-gate uint32_t node_spec_id, node_sw_version;
1490Sstevel@tonic-gate uint32_t node_vendor_id, node_hw_version;
1500Sstevel@tonic-gate uint32_t module_spec_id, module_sw_version;
1510Sstevel@tonic-gate uint32_t module_vendor_id, module_hw_version;
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate char *fmt = "firewire%06x,%06x";
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate char *buf[5], data[5][24];
1560Sstevel@tonic-gate uint32_t reg[6];
1570Sstevel@tonic-gate
1580Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate TNF_PROBE_2_DEBUG(s1394_create_devinfo_enter,
1610Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, guid_hi,
1620Sstevel@tonic-gate node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo);
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate hal_dip = hal->halinfo.dip;
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate /* Allocate and init a new device node instance. */
167*789Sahrens result = ndi_devi_alloc(hal_dip, "unit", (pnode_t)DEVI_SID_NODEID,
1680Sstevel@tonic-gate &target_dip);
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate if (result != NDI_SUCCESS) {
1710Sstevel@tonic-gate cmn_err(CE_NOTE, "!Unable to create devinfo"
1720Sstevel@tonic-gate " (node's GUID %08x%08x)", node->node_guid_hi,
1730Sstevel@tonic-gate node->node_guid_lo);
1740Sstevel@tonic-gate TNF_PROBE_2(s1394_create_devinfo_fail_alloc,
1750Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
1760Sstevel@tonic-gate node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo);
1770Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
1780Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
1790Sstevel@tonic-gate return (NULL);
1800Sstevel@tonic-gate }
1810Sstevel@tonic-gate
1820Sstevel@tonic-gate /* Add "hp-node" property */
1830Sstevel@tonic-gate result = ndi_prop_update_int(DDI_DEV_T_NONE, target_dip, "hp-node", 0);
1840Sstevel@tonic-gate if (result != NDI_SUCCESS) {
1850Sstevel@tonic-gate cmn_err(CE_NOTE, "!Unable to add \"hp-node\" property"
1860Sstevel@tonic-gate " (node's GUID %08x%08x)", node->node_guid_hi,
1870Sstevel@tonic-gate node->node_guid_lo);
1880Sstevel@tonic-gate #if defined(DEBUG)
1890Sstevel@tonic-gate cmn_err(CE_CONT, "!Error code %d", result);
1900Sstevel@tonic-gate #endif
1910Sstevel@tonic-gate TNF_PROBE_3(s1394_create_devinfo_hp_node,
1920Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
1930Sstevel@tonic-gate node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
1940Sstevel@tonic-gate tnf_int, error, result);
1950Sstevel@tonic-gate ndi_prop_remove_all(target_dip);
1960Sstevel@tonic-gate (void) ndi_devi_free(target_dip);
1970Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
1980Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
1990Sstevel@tonic-gate return (NULL);
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate spec_id = sw_version = mod_ven = mod_hw = mod_spec = mod_sw =
2030Sstevel@tonic-gate node_ven = node_hw = node_spec = node_sw = 0;
2040Sstevel@tonic-gate unit_sw_version = node_sw_version = node_hw_version =
2050Sstevel@tonic-gate module_sw_version = module_hw_version = 0;
2060Sstevel@tonic-gate
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate root_dir = CFGROM_ROOT_DIR(node->cfgrom);
2090Sstevel@tonic-gate root_dir_len = CFGROM_DIR_LEN(root_dir);
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate for (i = 0; i < root_dir_len; i++) {
2120Sstevel@tonic-gate
2130Sstevel@tonic-gate CFGROM_TYPE_KEY_VALUE(root_dir[i + 1], type, key, value);
2140Sstevel@tonic-gate switch (key) {
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate case IEEE1212_MODULE_VENDOR_ID:
2170Sstevel@tonic-gate module_vendor_id = value;
2180Sstevel@tonic-gate mod_ven++;
2190Sstevel@tonic-gate break;
2200Sstevel@tonic-gate case IEEE1212_MODULE_HW_VERSION:
2210Sstevel@tonic-gate module_hw_version = value;
2220Sstevel@tonic-gate mod_hw++;
2230Sstevel@tonic-gate break;
2240Sstevel@tonic-gate case IEEE1212_MODULE_SPEC_ID:
2250Sstevel@tonic-gate module_spec_id = value;
2260Sstevel@tonic-gate mod_spec++;
2270Sstevel@tonic-gate break;
2280Sstevel@tonic-gate case IEEE1212_MODULE_SW_VERSION:
2290Sstevel@tonic-gate module_sw_version = value;
2300Sstevel@tonic-gate mod_sw++;
2310Sstevel@tonic-gate break;
2320Sstevel@tonic-gate case IEEE1212_NODE_VENDOR_ID:
2330Sstevel@tonic-gate node_vendor_id = value;
2340Sstevel@tonic-gate node_ven++;
2350Sstevel@tonic-gate break;
2360Sstevel@tonic-gate case IEEE1212_NODE_UNIQUE_ID: {
2370Sstevel@tonic-gate uint32_t *node_unique_leaf =
2380Sstevel@tonic-gate &root_dir[i + 1] + value;
2390Sstevel@tonic-gate node_vendor_id = (node_unique_leaf[1] >> 8);
2400Sstevel@tonic-gate node_ven++;
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate break;
2430Sstevel@tonic-gate case IEEE1212_NODE_HW_VERSION:
2440Sstevel@tonic-gate node_hw_version = value;
2450Sstevel@tonic-gate node_hw++;
2460Sstevel@tonic-gate break;
2470Sstevel@tonic-gate case IEEE1212_NODE_SPEC_ID:
2480Sstevel@tonic-gate node_spec_id = value;
2490Sstevel@tonic-gate node_spec++;
2500Sstevel@tonic-gate break;
2510Sstevel@tonic-gate case IEEE1212_NODE_SW_VERSION:
2520Sstevel@tonic-gate node_sw_version = value;
2530Sstevel@tonic-gate node_sw++;
2540Sstevel@tonic-gate break;
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate
2570Sstevel@tonic-gate if (mod_ven && mod_hw && mod_spec && mod_sw && node_ven &&
2580Sstevel@tonic-gate node_hw && node_spec && node_sw) {
2590Sstevel@tonic-gate break;
2600Sstevel@tonic-gate }
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate * Search for unit spec and version
2650Sstevel@tonic-gate */
2660Sstevel@tonic-gate for (i = 0; i < CFGROM_DIR_LEN(unit_dir); i++) {
2670Sstevel@tonic-gate
2680Sstevel@tonic-gate CFGROM_TYPE_KEY_VALUE(unit_dir[i + 1], type, key, value);
2690Sstevel@tonic-gate if (key == IEEE1212_UNIT_SPEC_ID) {
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate unit_spec_id = value;
2720Sstevel@tonic-gate spec_id++;
2730Sstevel@tonic-gate } else if (key == IEEE1212_UNIT_SW_VERSION) {
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate unit_sw_version = value;
2760Sstevel@tonic-gate sw_version++;
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate if (spec_id && sw_version)
2790Sstevel@tonic-gate break;
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate /*
2830Sstevel@tonic-gate * Refer to IEEE1212 (pages 90-92) for information regarding various
2840Sstevel@tonic-gate * id's. Module_Vendor_Id is required. Node_Vendor_Id is optional and
2850Sstevel@tonic-gate * if not implemented, its assumed value is Module_Vendor_Id.
2860Sstevel@tonic-gate * Module_Spec_Id is optional and if not implemented, its assumed value
2870Sstevel@tonic-gate * is Module_Vendor_Id. Node_Spec_Id is optional, and if not
2880Sstevel@tonic-gate * implemented, its assumed value is Node_Vendor_Id. Unit_Spec_Id is
2890Sstevel@tonic-gate * optional, and if not implemented, its assumed value is
2900Sstevel@tonic-gate * Node_Vendor_Id.
2910Sstevel@tonic-gate */
2920Sstevel@tonic-gate if (node_ven == 0) {
2930Sstevel@tonic-gate node_vendor_id = module_vendor_id;
2940Sstevel@tonic-gate node_ven++;
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate
2970Sstevel@tonic-gate if (node_spec == 0) {
2980Sstevel@tonic-gate node_spec_id = node_vendor_id;
2990Sstevel@tonic-gate node_spec++;
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate
3020Sstevel@tonic-gate if (mod_spec == 0) {
3030Sstevel@tonic-gate module_spec_id = module_vendor_id;
3040Sstevel@tonic-gate mod_spec++;
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate if (spec_id == 0) {
3080Sstevel@tonic-gate unit_spec_id = node_vendor_id;
3090Sstevel@tonic-gate spec_id++;
3100Sstevel@tonic-gate }
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate i = 0;
3130Sstevel@tonic-gate if (sw_version != 0) {
3140Sstevel@tonic-gate buf[i] = data[i];
3150Sstevel@tonic-gate (void) sprintf(data[i++], fmt, unit_spec_id, unit_sw_version);
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate if (node_sw != 0) {
3180Sstevel@tonic-gate buf[i] = data[i];
3190Sstevel@tonic-gate (void) sprintf(data[i++], fmt, node_spec_id, node_sw_version);
3200Sstevel@tonic-gate }
3210Sstevel@tonic-gate if (node_hw != 0) {
3220Sstevel@tonic-gate buf[i] = data[i];
3230Sstevel@tonic-gate (void) sprintf(data[i++], fmt, node_vendor_id, node_hw_version);
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate if (mod_sw != 0) {
3260Sstevel@tonic-gate buf[i] = data[i];
3270Sstevel@tonic-gate (void) sprintf(data[i++], fmt, module_spec_id,
3280Sstevel@tonic-gate module_sw_version);
3290Sstevel@tonic-gate }
3300Sstevel@tonic-gate if (mod_hw != 0) {
3310Sstevel@tonic-gate buf[i] = data[i];
3320Sstevel@tonic-gate (void) sprintf(data[i++], fmt, module_vendor_id,
3330Sstevel@tonic-gate module_hw_version);
3340Sstevel@tonic-gate }
3350Sstevel@tonic-gate
3360Sstevel@tonic-gate result = ndi_prop_update_string_array(DDI_DEV_T_NONE, target_dip,
3370Sstevel@tonic-gate "compatible", (char **)&buf, i);
3380Sstevel@tonic-gate if (result != NDI_SUCCESS) {
3390Sstevel@tonic-gate cmn_err(CE_NOTE, "!Unable to add \"compatible\" property"
3400Sstevel@tonic-gate " (node's GUID %08x%08x)", node->node_guid_hi,
3410Sstevel@tonic-gate node->node_guid_lo);
3420Sstevel@tonic-gate #if defined(DEBUG)
3430Sstevel@tonic-gate cmn_err(CE_CONT, "!Error code %d; nelements %d", result, i);
3440Sstevel@tonic-gate for (j = 0; j < i; j++) {
3450Sstevel@tonic-gate cmn_err(CE_CONT, "!buf[%d]: %s", j, buf[j]);
3460Sstevel@tonic-gate }
3470Sstevel@tonic-gate #endif
3480Sstevel@tonic-gate ndi_prop_remove_all(target_dip);
3490Sstevel@tonic-gate (void) ndi_devi_free(target_dip);
3500Sstevel@tonic-gate TNF_PROBE_4(s1394_create_devinfo_fail_compat,
3510Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
3520Sstevel@tonic-gate node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
3530Sstevel@tonic-gate tnf_int, error, result, tnf_int, nelements, i);
3540Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
3550Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
3560Sstevel@tonic-gate return (NULL);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate for (j = 0; j < i; j++) {
3600Sstevel@tonic-gate TNF_PROBE_2_DEBUG(s1394_create_devinfo_props,
3610Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "",
3620Sstevel@tonic-gate tnf_int, compat_index, j,
3630Sstevel@tonic-gate tnf_string, compat_prop, buf[j]);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate /* GUID,ADDR */
3670Sstevel@tonic-gate reg[0] = node->node_guid_hi;
3680Sstevel@tonic-gate reg[1] = node->node_guid_lo;
3690Sstevel@tonic-gate s1394_cfgrom_parse_unit_dir(unit_dir, ®[2], ®[3], ®[4],
3700Sstevel@tonic-gate ®[5]);
3710Sstevel@tonic-gate
3720Sstevel@tonic-gate reg[3] = nunit;
3730Sstevel@tonic-gate
3740Sstevel@tonic-gate result = ndi_prop_update_int_array(DDI_DEV_T_NONE, target_dip, "reg",
3750Sstevel@tonic-gate (int *)reg, 6);
3760Sstevel@tonic-gate if (result != NDI_SUCCESS) {
3770Sstevel@tonic-gate cmn_err(CE_NOTE, "!Unable to add \"reg\" property");
3780Sstevel@tonic-gate #if defined(DEBUG)
3790Sstevel@tonic-gate cmn_err(CE_CONT, "!Error code %d", result);
3800Sstevel@tonic-gate for (j = 0; j < 6; j++) {
3810Sstevel@tonic-gate cmn_err(CE_CONT, "!reg[%d]: 0x%08x", j, reg[j]);
3820Sstevel@tonic-gate }
3830Sstevel@tonic-gate #endif
3840Sstevel@tonic-gate ndi_prop_remove_all(target_dip);
3850Sstevel@tonic-gate (void) ndi_devi_free(target_dip);
3860Sstevel@tonic-gate TNF_PROBE_3(s1394_create_devinfo_fail_reg,
3870Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
3880Sstevel@tonic-gate node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
3890Sstevel@tonic-gate tnf_int, error, result);
3900Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
3910Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
3920Sstevel@tonic-gate return (NULL);
3930Sstevel@tonic-gate }
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_create_devinfo_exit,
3960Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "",
3970Sstevel@tonic-gate tnf_opaque, target_dip, target_dip);
3980Sstevel@tonic-gate
3990Sstevel@tonic-gate return (target_dip);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate
4020Sstevel@tonic-gate /*
4030Sstevel@tonic-gate * s1394_devi_find()
4040Sstevel@tonic-gate * Searches all children of pdip for a match of name@caddr. Builds the
4050Sstevel@tonic-gate * name and address of each child node by looking up the reg property on
4060Sstevel@tonic-gate * the node and compares the built name@addr with the name@addr passed in.
4070Sstevel@tonic-gate * Returns the child dip if a match is found, otherwise, returns NULL.
4080Sstevel@tonic-gate * NOTE:
4090Sstevel@tonic-gate * This routine is decidedly non-ddi. We had to use this one since
4100Sstevel@tonic-gate * ndi_devi_find() can find only nodes that have valid addr field
4110Sstevel@tonic-gate * set and that won't happen unless the node goes through INITCHILD
4120Sstevel@tonic-gate * (at which time nx1394.c calls ddi_set_name_addr()). If, in future,
4130Sstevel@tonic-gate * the ndi_devi_find() provides a way of looking up nodes using criteria
4140Sstevel@tonic-gate * other than addr, we can get rid of this routine.
4150Sstevel@tonic-gate */
4160Sstevel@tonic-gate /*ARGSUSED*/
4170Sstevel@tonic-gate dev_info_t *
s1394_devi_find(dev_info_t * pdip,char * name,char * caddr)4180Sstevel@tonic-gate s1394_devi_find(dev_info_t *pdip, char *name, char *caddr)
4190Sstevel@tonic-gate {
4200Sstevel@tonic-gate int i, reglen;
4210Sstevel@tonic-gate char addr[32];
4220Sstevel@tonic-gate uint32_t *regptr;
4230Sstevel@tonic-gate dev_info_t *cdip = NULL;
4240Sstevel@tonic-gate
4250Sstevel@tonic-gate ASSERT((name != NULL) && (caddr != NULL));
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_devi_find_enter, S1394_TNF_SL_HOTPLUG_STACK,
4280Sstevel@tonic-gate "", tnf_string, addr, caddr);
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate * for each child of this parent, find name and addr and match with
4320Sstevel@tonic-gate * name and caddr passed in.
4330Sstevel@tonic-gate */
4340Sstevel@tonic-gate for (cdip = (dev_info_t *)DEVI(pdip)->devi_child; cdip != NULL;
4350Sstevel@tonic-gate cdip = (dev_info_t *)DEVI(cdip)->devi_sibling) {
4360Sstevel@tonic-gate
4370Sstevel@tonic-gate i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
4380Sstevel@tonic-gate DDI_PROP_DONTPASS, "reg", (int **)®ptr,
4390Sstevel@tonic-gate (uint_t *)®len);
4400Sstevel@tonic-gate
4410Sstevel@tonic-gate if (i != DDI_PROP_SUCCESS)
4420Sstevel@tonic-gate continue;
4430Sstevel@tonic-gate
4440Sstevel@tonic-gate /*
4450Sstevel@tonic-gate * Construct addr from the reg property (addr is of the format
4460Sstevel@tonic-gate * GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where GGGGGGGGGGGGGGGG is
4470Sstevel@tonic-gate * the address and AAAAAAAAAAAA is the optional unit address)
4480Sstevel@tonic-gate */
4490Sstevel@tonic-gate if (regptr[2] != NULL || regptr[3] != NULL) {
4500Sstevel@tonic-gate (void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
4510Sstevel@tonic-gate regptr[1], regptr[2], regptr[3]);
4520Sstevel@tonic-gate } else {
4530Sstevel@tonic-gate (void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate ddi_prop_free(regptr);
4560Sstevel@tonic-gate
4570Sstevel@tonic-gate if (strcmp(caddr, addr) == 0) {
4580Sstevel@tonic-gate ASSERT(strcmp(ddi_node_name(cdip), name) == 0);
4590Sstevel@tonic-gate break;
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate if (cdip == NULL) {
4640Sstevel@tonic-gate TNF_PROBE_1(s1394_devi_find_no_match,
4650Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, addr, caddr);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_devi_find_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
4690Sstevel@tonic-gate
4700Sstevel@tonic-gate return (cdip);
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate * s1394_update_devinfo_tree()
4750Sstevel@tonic-gate * Parses the config rom for the passed in node and creates/updates devinfo's
4760Sstevel@tonic-gate * for each unit directory found. If the devinfo corresponding to a unit
4770Sstevel@tonic-gate * already exists, any insert event callbacks registered for that devinfo
4780Sstevel@tonic-gate * are called (topology tree is unlocked and relocked around these
4790Sstevel@tonic-gate * callbacks). Returns DDI_SUCCESS if everything went fine and DDI_FAILURE
4800Sstevel@tonic-gate * if unable to reacquire the lock after callbacks (relock fails because of
4810Sstevel@tonic-gate * an intervening bus reset or if the services layer kills the bus reset
4820Sstevel@tonic-gate * thread). The node is marked as parsed before returning.
4830Sstevel@tonic-gate */
4840Sstevel@tonic-gate int
s1394_update_devinfo_tree(s1394_hal_t * hal,s1394_node_t * node)4850Sstevel@tonic-gate s1394_update_devinfo_tree(s1394_hal_t *hal, s1394_node_t *node)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate dev_info_t *tdip;
4880Sstevel@tonic-gate int j, units, d, lockfail = 0;
4890Sstevel@tonic-gate s1394_target_t *target, *t;
4900Sstevel@tonic-gate uint32_t hi, lo, size_hi, size_lo, type, key, value;
4910Sstevel@tonic-gate uint32_t *ptr, *root_dir, dir_len;
4920Sstevel@tonic-gate t1394_localinfo_t linfo;
4930Sstevel@tonic-gate
4940Sstevel@tonic-gate uint32_t *unit_dir_ptrs[32];
4950Sstevel@tonic-gate dev_info_t *devinfo_ptrs[32];
4960Sstevel@tonic-gate uint32_t new_devinfo = 0; /* to keep track of new allocations */
4970Sstevel@tonic-gate
4980Sstevel@tonic-gate char caddr[32];
4990Sstevel@tonic-gate
5000Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate ASSERT(CFGROM_PARSED(node) == B_FALSE);
5030Sstevel@tonic-gate ASSERT(node->cfgrom != NULL);
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate TNF_PROBE_2_DEBUG(s1394_update_devinfo_tree_enter,
5060Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num,
5070Sstevel@tonic-gate node->node_num, tnf_opaque, cfgrom, node->cfgrom);
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate /* scan through config rom looking for unit dirs */
5100Sstevel@tonic-gate root_dir = CFGROM_ROOT_DIR(node->cfgrom);
5110Sstevel@tonic-gate
5120Sstevel@tonic-gate if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
5130Sstevel@tonic-gate dir_len = node->cfgrom_valid_size;
5140Sstevel@tonic-gate else
5150Sstevel@tonic-gate dir_len = CFGROM_DIR_LEN(root_dir);
5160Sstevel@tonic-gate
5170Sstevel@tonic-gate CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
5180Sstevel@tonic-gate if (s1394_valid_dir(hal, node, key, root_dir) == B_FALSE) {
5190Sstevel@tonic-gate cmn_err(CE_NOTE,
5200Sstevel@tonic-gate "!Bad root directory in config rom (node's GUID %08x%08x)",
5210Sstevel@tonic-gate node->node_guid_hi, node->node_guid_lo);
5220Sstevel@tonic-gate
5230Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_update_devinfo_tree_exit,
5240Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
5250Sstevel@tonic-gate "bad directory");
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate SET_CFGROM_PARSED(node);
5280Sstevel@tonic-gate CLEAR_CFGROM_GEN_CHANGED(node); /* if set */
5290Sstevel@tonic-gate CLEAR_CFGROM_NEW_ALLOC(node);
5300Sstevel@tonic-gate
5310Sstevel@tonic-gate return (DDI_SUCCESS);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate for (units = 0, j = 1; j <= dir_len; j++) {
5350Sstevel@tonic-gate CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
5360Sstevel@tonic-gate if (key == IEEE1212_UNIT_DIRECTORY && type ==
5370Sstevel@tonic-gate IEEE1212_DIRECTORY_TYPE) {
5380Sstevel@tonic-gate ptr = &root_dir[j] + value;
5390Sstevel@tonic-gate if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
5400Sstevel@tonic-gate unit_dir_ptrs[units++] = ptr;
5410Sstevel@tonic-gate } else {
5420Sstevel@tonic-gate cmn_err(CE_NOTE, "!Bad unit directory in config"
5430Sstevel@tonic-gate " rom (node's GUID %08x%08x)",
5440Sstevel@tonic-gate node->node_guid_hi, node->node_guid_lo);
5450Sstevel@tonic-gate TNF_PROBE_2(s1394_update_devinfo_tree_bad_dir,
5460Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint,
5470Sstevel@tonic-gate guid_hi, node->node_guid_hi, tnf_uint,
5480Sstevel@tonic-gate guid_lo, node->node_guid_lo);
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate }
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate
5530Sstevel@tonic-gate for (d = 0, j = 0; j < units; j++) {
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
5560Sstevel@tonic-gate &hi, &lo, &size_hi, &size_lo);
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate lo = j;
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate if (hi || lo) {
5610Sstevel@tonic-gate (void) sprintf(caddr, "%08x%08x,%04x%08x",
5620Sstevel@tonic-gate node->node_guid_hi, node->node_guid_lo, hi, lo);
5630Sstevel@tonic-gate } else {
5640Sstevel@tonic-gate (void) sprintf(caddr, "%08x%08x",
5650Sstevel@tonic-gate node->node_guid_hi, node->node_guid_lo);
5660Sstevel@tonic-gate }
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr);
5690Sstevel@tonic-gate if (tdip != NULL) {
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate rw_enter(&hal->target_list_rwlock, RW_WRITER);
5720Sstevel@tonic-gate target = s1394_target_from_dip_locked(hal, tdip);
5730Sstevel@tonic-gate if (target != NULL) {
5740Sstevel@tonic-gate target->target_sibling = NULL;
5750Sstevel@tonic-gate target->on_node = node;
5760Sstevel@tonic-gate target->target_state &= ~S1394_TARG_GONE;
5770Sstevel@tonic-gate target->unit_dir = unit_dir_ptrs[j] - root_dir;
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate if ((t = node->target_list) != NULL) {
5800Sstevel@tonic-gate ASSERT(t != target);
5810Sstevel@tonic-gate while (t->target_sibling != NULL) {
5820Sstevel@tonic-gate t = t->target_sibling;
5830Sstevel@tonic-gate ASSERT(t != target);
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate t->target_sibling = target;
5860Sstevel@tonic-gate } else {
5870Sstevel@tonic-gate node->target_list = target;
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate target->target_list = node->target_list;
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate rw_exit(&hal->target_list_rwlock);
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate s1394_update_unit_dir_location(hal, tdip,
5950Sstevel@tonic-gate unit_dir_ptrs[j] - root_dir);
5960Sstevel@tonic-gate
5970Sstevel@tonic-gate } else {
5980Sstevel@tonic-gate /* create devinfo for unit@caddr */
5990Sstevel@tonic-gate tdip = s1394_create_devinfo(hal, node,
6000Sstevel@tonic-gate unit_dir_ptrs[j], j);
6010Sstevel@tonic-gate if (tdip != NULL) {
6020Sstevel@tonic-gate new_devinfo |= (1 << d);
6030Sstevel@tonic-gate s1394_update_unit_dir_location(hal, tdip,
6040Sstevel@tonic-gate unit_dir_ptrs[j] - root_dir);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate }
6070Sstevel@tonic-gate if (tdip != NULL)
6080Sstevel@tonic-gate devinfo_ptrs[d++] = tdip;
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate
6110Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
6120Sstevel@tonic-gate /* Online all valid units */
6130Sstevel@tonic-gate for (j = 0; j < d; j++) {
6140Sstevel@tonic-gate if ((new_devinfo & (1 << j)) == 0) {
6150Sstevel@tonic-gate linfo.bus_generation = hal->generation_count;
6160Sstevel@tonic-gate linfo.local_nodeID = hal->node_id;
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate /* don't need to drop topology_tree_mutex across ndi calls */
6190Sstevel@tonic-gate (void) ndi_devi_online_async(devinfo_ptrs[j], 0);
6200Sstevel@tonic-gate if ((new_devinfo & (1 << j)) == 0) {
6210Sstevel@tonic-gate /*
6220Sstevel@tonic-gate * send an insert event if this an existing devinfo.
6230Sstevel@tonic-gate * drop and reacquire topology_tree_mutex across
6240Sstevel@tonic-gate * the event calls
6250Sstevel@tonic-gate */
6260Sstevel@tonic-gate s1394_unlock_tree(hal);
6270Sstevel@tonic-gate s1394_send_insert_event(hal, devinfo_ptrs[j], &linfo);
6280Sstevel@tonic-gate if (s1394_lock_tree(hal) != DDI_SUCCESS) {
6290Sstevel@tonic-gate TNF_PROBE_4(s1394_update_devinfo_tree_lock_fail,
6300Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "",
6310Sstevel@tonic-gate tnf_int, node_num, node->node_num,
6320Sstevel@tonic-gate tnf_opaque, cfgrom, node->cfgrom,
6330Sstevel@tonic-gate tnf_int, unit, j,
6340Sstevel@tonic-gate tnf_opaque, devinfo, devinfo_ptrs[j]);
6350Sstevel@tonic-gate lockfail = 1;
6360Sstevel@tonic-gate break;
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate
6410Sstevel@tonic-gate if (lockfail) {
6420Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit,
6430Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "");
6440Sstevel@tonic-gate return (DDI_FAILURE);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate SET_CFGROM_PARSED(node);
6480Sstevel@tonic-gate CLEAR_CFGROM_GEN_CHANGED(node); /* if set */
6490Sstevel@tonic-gate CLEAR_CFGROM_NEW_ALLOC(node);
6500Sstevel@tonic-gate
6510Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit,
6520Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate return (DDI_SUCCESS);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate /*
6580Sstevel@tonic-gate * s1394_offline_node()
6590Sstevel@tonic-gate * Offlines a node. This involves marking all targets attached to the
6600Sstevel@tonic-gate * node as gone, invoking any remove event callbacks and calling
6610Sstevel@tonic-gate * ndi_devi_offline to mark the devinfo as OFFLINE (for each unit
6620Sstevel@tonic-gate * directory on the node). The tree is unlocked and relocked around
6630Sstevel@tonic-gate * the callbacks. If unable to relock the tree, DDI_FAILURE, else
6640Sstevel@tonic-gate * returns DDI_SUCCESS.
6650Sstevel@tonic-gate */
6660Sstevel@tonic-gate int
s1394_offline_node(s1394_hal_t * hal,s1394_node_t * node)6670Sstevel@tonic-gate s1394_offline_node(s1394_hal_t *hal, s1394_node_t *node)
6680Sstevel@tonic-gate {
6690Sstevel@tonic-gate s1394_target_t *t;
6700Sstevel@tonic-gate dev_info_t *tdip;
6710Sstevel@tonic-gate int j, d, units;
6720Sstevel@tonic-gate uint32_t *unit_dir_ptrs[32];
6730Sstevel@tonic-gate dev_info_t *devinfo_ptrs[32];
6740Sstevel@tonic-gate t1394_localinfo_t linfo;
6750Sstevel@tonic-gate uint_t node_num;
6760Sstevel@tonic-gate uint32_t *ptr, *root_dir, dir_len;
6770Sstevel@tonic-gate uint32_t hi, lo, size_hi, size_lo, type, key, value;
6780Sstevel@tonic-gate char caddr[32];
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate node_num = node->node_num;
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_offline_node_enter, S1394_TNF_SL_HOTPLUG_STACK,
6830Sstevel@tonic-gate "", tnf_uint, node_num, node_num);
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
6860Sstevel@tonic-gate
6870Sstevel@tonic-gate d = 0;
6880Sstevel@tonic-gate rw_enter(&hal->target_list_rwlock, RW_WRITER);
6890Sstevel@tonic-gate t = node->target_list;
6900Sstevel@tonic-gate while (t != NULL) {
6910Sstevel@tonic-gate TNF_PROBE_2(s1394_process_old_tree_mark,
6920Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num, node_num,
6930Sstevel@tonic-gate tnf_opaque, target, t);
6940Sstevel@tonic-gate t->target_state |= S1394_TARG_GONE;
6950Sstevel@tonic-gate t->on_node = NULL;
6960Sstevel@tonic-gate t = t->target_sibling;
6970Sstevel@tonic-gate }
6980Sstevel@tonic-gate rw_exit(&hal->target_list_rwlock);
6990Sstevel@tonic-gate
7000Sstevel@tonic-gate /* scan through config rom looking for unit dirs */
7010Sstevel@tonic-gate root_dir = CFGROM_ROOT_DIR(node->cfgrom);
7020Sstevel@tonic-gate
7030Sstevel@tonic-gate if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
7040Sstevel@tonic-gate dir_len = node->cfgrom_valid_size;
7050Sstevel@tonic-gate else
7060Sstevel@tonic-gate dir_len = CFGROM_DIR_LEN(root_dir);
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate for (units = 0, j = 1; j <= dir_len; j++) {
7110Sstevel@tonic-gate CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
7120Sstevel@tonic-gate if (key == IEEE1212_UNIT_DIRECTORY && type ==
7130Sstevel@tonic-gate IEEE1212_DIRECTORY_TYPE) {
7140Sstevel@tonic-gate ptr = &root_dir[j] + value;
7150Sstevel@tonic-gate if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
7160Sstevel@tonic-gate unit_dir_ptrs[units++] = ptr;
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate }
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate for (d = 0, j = 0; j < units; j++) {
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
7240Sstevel@tonic-gate &hi, &lo, &size_hi, &size_lo);
7250Sstevel@tonic-gate
7260Sstevel@tonic-gate lo = j;
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate if (hi || lo) {
7290Sstevel@tonic-gate (void) sprintf(caddr, "%08x%08x,%04x%08x",
7300Sstevel@tonic-gate node->node_guid_hi, node->node_guid_lo, hi, lo);
7310Sstevel@tonic-gate } else {
7320Sstevel@tonic-gate (void) sprintf(caddr, "%08x%08x",
7330Sstevel@tonic-gate node->node_guid_hi, node->node_guid_lo);
7340Sstevel@tonic-gate }
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate if ((tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr)) !=
7370Sstevel@tonic-gate NULL)
7380Sstevel@tonic-gate devinfo_ptrs[d++] = tdip;
7390Sstevel@tonic-gate }
7400Sstevel@tonic-gate
7410Sstevel@tonic-gate node->old_node = NULL;
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate linfo.bus_generation = hal->generation_count;
7440Sstevel@tonic-gate linfo.local_nodeID = hal->node_id;
7450Sstevel@tonic-gate
7460Sstevel@tonic-gate for (j = 0; j < d; j++) {
7470Sstevel@tonic-gate s1394_unlock_tree(hal);
7480Sstevel@tonic-gate
7490Sstevel@tonic-gate TNF_PROBE_2(s1394_offline_node,
7500Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num, node_num,
7510Sstevel@tonic-gate tnf_opaque, devinfo, devinfo_ptrs[j]);
7520Sstevel@tonic-gate
7530Sstevel@tonic-gate s1394_send_remove_event(hal, devinfo_ptrs[j], &linfo);
7540Sstevel@tonic-gate (void) ndi_devi_offline(devinfo_ptrs[j], NDI_DEVI_REMOVE);
7550Sstevel@tonic-gate if (s1394_lock_tree(hal) != DDI_SUCCESS) {
7560Sstevel@tonic-gate TNF_PROBE_2(s1394_offline_node,
7570Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
7580Sstevel@tonic-gate "unlock to relock tree", tnf_uint, node_num,
7590Sstevel@tonic-gate node_num);
7600Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_offline_node_exit,
7610Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
7620Sstevel@tonic-gate return (DDI_FAILURE);
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate
7660Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
7670Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_offline_node_exit, S1394_TNF_SL_HOTPLUG_STACK,
7680Sstevel@tonic-gate "");
7690Sstevel@tonic-gate return (DDI_SUCCESS);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate
7720Sstevel@tonic-gate /*
7730Sstevel@tonic-gate * s1394_process_topology_tree()
7740Sstevel@tonic-gate * Walks the topology tree, processing each node. If node that has
7750Sstevel@tonic-gate * already been parsed, updates the generation property on all devinfos
7760Sstevel@tonic-gate * for the node. Also, if the node exists in both old & new trees, ASSERTS
7770Sstevel@tonic-gate * that both point to the same config rom. If the node has valid config
7780Sstevel@tonic-gate * rom but hasn't been parsed yet, calls s1394_update_devinfo_tree()
7790Sstevel@tonic-gate * to parse and create devinfos for the node. Kicks off further config
7800Sstevel@tonic-gate * rom reading if only the bus info block for the node is read.
7810Sstevel@tonic-gate * Returns DDI_SUCCESS if everything went fine, else returns DDI_FAILURE
7820Sstevel@tonic-gate * (for eg. unable to reacquire the tree lock etc). wait_for_cbs argument
7830Sstevel@tonic-gate * tells the caller if some completions can be expected. wait_gen tells
7840Sstevel@tonic-gate * the generation the commands were issued at.
7850Sstevel@tonic-gate */
7860Sstevel@tonic-gate int
s1394_process_topology_tree(s1394_hal_t * hal,int * wait_for_cbs,uint_t * wait_gen)7870Sstevel@tonic-gate s1394_process_topology_tree(s1394_hal_t *hal, int *wait_for_cbs,
7880Sstevel@tonic-gate uint_t *wait_gen)
7890Sstevel@tonic-gate {
7900Sstevel@tonic-gate int i;
7910Sstevel@tonic-gate uint_t hal_node_num, number_of_nodes;
7920Sstevel@tonic-gate s1394_node_t *node, *onode;
7930Sstevel@tonic-gate s1394_status_t status;
7940Sstevel@tonic-gate
7950Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
7960Sstevel@tonic-gate
7970Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_process_topology_tree_enter,
7980Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate if (s1394_lock_tree(hal) != DDI_SUCCESS) {
8010Sstevel@tonic-gate TNF_PROBE_0(s1394_process_topology_tree_lock_failed,
8020Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "");
8030Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit,
8040Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
8050Sstevel@tonic-gate return (DDI_FAILURE);
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate
8080Sstevel@tonic-gate hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
8090Sstevel@tonic-gate hal->cfgroms_being_read = 0;
8100Sstevel@tonic-gate number_of_nodes = hal->number_of_nodes;
8110Sstevel@tonic-gate s1394_unlock_tree(hal);
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate for (i = 0; i < number_of_nodes; i++) {
8140Sstevel@tonic-gate
8150Sstevel@tonic-gate if (i == hal_node_num)
8160Sstevel@tonic-gate continue;
8170Sstevel@tonic-gate if (s1394_lock_tree(hal) != DDI_SUCCESS) {
8180Sstevel@tonic-gate return (DDI_FAILURE);
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate node = &hal->topology_tree[i];
8210Sstevel@tonic-gate
8220Sstevel@tonic-gate TNF_PROBE_4_DEBUG(s1394_process_topology_tree,
8230Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "",
8240Sstevel@tonic-gate tnf_int, node_num, i,
8250Sstevel@tonic-gate tnf_int, parsed, CFGROM_PARSED(node),
8260Sstevel@tonic-gate tnf_int, matched, NODE_MATCHED(node),
8270Sstevel@tonic-gate tnf_int, visited, NODE_VISITED(node));
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate if (LINK_ACTIVE(node) == B_FALSE) {
8300Sstevel@tonic-gate s1394_unlock_tree(hal);
8310Sstevel@tonic-gate continue;
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate if (node->cfgrom == NULL) {
8340Sstevel@tonic-gate s1394_unlock_tree(hal);
8350Sstevel@tonic-gate continue;
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate
8380Sstevel@tonic-gate onode = node->old_node;
8390Sstevel@tonic-gate
8400Sstevel@tonic-gate if (onode != NULL && onode->cfgrom != NULL && node->cfgrom !=
8410Sstevel@tonic-gate NULL) {
8420Sstevel@tonic-gate /*
8430Sstevel@tonic-gate * onode->cfgrom != node->cfgrom should have been
8440Sstevel@tonic-gate * handled by s1394_match_GUID()!!!
8450Sstevel@tonic-gate */
8460Sstevel@tonic-gate if (onode->cfgrom != node->cfgrom)
8470Sstevel@tonic-gate TNF_PROBE_5(s1394_process_topology_tree_err,
8480Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "",
8490Sstevel@tonic-gate tnf_int, node_num, i, tnf_int, gen_changed,
8500Sstevel@tonic-gate CFGROM_GEN_CHANGED(node), tnf_int, parsed,
8510Sstevel@tonic-gate CFGROM_PARSED(node), tnf_opaque, old_cfgrom,
8520Sstevel@tonic-gate onode->cfgrom, tnf_opaque, new_cfgrom,
8530Sstevel@tonic-gate node->cfgrom);
8540Sstevel@tonic-gate ASSERT(onode->cfgrom == node->cfgrom);
8550Sstevel@tonic-gate }
8560Sstevel@tonic-gate
8570Sstevel@tonic-gate if (CFGROM_PARSED(node) == B_FALSE && CFGROM_ALL_READ(node) ==
8580Sstevel@tonic-gate B_TRUE) {
8590Sstevel@tonic-gate ASSERT((node->cfgrom_size <
8600Sstevel@tonic-gate IEEE1394_CONFIG_ROM_QUAD_SZ) ||
8610Sstevel@tonic-gate NODE_MATCHED(node) == B_TRUE);
8620Sstevel@tonic-gate rw_enter(&hal->target_list_rwlock, RW_READER);
8630Sstevel@tonic-gate ASSERT(node->target_list == NULL);
8640Sstevel@tonic-gate rw_exit(&hal->target_list_rwlock);
8650Sstevel@tonic-gate if (s1394_update_devinfo_tree(hal, node) ==
8660Sstevel@tonic-gate DDI_FAILURE) {
8670Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(
8680Sstevel@tonic-gate &hal->topology_tree_mutex));
8690Sstevel@tonic-gate TNF_PROBE_1(s1394_process_topology_tree,
8700Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
8710Sstevel@tonic-gate msg, "failure from update devinfo");
8720Sstevel@tonic-gate TNF_PROBE_0_DEBUG(
8730Sstevel@tonic-gate s1394_process_topology_tree_exit,
8740Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
8750Sstevel@tonic-gate return (DDI_FAILURE);
8760Sstevel@tonic-gate }
8770Sstevel@tonic-gate } else if (CFGROM_PARSED(node) == B_FALSE && CFGROM_BIB_READ(
8780Sstevel@tonic-gate node) == B_TRUE) {
8790Sstevel@tonic-gate if (s1394_read_rest_of_cfgrom(hal, node, &status) !=
8800Sstevel@tonic-gate DDI_SUCCESS) {
8810Sstevel@tonic-gate TNF_PROBE_1(s1394_process_topology_tree,
8820Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
8830Sstevel@tonic-gate msg, "failure reading rest of cfgrom");
8840Sstevel@tonic-gate if ((status & S1394_LOCK_FAILED) == 0) {
8850Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->
8860Sstevel@tonic-gate topology_tree_mutex));
8870Sstevel@tonic-gate *wait_for_cbs = 0;
8880Sstevel@tonic-gate s1394_unlock_tree(hal);
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate TNF_PROBE_0_DEBUG(
8910Sstevel@tonic-gate s1394_process_topology_tree_exit,
8920Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
8930Sstevel@tonic-gate return (DDI_FAILURE);
8940Sstevel@tonic-gate } else {
8950Sstevel@tonic-gate *wait_for_cbs = 1;
8960Sstevel@tonic-gate *wait_gen = hal->br_cfgrom_read_gen;
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate }
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate s1394_unlock_tree(hal);
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate
9030Sstevel@tonic-gate /*
9040Sstevel@tonic-gate * flag the tree as processed; if a single bus reset happens after
9050Sstevel@tonic-gate * this, we will use tree matching.
9060Sstevel@tonic-gate */
9070Sstevel@tonic-gate if (s1394_lock_tree(hal) != DDI_SUCCESS) {
9080Sstevel@tonic-gate TNF_PROBE_1(s1394_process_topology_tree,
9090Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
9100Sstevel@tonic-gate msg, "relock failed while marking tree processed");
9110Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit,
9120Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
9130Sstevel@tonic-gate return (DDI_FAILURE);
9140Sstevel@tonic-gate }
9150Sstevel@tonic-gate hal->topology_tree_processed = B_TRUE;
9160Sstevel@tonic-gate s1394_unlock_tree(hal);
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_process_topology_tree_exit,
9190Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, hal_instance,
9200Sstevel@tonic-gate ddi_get_instance(hal->halinfo.dip));
9210Sstevel@tonic-gate
9220Sstevel@tonic-gate return (DDI_SUCCESS);
9230Sstevel@tonic-gate }
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate /*
9260Sstevel@tonic-gate * s1394_process_old_tree()
9270Sstevel@tonic-gate * Walks through the old tree and offlines nodes that are removed. Nodes
9280Sstevel@tonic-gate * with an active link in the old tree but link powered off in the current
9290Sstevel@tonic-gate * generation are also offlined, as well as nodes with invalid config
9300Sstevel@tonic-gate * rom in current generation.
9310Sstevel@tonic-gate * The topology tree is locked/unlocked while walking through all the nodes;
9320Sstevel@tonic-gate * if the locking fails at any stage, stops further walking and returns
9330Sstevel@tonic-gate * DDI_FAILURE. Returns DDI_SUCCESS if everything went fine.
9340Sstevel@tonic-gate */
9350Sstevel@tonic-gate int
s1394_process_old_tree(s1394_hal_t * hal)9360Sstevel@tonic-gate s1394_process_old_tree(s1394_hal_t *hal)
9370Sstevel@tonic-gate {
9380Sstevel@tonic-gate int i;
9390Sstevel@tonic-gate uint_t hal_node_num_old, old_number_of_nodes;
9400Sstevel@tonic-gate s1394_node_t *onode;
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_process_old_tree_enter,
9430Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
9440Sstevel@tonic-gate
9450Sstevel@tonic-gate /*
9460Sstevel@tonic-gate * NODE_MATCHED(onode) == 0 indicates this node doesn't exist
9470Sstevel@tonic-gate * any more.
9480Sstevel@tonic-gate */
9490Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
9500Sstevel@tonic-gate
9510Sstevel@tonic-gate if (s1394_lock_tree(hal) != DDI_SUCCESS) {
9520Sstevel@tonic-gate TNF_PROBE_0(s1394_process_old_tree_lock_failed,
9530Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "");
9540Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
9550Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
9560Sstevel@tonic-gate return (DDI_FAILURE);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate hal_node_num_old = IEEE1394_NODE_NUM(hal->old_node_id);
9590Sstevel@tonic-gate old_number_of_nodes = hal->old_number_of_nodes;
9600Sstevel@tonic-gate s1394_unlock_tree(hal);
9610Sstevel@tonic-gate
9620Sstevel@tonic-gate for (i = 0; i < old_number_of_nodes; i++) {
9630Sstevel@tonic-gate
9640Sstevel@tonic-gate if (i == hal_node_num_old)
9650Sstevel@tonic-gate continue;
9660Sstevel@tonic-gate if (s1394_lock_tree(hal) != DDI_SUCCESS) {
9670Sstevel@tonic-gate TNF_PROBE_2(s1394_process_old_tree,
9680Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
9690Sstevel@tonic-gate "lock failed while processing node", tnf_uint,
9700Sstevel@tonic-gate node_num, i);
9710Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
9720Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
9730Sstevel@tonic-gate return (DDI_FAILURE);
9740Sstevel@tonic-gate }
9750Sstevel@tonic-gate
9760Sstevel@tonic-gate onode = &hal->old_tree[i];
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate if (onode->cfgrom == NULL) {
9790Sstevel@tonic-gate CLEAR_CFGROM_STATE(onode);
9800Sstevel@tonic-gate s1394_unlock_tree(hal);
9810Sstevel@tonic-gate continue;
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate
9840Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_process_old_tree,
9850Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque,
9860Sstevel@tonic-gate cfgrom, onode->cfgrom);
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate TNF_PROBE_5_DEBUG(s1394_process_old_tree,
9890Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int,
9900Sstevel@tonic-gate node_num, i, tnf_int, parsed, CFGROM_PARSED(onode), tnf_int,
9910Sstevel@tonic-gate matched, NODE_MATCHED(onode), tnf_int, visited,
9920Sstevel@tonic-gate NODE_VISITED(onode), tnf_int, generation_changed,
9930Sstevel@tonic-gate CFGROM_GEN_CHANGED(onode));
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate /*
9960Sstevel@tonic-gate * onode->cur_node == NULL iff we couldn't read cfgrom in the
9970Sstevel@tonic-gate * current generation in non-tree matching case (and thus
9980Sstevel@tonic-gate * match_GUIDs couldn't set cur_node).
9990Sstevel@tonic-gate */
10000Sstevel@tonic-gate if (NODE_MATCHED(onode) == B_FALSE || (onode->cur_node ==
10010Sstevel@tonic-gate NULL || ((CFGROM_VALID(onode) == B_TRUE &&
10020Sstevel@tonic-gate CFGROM_VALID(onode->cur_node) == B_FALSE) ||
10030Sstevel@tonic-gate (LINK_ACTIVE(onode) == B_TRUE && LINK_ACTIVE(onode->
10040Sstevel@tonic-gate cur_node) == B_FALSE)))) {
10050Sstevel@tonic-gate
10060Sstevel@tonic-gate if (onode->cur_node != NULL && CFGROM_VALID(onode) ==
10070Sstevel@tonic-gate B_TRUE && CFGROM_VALID(onode->cur_node) == B_FALSE)
10080Sstevel@tonic-gate TNF_PROBE_1_DEBUG
10090Sstevel@tonic-gate (s1394_process_old_tree_invalid_cfgrom,
10100Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "",
10110Sstevel@tonic-gate tnf_int, node_num, i);
10120Sstevel@tonic-gate if (onode->cur_node != NULL && LINK_ACTIVE(onode) ==
10130Sstevel@tonic-gate B_TRUE && LINK_ACTIVE(onode->cur_node) == B_FALSE)
10140Sstevel@tonic-gate TNF_PROBE_1_DEBUG
10150Sstevel@tonic-gate (s1394_process_old_tree_link_off,
10160Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK,
10170Sstevel@tonic-gate "", tnf_int, node_num, i);
10180Sstevel@tonic-gate if (s1394_offline_node(hal, onode) != DDI_SUCCESS) {
10190Sstevel@tonic-gate TNF_PROBE_2(s1394_process_old_tree,
10200Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
10210Sstevel@tonic-gate msg, "failure from offline node", tnf_uint,
10220Sstevel@tonic-gate node_num, i);
10230Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
10240Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
10250Sstevel@tonic-gate return (DDI_FAILURE);
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate s1394_free_cfgrom(hal, onode, S1394_FREE_CFGROM_OLD);
10280Sstevel@tonic-gate }
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate s1394_unlock_tree(hal);
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
10360Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate return (DDI_SUCCESS);
10390Sstevel@tonic-gate }
10400Sstevel@tonic-gate
10410Sstevel@tonic-gate /*
10420Sstevel@tonic-gate * s1394_update_unit_dir_location()
10430Sstevel@tonic-gate * Updates the unit-dir-offset property on the devinfo.
10440Sstevel@tonic-gate * NOTE: ndi_prop_update_int() is interrupt callable (and thus won't block);
10450Sstevel@tonic-gate * so, the caller doesn't drop topology_tree_mutex when calling this routine.
10460Sstevel@tonic-gate */
10470Sstevel@tonic-gate /*ARGSUSED*/
10480Sstevel@tonic-gate static void
s1394_update_unit_dir_location(s1394_hal_t * hal,dev_info_t * tdip,uint_t offset)10490Sstevel@tonic-gate s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
10500Sstevel@tonic-gate uint_t offset)
10510Sstevel@tonic-gate {
10520Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
10530Sstevel@tonic-gate ASSERT(tdip != NULL);
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_update_unit_dir_location_enter,
10560Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, offset, offset);
10570Sstevel@tonic-gate (void) ndi_prop_update_int(DDI_DEV_T_NONE, tdip, "unit-dir-offset",
10580Sstevel@tonic-gate offset);
10590Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_update_unit_dir_location_exit,
10600Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
10610Sstevel@tonic-gate }
10620Sstevel@tonic-gate
10630Sstevel@tonic-gate /*
10640Sstevel@tonic-gate * s1394_add_target_to_node()
10650Sstevel@tonic-gate * adds target to the list of targets hanging off the node. Figures out
10660Sstevel@tonic-gate * the node by searching the topology tree for the GUID corresponding
10670Sstevel@tonic-gate * to the target. Points on_node field of target structure at the node.
10680Sstevel@tonic-gate */
10690Sstevel@tonic-gate void
s1394_add_target_to_node(s1394_target_t * target)10700Sstevel@tonic-gate s1394_add_target_to_node(s1394_target_t *target)
10710Sstevel@tonic-gate {
10720Sstevel@tonic-gate s1394_target_t *t;
10730Sstevel@tonic-gate s1394_hal_t *hal;
10740Sstevel@tonic-gate uint32_t guid_hi;
10750Sstevel@tonic-gate uint32_t guid_lo;
10760Sstevel@tonic-gate int i;
10770Sstevel@tonic-gate char name[MAXNAMELEN];
10780Sstevel@tonic-gate char *ptr;
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_add_target_to_node_enter,
10810Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
10820Sstevel@tonic-gate
10830Sstevel@tonic-gate hal = target->on_hal;
10840Sstevel@tonic-gate ASSERT(hal != NULL);
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate /* Topology tree must be locked when it gets here! */
10870Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
10880Sstevel@tonic-gate
10890Sstevel@tonic-gate /* target_list_rwlock should be held in write mode */
10900Sstevel@tonic-gate ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
10910Sstevel@tonic-gate
10920Sstevel@tonic-gate if ((ptr = ddi_get_name_addr(target->target_dip)) == NULL) {
10930Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit_no_name,
10940Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
10950Sstevel@tonic-gate return;
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate
10980Sstevel@tonic-gate (void) sprintf(name, ptr);
10990Sstevel@tonic-gate /* Drop the ,<ADDR> part, if present */
11000Sstevel@tonic-gate if ((ptr = strchr(name, ',')) != NULL)
11010Sstevel@tonic-gate *ptr = '\0';
11020Sstevel@tonic-gate
11030Sstevel@tonic-gate ptr = name;
11040Sstevel@tonic-gate guid_hi = s1394_stoi(ptr, 8, 16);
11050Sstevel@tonic-gate guid_lo = s1394_stoi(ptr + 8, 8, 16);
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate /* Search the HAL's node list for this GUID */
11080Sstevel@tonic-gate for (i = 0; i < hal->number_of_nodes; i++) {
11090Sstevel@tonic-gate if (CFGROM_VALID(&hal->topology_tree[i]) == B_TRUE) {
11100Sstevel@tonic-gate ASSERT(hal->topology_tree[i].cfgrom != NULL);
11110Sstevel@tonic-gate
11120Sstevel@tonic-gate if ((hal->topology_tree[i].node_guid_hi == guid_hi) &&
11130Sstevel@tonic-gate (hal->topology_tree[i].node_guid_lo == guid_lo)) {
11140Sstevel@tonic-gate target->on_node = &hal->topology_tree[i];
11150Sstevel@tonic-gate if ((t = hal->topology_tree[i].target_list) !=
11160Sstevel@tonic-gate NULL) {
11170Sstevel@tonic-gate ASSERT(t != target);
11180Sstevel@tonic-gate while (t->target_sibling != NULL) {
11190Sstevel@tonic-gate t = t->target_sibling;
11200Sstevel@tonic-gate ASSERT(t != target);
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate t->target_sibling = target;
11230Sstevel@tonic-gate } else {
11240Sstevel@tonic-gate hal->topology_tree[i].target_list =
11250Sstevel@tonic-gate target;
11260Sstevel@tonic-gate }
11270Sstevel@tonic-gate
11280Sstevel@tonic-gate /*
11290Sstevel@tonic-gate * update target_list in all targets on the
11300Sstevel@tonic-gate * node
11310Sstevel@tonic-gate */
11320Sstevel@tonic-gate t = hal->topology_tree[i].target_list;
11330Sstevel@tonic-gate while (t != NULL) {
11340Sstevel@tonic-gate t->target_list =
11350Sstevel@tonic-gate hal->topology_tree[i].target_list;
11360Sstevel@tonic-gate t = t->target_sibling;
11370Sstevel@tonic-gate }
11380Sstevel@tonic-gate break;
11390Sstevel@tonic-gate }
11400Sstevel@tonic-gate }
11410Sstevel@tonic-gate }
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit,
11440Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
11450Sstevel@tonic-gate }
11460Sstevel@tonic-gate
11470Sstevel@tonic-gate /*
11480Sstevel@tonic-gate * s1394_remove_target_from_node()
11490Sstevel@tonic-gate * Removes target from the corresponding node's target_list.
11500Sstevel@tonic-gate */
11510Sstevel@tonic-gate void
s1394_remove_target_from_node(s1394_target_t * target)11520Sstevel@tonic-gate s1394_remove_target_from_node(s1394_target_t *target)
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate s1394_target_t *t, *t1;
11550Sstevel@tonic-gate s1394_hal_t *hal;
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_enter,
11580Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
11590Sstevel@tonic-gate
11600Sstevel@tonic-gate hal = target->on_hal;
11610Sstevel@tonic-gate ASSERT(hal != NULL);
11620Sstevel@tonic-gate
11630Sstevel@tonic-gate /* Topology tree must be locked when it gets here! */
11640Sstevel@tonic-gate ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate /* target_list_rwlock should be held in write mode */
11670Sstevel@tonic-gate ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
11680Sstevel@tonic-gate
11690Sstevel@tonic-gate if (target->on_node == NULL) {
11700Sstevel@tonic-gate TNF_PROBE_1_DEBUG(s1394_remove_target_from_node_NULL,
11710Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "",
11720Sstevel@tonic-gate tnf_uint, target_state, target->target_state);
11730Sstevel@tonic-gate }
11740Sstevel@tonic-gate
11750Sstevel@tonic-gate t = target->target_list;
11760Sstevel@tonic-gate t1 = NULL;
11770Sstevel@tonic-gate while (t != NULL) {
11780Sstevel@tonic-gate if (t == target) {
11790Sstevel@tonic-gate if (t1 == NULL) {
11800Sstevel@tonic-gate target->target_list = t->target_sibling;
11810Sstevel@tonic-gate } else {
11820Sstevel@tonic-gate t1->target_sibling = t->target_sibling;
11830Sstevel@tonic-gate }
11840Sstevel@tonic-gate break;
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate t1 = t;
11870Sstevel@tonic-gate t = t->target_sibling;
11880Sstevel@tonic-gate }
11890Sstevel@tonic-gate /* Update the target_list pointer in all the targets */
11900Sstevel@tonic-gate if (target->on_node != NULL)
11910Sstevel@tonic-gate target->on_node->target_list = target->target_list;
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate t = t1 = target->target_list;
11940Sstevel@tonic-gate while (t != NULL) {
11950Sstevel@tonic-gate t->target_list = t1;
11960Sstevel@tonic-gate t = t->target_sibling;
11970Sstevel@tonic-gate }
11980Sstevel@tonic-gate
11990Sstevel@tonic-gate target->on_node = NULL;
12000Sstevel@tonic-gate target->target_sibling = NULL;
12010Sstevel@tonic-gate
12020Sstevel@tonic-gate TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_exit,
12030Sstevel@tonic-gate S1394_TNF_SL_HOTPLUG_STACK, "");
12040Sstevel@tonic-gate }
1205