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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright (c) 2019, Joyent, Inc. All rights reserved. 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; 134 topo_nodehash_t *nhp; 135 topo_mod_t *hmod, *mod; 136 137 if (node == NULL) 138 return; 139 140 pnode = node->tn_parent; 141 mod = node->tn_enum; 142 143 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "destroying node %s=%d\n", 144 topo_node_name(node), topo_node_instance(node)); 145 146 assert(node->tn_refs == 0); 147 148 /* 149 * If not a root node, remove this node from the parent's node hash 150 */ 151 152 if (!(node->tn_state & TOPO_NODE_ROOT)) { 153 topo_node_lock(pnode); 154 155 nhp = node->tn_phash; 156 for (i = 0; i < nhp->th_arrlen; i++) { 157 if (node == nhp->th_nodearr[i]) { 158 nhp->th_nodearr[i] = NULL; 159 160 /* 161 * Release hold on parent 162 */ 163 --pnode->tn_refs; 164 if (pnode->tn_refs == 0) 165 topo_node_destroy(pnode); 166 } 167 } 168 topo_node_unlock(pnode); 169 } 170 171 topo_node_unlock(node); 172 173 /* 174 * Allow enumerator to clean-up private data and then release 175 * ref count 176 */ 177 if (mod->tm_info->tmi_ops->tmo_release != NULL) 178 mod->tm_info->tmi_ops->tmo_release(mod, node); 179 180 topo_method_unregister_all(mod, node); 181 182 /* 183 * Destroy all node hash lists 184 */ 185 while ((nhp = topo_list_next(&node->tn_children)) != NULL) { 186 for (i = 0; i < nhp->th_arrlen; i++) { 187 assert(nhp->th_nodearr[i] == NULL); 188 } 189 hmod = nhp->th_enum; 190 topo_mod_strfree(hmod, nhp->th_name); 191 topo_mod_free(hmod, nhp->th_nodearr, 192 nhp->th_arrlen * sizeof (tnode_t *)); 193 topo_list_delete(&node->tn_children, nhp); 194 topo_mod_free(hmod, nhp, sizeof (topo_nodehash_t)); 195 topo_mod_rele(hmod); 196 } 197 198 /* 199 * Destroy all property data structures, free the node and release 200 * the module that created it 201 */ 202 topo_pgroup_destroy_all(node); 203 topo_mod_free(mod, node, sizeof (tnode_t)); 204 topo_mod_rele(mod); 205 } 206 207 void 208 topo_node_lock(tnode_t *node) 209 { 210 (void) pthread_mutex_lock(&node->tn_lock); 211 } 212 213 void 214 topo_node_unlock(tnode_t *node) 215 { 216 (void) pthread_mutex_unlock(&node->tn_lock); 217 } 218 219 void 220 topo_node_hold(tnode_t *node) 221 { 222 topo_node_lock(node); 223 ++node->tn_refs; 224 topo_node_unlock(node); 225 } 226 227 void 228 topo_node_rele(tnode_t *node) 229 { 230 topo_node_lock(node); 231 --node->tn_refs; 232 233 /* 234 * Ok to remove this node from the topo tree and destroy it 235 */ 236 if (node->tn_refs == 0) 237 topo_node_destroy(node); 238 else 239 topo_node_unlock(node); 240 } 241 242 char * 243 topo_node_name(tnode_t *node) 244 { 245 return (node->tn_name); 246 } 247 248 topo_instance_t 249 topo_node_instance(tnode_t *node) 250 { 251 return (node->tn_instance); 252 } 253 254 tnode_t * 255 topo_node_parent(tnode_t *node) 256 { 257 return (node->tn_parent); 258 } 259 260 int 261 topo_node_flags(tnode_t *node) 262 { 263 return (node->tn_fflags); 264 } 265 266 void 267 topo_node_setspecific(tnode_t *node, void *data) 268 { 269 node->tn_priv = data; 270 } 271 272 void * 273 topo_node_getspecific(tnode_t *node) 274 { 275 return (node->tn_priv); 276 } 277 278 static int 279 node_create_seterror(topo_mod_t *mod, tnode_t *pnode, topo_nodehash_t *nhp, 280 int err) 281 { 282 topo_node_unlock(pnode); 283 284 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to insert child:" 285 "%s\n", topo_strerror(err)); 286 287 if (nhp != NULL) { 288 if (nhp->th_name != NULL) 289 topo_mod_strfree(mod, nhp->th_name); 290 if (nhp->th_nodearr != NULL) { 291 topo_mod_free(mod, nhp->th_nodearr, 292 nhp->th_arrlen * sizeof (tnode_t *)); 293 } 294 topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); 295 } 296 297 return (topo_mod_seterrno(mod, err)); 298 } 299 300 int 301 topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 302 topo_instance_t min, topo_instance_t max) 303 { 304 topo_nodehash_t *nhp; 305 306 topo_node_lock(pnode); 307 308 assert((pnode->tn_state & TOPO_NODE_BOUND) || 309 (pnode->tn_state & TOPO_NODE_ROOT)); 310 311 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 312 nhp = topo_list_next(nhp)) { 313 if (strcmp(nhp->th_name, name) == 0) 314 return (node_create_seterror(mod, pnode, NULL, 315 EMOD_NODE_DUP)); 316 } 317 318 if (min < 0 || max < min) 319 return (node_create_seterror(mod, pnode, NULL, 320 EMOD_NODE_RANGE)); 321 322 if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL) 323 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 324 325 if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL) 326 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 327 328 nhp->th_arrlen = max - min + 1; 329 330 if ((nhp->th_nodearr = topo_mod_zalloc(mod, 331 nhp->th_arrlen * sizeof (tnode_t *))) == NULL) 332 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 333 334 nhp->th_range.tr_min = min; 335 nhp->th_range.tr_max = max; 336 nhp->th_enum = mod; 337 topo_mod_hold(mod); 338 339 /* 340 * Add these nodes to parent child list 341 */ 342 topo_list_append(&pnode->tn_children, nhp); 343 topo_node_unlock(pnode); 344 345 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 346 "created node range %s[%d-%d]\n", name, min, max); 347 348 return (0); 349 } 350 351 void 352 topo_node_range_destroy(tnode_t *pnode, const char *name) 353 { 354 int i; 355 topo_nodehash_t *nhp; 356 topo_mod_t *mod; 357 358 topo_node_lock(pnode); 359 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 360 nhp = topo_list_next(nhp)) { 361 if (strcmp(nhp->th_name, name) == 0) { 362 break; 363 } 364 } 365 366 if (nhp == NULL) { 367 topo_node_unlock(pnode); 368 return; 369 } 370 371 for (i = 0; i < nhp->th_arrlen; i++) 372 assert(nhp->th_nodearr[i] == NULL); 373 374 topo_list_delete(&pnode->tn_children, nhp); 375 topo_node_unlock(pnode); 376 377 mod = nhp->th_enum; 378 if (nhp->th_name != NULL) 379 topo_mod_strfree(mod, nhp->th_name); 380 if (nhp->th_nodearr != NULL) { 381 topo_mod_free(mod, nhp->th_nodearr, 382 nhp->th_arrlen * sizeof (tnode_t *)); 383 } 384 topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); 385 topo_mod_rele(mod); 386 387 } 388 389 tnode_t * 390 topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst) 391 { 392 int h; 393 tnode_t *node; 394 topo_nodehash_t *nhp; 395 396 topo_dprintf(pnode->tn_hdl, TOPO_DBG_MODSVC, 397 "topo_node_lookup: looking for '%s' instance %d\n", name, inst); 398 399 topo_node_lock(pnode); 400 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 401 nhp = topo_list_next(nhp)) { 402 if (strcmp(nhp->th_name, name) == 0) { 403 404 if (inst > nhp->th_range.tr_max || 405 inst < nhp->th_range.tr_min) { 406 topo_node_unlock(pnode); 407 return (NULL); 408 } 409 410 h = topo_node_hash(nhp, inst); 411 node = nhp->th_nodearr[h]; 412 topo_node_unlock(pnode); 413 return (node); 414 } 415 } 416 topo_node_unlock(pnode); 417 418 return (NULL); 419 } 420 421 int 422 topo_node_hash(topo_nodehash_t *nhp, topo_instance_t inst) 423 { 424 return ((inst - nhp->th_range.tr_min) % nhp->th_arrlen); 425 } 426 427 static tnode_t * 428 node_bind_seterror(topo_mod_t *mod, tnode_t *pnode, tnode_t *node, 429 boolean_t pnode_locked, int err) 430 { 431 if (pnode_locked) 432 topo_node_unlock(pnode); 433 434 (void) topo_mod_seterrno(mod, err); 435 436 if (node == NULL) 437 return (NULL); 438 439 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to bind %s=%d: " 440 "%s\n", (node->tn_name != NULL ? node->tn_name : "unknown"), 441 node->tn_instance, topo_strerror(err)); 442 443 topo_node_lock(node); /* expected to be locked */ 444 topo_node_destroy(node); 445 446 return (NULL); 447 } 448 449 tnode_t * 450 topo_node_bind(topo_mod_t *mod, tnode_t *pnode, const char *name, 451 topo_instance_t inst, nvlist_t *fmri) 452 { 453 int h, err; 454 tnode_t *node; 455 topo_nodehash_t *nhp; 456 457 topo_node_lock(pnode); 458 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 459 nhp = topo_list_next(nhp)) { 460 if (strcmp(nhp->th_name, name) == 0) { 461 462 if (inst > nhp->th_range.tr_max || 463 inst < nhp->th_range.tr_min) 464 return (node_bind_seterror(mod, pnode, NULL, 465 B_TRUE, EMOD_NODE_RANGE)); 466 467 h = topo_node_hash(nhp, inst); 468 if (nhp->th_nodearr[h] != NULL) 469 return (node_bind_seterror(mod, pnode, NULL, 470 B_TRUE, EMOD_NODE_BOUND)); 471 else 472 break; 473 474 } 475 } 476 477 if (nhp == NULL) 478 return (node_bind_seterror(mod, pnode, NULL, B_TRUE, 479 EMOD_NODE_NOENT)); 480 481 if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) 482 return (node_bind_seterror(mod, pnode, NULL, B_TRUE, 483 EMOD_NOMEM)); 484 485 (void) pthread_mutex_init(&node->tn_lock, NULL); 486 487 node->tn_enum = mod; 488 node->tn_hdl = mod->tm_hdl; 489 node->tn_parent = pnode; 490 node->tn_name = nhp->th_name; 491 node->tn_instance = inst; 492 node->tn_phash = nhp; 493 node->tn_refs = 0; 494 495 /* Ref count module that bound this node */ 496 topo_mod_hold(mod); 497 498 if (fmri == NULL) 499 return (node_bind_seterror(mod, pnode, node, B_TRUE, 500 EMOD_NVL_INVAL)); 501 502 if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0) 503 return (node_bind_seterror(mod, pnode, node, B_TRUE, err)); 504 505 if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE, 506 TOPO_PROP_IMMUTABLE, fmri, &err) < 0) 507 return (node_bind_seterror(mod, pnode, node, B_TRUE, err)); 508 509 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 510 "node bound %s=%d/%s=%d\n", topo_node_name(pnode), 511 topo_node_instance(pnode), node->tn_name, node->tn_instance); 512 513 node->tn_state |= TOPO_NODE_BOUND; 514 515 topo_node_hold(node); 516 nhp->th_nodearr[h] = node; 517 ++pnode->tn_refs; 518 519 topo_node_unlock(pnode); 520 521 if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) { 522 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 523 FM_FMRI_AUTH_PRODUCT, &err); 524 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 525 FM_FMRI_AUTH_PRODUCT_SN, &err); 526 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 527 FM_FMRI_AUTH_CHASSIS, &err); 528 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 529 FM_FMRI_AUTH_SERVER, &err); 530 } 531 532 return (node); 533 } 534 535 tnode_t * 536 topo_node_facbind(topo_mod_t *mod, tnode_t *pnode, const char *name, 537 const char *type) 538 { 539 int h, err; 540 tnode_t *node; 541 topo_nodehash_t *nhp; 542 topo_instance_t inst = 0; 543 nvlist_t *pfmri, *fnvl; 544 545 /* 546 * Create a single entry range for this facility 547 */ 548 if (topo_node_range_create(mod, pnode, name, 0, 0) < 0) 549 return (NULL); /* mod errno set */ 550 551 topo_node_hold(pnode); 552 topo_node_lock(pnode); 553 for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 554 nhp = topo_list_next(nhp)) { 555 if (strcmp(nhp->th_name, name) == 0) { 556 557 if (inst > nhp->th_range.tr_max || 558 inst < nhp->th_range.tr_min) { 559 topo_node_rele(pnode); 560 return (node_bind_seterror(mod, pnode, NULL, 561 B_TRUE, EMOD_NVL_INVAL)); 562 } 563 h = topo_node_hash(nhp, inst); 564 if (nhp->th_nodearr[h] != NULL) { 565 topo_node_rele(pnode); 566 return (node_bind_seterror(mod, pnode, NULL, 567 B_TRUE, EMOD_NODE_BOUND)); 568 } else 569 break; 570 571 } 572 } 573 topo_node_unlock(pnode); 574 575 if (nhp == NULL) { 576 topo_node_rele(pnode); 577 return (node_bind_seterror(mod, pnode, NULL, B_FALSE, 578 EMOD_NODE_NOENT)); 579 } 580 if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) { 581 topo_node_rele(pnode); 582 return (node_bind_seterror(mod, pnode, NULL, B_FALSE, 583 EMOD_NOMEM)); 584 } 585 586 (void) pthread_mutex_init(&node->tn_lock, NULL); 587 588 node->tn_enum = mod; 589 node->tn_hdl = mod->tm_hdl; 590 node->tn_parent = pnode; 591 node->tn_name = nhp->th_name; 592 node->tn_instance = inst; 593 node->tn_phash = nhp; 594 node->tn_refs = 0; 595 node->tn_fflags = TOPO_NODE_FACILITY; 596 597 /* Ref count module that bound this node */ 598 topo_mod_hold(mod); 599 600 if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0) { 601 topo_node_rele(pnode); 602 return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 603 } 604 if (topo_mod_nvalloc(mod, &fnvl, NV_UNIQUE_NAME) < 0) { 605 topo_node_rele(pnode); 606 return (node_bind_seterror(mod, pnode, node, B_FALSE, 607 EMOD_NOMEM)); 608 } 609 if (nvlist_add_string(fnvl, FM_FMRI_FACILITY_NAME, name) != 0 || 610 nvlist_add_string(fnvl, FM_FMRI_FACILITY_TYPE, type) != 0) { 611 nvlist_free(fnvl); 612 topo_node_rele(pnode); 613 return (node_bind_seterror(mod, pnode, node, B_FALSE, 614 EMOD_FMRI_NVL)); 615 } 616 617 if (topo_node_resource(pnode, &pfmri, &err) < 0) { 618 nvlist_free(fnvl); 619 topo_node_rele(pnode); 620 return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 621 } 622 623 if (nvlist_add_nvlist(pfmri, FM_FMRI_FACILITY, fnvl) != 0) { 624 nvlist_free(fnvl); 625 nvlist_free(pfmri); 626 topo_node_rele(pnode); 627 return (node_bind_seterror(mod, pnode, node, B_FALSE, 628 EMOD_FMRI_NVL)); 629 } 630 631 nvlist_free(fnvl); 632 633 if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE, 634 TOPO_PROP_IMMUTABLE, pfmri, &err) < 0) { 635 nvlist_free(pfmri); 636 topo_node_rele(pnode); 637 return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 638 } 639 640 nvlist_free(pfmri); 641 642 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 643 "facility node bound %s=%s\n", type, node->tn_name); 644 645 node->tn_state |= TOPO_NODE_BOUND; 646 647 topo_node_hold(node); 648 nhp->th_nodearr[h] = node; 649 650 topo_node_lock(pnode); 651 ++pnode->tn_refs; 652 topo_node_unlock(pnode); 653 topo_node_rele(pnode); 654 655 if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) { 656 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 657 FM_FMRI_AUTH_PRODUCT, &err); 658 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 659 FM_FMRI_AUTH_PRODUCT_SN, &err); 660 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 661 FM_FMRI_AUTH_CHASSIS, &err); 662 (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 663 FM_FMRI_AUTH_SERVER, &err); 664 } 665 666 return (node); 667 } 668 669 int 670 topo_node_facility(topo_hdl_t *thp, tnode_t *node, const char *fac_type, 671 uint32_t fac_subtype, topo_faclist_t *faclist, int *errp) 672 { 673 tnode_t *tmp; 674 nvlist_t *rsrc, *fac; 675 char *tmp_factype; 676 uint32_t tmp_facsubtype; 677 boolean_t list_empty = 1; 678 topo_faclist_t *fac_ele; 679 680 bzero(faclist, sizeof (topo_faclist_t)); 681 for (tmp = topo_child_first(node); tmp != NULL; 682 tmp = topo_child_next(node, tmp)) { 683 684 topo_node_hold(tmp); 685 /* 686 * If it's not a facility node, move on 687 */ 688 if (topo_node_flags(tmp) != TOPO_NODE_FACILITY) { 689 topo_node_rele(tmp); 690 continue; 691 } 692 693 /* 694 * Lookup whether the fac type is sensor or indicator and if 695 * it's not the type we're looking for, move on 696 */ 697 if (topo_node_resource(tmp, &rsrc, errp) != 0) { 698 topo_dprintf(thp, TOPO_DBG_ERR, 699 "Failed to get resource for node %s=%d (%s)\n", 700 topo_node_name(node), topo_node_instance(node), 701 topo_strerror(*errp)); 702 topo_node_rele(tmp); 703 return (-1); 704 } 705 if ((nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0) || 706 (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE, 707 &tmp_factype) != 0)) { 708 709 nvlist_free(rsrc); 710 topo_node_rele(tmp); 711 return (-1); 712 } 713 714 if (strcmp(fac_type, tmp_factype) != 0) { 715 topo_node_rele(tmp); 716 nvlist_free(rsrc); 717 continue; 718 } 719 nvlist_free(rsrc); 720 721 /* 722 * Finally, look up the subtype, which is a property in the 723 * facility propgroup. If it's a match return a pointer to the 724 * node. Otherwise, move on. 725 */ 726 if (topo_prop_get_uint32(tmp, TOPO_PGROUP_FACILITY, 727 TOPO_FACILITY_TYPE, &tmp_facsubtype, errp) != 0) { 728 topo_node_rele(tmp); 729 return (-1); 730 } 731 if (fac_subtype == tmp_facsubtype || 732 fac_subtype == TOPO_FAC_TYPE_ANY) { 733 if ((fac_ele = topo_mod_zalloc(tmp->tn_enum, 734 sizeof (topo_faclist_t))) == NULL) { 735 *errp = ETOPO_NOMEM; 736 topo_node_rele(tmp); 737 return (-1); 738 } 739 fac_ele->tf_node = tmp; 740 topo_list_append(&faclist->tf_list, fac_ele); 741 list_empty = 0; 742 } 743 topo_node_rele(tmp); 744 } 745 746 if (list_empty) { 747 *errp = ETOPO_FAC_NOENT; 748 return (-1); 749 } 750 return (0); 751 } 752 753 void 754 topo_node_unbind(tnode_t *node) 755 { 756 if (node == NULL) 757 return; 758 759 topo_node_lock(node); 760 if (!(node->tn_state & TOPO_NODE_BOUND)) { 761 topo_node_unlock(node); 762 return; 763 } 764 765 node->tn_state &= ~TOPO_NODE_BOUND; 766 topo_node_unlock(node); 767 768 topo_dprintf(node->tn_hdl, TOPO_DBG_MODSVC, 769 "node unbound %s=%d/%s=%d refs = %d\n", 770 topo_node_name(node->tn_parent), 771 topo_node_instance(node->tn_parent), node->tn_name, 772 node->tn_instance, node->tn_refs); 773 774 topo_node_rele(node); 775 } 776 777 /*ARGSUSED*/ 778 int 779 topo_node_present(tnode_t *node) 780 { 781 return (0); 782 } 783 784 /*ARGSUSED*/ 785 int 786 topo_node_contains(tnode_t *er, tnode_t *ee) 787 { 788 return (0); 789 } 790 791 /*ARGSUSED*/ 792 int 793 topo_node_unusable(tnode_t *node) 794 { 795 return (0); 796 } 797 798 topo_walk_t * 799 topo_node_walk_init(topo_hdl_t *thp, topo_mod_t *mod, tnode_t *node, 800 int (*cb_f)(), void *pdata, int *errp) 801 { 802 tnode_t *child; 803 topo_walk_t *wp; 804 805 topo_node_hold(node); 806 807 if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) { 808 *errp = ETOPO_HDL_NOMEM; 809 topo_node_rele(node); 810 return (NULL); 811 } 812 813 /* 814 * If this is the root of the scheme tree, start with the first 815 * child 816 */ 817 topo_node_lock(node); 818 if (node->tn_state & TOPO_NODE_ROOT) { 819 if ((child = topo_child_first(node)) == NULL) { 820 /* Nothing to walk */ 821 *errp = ETOPO_WALK_EMPTY; 822 topo_node_unlock(node); 823 topo_node_rele(node); 824 topo_hdl_free(thp, wp, sizeof (topo_walk_t)); 825 return (NULL); 826 } 827 topo_node_unlock(node); 828 topo_node_hold(child); 829 wp->tw_node = child; 830 } else { 831 topo_node_unlock(node); 832 topo_node_hold(node); /* rele at walk end */ 833 wp->tw_node = node; 834 } 835 836 wp->tw_root = node; 837 wp->tw_cb = cb_f; 838 wp->tw_pdata = pdata; 839 wp->tw_thp = thp; 840 wp->tw_mod = mod; 841 842 return (wp); 843 } 844 845 /* 846 * Walk the direct children of the given node. 847 */ 848 int 849 topo_node_child_walk(topo_hdl_t *thp, tnode_t *pnode, topo_walk_cb_t cb_f, 850 void *arg, int *errp) 851 { 852 int ret = TOPO_WALK_TERMINATE; 853 tnode_t *cnode; 854 855 topo_node_hold(pnode); 856 857 /* 858 * First Child: 859 */ 860 topo_node_lock(pnode); 861 cnode = topo_child_first(pnode); 862 topo_node_unlock(pnode); 863 864 if (cnode == NULL) { 865 *errp = ETOPO_WALK_EMPTY; 866 ret = TOPO_WALK_ERR; 867 goto out; 868 } 869 870 while (cnode != NULL) { 871 int iret; 872 873 /* 874 * Call the walker callback: 875 */ 876 topo_node_hold(cnode); 877 iret = cb_f(thp, cnode, arg); 878 topo_node_rele(cnode); 879 if (iret != TOPO_WALK_NEXT) { 880 ret = iret; 881 break; 882 } 883 884 /* 885 * Next child: 886 */ 887 topo_node_lock(pnode); 888 cnode = topo_child_next(pnode, cnode); 889 topo_node_unlock(pnode); 890 } 891 892 out: 893 topo_node_rele(pnode); 894 return (ret); 895 } 896 897 int 898 topo_node_occupied(tnode_t *node, boolean_t *is_occupied) 899 { 900 nvlist_t *out; 901 int err; 902 903 if (topo_method_invoke(node, TOPO_METH_OCCUPIED, 904 TOPO_METH_OCCUPIED_VERSION, NULL, &out, &err) != 0) { 905 return (err); 906 } 907 (void) nvlist_lookup_boolean_value(out, TOPO_METH_OCCUPIED_RET, 908 is_occupied); 909 910 nvlist_free(out); 911 return (0); 912 } 913