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