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, ®[2], ®[3], ®[4],
368 ®[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 **)®ptr,
437 (uint_t *)®len);
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