1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * s1394_hotplug.c
29  *    1394 Services Layer Hotplug Routines
30  *    This file contains routines that walk the old and topology
31  *    trees, at bus reset time, creating devinfo's for new nodes and offlining
32  *    nodes that are removed.
33  */
34 
35 #include <sys/conf.h>
36 #include <sys/sysmacros.h>
37 #include <sys/ddi.h>
38 #include <sys/sunddi.h>
39 #include <sys/sunndi.h>
40 #include <sys/modctl.h>
41 #include <sys/sunddi.h>
42 #include <sys/ddi_impldefs.h>
43 #include <sys/types.h>
44 
45 #include <sys/tnf_probe.h>
46 
47 #include <sys/1394/t1394.h>
48 #include <sys/1394/s1394.h>
49 #include <sys/1394/h1394.h>
50 #include <sys/1394/ieee1394.h>
51 
52 static void s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
53     t1394_localinfo_t *localinfo);
54 static void s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
55     t1394_localinfo_t *localinfo);
56 static dev_info_t *s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node,
57     uint32_t *unit_dir, int nunit);
58 static void s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
59     uint_t offset);
60 
61 /*
62  * s1394_send_remove_event()
63  *    Invokes any "remove event" callback registered for dip. Passes
64  *    t1394_localinfo_t as impl_data for the callback.
65  */
66 static void
s1394_send_remove_event(s1394_hal_t * hal,dev_info_t * dip,t1394_localinfo_t * localinfo)67 s1394_send_remove_event(s1394_hal_t *hal, dev_info_t *dip,
68     t1394_localinfo_t *localinfo)
69 {
70 	char name[128];
71 	ddi_eventcookie_t cookie;
72 
73 	(void) sprintf(name, "%s%d", ddi_driver_name(dip),
74 	    ddi_get_instance(dip));
75 
76 	TNF_PROBE_1_DEBUG(s1394_send_remove_event_enter,
77 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, device,
78 	    name);
79 
80 	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
81 	    DDI_DEVI_REMOVE_EVENT, &cookie, NDI_EVENT_NOPASS)
82 	    == NDI_SUCCESS) {
83 		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
84 		    cookie, localinfo);
85 	}
86 	TNF_PROBE_0_DEBUG(s1394_send_remove_event_exit,
87 	    S1394_TNF_SL_HOTPLUG_STACK, "");
88 }
89 
90 /*
91  * s1394_send_insert_event()
92  *    Invokes any "insert event" callback registered for dip. Passes
93  *    t1394_localinfo_t as impl_data for the callback.
94  */
95 static void
s1394_send_insert_event(s1394_hal_t * hal,dev_info_t * dip,t1394_localinfo_t * localinfo)96 s1394_send_insert_event(s1394_hal_t *hal, dev_info_t *dip,
97     t1394_localinfo_t *localinfo)
98 {
99 	char name[128];
100 	ddi_eventcookie_t cookie;
101 
102 	(void) sprintf(name, "%s%d", ddi_driver_name(dip),
103 	    ddi_get_instance(dip));
104 
105 	TNF_PROBE_1_DEBUG(s1394_send_insert_event_enter,
106 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, device,
107 	    name);
108 
109 	if (ndi_event_retrieve_cookie(hal->hal_ndi_event_hdl, dip,
110 	    DDI_DEVI_INSERT_EVENT, &cookie, NDI_EVENT_NOPASS) ==
111 	    NDI_SUCCESS)
112 		(void) ndi_event_run_callbacks(hal->hal_ndi_event_hdl, dip,
113 		    cookie, localinfo);
114 
115 	TNF_PROBE_0_DEBUG(s1394_send_insert_event_exit,
116 	    S1394_TNF_SL_HOTPLUG_STACK, "");
117 }
118 
119 /*
120  * s1394_create_devinfo()
121  *    This routine creates a devinfo corresponding to the unit_dir passed in.
122  *    It adds "hp-node", "reg", "compatible" properties to the devinfo
123  *    (formats for "reg" and "compatible" properties are specified by 1275
124  *    binding for IEEE1394). If unable to create the devinfo and/or add the
125  *    the properties, returns NULL, otherwise, returns the devinfo created.
126  *
127  *    NOTE: All ndi_* routines are interrupt callable (and thus won't sleep).
128  *    So, we don't drop topology_mutex across ndi calls.
129  */
130 static dev_info_t *
s1394_create_devinfo(s1394_hal_t * hal,s1394_node_t * node,uint32_t * unit_dir,int nunit)131 s1394_create_devinfo(s1394_hal_t *hal, s1394_node_t *node, uint32_t *unit_dir,
132     int nunit)
133 {
134 	dev_info_t *hal_dip;
135 	uint32_t *root_dir;
136 	dev_info_t *target_dip;
137 
138 	int root_dir_len;
139 	int result, i, j, spec_id, sw_version;
140 	int mod_ven, mod_hw, mod_spec, mod_sw;
141 	int node_ven, node_hw, node_spec, node_sw;
142 
143 	/*LINTED type is unused*/
144 	uint32_t type __unused, key, value;
145 	uint32_t unit_spec_id, unit_sw_version;
146 	uint32_t node_spec_id, node_sw_version;
147 	uint32_t node_vendor_id, node_hw_version;
148 	uint32_t module_spec_id, module_sw_version;
149 	uint32_t module_vendor_id, module_hw_version;
150 
151 	char *fmt = "firewire%06x,%06x";
152 
153 	char *buf[5], data[5][24];
154 	uint32_t reg[6];
155 
156 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
157 
158 	TNF_PROBE_2_DEBUG(s1394_create_devinfo_enter,
159 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, guid_hi,
160 	    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo);
161 
162 	hal_dip = hal->halinfo.dip;
163 
164 	/* Allocate and init a new device node instance. */
165 	result = ndi_devi_alloc(hal_dip, "unit", (pnode_t)DEVI_SID_NODEID,
166 	    &target_dip);
167 
168 	if (result != NDI_SUCCESS) {
169 		cmn_err(CE_NOTE, "!Unable to create devinfo"
170 		    " (node's GUID %08x%08x)", node->node_guid_hi,
171 		    node->node_guid_lo);
172 		TNF_PROBE_2(s1394_create_devinfo_fail_alloc,
173 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
174 		    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo);
175 		TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
176 		    S1394_TNF_SL_HOTPLUG_STACK, "");
177 		return (NULL);
178 	}
179 
180 	/* Add "hp-node" property */
181 	result = ndi_prop_update_int(DDI_DEV_T_NONE, target_dip, "hp-node", 0);
182 	if (result != NDI_SUCCESS) {
183 		cmn_err(CE_NOTE, "!Unable to add \"hp-node\" property"
184 		    " (node's GUID %08x%08x)", node->node_guid_hi,
185 		    node->node_guid_lo);
186 #if defined(DEBUG)
187 		cmn_err(CE_CONT, "!Error code %d", result);
188 #endif
189 		TNF_PROBE_3(s1394_create_devinfo_hp_node,
190 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
191 		    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
192 		    tnf_int, error, result);
193 		ndi_prop_remove_all(target_dip);
194 		(void) ndi_devi_free(target_dip);
195 		TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
196 		    S1394_TNF_SL_HOTPLUG_STACK, "");
197 		return (NULL);
198 	}
199 
200 	spec_id = sw_version = mod_ven = mod_hw = mod_spec = mod_sw =
201 	    node_ven = node_hw = node_spec = node_sw = 0;
202 	unit_sw_version = node_sw_version = node_hw_version =
203 	    module_sw_version = module_hw_version = 0;
204 
205 
206 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
207 	root_dir_len = CFGROM_DIR_LEN(root_dir);
208 
209 	for (i = 0; i < root_dir_len; i++) {
210 
211 		CFGROM_TYPE_KEY_VALUE(root_dir[i + 1], type, key, value);
212 		switch (key) {
213 
214 		case IEEE1212_MODULE_VENDOR_ID:
215 			module_vendor_id = value;
216 			mod_ven++;
217 			break;
218 		case IEEE1212_MODULE_HW_VERSION:
219 			module_hw_version = value;
220 			mod_hw++;
221 			break;
222 		case IEEE1212_MODULE_SPEC_ID:
223 			module_spec_id = value;
224 			mod_spec++;
225 			break;
226 		case IEEE1212_MODULE_SW_VERSION:
227 			module_sw_version = value;
228 			mod_sw++;
229 			break;
230 		case IEEE1212_NODE_VENDOR_ID:
231 			node_vendor_id = value;
232 			node_ven++;
233 			break;
234 		case IEEE1212_NODE_UNIQUE_ID: {
235 				uint32_t *node_unique_leaf =
236 				    &root_dir[i + 1] + value;
237 				node_vendor_id = (node_unique_leaf[1] >> 8);
238 				node_ven++;
239 			}
240 			break;
241 		case IEEE1212_NODE_HW_VERSION:
242 			node_hw_version = value;
243 			node_hw++;
244 			break;
245 		case IEEE1212_NODE_SPEC_ID:
246 			node_spec_id = value;
247 			node_spec++;
248 			break;
249 		case IEEE1212_NODE_SW_VERSION:
250 			node_sw_version = value;
251 			node_sw++;
252 			break;
253 		}
254 
255 		if (mod_ven && mod_hw && mod_spec && mod_sw && node_ven &&
256 		    node_hw && node_spec && node_sw) {
257 			break;
258 		}
259 	}
260 
261 	/*
262 	 * Search for unit spec and version
263 	 */
264 	for (i = 0; i < CFGROM_DIR_LEN(unit_dir); i++) {
265 
266 		CFGROM_TYPE_KEY_VALUE(unit_dir[i + 1], type, key, value);
267 		if (key == IEEE1212_UNIT_SPEC_ID) {
268 
269 			unit_spec_id = value;
270 			spec_id++;
271 		} else if (key == IEEE1212_UNIT_SW_VERSION) {
272 
273 			unit_sw_version = value;
274 			sw_version++;
275 		}
276 		if (spec_id && sw_version)
277 			break;
278 	}
279 
280 	/*
281 	 * Refer to IEEE1212 (pages 90-92) for information regarding various
282 	 * id's. Module_Vendor_Id is required. Node_Vendor_Id is optional and
283 	 * if not implemented, its assumed value is Module_Vendor_Id.
284 	 * Module_Spec_Id is optional and if not implemented, its assumed value
285 	 * is Module_Vendor_Id. Node_Spec_Id is optional, and if not
286 	 * implemented, its assumed value is Node_Vendor_Id. Unit_Spec_Id is
287 	 * optional, and if not implemented, its assumed value is
288 	 * Node_Vendor_Id.
289 	 */
290 	if (node_ven == 0) {
291 		node_vendor_id = module_vendor_id;
292 		node_ven++;
293 	}
294 
295 	if (node_spec == 0) {
296 		node_spec_id = node_vendor_id;
297 		node_spec++;
298 	}
299 
300 	if (mod_spec == 0) {
301 		module_spec_id = module_vendor_id;
302 		mod_spec++;
303 	}
304 
305 	if (spec_id == 0) {
306 		unit_spec_id = node_vendor_id;
307 		spec_id++;
308 	}
309 
310 	i = 0;
311 	if (sw_version != 0) {
312 		buf[i] = data[i];
313 		(void) sprintf(data[i++], fmt, unit_spec_id, unit_sw_version);
314 	}
315 	if (node_sw != 0) {
316 		buf[i] = data[i];
317 		(void) sprintf(data[i++], fmt, node_spec_id, node_sw_version);
318 	}
319 	if (node_hw != 0) {
320 		buf[i] = data[i];
321 		(void) sprintf(data[i++], fmt, node_vendor_id, node_hw_version);
322 	}
323 	if (mod_sw != 0) {
324 		buf[i] = data[i];
325 		(void) sprintf(data[i++], fmt, module_spec_id,
326 		    module_sw_version);
327 	}
328 	if (mod_hw != 0) {
329 		buf[i] = data[i];
330 		(void) sprintf(data[i++], fmt, module_vendor_id,
331 		    module_hw_version);
332 	}
333 
334 	result = ndi_prop_update_string_array(DDI_DEV_T_NONE, target_dip,
335 	    "compatible", (char **)&buf, i);
336 	if (result != NDI_SUCCESS) {
337 		cmn_err(CE_NOTE, "!Unable to add \"compatible\" property"
338 		    " (node's GUID %08x%08x)", node->node_guid_hi,
339 		    node->node_guid_lo);
340 #if defined(DEBUG)
341 		cmn_err(CE_CONT, "!Error code %d; nelements %d", result, i);
342 		for (j = 0; j < i; j++) {
343 			cmn_err(CE_CONT, "!buf[%d]: %s", j, buf[j]);
344 		}
345 #endif
346 		ndi_prop_remove_all(target_dip);
347 		(void) ndi_devi_free(target_dip);
348 		TNF_PROBE_4(s1394_create_devinfo_fail_compat,
349 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
350 		    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
351 		    tnf_int, error, result, tnf_int, nelements, i);
352 		TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
353 		    S1394_TNF_SL_HOTPLUG_STACK, "");
354 		return (NULL);
355 	}
356 
357 	for (j = 0; j < i; j++) {
358 		TNF_PROBE_2_DEBUG(s1394_create_devinfo_props,
359 		    S1394_TNF_SL_HOTPLUG_STACK, "",
360 		    tnf_int, compat_index, j,
361 		    tnf_string, compat_prop, buf[j]);
362 	}
363 
364 	/* GUID,ADDR */
365 	reg[0] = node->node_guid_hi;
366 	reg[1] = node->node_guid_lo;
367 	s1394_cfgrom_parse_unit_dir(unit_dir, &reg[2], &reg[3], &reg[4],
368 	    &reg[5]);
369 
370 	reg[3] = nunit;
371 
372 	result = ndi_prop_update_int_array(DDI_DEV_T_NONE, target_dip, "reg",
373 	    (int *)reg, 6);
374 	if (result != NDI_SUCCESS) {
375 		cmn_err(CE_NOTE, "!Unable to add \"reg\" property");
376 #if defined(DEBUG)
377 		cmn_err(CE_CONT, "!Error code %d", result);
378 		for (j = 0; j < 6; j++) {
379 			cmn_err(CE_CONT, "!reg[%d]: 0x%08x", j, reg[j]);
380 		}
381 #endif
382 		ndi_prop_remove_all(target_dip);
383 		(void) ndi_devi_free(target_dip);
384 		TNF_PROBE_3(s1394_create_devinfo_fail_reg,
385 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint, guid_hi,
386 		    node->node_guid_hi, tnf_uint, guid_lo, node->node_guid_lo,
387 		    tnf_int, error, result);
388 		TNF_PROBE_0_DEBUG(s1394_create_devinfo_exit,
389 		    S1394_TNF_SL_HOTPLUG_STACK, "");
390 		return (NULL);
391 	}
392 
393 	TNF_PROBE_1_DEBUG(s1394_create_devinfo_exit,
394 	    S1394_TNF_SL_HOTPLUG_STACK, "",
395 	    tnf_opaque, target_dip, target_dip);
396 
397 	return (target_dip);
398 }
399 
400 /*
401  * s1394_devi_find()
402  *    Searches all children of pdip for a match of name@caddr. Builds the
403  *    name and address of each child node by looking up the reg property on
404  *    the node and compares the built name@addr with the name@addr passed in.
405  *    Returns the child dip if a match is found, otherwise, returns NULL.
406  *    NOTE:
407  *    This routine is decidedly non-ddi. We had to use this one since
408  *    ndi_devi_find() can find only nodes that have valid addr field
409  *    set and that won't happen unless the node goes through INITCHILD
410  *    (at which time nx1394.c calls ddi_set_name_addr()). If, in future,
411  *    the ndi_devi_find() provides a way of looking up nodes using criteria
412  *    other than addr, we can get rid of this routine.
413  */
414 /*ARGSUSED*/
415 dev_info_t *
s1394_devi_find(dev_info_t * pdip,char * name,char * caddr)416 s1394_devi_find(dev_info_t *pdip, char *name, char *caddr)
417 {
418 	int i, reglen;
419 	char addr[32];
420 	uint32_t *regptr;
421 	dev_info_t *cdip = NULL;
422 
423 	ASSERT((name != NULL) && (caddr != NULL));
424 
425 	TNF_PROBE_1_DEBUG(s1394_devi_find_enter, S1394_TNF_SL_HOTPLUG_STACK,
426 	    "", tnf_string, addr, caddr);
427 
428 	/*
429 	 * for each child of this parent, find name and addr and match with
430 	 * name and caddr passed in.
431 	 */
432 	for (cdip = (dev_info_t *)DEVI(pdip)->devi_child; cdip != NULL;
433 	    cdip = (dev_info_t *)DEVI(cdip)->devi_sibling) {
434 
435 		i = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, cdip,
436 		    DDI_PROP_DONTPASS, "reg", (int **)&regptr,
437 		    (uint_t *)&reglen);
438 
439 		if (i != DDI_PROP_SUCCESS)
440 			continue;
441 
442 		/*
443 		 * Construct addr from the reg property (addr is of the format
444 		 * GGGGGGGGGGGGGGGG[,AAAAAAAAAAAA], where GGGGGGGGGGGGGGGG is
445 		 * the address and AAAAAAAAAAAA is the optional unit address)
446 		 */
447 		if (regptr[2] != 0 || regptr[3] != 0) {
448 			(void) sprintf(addr, "%08x%08x,%04x%08x", regptr[0],
449 			    regptr[1], regptr[2], regptr[3]);
450 		} else {
451 			(void) sprintf(addr, "%08x%08x", regptr[0], regptr[1]);
452 		}
453 		ddi_prop_free(regptr);
454 
455 		if (strcmp(caddr, addr) == 0) {
456 			ASSERT(strcmp(ddi_node_name(cdip), name) == 0);
457 			break;
458 		}
459 	}
460 
461 	if (cdip == NULL) {
462 		TNF_PROBE_1(s1394_devi_find_no_match,
463 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, addr, caddr);
464 	}
465 
466 	TNF_PROBE_0_DEBUG(s1394_devi_find_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
467 
468 	return (cdip);
469 }
470 
471 /*
472  * s1394_update_devinfo_tree()
473  *    Parses the config rom for the passed in node and creates/updates devinfo's
474  *    for each unit directory found. If the devinfo corresponding to a unit
475  *    already exists, any insert event callbacks registered for that devinfo
476  *    are called (topology tree is unlocked and relocked around these
477  *    callbacks). Returns DDI_SUCCESS if everything went fine and DDI_FAILURE
478  *    if unable to reacquire the lock after callbacks (relock fails because of
479  *    an intervening bus reset or if the services layer kills the bus reset
480  *    thread). The node is marked as parsed before returning.
481  */
482 int
s1394_update_devinfo_tree(s1394_hal_t * hal,s1394_node_t * node)483 s1394_update_devinfo_tree(s1394_hal_t *hal, s1394_node_t *node)
484 {
485 	dev_info_t *tdip;
486 	int j, units, d, lockfail = 0;
487 	s1394_target_t *target, *t;
488 	uint32_t hi, lo, size_hi, size_lo, type, key, value;
489 	uint32_t *ptr, *root_dir, dir_len;
490 	t1394_localinfo_t linfo;
491 
492 	uint32_t *unit_dir_ptrs[32];
493 	dev_info_t *devinfo_ptrs[32];
494 	uint32_t new_devinfo = 0;	/* to keep track of new allocations */
495 
496 	char caddr[32];
497 
498 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
499 
500 	ASSERT(CFGROM_PARSED(node) == B_FALSE);
501 	ASSERT(node->cfgrom != NULL);
502 
503 	TNF_PROBE_2_DEBUG(s1394_update_devinfo_tree_enter,
504 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num,
505 	    node->node_num, tnf_opaque, cfgrom, node->cfgrom);
506 
507 	/* scan through config rom looking for unit dirs */
508 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
509 
510 	if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
511 		dir_len = node->cfgrom_valid_size;
512 	else
513 		dir_len = CFGROM_DIR_LEN(root_dir);
514 
515 	CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
516 	if (s1394_valid_dir(hal, node, key, root_dir) == B_FALSE) {
517 		cmn_err(CE_NOTE,
518 		    "!Bad root directory in config rom (node's GUID %08x%08x)",
519 		    node->node_guid_hi, node->node_guid_lo);
520 
521 		TNF_PROBE_1_DEBUG(s1394_update_devinfo_tree_exit,
522 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_string, msg,
523 		    "bad directory");
524 
525 		SET_CFGROM_PARSED(node);
526 		CLEAR_CFGROM_GEN_CHANGED(node);	/* if set */
527 		CLEAR_CFGROM_NEW_ALLOC(node);
528 
529 		return (DDI_SUCCESS);
530 	}
531 
532 	for (units = 0, j = 1; j <= dir_len; j++) {
533 		CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
534 		if (key == IEEE1212_UNIT_DIRECTORY && type ==
535 		    IEEE1212_DIRECTORY_TYPE) {
536 			ptr = &root_dir[j] + value;
537 			if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
538 				unit_dir_ptrs[units++] = ptr;
539 			} else {
540 				cmn_err(CE_NOTE, "!Bad unit directory in config"
541 				    " rom (node's GUID %08x%08x)",
542 				    node->node_guid_hi, node->node_guid_lo);
543 				TNF_PROBE_2(s1394_update_devinfo_tree_bad_dir,
544 				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_uint,
545 				    guid_hi, node->node_guid_hi, tnf_uint,
546 				    guid_lo, node->node_guid_lo);
547 			}
548 		}
549 	}
550 
551 	for (d = 0, j = 0; j < units; j++) {
552 
553 		s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
554 		    &hi, &lo, &size_hi, &size_lo);
555 
556 		lo = j;
557 
558 		if (hi || lo) {
559 			(void) sprintf(caddr, "%08x%08x,%04x%08x",
560 			    node->node_guid_hi, node->node_guid_lo, hi, lo);
561 		} else {
562 			(void) sprintf(caddr, "%08x%08x",
563 			    node->node_guid_hi, node->node_guid_lo);
564 		}
565 
566 		tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr);
567 		if (tdip != NULL) {
568 
569 			rw_enter(&hal->target_list_rwlock, RW_WRITER);
570 			target = s1394_target_from_dip_locked(hal, tdip);
571 			if (target != NULL) {
572 				target->target_sibling = NULL;
573 				target->on_node = node;
574 				target->target_state &= ~S1394_TARG_GONE;
575 				target->unit_dir = unit_dir_ptrs[j] - root_dir;
576 
577 				if ((t = node->target_list) != NULL) {
578 					ASSERT(t != target);
579 					while (t->target_sibling != NULL) {
580 						t = t->target_sibling;
581 						ASSERT(t != target);
582 					}
583 					t->target_sibling = target;
584 				} else {
585 					node->target_list = target;
586 				}
587 
588 				target->target_list = node->target_list;
589 			}
590 			rw_exit(&hal->target_list_rwlock);
591 
592 			s1394_update_unit_dir_location(hal, tdip,
593 			    unit_dir_ptrs[j] - root_dir);
594 
595 		} else {
596 			/* create devinfo for unit@caddr */
597 			tdip = s1394_create_devinfo(hal, node,
598 			    unit_dir_ptrs[j], j);
599 			if (tdip != NULL) {
600 				new_devinfo |= (1 << d);
601 				s1394_update_unit_dir_location(hal, tdip,
602 				    unit_dir_ptrs[j] - root_dir);
603 			}
604 		}
605 		if (tdip != NULL)
606 			devinfo_ptrs[d++] = tdip;
607 	}
608 
609 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
610 	/* Online all valid units */
611 	for (j = 0; j < d; j++) {
612 		if ((new_devinfo & (1 << j)) == 0) {
613 			linfo.bus_generation = hal->generation_count;
614 			linfo.local_nodeID = hal->node_id;
615 		}
616 		/* don't need to drop topology_tree_mutex across ndi calls */
617 		(void) ndi_devi_online_async(devinfo_ptrs[j], 0);
618 		if ((new_devinfo & (1 << j)) == 0) {
619 			/*
620 			 * send an insert event if this an existing devinfo.
621 			 * drop and reacquire topology_tree_mutex across
622 			 * the event calls
623 			 */
624 			s1394_unlock_tree(hal);
625 			s1394_send_insert_event(hal, devinfo_ptrs[j], &linfo);
626 			if (s1394_lock_tree(hal) != DDI_SUCCESS) {
627 				TNF_PROBE_4(s1394_update_devinfo_tree_lock_fail,
628 				    S1394_TNF_SL_HOTPLUG_ERROR, "",
629 				    tnf_int, node_num, node->node_num,
630 				    tnf_opaque, cfgrom, node->cfgrom,
631 				    tnf_int, unit, j,
632 				    tnf_opaque, devinfo, devinfo_ptrs[j]);
633 				lockfail = 1;
634 				break;
635 			}
636 		}
637 	}
638 
639 	if (lockfail) {
640 		TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit,
641 		    S1394_TNF_SL_HOTPLUG_ERROR, "");
642 		return (DDI_FAILURE);
643 	}
644 
645 	SET_CFGROM_PARSED(node);
646 	CLEAR_CFGROM_GEN_CHANGED(node);	/* if set */
647 	CLEAR_CFGROM_NEW_ALLOC(node);
648 
649 	TNF_PROBE_0_DEBUG(s1394_update_devinfo_tree_exit,
650 	    S1394_TNF_SL_HOTPLUG_STACK, "");
651 
652 	return (DDI_SUCCESS);
653 }
654 
655 /*
656  * s1394_offline_node()
657  *    Offlines a node. This involves marking all targets attached to the
658  *    node as gone, invoking any remove event callbacks and calling
659  *    ndi_devi_offline to mark the devinfo as OFFLINE (for each unit
660  *    directory on the node). The tree is unlocked and relocked around
661  *    the callbacks. If unable to relock the tree, DDI_FAILURE, else
662  *    returns DDI_SUCCESS.
663  */
664 int
s1394_offline_node(s1394_hal_t * hal,s1394_node_t * node)665 s1394_offline_node(s1394_hal_t *hal, s1394_node_t *node)
666 {
667 	s1394_target_t *t;
668 	dev_info_t *tdip;
669 	int j, d, units;
670 	uint32_t *unit_dir_ptrs[32];
671 	dev_info_t *devinfo_ptrs[32];
672 	t1394_localinfo_t linfo;
673 	uint_t node_num;
674 	uint32_t *ptr, *root_dir, dir_len;
675 	uint32_t hi, lo, size_hi, size_lo, type, key, value;
676 	char caddr[32];
677 
678 	node_num = node->node_num;
679 
680 	TNF_PROBE_1_DEBUG(s1394_offline_node_enter, S1394_TNF_SL_HOTPLUG_STACK,
681 	    "", tnf_uint, node_num, node_num);
682 
683 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
684 
685 	d = 0;
686 	rw_enter(&hal->target_list_rwlock, RW_WRITER);
687 	t = node->target_list;
688 	while (t != NULL) {
689 		TNF_PROBE_2(s1394_process_old_tree_mark,
690 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num, node_num,
691 		    tnf_opaque, target, t);
692 		t->target_state |= S1394_TARG_GONE;
693 		t->on_node = NULL;
694 		t = t->target_sibling;
695 	}
696 	rw_exit(&hal->target_list_rwlock);
697 
698 	/* scan through config rom looking for unit dirs */
699 	root_dir = CFGROM_ROOT_DIR(node->cfgrom);
700 
701 	if (node->cfgrom_valid_size < CFGROM_DIR_LEN(root_dir))
702 		dir_len = node->cfgrom_valid_size;
703 	else
704 		dir_len = CFGROM_DIR_LEN(root_dir);
705 
706 	CFGROM_TYPE_KEY_VALUE(root_dir[0], type, key, value);
707 
708 	for (units = 0, j = 1; j <= dir_len; j++) {
709 		CFGROM_TYPE_KEY_VALUE(root_dir[j], type, key, value);
710 		if (key == IEEE1212_UNIT_DIRECTORY && type ==
711 		    IEEE1212_DIRECTORY_TYPE) {
712 			ptr = &root_dir[j] + value;
713 			if (s1394_valid_dir(hal, node, key, ptr) == B_TRUE) {
714 				unit_dir_ptrs[units++] = ptr;
715 			}
716 		}
717 	}
718 
719 	for (d = 0, j = 0; j < units; j++) {
720 
721 		s1394_cfgrom_parse_unit_dir(unit_dir_ptrs[j],
722 		    &hi, &lo, &size_hi, &size_lo);
723 
724 		lo = j;
725 
726 		if (hi || lo) {
727 			(void) sprintf(caddr, "%08x%08x,%04x%08x",
728 			    node->node_guid_hi, node->node_guid_lo, hi, lo);
729 		} else {
730 			(void) sprintf(caddr, "%08x%08x",
731 			    node->node_guid_hi, node->node_guid_lo);
732 		}
733 
734 		if ((tdip = s1394_devi_find(hal->halinfo.dip, "unit", caddr)) !=
735 		    NULL)
736 			devinfo_ptrs[d++] = tdip;
737 	}
738 
739 	node->old_node = NULL;
740 
741 	linfo.bus_generation = hal->generation_count;
742 	linfo.local_nodeID = hal->node_id;
743 
744 	for (j = 0; j < d; j++) {
745 		s1394_unlock_tree(hal);
746 
747 		TNF_PROBE_2(s1394_offline_node,
748 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, node_num, node_num,
749 		    tnf_opaque, devinfo, devinfo_ptrs[j]);
750 
751 		s1394_send_remove_event(hal, devinfo_ptrs[j], &linfo);
752 		(void) ndi_devi_offline(devinfo_ptrs[j], NDI_DEVI_REMOVE);
753 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
754 			TNF_PROBE_2(s1394_offline_node,
755 			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
756 			    "unlock to relock tree", tnf_uint, node_num,
757 			    node_num);
758 			TNF_PROBE_0_DEBUG(s1394_offline_node_exit,
759 			    S1394_TNF_SL_HOTPLUG_STACK, "");
760 			return (DDI_FAILURE);
761 		}
762 	}
763 
764 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
765 	TNF_PROBE_0_DEBUG(s1394_offline_node_exit, S1394_TNF_SL_HOTPLUG_STACK,
766 	    "");
767 	return (DDI_SUCCESS);
768 }
769 
770 /*
771  * s1394_process_topology_tree()
772  *    Walks the topology tree, processing each node. If node that has
773  *    already been parsed, updates the generation property on all devinfos
774  *    for the node. Also, if the node exists in both old & new trees, ASSERTS
775  *    that both point to the same config rom. If the node has valid config
776  *    rom but hasn't been parsed yet, calls s1394_update_devinfo_tree()
777  *    to parse and create devinfos for the node. Kicks off further config
778  *    rom reading if only the bus info block for the node is read.
779  *    Returns DDI_SUCCESS if everything went fine, else returns DDI_FAILURE
780  *    (for eg. unable to reacquire the tree lock etc). wait_for_cbs argument
781  *    tells the caller if some completions can be expected. wait_gen tells
782  *    the generation the commands were issued at.
783  */
784 int
s1394_process_topology_tree(s1394_hal_t * hal,int * wait_for_cbs,uint_t * wait_gen)785 s1394_process_topology_tree(s1394_hal_t *hal, int *wait_for_cbs,
786     uint_t *wait_gen)
787 {
788 	int i;
789 	uint_t hal_node_num, number_of_nodes;
790 	s1394_node_t *node, *onode;
791 	s1394_status_t status;
792 
793 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
794 
795 	TNF_PROBE_0_DEBUG(s1394_process_topology_tree_enter,
796 	    S1394_TNF_SL_HOTPLUG_STACK, "");
797 
798 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
799 		TNF_PROBE_0(s1394_process_topology_tree_lock_failed,
800 		    S1394_TNF_SL_HOTPLUG_ERROR, "");
801 		TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit,
802 		    S1394_TNF_SL_HOTPLUG_STACK, "");
803 		return (DDI_FAILURE);
804 	}
805 
806 	hal_node_num = IEEE1394_NODE_NUM(hal->node_id);
807 	hal->cfgroms_being_read = 0;
808 	number_of_nodes = hal->number_of_nodes;
809 	s1394_unlock_tree(hal);
810 
811 	for (i = 0; i < number_of_nodes; i++) {
812 
813 		if (i == hal_node_num)
814 			continue;
815 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
816 			return (DDI_FAILURE);
817 		}
818 		node = &hal->topology_tree[i];
819 
820 		TNF_PROBE_4_DEBUG(s1394_process_topology_tree,
821 		    S1394_TNF_SL_HOTPLUG_STACK, "",
822 		    tnf_int, node_num, i,
823 		    tnf_int, parsed, CFGROM_PARSED(node),
824 		    tnf_int, matched, NODE_MATCHED(node),
825 		    tnf_int, visited, NODE_VISITED(node));
826 
827 		if (LINK_ACTIVE(node) == B_FALSE) {
828 			s1394_unlock_tree(hal);
829 			continue;
830 		}
831 		if (node->cfgrom == NULL) {
832 			s1394_unlock_tree(hal);
833 			continue;
834 		}
835 
836 		onode = node->old_node;
837 
838 		if (onode != NULL && onode->cfgrom != NULL && node->cfgrom !=
839 		    NULL) {
840 			/*
841 			 * onode->cfgrom != node->cfgrom should have been
842 			 * handled by s1394_match_GUID()!!!
843 			 */
844 			if (onode->cfgrom != node->cfgrom)
845 				TNF_PROBE_5(s1394_process_topology_tree_err,
846 				    S1394_TNF_SL_HOTPLUG_ERROR, "",
847 				    tnf_int, node_num, i, tnf_int, gen_changed,
848 				    CFGROM_GEN_CHANGED(node), tnf_int, parsed,
849 				    CFGROM_PARSED(node), tnf_opaque, old_cfgrom,
850 				    onode->cfgrom, tnf_opaque, new_cfgrom,
851 				    node->cfgrom);
852 			ASSERT(onode->cfgrom == node->cfgrom);
853 		}
854 
855 		if (CFGROM_PARSED(node) == B_FALSE && CFGROM_ALL_READ(node) ==
856 		    B_TRUE) {
857 			ASSERT((node->cfgrom_size <
858 			    IEEE1394_CONFIG_ROM_QUAD_SZ) ||
859 			    NODE_MATCHED(node) == B_TRUE);
860 			rw_enter(&hal->target_list_rwlock, RW_READER);
861 			ASSERT(node->target_list == NULL);
862 			rw_exit(&hal->target_list_rwlock);
863 			if (s1394_update_devinfo_tree(hal, node) ==
864 			    DDI_FAILURE) {
865 				ASSERT(MUTEX_NOT_HELD(
866 				    &hal->topology_tree_mutex));
867 				TNF_PROBE_1(s1394_process_topology_tree,
868 				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
869 				    msg, "failure from update devinfo");
870 				TNF_PROBE_0_DEBUG(
871 				    s1394_process_topology_tree_exit,
872 				    S1394_TNF_SL_HOTPLUG_STACK, "");
873 				return (DDI_FAILURE);
874 			}
875 		} else if (CFGROM_PARSED(node) == B_FALSE && CFGROM_BIB_READ(
876 		    node) == B_TRUE) {
877 			if (s1394_read_rest_of_cfgrom(hal, node, &status) !=
878 			    DDI_SUCCESS) {
879 				TNF_PROBE_1(s1394_process_topology_tree,
880 				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
881 				    msg, "failure reading rest of cfgrom");
882 				if ((status & S1394_LOCK_FAILED) == 0) {
883 					ASSERT(MUTEX_HELD(&hal->
884 					    topology_tree_mutex));
885 					*wait_for_cbs = 0;
886 					s1394_unlock_tree(hal);
887 				}
888 				TNF_PROBE_0_DEBUG(
889 				    s1394_process_topology_tree_exit,
890 				    S1394_TNF_SL_HOTPLUG_STACK, "");
891 				return (DDI_FAILURE);
892 			} else {
893 				*wait_for_cbs = 1;
894 				*wait_gen = hal->br_cfgrom_read_gen;
895 			}
896 		}
897 
898 		s1394_unlock_tree(hal);
899 	}
900 
901 	/*
902 	 * flag the tree as processed; if a single bus reset happens after
903 	 * this, we will use tree matching.
904 	 */
905 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
906 		TNF_PROBE_1(s1394_process_topology_tree,
907 		    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
908 		    msg, "relock failed while marking tree processed");
909 		TNF_PROBE_0_DEBUG(s1394_process_topology_tree_exit,
910 		    S1394_TNF_SL_HOTPLUG_STACK, "");
911 		return (DDI_FAILURE);
912 	}
913 	hal->topology_tree_processed = B_TRUE;
914 	s1394_unlock_tree(hal);
915 
916 	TNF_PROBE_1_DEBUG(s1394_process_topology_tree_exit,
917 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int, hal_instance,
918 	    ddi_get_instance(hal->halinfo.dip));
919 
920 	return (DDI_SUCCESS);
921 }
922 
923 /*
924  * s1394_process_old_tree()
925  *    Walks through the old tree and offlines nodes that are removed. Nodes
926  *    with an active link in the old tree but link powered off in the current
927  *    generation are also offlined, as well as nodes with invalid config
928  *    rom in current generation.
929  *    The topology tree is locked/unlocked while walking through all the nodes;
930  *    if the locking fails at any stage, stops further walking and returns
931  *    DDI_FAILURE. Returns DDI_SUCCESS if everything went fine.
932  */
933 int
s1394_process_old_tree(s1394_hal_t * hal)934 s1394_process_old_tree(s1394_hal_t *hal)
935 {
936 	int i;
937 	uint_t hal_node_num_old, old_number_of_nodes;
938 	s1394_node_t *onode;
939 
940 	TNF_PROBE_0_DEBUG(s1394_process_old_tree_enter,
941 	    S1394_TNF_SL_HOTPLUG_STACK, "");
942 
943 	/*
944 	 * NODE_MATCHED(onode) == 0 indicates this node doesn't exist
945 	 * any more.
946 	 */
947 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
948 
949 	if (s1394_lock_tree(hal) != DDI_SUCCESS) {
950 		TNF_PROBE_0(s1394_process_old_tree_lock_failed,
951 		    S1394_TNF_SL_HOTPLUG_ERROR, "");
952 		TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
953 		    S1394_TNF_SL_HOTPLUG_STACK, "");
954 		return (DDI_FAILURE);
955 	}
956 	hal_node_num_old = IEEE1394_NODE_NUM(hal->old_node_id);
957 	old_number_of_nodes = hal->old_number_of_nodes;
958 	s1394_unlock_tree(hal);
959 
960 	for (i = 0; i < old_number_of_nodes; i++) {
961 
962 		if (i == hal_node_num_old)
963 			continue;
964 		if (s1394_lock_tree(hal) != DDI_SUCCESS) {
965 			TNF_PROBE_2(s1394_process_old_tree,
966 			    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
967 			    "lock failed while processing node", tnf_uint,
968 			    node_num, i);
969 			TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
970 			    S1394_TNF_SL_HOTPLUG_STACK, "");
971 			return (DDI_FAILURE);
972 		}
973 
974 		onode = &hal->old_tree[i];
975 
976 		if (onode->cfgrom == NULL) {
977 			CLEAR_CFGROM_STATE(onode);
978 			s1394_unlock_tree(hal);
979 			continue;
980 		}
981 
982 		TNF_PROBE_1_DEBUG(s1394_process_old_tree,
983 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_opaque,
984 		    cfgrom, onode->cfgrom);
985 
986 		TNF_PROBE_5_DEBUG(s1394_process_old_tree,
987 		    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_int,
988 		    node_num, i, tnf_int, parsed, CFGROM_PARSED(onode), tnf_int,
989 		    matched, NODE_MATCHED(onode), tnf_int, visited,
990 		    NODE_VISITED(onode), tnf_int, generation_changed,
991 		    CFGROM_GEN_CHANGED(onode));
992 
993 		/*
994 		 * onode->cur_node == NULL iff we couldn't read cfgrom in the
995 		 * current generation in non-tree matching case (and thus
996 		 * match_GUIDs couldn't set cur_node).
997 		 */
998 		if (NODE_MATCHED(onode) == B_FALSE || (onode->cur_node ==
999 		    NULL || ((CFGROM_VALID(onode) == B_TRUE &&
1000 		    CFGROM_VALID(onode->cur_node) == B_FALSE) ||
1001 		    (LINK_ACTIVE(onode) == B_TRUE && LINK_ACTIVE(onode->
1002 		    cur_node) == B_FALSE)))) {
1003 
1004 			if (onode->cur_node != NULL && CFGROM_VALID(onode) ==
1005 			    B_TRUE &&
1006 			    CFGROM_VALID(onode->cur_node) == B_FALSE) {
1007 				TNF_PROBE_1_DEBUG(
1008 				    s1394_process_old_tree_invalid_cfgrom,
1009 				    S1394_TNF_SL_HOTPLUG_STACK, "",
1010 				    tnf_int, node_num, i);
1011 			}
1012 			if (onode->cur_node != NULL && LINK_ACTIVE(onode) ==
1013 			    B_TRUE && LINK_ACTIVE(onode->cur_node) == B_FALSE) {
1014 				TNF_PROBE_1_DEBUG(
1015 				    s1394_process_old_tree_link_off,
1016 				    S1394_TNF_SL_HOTPLUG_STACK,
1017 				    "", tnf_int, node_num, i);
1018 			}
1019 			if (s1394_offline_node(hal, onode) != DDI_SUCCESS) {
1020 				TNF_PROBE_2(s1394_process_old_tree,
1021 				    S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string,
1022 				    msg, "failure from offline node", tnf_uint,
1023 				    node_num, i);
1024 				TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
1025 				    S1394_TNF_SL_HOTPLUG_STACK, "");
1026 				return (DDI_FAILURE);
1027 			}
1028 			s1394_free_cfgrom(hal, onode, S1394_FREE_CFGROM_OLD);
1029 		}
1030 
1031 		s1394_unlock_tree(hal);
1032 	}
1033 
1034 	ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
1035 
1036 	TNF_PROBE_0_DEBUG(s1394_process_old_tree_exit,
1037 	    S1394_TNF_SL_HOTPLUG_STACK, "");
1038 
1039 	return (DDI_SUCCESS);
1040 }
1041 
1042 /*
1043  * s1394_update_unit_dir_location()
1044  *    Updates the unit-dir-offset property on the devinfo.
1045  *    NOTE: ndi_prop_update_int() is interrupt callable (and thus won't block);
1046  *    so, the caller doesn't drop topology_tree_mutex when calling this routine.
1047  */
1048 /*ARGSUSED*/
1049 static void
s1394_update_unit_dir_location(s1394_hal_t * hal,dev_info_t * tdip,uint_t offset)1050 s1394_update_unit_dir_location(s1394_hal_t *hal, dev_info_t *tdip,
1051     uint_t offset)
1052 {
1053 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
1054 	ASSERT(tdip != NULL);
1055 
1056 	TNF_PROBE_1_DEBUG(s1394_update_unit_dir_location_enter,
1057 	    S1394_TNF_SL_HOTPLUG_STACK, "", tnf_uint, offset, offset);
1058 	(void) ndi_prop_update_int(DDI_DEV_T_NONE, tdip, "unit-dir-offset",
1059 	    offset);
1060 	TNF_PROBE_0_DEBUG(s1394_update_unit_dir_location_exit,
1061 	    S1394_TNF_SL_HOTPLUG_STACK, "");
1062 }
1063 
1064 /*
1065  * s1394_add_target_to_node()
1066  *    adds target to the list of targets hanging off the node. Figures out
1067  *    the node by searching the topology tree for the GUID corresponding
1068  *    to the target. Points on_node field of target structure at the node.
1069  */
1070 void
s1394_add_target_to_node(s1394_target_t * target)1071 s1394_add_target_to_node(s1394_target_t *target)
1072 {
1073 	s1394_target_t *t;
1074 	s1394_hal_t *hal;
1075 	uint32_t guid_hi;
1076 	uint32_t guid_lo;
1077 	int i;
1078 	char name[MAXNAMELEN];
1079 	char *ptr;
1080 
1081 	TNF_PROBE_0_DEBUG(s1394_add_target_to_node_enter,
1082 	    S1394_TNF_SL_HOTPLUG_STACK, "");
1083 
1084 	hal = target->on_hal;
1085 	ASSERT(hal != NULL);
1086 
1087 	/* Topology tree must be locked when it gets here! */
1088 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
1089 
1090 	/* target_list_rwlock should be held in write mode */
1091 	ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
1092 
1093 	if ((ptr = ddi_get_name_addr(target->target_dip)) == NULL) {
1094 		TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit_no_name,
1095 		    S1394_TNF_SL_HOTPLUG_STACK, "");
1096 		return;
1097 	}
1098 
1099 	(void) sprintf(name, ptr);
1100 	/* Drop the ,<ADDR> part, if present */
1101 	if ((ptr = strchr(name, ',')) != NULL)
1102 		*ptr = '\0';
1103 
1104 	ptr = name;
1105 	guid_hi = s1394_stoi(ptr, 8, 16);
1106 	guid_lo = s1394_stoi(ptr + 8, 8, 16);
1107 
1108 	/* Search the HAL's node list for this GUID */
1109 	for (i = 0; i < hal->number_of_nodes; i++) {
1110 		if (CFGROM_VALID(&hal->topology_tree[i]) == B_TRUE) {
1111 			ASSERT(hal->topology_tree[i].cfgrom != NULL);
1112 
1113 			if ((hal->topology_tree[i].node_guid_hi == guid_hi) &&
1114 			    (hal->topology_tree[i].node_guid_lo == guid_lo)) {
1115 				target->on_node = &hal->topology_tree[i];
1116 				if ((t = hal->topology_tree[i].target_list) !=
1117 				    NULL) {
1118 					ASSERT(t != target);
1119 					while (t->target_sibling != NULL) {
1120 						t = t->target_sibling;
1121 						ASSERT(t != target);
1122 					}
1123 					t->target_sibling = target;
1124 				} else {
1125 					hal->topology_tree[i].target_list =
1126 					    target;
1127 				}
1128 
1129 				/*
1130 				 * update target_list in all targets on the
1131 				 * node
1132 				 */
1133 				t = hal->topology_tree[i].target_list;
1134 				while (t != NULL) {
1135 					t->target_list =
1136 					    hal->topology_tree[i].target_list;
1137 					t = t->target_sibling;
1138 				}
1139 				break;
1140 			}
1141 		}
1142 	}
1143 
1144 	TNF_PROBE_0_DEBUG(s1394_add_target_to_node_exit,
1145 	    S1394_TNF_SL_HOTPLUG_STACK, "");
1146 }
1147 
1148 /*
1149  * s1394_remove_target_from_node()
1150  *    Removes target from the corresponding node's target_list.
1151  */
1152 void
s1394_remove_target_from_node(s1394_target_t * target)1153 s1394_remove_target_from_node(s1394_target_t *target)
1154 {
1155 	s1394_target_t *t, *t1;
1156 	s1394_hal_t *hal;
1157 
1158 	TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_enter,
1159 	    S1394_TNF_SL_HOTPLUG_STACK, "");
1160 
1161 	hal = target->on_hal;
1162 	ASSERT(hal != NULL);
1163 
1164 	/* Topology tree must be locked when it gets here! */
1165 	ASSERT(MUTEX_HELD(&hal->topology_tree_mutex));
1166 
1167 	/* target_list_rwlock should be held in write mode */
1168 	ASSERT(rw_read_locked(&target->on_hal->target_list_rwlock) == 0);
1169 
1170 	if (target->on_node == NULL) {
1171 		TNF_PROBE_1_DEBUG(s1394_remove_target_from_node_NULL,
1172 		    S1394_TNF_SL_HOTPLUG_STACK, "",
1173 		    tnf_uint, target_state, target->target_state);
1174 	}
1175 
1176 	t = target->target_list;
1177 	t1 = NULL;
1178 	while (t != NULL) {
1179 		if (t == target) {
1180 			if (t1 == NULL) {
1181 				target->target_list = t->target_sibling;
1182 			} else {
1183 				t1->target_sibling = t->target_sibling;
1184 			}
1185 			break;
1186 		}
1187 		t1 = t;
1188 		t = t->target_sibling;
1189 	}
1190 	/* Update the target_list pointer in all the targets */
1191 	if (target->on_node != NULL)
1192 		target->on_node->target_list = target->target_list;
1193 
1194 	t = t1 = target->target_list;
1195 	while (t != NULL) {
1196 		t->target_list = t1;
1197 		t = t->target_sibling;
1198 	}
1199 
1200 	target->on_node = NULL;
1201 	target->target_sibling = NULL;
1202 
1203 	TNF_PROBE_0_DEBUG(s1394_remove_target_from_node_exit,
1204 	    S1394_TNF_SL_HOTPLUG_STACK, "");
1205 }
1206