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