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