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