dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / fm / topo / libtopo / common / topo_node.c
blob00b828c49c97e5b6f285c7ddacb1f1fc47fdf8c4
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Topology Nodes
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.
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.
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.
52 * Node Interfaces
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.
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.
69 * Node Hash/Ranges
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.
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 * -----------
95 * Facility Nodes
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().
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>
114 static topo_pgroup_info_t protocol_pgroup = {
115 TOPO_PGROUP_PROTOCOL,
116 TOPO_STABILITY_PRIVATE,
117 TOPO_STABILITY_PRIVATE,
121 static const topo_pgroup_info_t auth_pgroup = {
122 FM_FMRI_AUTHORITY,
123 TOPO_STABILITY_PRIVATE,
124 TOPO_STABILITY_PRIVATE,
128 static void
129 topo_node_destroy(tnode_t *node)
131 int i;
132 tnode_t *pnode = node->tn_parent;
133 topo_nodehash_t *nhp;
134 topo_mod_t *hmod, *mod = node->tn_enum;
136 if (node == NULL)
137 return;
139 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "destroying node %s=%d\n",
140 topo_node_name(node), topo_node_instance(node));
142 assert(node->tn_refs == 0);
145 * If not a root node, remove this node from the parent's node hash
148 if (!(node->tn_state & TOPO_NODE_ROOT)) {
149 topo_node_lock(pnode);
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;
157 * Release hold on parent
159 --pnode->tn_refs;
160 if (pnode->tn_refs == 0)
161 topo_node_destroy(pnode);
164 topo_node_unlock(pnode);
167 topo_node_unlock(node);
170 * Allow enumerator to clean-up private data and then release
171 * ref count
173 if (mod->tm_info->tmi_ops->tmo_release != NULL)
174 mod->tm_info->tmi_ops->tmo_release(mod, node);
176 topo_method_unregister_all(mod, node);
179 * Destroy all node hash lists
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);
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);
195 * Destroy all property data structures, free the node and release
196 * the module that created it
198 topo_pgroup_destroy_all(node);
199 topo_mod_free(mod, node, sizeof (tnode_t));
200 topo_mod_rele(mod);
203 void
204 topo_node_lock(tnode_t *node)
206 (void) pthread_mutex_lock(&node->tn_lock);
209 void
210 topo_node_unlock(tnode_t *node)
212 (void) pthread_mutex_unlock(&node->tn_lock);
215 void
216 topo_node_hold(tnode_t *node)
218 topo_node_lock(node);
219 ++node->tn_refs;
220 topo_node_unlock(node);
223 void
224 topo_node_rele(tnode_t *node)
226 topo_node_lock(node);
227 --node->tn_refs;
230 * Ok to remove this node from the topo tree and destroy it
232 if (node->tn_refs == 0)
233 topo_node_destroy(node);
234 else
235 topo_node_unlock(node);
238 char *
239 topo_node_name(tnode_t *node)
241 return (node->tn_name);
244 topo_instance_t
245 topo_node_instance(tnode_t *node)
247 return (node->tn_instance);
250 tnode_t *
251 topo_node_parent(tnode_t *node)
253 return (node->tn_parent);
257 topo_node_flags(tnode_t *node)
259 return (node->tn_fflags);
262 void
263 topo_node_setspecific(tnode_t *node, void *data)
265 node->tn_priv = data;
268 void *
269 topo_node_getspecific(tnode_t *node)
271 return (node->tn_priv);
274 static int
275 node_create_seterror(topo_mod_t *mod, tnode_t *pnode, topo_nodehash_t *nhp,
276 int err)
278 topo_node_unlock(pnode);
280 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to insert child:"
281 "%s\n", topo_strerror(err));
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 *));
290 topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
293 return (topo_mod_seterrno(mod, err));
297 topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
298 topo_instance_t min, topo_instance_t max)
300 topo_nodehash_t *nhp;
302 topo_node_lock(pnode);
304 assert((pnode->tn_state & TOPO_NODE_BOUND) ||
305 (pnode->tn_state & TOPO_NODE_ROOT));
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));
314 if (min < 0 || max < min)
315 return (node_create_seterror(mod, pnode, NULL,
316 EMOD_NODE_RANGE));
318 if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL)
319 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM));
321 if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL)
322 return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM));
324 nhp->th_arrlen = max - min + 1;
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));
330 nhp->th_range.tr_min = min;
331 nhp->th_range.tr_max = max;
332 nhp->th_enum = mod;
333 topo_mod_hold(mod);
336 * Add these nodes to parent child list
338 topo_list_append(&pnode->tn_children, nhp);
339 topo_node_unlock(pnode);
341 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
342 "created node range %s[%d-%d]\n", name, min, max);
344 return (0);
347 void
348 topo_node_range_destroy(tnode_t *pnode, const char *name)
350 int i;
351 topo_nodehash_t *nhp;
352 topo_mod_t *mod;
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;
362 if (nhp == NULL) {
363 topo_node_unlock(pnode);
364 return;
367 for (i = 0; i < nhp->th_arrlen; i++)
368 assert(nhp->th_nodearr[i] == NULL);
370 topo_list_delete(&pnode->tn_children, nhp);
371 topo_node_unlock(pnode);
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 *));
380 topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
381 topo_mod_rele(mod);
385 tnode_t *
386 topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst)
388 int h;
389 tnode_t *node;
390 topo_nodehash_t *nhp;
392 topo_dprintf(pnode->tn_hdl, TOPO_DBG_MODSVC,
393 "topo_node_lookup: looking for '%s' instance %d\n", name, inst);
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) {
400 if (inst > nhp->th_range.tr_max ||
401 inst < nhp->th_range.tr_min) {
402 topo_node_unlock(pnode);
403 return (NULL);
406 h = topo_node_hash(nhp, inst);
407 node = nhp->th_nodearr[h];
408 topo_node_unlock(pnode);
409 return (node);
412 topo_node_unlock(pnode);
414 return (NULL);
418 topo_node_hash(topo_nodehash_t *nhp, topo_instance_t inst)
420 return ((inst - nhp->th_range.tr_min) % nhp->th_arrlen);
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)
427 if (pnode_locked)
428 topo_node_unlock(pnode);
430 (void) topo_mod_seterrno(mod, err);
432 if (node == NULL)
433 return (NULL);
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));
439 topo_node_lock(node); /* expected to be locked */
440 topo_node_destroy(node);
442 return (NULL);
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)
449 int h, err;
450 tnode_t *node;
451 topo_nodehash_t *nhp;
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) {
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));
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;
473 if (nhp == NULL)
474 return (node_bind_seterror(mod, pnode, NULL, B_TRUE,
475 EMOD_NODE_NOENT));
477 if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL)
478 return (node_bind_seterror(mod, pnode, NULL, B_TRUE,
479 EMOD_NOMEM));
481 (void) pthread_mutex_init(&node->tn_lock, NULL);
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;
491 /* Ref count module that bound this node */
492 topo_mod_hold(mod);
494 if (fmri == NULL)
495 return (node_bind_seterror(mod, pnode, node, B_TRUE,
496 EMOD_NVL_INVAL));
498 if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0)
499 return (node_bind_seterror(mod, pnode, node, B_TRUE, err));
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));
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);
509 node->tn_state |= TOPO_NODE_BOUND;
511 topo_node_hold(node);
512 nhp->th_nodearr[h] = node;
513 ++pnode->tn_refs;
515 topo_node_unlock(pnode);
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);
528 return (node);
531 tnode_t *
532 topo_node_facbind(topo_mod_t *mod, tnode_t *pnode, const char *name,
533 const char *type)
535 int h, err;
536 tnode_t *node;
537 topo_nodehash_t *nhp;
538 topo_instance_t inst = 0;
539 nvlist_t *pfmri, *fnvl;
542 * Create a single entry range for this facility
544 if (topo_node_range_create(mod, pnode, name, 0, 0) < 0)
545 return (NULL); /* mod errno set */
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) {
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));
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;
569 topo_node_unlock(pnode);
571 if (nhp == NULL) {
572 topo_node_rele(pnode);
573 return (node_bind_seterror(mod, pnode, NULL, B_FALSE,
574 EMOD_NODE_NOENT));
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));
582 (void) pthread_mutex_init(&node->tn_lock, NULL);
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;
593 /* Ref count module that bound this node */
594 topo_mod_hold(mod);
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));
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));
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));
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));
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));
627 nvlist_free(fnvl);
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));
636 nvlist_free(pfmri);
638 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
639 "facility node bound %s=%s\n", type, node->tn_name);
641 node->tn_state |= TOPO_NODE_BOUND;
643 topo_node_hold(node);
644 nhp->th_nodearr[h] = node;
646 topo_node_lock(pnode);
647 ++pnode->tn_refs;
648 topo_node_unlock(pnode);
649 topo_node_rele(pnode);
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);
662 return (node);
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)
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;
676 bzero(faclist, sizeof (topo_faclist_t));
677 for (tmp = topo_child_first(node); tmp != NULL;
678 tmp = topo_child_next(node, tmp)) {
680 topo_node_hold(tmp);
682 * If it's not a facility node, move on
684 if (topo_node_flags(tmp) != TOPO_NODE_FACILITY) {
685 topo_node_rele(tmp);
686 continue;
690 * Lookup whether the fac type is sensor or indicator and if
691 * it's not the type we're looking for, move on
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);
701 if ((nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0) ||
702 (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE,
703 &tmp_factype) != 0)) {
705 nvlist_free(rsrc);
706 topo_node_rele(tmp);
707 return (-1);
710 if (strcmp(fac_type, tmp_factype) != 0) {
711 topo_node_rele(tmp);
712 nvlist_free(rsrc);
713 continue;
715 nvlist_free(rsrc);
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.
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);
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);
735 fac_ele->tf_node = tmp;
736 topo_list_append(&faclist->tf_list, fac_ele);
737 list_empty = 0;
739 topo_node_rele(tmp);
742 if (list_empty) {
743 *errp = ETOPO_FAC_NOENT;
744 return (-1);
746 return (0);
749 void
750 topo_node_unbind(tnode_t *node)
752 if (node == NULL)
753 return;
755 topo_node_lock(node);
756 if (!(node->tn_state & TOPO_NODE_BOUND)) {
757 topo_node_unlock(node);
758 return;
761 node->tn_state &= ~TOPO_NODE_BOUND;
762 topo_node_unlock(node);
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);
770 topo_node_rele(node);
773 /*ARGSUSED*/
775 topo_node_present(tnode_t *node)
777 return (0);
780 /*ARGSUSED*/
782 topo_node_contains(tnode_t *er, tnode_t *ee)
784 return (0);
787 /*ARGSUSED*/
789 topo_node_unusable(tnode_t *node)
791 return (0);
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)
798 tnode_t *child;
799 topo_walk_t *wp;
801 topo_node_hold(node);
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);
810 * If this is the root of the scheme tree, start with the first
811 * child
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);
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;
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;
838 return (wp);
842 * Walk the direct children of the given node.
845 topo_node_child_walk(topo_hdl_t *thp, tnode_t *pnode, topo_walk_cb_t cb_f,
846 void *arg, int *errp)
848 int ret = TOPO_WALK_TERMINATE;
849 tnode_t *cnode;
851 topo_node_hold(pnode);
854 * First Child:
856 topo_node_lock(pnode);
857 cnode = topo_child_first(pnode);
858 topo_node_unlock(pnode);
860 if (cnode == NULL) {
861 *errp = ETOPO_WALK_EMPTY;
862 ret = TOPO_WALK_ERR;
863 goto out;
866 while (cnode != NULL) {
867 int iret;
870 * Call the walker callback:
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;
881 * Next child:
883 topo_node_lock(pnode);
884 cnode = topo_child_next(pnode, cnode);
885 topo_node_unlock(pnode);
888 out:
889 topo_node_rele(pnode);
890 return (ret);