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 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 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 * 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 * 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 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 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 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 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 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 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 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