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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * Topology Nodes 28 * 29 * Topology nodes, tnode_t, are data structures containing per-FMRI 30 * information and are linked together to form the topology tree. 31 * Nodes are created during the enumeration process of topo_snap_hold() 32 * and destroyed during topo_snap_rele(). For the most part, tnode_t data 33 * is read-only and no lock protection is required. Nodes are 34 * held in place during tree walk functions. Tree walk functions 35 * may access node data safely without locks. The exception to this rule 36 * is data associated with node properties (topo_prop.c). Properties 37 * may change at anytime and are protected by a per-property locking 38 * strategy. 39 * 40 * Enumerator plugin modules may also safely access topology nodes within their 41 * scope of operation: the parent node passed into the enumeration op or those 42 * nodes created by the enumerator. Enumeration occurs only during 43 * topo_snap_hold() where a per-topo_hdl_t lock prevents multi-threaded access 44 * to the topology trees. 45 * 46 * Enumerator method operation functions may safely access and change topology 47 * node property data, and contruct or destroy child nodes for the node 48 * on which the operation applies. The method may also be called to destroy 49 * the node for which the method operation is called. This permits 50 * dynamic topology tree snapshots and partial enumerations for branches that 51 * may not be needed right away. 52 * 53 * Node Interfaces 54 * 55 * Nodes are created when an enumerator calls topo_node_bind(). Prior to 56 * calling topo_node_bind(), the enumerator should have reserved a range of 57 * node instances with topo_node_range_create(). topo_node_range_create() 58 * does not allocate any node resources but creates the infrastruture 59 * required for a fully populated topology level. This allows enumerators 60 * reading from a <scheme>-topology.xml file to parse the file for a range 61 * of resources before confirming the existence of a resource via a helper 62 * plugin. Only when the resource has been confirmed to exist should 63 * the node be bound. 64 * 65 * Node range and node linkage and unlinkage is performed during enumeration and 66 * method operations when it is safe to change node hash lists. Nodes and node 67 * ranges are deallocated when all references to the node have been released: 68 * last walk completes and topo_snap_rele() is called. 69 * 70 * Node Hash/Ranges 71 * 72 * Each parent node may have one or more ranges of child nodes. Each range 73 * is uniquely named and serves as a hash list of like sibling nodes with 74 * different instance numbers. A parent may have more than one node hash 75 * (child range). If that is the case, the hash lists are strung together to 76 * form sibling relationships between ranges. Hash/Ranges are sparsely 77 * populated with only nodes that have represented resources in the system. 78 * 79 * _________________ 80 * | | 81 * | tnode_t | ----------------------------- 82 * | tn_phash ---> | topo_nodehash_t | 83 * | (children)| | th_nodearr (instances)| 84 * ----------------- | ------------------- | 85 * | ---| 0 | 1 | ...| N | | 86 * | | ------------------- | ------------------- 87 * | | th_list (siblings) ----->| topo_nodehash_t | 88 * | | | ------------------- 89 * ---|------------------------- 90 * | 91 * v 92 * ----------- 93 * | tnode_t | 94 * ----------- 95 * 96 * Facility Nodes 97 * 98 * Facility nodes are always leaf nodes in the topology and represent a FMRI 99 * sensor or indicator facility for the path to which it is connected. 100 * Facility nodes are bound to the topology with topo_node_facbind() and 101 * unbound with topo_node_unbind(). 102 */ 103 104 #include <assert.h> 105 #include <pthread.h> 106 #include <strings.h> 107 #include <sys/fm/protocol.h> 108 #include <topo_alloc.h> 109 #include <topo_error.h> 110 #include <topo_list.h> 111 #include <topo_method.h> 112 #include <topo_subr.h> 113 #include <topo_tree.h> 114 115 static topo_pgroup_info_t protocol_pgroup = { 116 TOPO_PGROUP_PROTOCOL, 117 TOPO_STABILITY_PRIVATE, 118 TOPO_STABILITY_PRIVATE, 119 1 120 }; 121 122 static const topo_pgroup_info_t auth_pgroup = { 123 FM_FMRI_AUTHORITY, 124 TOPO_STABILITY_PRIVATE, 125 TOPO_STABILITY_PRIVATE, 126 1 127 }; 128 129 static void 130 topo_node_destroy(tnode_t *node) 131 { 132 int i; 133 tnode_t *pnode = node->tn_parent; 134 topo_nodehash_t *nhp; 135 topo_mod_t *hmod, *mod = node->tn_enum; 136 137 if (node == NULL) 138 return; 139 140 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "destroying node %s=%d\n", 141 topo_node_name(node), topo_node_instance(node)); 142 143 assert(node->tn_refs == 0); 144 145 /* 146 * If not a root node, remove this node from the parent's node hash 147 */ 148 149 if (!(node->tn_state & TOPO_NODE_ROOT)) { 150 topo_node_lock(pnode); 151 152 nhp = node->tn_phash; 153 for (i = 0; i < nhp->th_arrlen; i++) { 154 if (node == nhp->th_nodearr[i]) { 155 nhp->th_nodearr[i] = NULL; 156 157 /* 158 * Release hold on parent 159 */ 160 --pnode->tn_refs; 161 if (pnode->tn_refs == 0) 162 topo_node_destroy(pnode); 163 } 164 } 165 topo_node_unlock(pnode); 166 } 167 168 topo_node_unlock(node); 169 170 /* 171 * Allow enumerator to clean-up private data and then release 172 * ref count 173 */ 174 if (mod->tm_info->tmi_ops->tmo_release != NULL) 175 mod->tm_info->tmi_ops->tmo_release(mod, node); 176 177 topo_method_unregister_all(mod, node); 178 179 /* 180 * Destroy all node hash lists 181 */ 182 while ((nhp = topo_list_next(&node->tn_children)) != NULL) { 183 for (i = 0; i < nhp->th_arrlen; i++) { 184 assert(nhp->th_nodearr[i] == NULL); 185 } 186 hmod = nhp->th_enum; 187 topo_mod_strfree(hmod, nhp->th_name); 188 topo_mod_free(hmod, nhp->th_nodearr, 189 nhp->th_arrlen * sizeof (tnode_t *)); 190 topo_list_delete(&node->tn_children, nhp); 191 topo_mod_free(hmod, nhp, sizeof (topo_nodehash_t)); 192 topo_mod_rele(hmod); 193 } 194 195 /* 196 * Destroy all property data structures, free the node and release 197 * the module that created it 198 */ 199 topo_pgroup_destroy_all(node); 200 topo_mod_free(mod, node, sizeof (tnode_t)); 201 topo_mod_rele(mod); 202 } 203 204 void 205 topo_node_lock(tnode_t *node) 206 { 207 (void) pthread_mutex_lock(&node->tn_lock); 208 } 209 210 void 211 topo_node_unlock(tnode_t *node) 212 { 213 (void) pthread_mutex_unlock(&node->tn_lock); 214 } 215 216 void 217 topo_node_hold(tnode_t *node) 218 { 219 topo_node_lock(node); 220 ++node->tn_refs; 221 topo_node_unlock(node); 222 } 223 224 void 225 topo_node_rele(tnode_t *node) 226 { 227 topo_node_lock(node); 228 --node->tn_refs; 229 230 /* 231 * Ok to remove this node from the topo tree and destroy it 232 */ 233 if (node->tn_refs == 0) 234 topo_node_destroy(node); 235 else 236 topo_node_unlock(node); 237 } 238 239 char * 240 topo_node_name(tnode_t *node) 241 { 242 return (node->tn_name); 243 } 244 245 topo_instance_t 246 topo_node_instance(tnode_t *node) 247 { 248 return (node->tn_instance); 249 } 250 251 tnode_t * 252 topo_node_parent(tnode_t *node) 253 { 254 return (node->tn_parent); 255 } 256 257 int 258 topo_node_flags(tnode_t *node) 259 { 260 return (node->tn_fflags); 261 } 262 263 void 264 topo_node_setspecific(tnode_t *node, void *data) 265 { 266 node->tn_priv = data; 267 } 268 269 void * 270 topo_node_getspecific(tnode_t *node) 271 { 272 return (node->tn_priv); 273 } 274 275 static int 276 node_create_seterror(topo_mod_t *mod, tnode_t *pnode, topo_nodehash_t *nhp, 277 int err) 278 { 279 topo_node_unlock(pnode); 280 281 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to insert child:" 282 "%s\n", topo_strerror(err)); 283 284 if (nhp != NULL) { 285 if (nhp->th_name != NULL) 286 topo_mod_strfree(mod, nhp->th_name); 287 if (nhp->th_nodearr != NULL) { 288 topo_mod_free(mod, nhp->th_nodearr, 289 nhp->th_arrlen * sizeof (tnode_t *)); 290 } 291 topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); 292 } 293 294 return (topo_mod_seterrno(mod, err)); 295 } 296 297 int 298 topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 299 topo_instance_t min, topo_instance_t max) 300 { 301 topo_nodehash_t *nhp; 302 303 topo_node_lock(pnode); 304 305 assert((pnode->tn_state & TOPO_NODE_BOUND) || 306 (pnode->tn_state & TOPO_NODE_ROOT)); 307 308 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 309 nhp = topo_list_next(nhp)) { 310 if (strcmp(nhp->th_name, name) == 0) 311 return (node_create_seterror(mod, pnode, NULL, 312 EMOD_NODE_DUP)); 313 } 314 315 if (min < 0 || max < min) 316 return (node_create_seterror(mod, pnode, NULL, 317 EMOD_NODE_RANGE)); 318 319 if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL) 320 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 321 322 if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL) 323 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 324 325 nhp->th_arrlen = max - min + 1; 326 327 if ((nhp->th_nodearr = topo_mod_zalloc(mod, 328 nhp->th_arrlen * sizeof (tnode_t *))) == NULL) 329 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 330 331 nhp->th_range.tr_min = min; 332 nhp->th_range.tr_max = max; 333 nhp->th_enum = mod; 334 topo_mod_hold(mod); 335 336 /* 337 * Add these nodes to parent child list 338 */ 339 topo_list_append(&pnode->tn_children, nhp); 340 topo_node_unlock(pnode); 341 342 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 343 "created node range %s[%d-%d]\n", name, min, max); 344 345 return (0); 346 } 347 348 void 349 topo_node_range_destroy(tnode_t *pnode, const char *name) 350 { 351 int i; 352 topo_nodehash_t *nhp; 353 topo_mod_t *mod; 354 355 topo_node_lock(pnode); 356 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 357 nhp = topo_list_next(nhp)) { 358 if (strcmp(nhp->th_name, name) == 0) { 359 break; 360 } 361 } 362 363 if (nhp == NULL) { 364 topo_node_unlock(pnode); 365 return; 366 } 367 368 for (i = 0; i < nhp->th_arrlen; i++) 369 assert(nhp->th_nodearr[i] == NULL); 370 371 topo_list_delete(&pnode->tn_children, nhp); 372 topo_node_unlock(pnode); 373 374 mod = nhp->th_enum; 375 if (nhp->th_name != NULL) 376 topo_mod_strfree(mod, nhp->th_name); 377 if (nhp->th_nodearr != NULL) { 378 topo_mod_free(mod, nhp->th_nodearr, 379 nhp->th_arrlen * sizeof (tnode_t *)); 380 } 381 topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); 382 topo_mod_rele(mod); 383 384 } 385 386 tnode_t * 387 topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst) 388 { 389 int h; 390 tnode_t *node; 391 topo_nodehash_t *nhp; 392 393 topo_node_lock(pnode); 394 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 395 nhp = topo_list_next(nhp)) { 396 if (strcmp(nhp->th_name, name) == 0) { 397 398 if (inst > nhp->th_range.tr_max || 399 inst < nhp->th_range.tr_min) { 400 topo_node_unlock(pnode); 401 return (NULL); 402 } 403 404 h = topo_node_hash(nhp, inst); 405 node = nhp->th_nodearr[h]; 406 topo_node_unlock(pnode); 407 return (node); 408 } 409 } 410 topo_node_unlock(pnode); 411 412 return (NULL); 413 } 414 415 int 416 topo_node_hash(topo_nodehash_t *nhp, topo_instance_t inst) 417 { 418 return ((inst - nhp->th_range.tr_min) % nhp->th_arrlen); 419 } 420 421 static tnode_t * 422 node_bind_seterror(topo_mod_t *mod, tnode_t *pnode, tnode_t *node, 423 boolean_t pnode_locked, int err) 424 { 425 if (pnode_locked) 426 topo_node_unlock(pnode); 427 428 (void) topo_mod_seterrno(mod, err); 429 430 if (node == NULL) 431 return (NULL); 432 433 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to bind %s=%d: " 434 "%s\n", (node->tn_name != NULL ? node->tn_name : "unknown"), 435 node->tn_instance, topo_strerror(err)); 436 437 topo_node_lock(node); /* expected to be locked */ 438 topo_node_destroy(node); 439 440 return (NULL); 441 } 442 443 tnode_t * 444 topo_node_bind(topo_mod_t *mod, tnode_t *pnode, const char *name, 445 topo_instance_t inst, nvlist_t *fmri) 446 { 447 int h, err; 448 tnode_t *node; 449 topo_nodehash_t *nhp; 450 451 topo_node_lock(pnode); 452 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 453 nhp = topo_list_next(nhp)) { 454 if (strcmp(nhp->th_name, name) == 0) { 455 456 if (inst > nhp->th_range.tr_max || 457 inst < nhp->th_range.tr_min) 458 return (node_bind_seterror(mod, pnode, NULL, 459 B_TRUE, EMOD_NODE_RANGE)); 460 461 h = topo_node_hash(nhp, inst); 462 if (nhp->th_nodearr[h] != NULL) 463 return (node_bind_seterror(mod, pnode, NULL, 464 B_TRUE, EMOD_NODE_BOUND)); 465 else 466 break; 467 468 } 469 } 470 471 if (nhp == NULL) 472 return (node_bind_seterror(mod, pnode, NULL, B_TRUE, 473 EMOD_NODE_NOENT)); 474 475 if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) 476 return (node_bind_seterror(mod, pnode, NULL, B_TRUE, 477 EMOD_NOMEM)); 478 479 (void) pthread_mutex_init(&node->tn_lock, NULL); 480 481 node->tn_enum = mod; 482 node->tn_hdl = mod->tm_hdl; 483 node->tn_parent = pnode; 484 node->tn_name = nhp->th_name; 485 node->tn_instance = inst; 486 node->tn_phash = nhp; 487 node->tn_refs = 0; 488 489 /* Ref count module that bound this node */ 490 topo_mod_hold(mod); 491 492 if (fmri == NULL) 493 return (node_bind_seterror(mod, pnode, node, B_TRUE, 494 EMOD_NVL_INVAL)); 495 496 if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0) 497 return (node_bind_seterror(mod, pnode, node, B_TRUE, err)); 498 499 if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE, 500 TOPO_PROP_IMMUTABLE, fmri, &err) < 0) 501 return (node_bind_seterror(mod, pnode, node, B_TRUE, err)); 502 503 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 504 "node bound %s=%d/%s=%d\n", topo_node_name(pnode), 505 topo_node_instance(pnode), node->tn_name, node->tn_instance); 506 507 node->tn_state |= TOPO_NODE_BOUND; 508 509 topo_node_hold(node); 510 nhp->th_nodearr[h] = node; 511 ++pnode->tn_refs; 512 513 topo_node_unlock(pnode); 514 515 if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) { 516 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 517 FM_FMRI_AUTH_PRODUCT, &err); 518 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 519 FM_FMRI_AUTH_PRODUCT_SN, &err); 520 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 521 FM_FMRI_AUTH_CHASSIS, &err); 522 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 523 FM_FMRI_AUTH_SERVER, &err); 524 } 525 526 return (node); 527 } 528 529 tnode_t * 530 topo_node_facbind(topo_mod_t *mod, tnode_t *pnode, const char *name, 531 const char *type) 532 { 533 int h, err; 534 tnode_t *node; 535 topo_nodehash_t *nhp; 536 topo_instance_t inst = 0; 537 nvlist_t *pfmri, *fnvl; 538 539 /* 540 * Create a single entry range for this facility 541 */ 542 if (topo_node_range_create(mod, pnode, name, 0, 0) < 0) 543 return (NULL); /* mod errno set */ 544 545 topo_node_hold(pnode); 546 topo_node_lock(pnode); 547 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 548 nhp = topo_list_next(nhp)) { 549 if (strcmp(nhp->th_name, name) == 0) { 550 551 if (inst > nhp->th_range.tr_max || 552 inst < nhp->th_range.tr_min) { 553 topo_node_rele(pnode); 554 return (node_bind_seterror(mod, pnode, NULL, 555 B_TRUE, EMOD_NVL_INVAL)); 556 } 557 h = topo_node_hash(nhp, inst); 558 if (nhp->th_nodearr[h] != NULL) { 559 topo_node_rele(pnode); 560 return (node_bind_seterror(mod, pnode, NULL, 561 B_TRUE, EMOD_NODE_BOUND)); 562 } else 563 break; 564 565 } 566 } 567 topo_node_unlock(pnode); 568 569 if (nhp == NULL) { 570 topo_node_rele(pnode); 571 return (node_bind_seterror(mod, pnode, NULL, B_FALSE, 572 EMOD_NODE_NOENT)); 573 } 574 if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) { 575 topo_node_rele(pnode); 576 return (node_bind_seterror(mod, pnode, NULL, B_FALSE, 577 EMOD_NOMEM)); 578 } 579 580 (void) pthread_mutex_init(&node->tn_lock, NULL); 581 582 node->tn_enum = mod; 583 node->tn_hdl = mod->tm_hdl; 584 node->tn_parent = pnode; 585 node->tn_name = nhp->th_name; 586 node->tn_instance = inst; 587 node->tn_phash = nhp; 588 node->tn_refs = 0; 589 node->tn_fflags = TOPO_NODE_FACILITY; 590 591 /* Ref count module that bound this node */ 592 topo_mod_hold(mod); 593 594 if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0) { 595 topo_node_rele(pnode); 596 return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 597 } 598 if (topo_mod_nvalloc(mod, &fnvl, NV_UNIQUE_NAME) < 0) { 599 topo_node_rele(pnode); 600 return (node_bind_seterror(mod, pnode, node, B_FALSE, 601 EMOD_NOMEM)); 602 } 603 if (nvlist_add_string(fnvl, FM_FMRI_FACILITY_NAME, name) != 0 || 604 nvlist_add_string(fnvl, FM_FMRI_FACILITY_TYPE, type) != 0) { 605 nvlist_free(fnvl); 606 topo_node_rele(pnode); 607 return (node_bind_seterror(mod, pnode, node, B_FALSE, 608 EMOD_FMRI_NVL)); 609 } 610 611 if (topo_node_resource(pnode, &pfmri, &err) < 0) { 612 nvlist_free(fnvl); 613 topo_node_rele(pnode); 614 return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 615 } 616 617 if (nvlist_add_nvlist(pfmri, FM_FMRI_FACILITY, fnvl) != 0) { 618 nvlist_free(fnvl); 619 nvlist_free(pfmri); 620 topo_node_rele(pnode); 621 return (node_bind_seterror(mod, pnode, node, B_FALSE, 622 EMOD_FMRI_NVL)); 623 } 624 625 nvlist_free(fnvl); 626 627 if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE, 628 TOPO_PROP_IMMUTABLE, pfmri, &err) < 0) { 629 nvlist_free(pfmri); 630 topo_node_rele(pnode); 631 return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 632 } 633 634 nvlist_free(pfmri); 635 636 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 637 "facility node bound %s=%s\n", type, node->tn_name); 638 639 node->tn_state |= TOPO_NODE_BOUND; 640 641 topo_node_hold(node); 642 nhp->th_nodearr[h] = node; 643 644 topo_node_lock(pnode); 645 ++pnode->tn_refs; 646 topo_node_unlock(pnode); 647 topo_node_rele(pnode); 648 649 if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) { 650 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 651 FM_FMRI_AUTH_PRODUCT, &err); 652 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 653 FM_FMRI_AUTH_PRODUCT_SN, &err); 654 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 655 FM_FMRI_AUTH_CHASSIS, &err); 656 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 657 FM_FMRI_AUTH_SERVER, &err); 658 } 659 660 return (node); 661 } 662 663 int 664 topo_node_facility(topo_hdl_t *thp, tnode_t *node, const char *fac_type, 665 uint32_t fac_subtype, topo_faclist_t *faclist, int *errp) 666 { 667 tnode_t *tmp; 668 nvlist_t *rsrc, *fac; 669 char *tmp_factype; 670 uint32_t tmp_facsubtype; 671 boolean_t list_empty = 1; 672 topo_faclist_t *fac_ele; 673 674 bzero(faclist, sizeof (topo_faclist_t)); 675 for (tmp = topo_child_first(node); tmp != NULL; 676 tmp = topo_child_next(node, tmp)) { 677 678 topo_node_hold(tmp); 679 /* 680 * If it's not a facility node, move on 681 */ 682 if (topo_node_flags(tmp) != TOPO_NODE_FACILITY) { 683 topo_node_rele(tmp); 684 continue; 685 } 686 687 /* 688 * Lookup whether the fac type is sensor or indicator and if 689 * it's not the type we're looking for, move on 690 */ 691 if (topo_node_resource(tmp, &rsrc, errp) != 0) { 692 topo_dprintf(thp, TOPO_DBG_ERR, 693 "Failed to get resource for node %s=%d (%s)\n", 694 topo_node_name(node), topo_node_instance(node), 695 topo_strerror(*errp)); 696 topo_node_rele(tmp); 697 return (-1); 698 } 699 if ((nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0) || 700 (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE, 701 &tmp_factype) != 0)) { 702 703 nvlist_free(rsrc); 704 topo_node_rele(tmp); 705 return (-1); 706 } 707 708 if (strcmp(fac_type, tmp_factype) != 0) { 709 topo_node_rele(tmp); 710 nvlist_free(rsrc); 711 continue; 712 } 713 nvlist_free(rsrc); 714 715 /* 716 * Finally, look up the subtype, which is a property in the 717 * facility propgroup. If it's a match return a pointer to the 718 * node. Otherwise, move on. 719 */ 720 if (topo_prop_get_uint32(tmp, TOPO_PGROUP_FACILITY, 721 TOPO_FACILITY_TYPE, &tmp_facsubtype, errp) != 0) { 722 topo_node_rele(tmp); 723 return (-1); 724 } 725 if (fac_subtype == tmp_facsubtype || 726 fac_subtype == TOPO_FAC_TYPE_ANY) { 727 if ((fac_ele = topo_mod_zalloc(tmp->tn_enum, 728 sizeof (topo_faclist_t))) == NULL) { 729 *errp = ETOPO_NOMEM; 730 topo_node_rele(tmp); 731 return (-1); 732 } 733 fac_ele->tf_node = tmp; 734 topo_list_append(&faclist->tf_list, fac_ele); 735 list_empty = 0; 736 } 737 topo_node_rele(tmp); 738 } 739 740 if (list_empty) { 741 *errp = ETOPO_FAC_NOENT; 742 return (-1); 743 } 744 return (0); 745 } 746 747 void 748 topo_node_unbind(tnode_t *node) 749 { 750 if (node == NULL) 751 return; 752 753 topo_node_lock(node); 754 if (!(node->tn_state & TOPO_NODE_BOUND)) { 755 topo_node_unlock(node); 756 return; 757 } 758 759 node->tn_state &= ~TOPO_NODE_BOUND; 760 topo_node_unlock(node); 761 762 topo_dprintf(node->tn_hdl, TOPO_DBG_MODSVC, 763 "node unbound %s=%d/%s=%d refs = %d\n", 764 topo_node_name(node->tn_parent), 765 topo_node_instance(node->tn_parent), node->tn_name, 766 node->tn_instance, node->tn_refs); 767 768 topo_node_rele(node); 769 } 770 771 /*ARGSUSED*/ 772 int 773 topo_node_present(tnode_t *node) 774 { 775 return (0); 776 } 777 778 /*ARGSUSED*/ 779 int 780 topo_node_contains(tnode_t *er, tnode_t *ee) 781 { 782 return (0); 783 } 784 785 /*ARGSUSED*/ 786 int 787 topo_node_unusable(tnode_t *node) 788 { 789 return (0); 790 } 791 792 topo_walk_t * 793 topo_node_walk_init(topo_hdl_t *thp, topo_mod_t *mod, tnode_t *node, 794 int (*cb_f)(), void *pdata, int *errp) 795 { 796 tnode_t *child; 797 topo_walk_t *wp; 798 799 topo_node_hold(node); 800 801 if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) { 802 *errp = ETOPO_HDL_NOMEM; 803 topo_node_rele(node); 804 return (NULL); 805 } 806 807 /* 808 * If this is the root of the scheme tree, start with the first 809 * child 810 */ 811 topo_node_lock(node); 812 if (node->tn_state & TOPO_NODE_ROOT) { 813 if ((child = topo_child_first(node)) == NULL) { 814 /* Nothing to walk */ 815 *errp = ETOPO_WALK_EMPTY; 816 topo_node_unlock(node); 817 topo_node_rele(node); 818 topo_hdl_free(thp, wp, sizeof (topo_walk_t)); 819 return (NULL); 820 } 821 topo_node_unlock(node); 822 topo_node_hold(child); 823 wp->tw_node = child; 824 } else { 825 topo_node_unlock(node); 826 topo_node_hold(node); /* rele at walk end */ 827 wp->tw_node = node; 828 } 829 830 wp->tw_root = node; 831 wp->tw_cb = cb_f; 832 wp->tw_pdata = pdata; 833 wp->tw_thp = thp; 834 wp->tw_mod = mod; 835 836 return (wp); 837 } 838