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