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