17aec1d6eScindi /*
27aec1d6eScindi * CDDL HEADER START
37aec1d6eScindi *
47aec1d6eScindi * The contents of this file are subject to the terms of the
50eb822a1Scindi * Common Development and Distribution License (the "License").
60eb822a1Scindi * You may not use this file except in compliance with the License.
77aec1d6eScindi *
87aec1d6eScindi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97aec1d6eScindi * or http://www.opensolaris.org/os/licensing.
107aec1d6eScindi * See the License for the specific language governing permissions
117aec1d6eScindi * and limitations under the License.
127aec1d6eScindi *
137aec1d6eScindi * When distributing Covered Code, include this CDDL HEADER in each
147aec1d6eScindi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157aec1d6eScindi * If applicable, add the following below this CDDL HEADER, with the
167aec1d6eScindi * fields enclosed by brackets "[]" replaced with your own identifying
177aec1d6eScindi * information: Portions Copyright [yyyy] [name of copyright owner]
187aec1d6eScindi *
197aec1d6eScindi * CDDL HEADER END
207aec1d6eScindi */
217aec1d6eScindi /*
22f6e214c7SGavin Maltby * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
23*c5591576SRob Johnston * Copyright 2020 Joyent, Inc.
247aec1d6eScindi */
257aec1d6eScindi
267aec1d6eScindi /*
277aec1d6eScindi * Topology Nodes
287aec1d6eScindi *
297aec1d6eScindi * Topology nodes, tnode_t, are data structures containing per-FMRI
307aec1d6eScindi * information and are linked together to form the topology tree.
317aec1d6eScindi * Nodes are created during the enumeration process of topo_snap_hold()
327aec1d6eScindi * and destroyed during topo_snap_rele(). For the most part, tnode_t data
337aec1d6eScindi * is read-only and no lock protection is required. Nodes are
347aec1d6eScindi * held in place during tree walk functions. Tree walk functions
357aec1d6eScindi * may access node data safely without locks. The exception to this rule
367aec1d6eScindi * is data associated with node properties (topo_prop.c). Properties
377aec1d6eScindi * may change at anytime and are protected by a per-property locking
387aec1d6eScindi * strategy.
397aec1d6eScindi *
40c40d7343Scindi * Enumerator plugin modules may also safely access topology nodes within their
41c40d7343Scindi * scope of operation: the parent node passed into the enumeration op or those
42c40d7343Scindi * nodes created by the enumerator. Enumeration occurs only during
43c40d7343Scindi * topo_snap_hold() where a per-topo_hdl_t lock prevents multi-threaded access
44c40d7343Scindi * to the topology trees.
457aec1d6eScindi *
46c40d7343Scindi * Enumerator method operation functions may safely access and change topology
47c40d7343Scindi * node property data, and contruct or destroy child nodes for the node
48c40d7343Scindi * on which the operation applies. The method may also be called to destroy
49c40d7343Scindi * the node for which the method operation is called. This permits
50c40d7343Scindi * dynamic topology tree snapshots and partial enumerations for branches that
51c40d7343Scindi * may not be needed right away.
527aec1d6eScindi *
537aec1d6eScindi * Node Interfaces
547aec1d6eScindi *
55c40d7343Scindi * Nodes are created when an enumerator calls topo_node_bind(). Prior to
56c40d7343Scindi * calling topo_node_bind(), the enumerator should have reserved a range of
577aec1d6eScindi * node instances with topo_node_range_create(). topo_node_range_create()
587aec1d6eScindi * does not allocate any node resources but creates the infrastruture
597aec1d6eScindi * required for a fully populated topology level. This allows enumerators
607aec1d6eScindi * reading from a <scheme>-topology.xml file to parse the file for a range
617aec1d6eScindi * of resources before confirming the existence of a resource via a helper
627aec1d6eScindi * plugin. Only when the resource has been confirmed to exist should
637aec1d6eScindi * the node be bound.
647aec1d6eScindi *
65c40d7343Scindi * Node range and node linkage and unlinkage is performed during enumeration and
66c40d7343Scindi * method operations when it is safe to change node hash lists. Nodes and node
67c40d7343Scindi * ranges are deallocated when all references to the node have been released:
687aec1d6eScindi * last walk completes and topo_snap_rele() is called.
697aec1d6eScindi *
707aec1d6eScindi * Node Hash/Ranges
717aec1d6eScindi *
727aec1d6eScindi * Each parent node may have one or more ranges of child nodes. Each range
73c40d7343Scindi * is uniquely named and serves as a hash list of like sibling nodes with
747aec1d6eScindi * different instance numbers. A parent may have more than one node hash
757aec1d6eScindi * (child range). If that is the case, the hash lists are strung together to
767aec1d6eScindi * form sibling relationships between ranges. Hash/Ranges are sparsely
777aec1d6eScindi * populated with only nodes that have represented resources in the system.
78c40d7343Scindi *
79c40d7343Scindi * _________________
80c40d7343Scindi * | |
81c40d7343Scindi * | tnode_t | -----------------------------
82c40d7343Scindi * | tn_phash ---> | topo_nodehash_t |
83c40d7343Scindi * | (children)| | th_nodearr (instances)|
84c40d7343Scindi * ----------------- | ------------------- |
85c40d7343Scindi * | ---| 0 | 1 | ...| N | |
86c40d7343Scindi * | | ------------------- | -------------------
87c40d7343Scindi * | | th_list (siblings) ----->| topo_nodehash_t |
88c40d7343Scindi * | | | -------------------
89c40d7343Scindi * ---|-------------------------
90c40d7343Scindi * |
91c40d7343Scindi * v
92c40d7343Scindi * -----------
93c40d7343Scindi * | tnode_t |
94c40d7343Scindi * -----------
95825ba0f2Srobj *
96825ba0f2Srobj * Facility Nodes
97825ba0f2Srobj *
98825ba0f2Srobj * Facility nodes are always leaf nodes in the topology and represent a FMRI
99825ba0f2Srobj * sensor or indicator facility for the path to which it is connected.
100825ba0f2Srobj * Facility nodes are bound to the topology with topo_node_facbind() and
101825ba0f2Srobj * unbound with topo_node_unbind().
1027aec1d6eScindi */
1037aec1d6eScindi
1047aec1d6eScindi #include <assert.h>
1057aec1d6eScindi #include <pthread.h>
1067aec1d6eScindi #include <strings.h>
1070eb822a1Scindi #include <sys/fm/protocol.h>
1087aec1d6eScindi #include <topo_alloc.h>
1097aec1d6eScindi #include <topo_error.h>
110825ba0f2Srobj #include <topo_list.h>
1110eb822a1Scindi #include <topo_method.h>
1120eb822a1Scindi #include <topo_subr.h>
1130eb822a1Scindi #include <topo_tree.h>
1140eb822a1Scindi
1150eb822a1Scindi static topo_pgroup_info_t protocol_pgroup = {
1160eb822a1Scindi TOPO_PGROUP_PROTOCOL,
1170eb822a1Scindi TOPO_STABILITY_PRIVATE,
1180eb822a1Scindi TOPO_STABILITY_PRIVATE,
1190eb822a1Scindi 1
1200eb822a1Scindi };
1210eb822a1Scindi
1220eb822a1Scindi static const topo_pgroup_info_t auth_pgroup = {
1230eb822a1Scindi FM_FMRI_AUTHORITY,
1240eb822a1Scindi TOPO_STABILITY_PRIVATE,
1250eb822a1Scindi TOPO_STABILITY_PRIVATE,
1260eb822a1Scindi 1
1270eb822a1Scindi };
1287aec1d6eScindi
1297aec1d6eScindi static void
topo_node_destroy(tnode_t * node)1307aec1d6eScindi topo_node_destroy(tnode_t *node)
1317aec1d6eScindi {
1327aec1d6eScindi int i;
1331e95bfe1SRob Johnston tnode_t *pnode;
1347aec1d6eScindi topo_nodehash_t *nhp;
1351e95bfe1SRob Johnston topo_mod_t *hmod, *mod;
1367aec1d6eScindi
1377aec1d6eScindi if (node == NULL)
1387aec1d6eScindi return;
1397aec1d6eScindi
1401e95bfe1SRob Johnston pnode = node->tn_parent;
1411e95bfe1SRob Johnston mod = node->tn_enum;
1421e95bfe1SRob Johnston
14312cc75c8Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "destroying node %s=%d\n",
14412cc75c8Scindi topo_node_name(node), topo_node_instance(node));
14512cc75c8Scindi
1467aec1d6eScindi assert(node->tn_refs == 0);
1477aec1d6eScindi
1487aec1d6eScindi /*
1497aec1d6eScindi * If not a root node, remove this node from the parent's node hash
1507aec1d6eScindi */
1517aec1d6eScindi
1527aec1d6eScindi if (!(node->tn_state & TOPO_NODE_ROOT)) {
1537aec1d6eScindi topo_node_lock(pnode);
1547aec1d6eScindi
1557aec1d6eScindi nhp = node->tn_phash;
1567aec1d6eScindi for (i = 0; i < nhp->th_arrlen; i++) {
1577aec1d6eScindi if (node == nhp->th_nodearr[i]) {
1587aec1d6eScindi nhp->th_nodearr[i] = NULL;
1597aec1d6eScindi
1607aec1d6eScindi /*
1617aec1d6eScindi * Release hold on parent
1627aec1d6eScindi */
1637aec1d6eScindi --pnode->tn_refs;
1647aec1d6eScindi if (pnode->tn_refs == 0)
1657aec1d6eScindi topo_node_destroy(pnode);
1667aec1d6eScindi }
1677aec1d6eScindi }
1687aec1d6eScindi topo_node_unlock(pnode);
1697aec1d6eScindi }
1707aec1d6eScindi
1717aec1d6eScindi topo_node_unlock(node);
1727aec1d6eScindi
1737aec1d6eScindi /*
1747aec1d6eScindi * Allow enumerator to clean-up private data and then release
1757aec1d6eScindi * ref count
1767aec1d6eScindi */
1770eb822a1Scindi if (mod->tm_info->tmi_ops->tmo_release != NULL)
1780eb822a1Scindi mod->tm_info->tmi_ops->tmo_release(mod, node);
1797aec1d6eScindi
1807aec1d6eScindi topo_method_unregister_all(mod, node);
1817aec1d6eScindi
1827aec1d6eScindi /*
1837aec1d6eScindi * Destroy all node hash lists
1847aec1d6eScindi */
1857aec1d6eScindi while ((nhp = topo_list_next(&node->tn_children)) != NULL) {
1867aec1d6eScindi for (i = 0; i < nhp->th_arrlen; i++) {
1877aec1d6eScindi assert(nhp->th_nodearr[i] == NULL);
1887aec1d6eScindi }
1897aec1d6eScindi hmod = nhp->th_enum;
1907aec1d6eScindi topo_mod_strfree(hmod, nhp->th_name);
1917aec1d6eScindi topo_mod_free(hmod, nhp->th_nodearr,
1927aec1d6eScindi nhp->th_arrlen * sizeof (tnode_t *));
1937aec1d6eScindi topo_list_delete(&node->tn_children, nhp);
1947aec1d6eScindi topo_mod_free(hmod, nhp, sizeof (topo_nodehash_t));
1957aec1d6eScindi topo_mod_rele(hmod);
1967aec1d6eScindi }
1977aec1d6eScindi
198*c5591576SRob Johnston /*
199*c5591576SRob Johnston * Nodes in a directed graph structure have no children, so the node
200*c5591576SRob Johnston * name is still intact. We must free it now.
201*c5591576SRob Johnston */
202*c5591576SRob Johnston if (node->tn_vtx != NULL) {
203*c5591576SRob Johnston topo_mod_strfree(mod, node->tn_name);
204*c5591576SRob Johnston }
205*c5591576SRob Johnston
2067aec1d6eScindi /*
2077aec1d6eScindi * Destroy all property data structures, free the node and release
2087aec1d6eScindi * the module that created it
2097aec1d6eScindi */
2107aec1d6eScindi topo_pgroup_destroy_all(node);
2117aec1d6eScindi topo_mod_free(mod, node, sizeof (tnode_t));
2127aec1d6eScindi topo_mod_rele(mod);
2137aec1d6eScindi }
2147aec1d6eScindi
2157aec1d6eScindi void
topo_node_lock(tnode_t * node)2167aec1d6eScindi topo_node_lock(tnode_t *node)
2177aec1d6eScindi {
2187aec1d6eScindi (void) pthread_mutex_lock(&node->tn_lock);
2197aec1d6eScindi }
2207aec1d6eScindi
2217aec1d6eScindi void
topo_node_unlock(tnode_t * node)2227aec1d6eScindi topo_node_unlock(tnode_t *node)
2237aec1d6eScindi {
2247aec1d6eScindi (void) pthread_mutex_unlock(&node->tn_lock);
2257aec1d6eScindi }
2267aec1d6eScindi
2277aec1d6eScindi void
topo_node_hold(tnode_t * node)2287aec1d6eScindi topo_node_hold(tnode_t *node)
2297aec1d6eScindi {
2307aec1d6eScindi topo_node_lock(node);
2317aec1d6eScindi ++node->tn_refs;
2327aec1d6eScindi topo_node_unlock(node);
2337aec1d6eScindi }
2347aec1d6eScindi
2357aec1d6eScindi void
topo_node_rele(tnode_t * node)2367aec1d6eScindi topo_node_rele(tnode_t *node)
2377aec1d6eScindi {
2387aec1d6eScindi topo_node_lock(node);
2397aec1d6eScindi --node->tn_refs;
2407aec1d6eScindi
2417aec1d6eScindi /*
2427aec1d6eScindi * Ok to remove this node from the topo tree and destroy it
2437aec1d6eScindi */
2447aec1d6eScindi if (node->tn_refs == 0)
2457aec1d6eScindi topo_node_destroy(node);
2467aec1d6eScindi else
2477aec1d6eScindi topo_node_unlock(node);
2487aec1d6eScindi }
2497aec1d6eScindi
2507aec1d6eScindi char *
topo_node_name(tnode_t * node)2517aec1d6eScindi topo_node_name(tnode_t *node)
2527aec1d6eScindi {
2537aec1d6eScindi return (node->tn_name);
2547aec1d6eScindi }
2557aec1d6eScindi
2567aec1d6eScindi topo_instance_t
topo_node_instance(tnode_t * node)2577aec1d6eScindi topo_node_instance(tnode_t *node)
2587aec1d6eScindi {
2597aec1d6eScindi return (node->tn_instance);
2607aec1d6eScindi }
2617aec1d6eScindi
2624557a2a1Srobj tnode_t *
topo_node_parent(tnode_t * node)2634557a2a1Srobj topo_node_parent(tnode_t *node)
2644557a2a1Srobj {
2654557a2a1Srobj return (node->tn_parent);
2664557a2a1Srobj }
2674557a2a1Srobj
268*c5591576SRob Johnston topo_vertex_t *
topo_node_vertex(tnode_t * node)269*c5591576SRob Johnston topo_node_vertex(tnode_t *node)
270*c5591576SRob Johnston {
271*c5591576SRob Johnston return (node->tn_vtx);
272*c5591576SRob Johnston }
273*c5591576SRob Johnston
274825ba0f2Srobj int
topo_node_flags(tnode_t * node)275825ba0f2Srobj topo_node_flags(tnode_t *node)
276825ba0f2Srobj {
277825ba0f2Srobj return (node->tn_fflags);
278825ba0f2Srobj }
279825ba0f2Srobj
2800eb822a1Scindi void
topo_node_setspecific(tnode_t * node,void * data)2810eb822a1Scindi topo_node_setspecific(tnode_t *node, void *data)
2820eb822a1Scindi {
2830eb822a1Scindi node->tn_priv = data;
2840eb822a1Scindi }
2850eb822a1Scindi
2867aec1d6eScindi void *
topo_node_getspecific(tnode_t * node)2870eb822a1Scindi topo_node_getspecific(tnode_t *node)
2887aec1d6eScindi {
2897aec1d6eScindi return (node->tn_priv);
2907aec1d6eScindi }
2917aec1d6eScindi
2927aec1d6eScindi static int
node_create_seterror(topo_mod_t * mod,tnode_t * pnode,topo_nodehash_t * nhp,int err)2937aec1d6eScindi node_create_seterror(topo_mod_t *mod, tnode_t *pnode, topo_nodehash_t *nhp,
2947aec1d6eScindi int err)
2957aec1d6eScindi {
2967aec1d6eScindi topo_node_unlock(pnode);
2977aec1d6eScindi
2980eb822a1Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to insert child:"
2997aec1d6eScindi "%s\n", topo_strerror(err));
3007aec1d6eScindi
3017aec1d6eScindi if (nhp != NULL) {
3027aec1d6eScindi if (nhp->th_name != NULL)
3037aec1d6eScindi topo_mod_strfree(mod, nhp->th_name);
3047aec1d6eScindi if (nhp->th_nodearr != NULL) {
3057aec1d6eScindi topo_mod_free(mod, nhp->th_nodearr,
3067aec1d6eScindi nhp->th_arrlen * sizeof (tnode_t *));
3077aec1d6eScindi }
3087aec1d6eScindi topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
3097aec1d6eScindi }
3107aec1d6eScindi
3117aec1d6eScindi return (topo_mod_seterrno(mod, err));
3127aec1d6eScindi }
3137aec1d6eScindi
3147aec1d6eScindi int
topo_node_range_create(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t min,topo_instance_t max)3157aec1d6eScindi topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
3167aec1d6eScindi topo_instance_t min, topo_instance_t max)
3177aec1d6eScindi {
3187aec1d6eScindi topo_nodehash_t *nhp;
3197aec1d6eScindi
3207aec1d6eScindi topo_node_lock(pnode);
3217aec1d6eScindi
3227aec1d6eScindi assert((pnode->tn_state & TOPO_NODE_BOUND) ||
3237aec1d6eScindi (pnode->tn_state & TOPO_NODE_ROOT));
3247aec1d6eScindi
3257aec1d6eScindi for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
3267aec1d6eScindi nhp = topo_list_next(nhp)) {
3277aec1d6eScindi if (strcmp(nhp->th_name, name) == 0)
3287aec1d6eScindi return (node_create_seterror(mod, pnode, NULL,
329825ba0f2Srobj EMOD_NODE_DUP));
3307aec1d6eScindi }
3317aec1d6eScindi
332*c5591576SRob Johnston if (max < min)
3337aec1d6eScindi return (node_create_seterror(mod, pnode, NULL,
334825ba0f2Srobj EMOD_NODE_RANGE));
3357aec1d6eScindi
3367aec1d6eScindi if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL)
337825ba0f2Srobj return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM));
3387aec1d6eScindi
3397aec1d6eScindi if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL)
340825ba0f2Srobj return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM));
3417aec1d6eScindi
3427aec1d6eScindi nhp->th_arrlen = max - min + 1;
3437aec1d6eScindi
3447aec1d6eScindi if ((nhp->th_nodearr = topo_mod_zalloc(mod,
3457aec1d6eScindi nhp->th_arrlen * sizeof (tnode_t *))) == NULL)
346825ba0f2Srobj return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM));
3477aec1d6eScindi
3487aec1d6eScindi nhp->th_range.tr_min = min;
3497aec1d6eScindi nhp->th_range.tr_max = max;
3507aec1d6eScindi nhp->th_enum = mod;
3517aec1d6eScindi topo_mod_hold(mod);
3527aec1d6eScindi
3537aec1d6eScindi /*
3547aec1d6eScindi * Add these nodes to parent child list
3557aec1d6eScindi */
3567aec1d6eScindi topo_list_append(&pnode->tn_children, nhp);
3577aec1d6eScindi topo_node_unlock(pnode);
3587aec1d6eScindi
3590eb822a1Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
3600eb822a1Scindi "created node range %s[%d-%d]\n", name, min, max);
3617aec1d6eScindi
3627aec1d6eScindi return (0);
3637aec1d6eScindi }
3647aec1d6eScindi
3657aec1d6eScindi void
topo_node_range_destroy(tnode_t * pnode,const char * name)3667aec1d6eScindi topo_node_range_destroy(tnode_t *pnode, const char *name)
3677aec1d6eScindi {
3687aec1d6eScindi int i;
3697aec1d6eScindi topo_nodehash_t *nhp;
3707aec1d6eScindi topo_mod_t *mod;
3717aec1d6eScindi
3727aec1d6eScindi topo_node_lock(pnode);
3737aec1d6eScindi for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
3747aec1d6eScindi nhp = topo_list_next(nhp)) {
3757aec1d6eScindi if (strcmp(nhp->th_name, name) == 0) {
3767aec1d6eScindi break;
3777aec1d6eScindi }
3787aec1d6eScindi }
3797aec1d6eScindi
3807aec1d6eScindi if (nhp == NULL) {
3817aec1d6eScindi topo_node_unlock(pnode);
3827aec1d6eScindi return;
3837aec1d6eScindi }
3847aec1d6eScindi
38512cc75c8Scindi for (i = 0; i < nhp->th_arrlen; i++)
38612cc75c8Scindi assert(nhp->th_nodearr[i] == NULL);
38712cc75c8Scindi
3887aec1d6eScindi topo_list_delete(&pnode->tn_children, nhp);
3897aec1d6eScindi topo_node_unlock(pnode);
3907aec1d6eScindi
3917aec1d6eScindi mod = nhp->th_enum;
3927aec1d6eScindi if (nhp->th_name != NULL)
3937aec1d6eScindi topo_mod_strfree(mod, nhp->th_name);
3947aec1d6eScindi if (nhp->th_nodearr != NULL) {
3957aec1d6eScindi topo_mod_free(mod, nhp->th_nodearr,
3967aec1d6eScindi nhp->th_arrlen * sizeof (tnode_t *));
3977aec1d6eScindi }
3987aec1d6eScindi topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
3997aec1d6eScindi topo_mod_rele(mod);
4007aec1d6eScindi
4017aec1d6eScindi }
4027aec1d6eScindi
4037aec1d6eScindi tnode_t *
topo_node_lookup(tnode_t * pnode,const char * name,topo_instance_t inst)4047aec1d6eScindi topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst)
4057aec1d6eScindi {
4067aec1d6eScindi int h;
4077aec1d6eScindi tnode_t *node;
4087aec1d6eScindi topo_nodehash_t *nhp;
4097aec1d6eScindi
410f6e214c7SGavin Maltby topo_dprintf(pnode->tn_hdl, TOPO_DBG_MODSVC,
411f6e214c7SGavin Maltby "topo_node_lookup: looking for '%s' instance %d\n", name, inst);
412f6e214c7SGavin Maltby
4137aec1d6eScindi topo_node_lock(pnode);
4147aec1d6eScindi for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
4157aec1d6eScindi nhp = topo_list_next(nhp)) {
4167aec1d6eScindi if (strcmp(nhp->th_name, name) == 0) {
4177aec1d6eScindi
4187aec1d6eScindi if (inst > nhp->th_range.tr_max ||
4197aec1d6eScindi inst < nhp->th_range.tr_min) {
4207aec1d6eScindi topo_node_unlock(pnode);
4217aec1d6eScindi return (NULL);
4227aec1d6eScindi }
4237aec1d6eScindi
4247aec1d6eScindi h = topo_node_hash(nhp, inst);
4257aec1d6eScindi node = nhp->th_nodearr[h];
4267aec1d6eScindi topo_node_unlock(pnode);
4277aec1d6eScindi return (node);
4287aec1d6eScindi }
4297aec1d6eScindi }
4307aec1d6eScindi topo_node_unlock(pnode);
4317aec1d6eScindi
4327aec1d6eScindi return (NULL);
4337aec1d6eScindi }
4347aec1d6eScindi
4357aec1d6eScindi int
topo_node_hash(topo_nodehash_t * nhp,topo_instance_t inst)4367aec1d6eScindi topo_node_hash(topo_nodehash_t *nhp, topo_instance_t inst)
4377aec1d6eScindi {
43820c794b3Sgavinm return ((inst - nhp->th_range.tr_min) % nhp->th_arrlen);
4397aec1d6eScindi }
4407aec1d6eScindi
4417aec1d6eScindi static tnode_t *
node_bind_seterror(topo_mod_t * mod,tnode_t * pnode,tnode_t * node,boolean_t pnode_locked,int err)442a38fc4eaSRobert Johnston node_bind_seterror(topo_mod_t *mod, tnode_t *pnode, tnode_t *node,
443a38fc4eaSRobert Johnston boolean_t pnode_locked, int err)
4447aec1d6eScindi {
445a38fc4eaSRobert Johnston if (pnode_locked)
446a38fc4eaSRobert Johnston topo_node_unlock(pnode);
4477aec1d6eScindi
4487aec1d6eScindi (void) topo_mod_seterrno(mod, err);
4497aec1d6eScindi
4507aec1d6eScindi if (node == NULL)
4517aec1d6eScindi return (NULL);
4527aec1d6eScindi
4530eb822a1Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to bind %s=%d: "
4547aec1d6eScindi "%s\n", (node->tn_name != NULL ? node->tn_name : "unknown"),
4557aec1d6eScindi node->tn_instance, topo_strerror(err));
4567aec1d6eScindi
4577aec1d6eScindi topo_node_lock(node); /* expected to be locked */
4587aec1d6eScindi topo_node_destroy(node);
4597aec1d6eScindi
4607aec1d6eScindi return (NULL);
4617aec1d6eScindi }
4627aec1d6eScindi
4637aec1d6eScindi tnode_t *
topo_node_bind(topo_mod_t * mod,tnode_t * pnode,const char * name,topo_instance_t inst,nvlist_t * fmri)4647aec1d6eScindi topo_node_bind(topo_mod_t *mod, tnode_t *pnode, const char *name,
4650eb822a1Scindi topo_instance_t inst, nvlist_t *fmri)
4667aec1d6eScindi {
4677aec1d6eScindi int h, err;
4687aec1d6eScindi tnode_t *node;
4697aec1d6eScindi topo_nodehash_t *nhp;
4707aec1d6eScindi
4717aec1d6eScindi topo_node_lock(pnode);
4727aec1d6eScindi for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
4737aec1d6eScindi nhp = topo_list_next(nhp)) {
4747aec1d6eScindi if (strcmp(nhp->th_name, name) == 0) {
4757aec1d6eScindi
4767aec1d6eScindi if (inst > nhp->th_range.tr_max ||
4777aec1d6eScindi inst < nhp->th_range.tr_min)
4787aec1d6eScindi return (node_bind_seterror(mod, pnode, NULL,
479a38fc4eaSRobert Johnston B_TRUE, EMOD_NODE_RANGE));
4807aec1d6eScindi
4817aec1d6eScindi h = topo_node_hash(nhp, inst);
4827aec1d6eScindi if (nhp->th_nodearr[h] != NULL)
4837aec1d6eScindi return (node_bind_seterror(mod, pnode, NULL,
484a38fc4eaSRobert Johnston B_TRUE, EMOD_NODE_BOUND));
4857aec1d6eScindi else
4867aec1d6eScindi break;
4877aec1d6eScindi
4887aec1d6eScindi }
4897aec1d6eScindi }
4907aec1d6eScindi
4917aec1d6eScindi if (nhp == NULL)
492a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, NULL, B_TRUE,
493a38fc4eaSRobert Johnston EMOD_NODE_NOENT));
4947aec1d6eScindi
4957aec1d6eScindi if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL)
496a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, NULL, B_TRUE,
497a38fc4eaSRobert Johnston EMOD_NOMEM));
4987aec1d6eScindi
4997aec1d6eScindi (void) pthread_mutex_init(&node->tn_lock, NULL);
5007aec1d6eScindi
5017aec1d6eScindi node->tn_enum = mod;
5027aec1d6eScindi node->tn_hdl = mod->tm_hdl;
5037aec1d6eScindi node->tn_parent = pnode;
5047aec1d6eScindi node->tn_name = nhp->th_name;
5057aec1d6eScindi node->tn_instance = inst;
5067aec1d6eScindi node->tn_phash = nhp;
5077aec1d6eScindi node->tn_refs = 0;
5087aec1d6eScindi
5097aec1d6eScindi /* Ref count module that bound this node */
5107aec1d6eScindi topo_mod_hold(mod);
5117aec1d6eScindi
5127aec1d6eScindi if (fmri == NULL)
513a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_TRUE,
514a38fc4eaSRobert Johnston EMOD_NVL_INVAL));
5157aec1d6eScindi
5160eb822a1Scindi if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0)
517a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_TRUE, err));
5187aec1d6eScindi
5197aec1d6eScindi if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
5200eb822a1Scindi TOPO_PROP_IMMUTABLE, fmri, &err) < 0)
521a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_TRUE, err));
5227aec1d6eScindi
5230eb822a1Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
52412cc75c8Scindi "node bound %s=%d/%s=%d\n", topo_node_name(pnode),
52512cc75c8Scindi topo_node_instance(pnode), node->tn_name, node->tn_instance);
5267aec1d6eScindi
5277aec1d6eScindi node->tn_state |= TOPO_NODE_BOUND;
5287aec1d6eScindi
5297aec1d6eScindi topo_node_hold(node);
5307aec1d6eScindi nhp->th_nodearr[h] = node;
5317aec1d6eScindi ++pnode->tn_refs;
532825ba0f2Srobj
5337aec1d6eScindi topo_node_unlock(pnode);
5347aec1d6eScindi
5350eb822a1Scindi if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) {
5360eb822a1Scindi (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
5370eb822a1Scindi FM_FMRI_AUTH_PRODUCT, &err);
5389c94f155SCheng Sean Ye (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
5399c94f155SCheng Sean Ye FM_FMRI_AUTH_PRODUCT_SN, &err);
5400eb822a1Scindi (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
5410eb822a1Scindi FM_FMRI_AUTH_CHASSIS, &err);
5420eb822a1Scindi (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
5430eb822a1Scindi FM_FMRI_AUTH_SERVER, &err);
5447aec1d6eScindi }
5457aec1d6eScindi
5467aec1d6eScindi return (node);
5477aec1d6eScindi }
5487aec1d6eScindi
549825ba0f2Srobj tnode_t *
topo_node_facbind(topo_mod_t * mod,tnode_t * pnode,const char * name,const char * type)550825ba0f2Srobj topo_node_facbind(topo_mod_t *mod, tnode_t *pnode, const char *name,
551825ba0f2Srobj const char *type)
552825ba0f2Srobj {
553825ba0f2Srobj int h, err;
554825ba0f2Srobj tnode_t *node;
555825ba0f2Srobj topo_nodehash_t *nhp;
556825ba0f2Srobj topo_instance_t inst = 0;
557825ba0f2Srobj nvlist_t *pfmri, *fnvl;
558825ba0f2Srobj
559825ba0f2Srobj /*
560825ba0f2Srobj * Create a single entry range for this facility
561825ba0f2Srobj */
562825ba0f2Srobj if (topo_node_range_create(mod, pnode, name, 0, 0) < 0)
563825ba0f2Srobj return (NULL); /* mod errno set */
564825ba0f2Srobj
565a38fc4eaSRobert Johnston topo_node_hold(pnode);
566825ba0f2Srobj topo_node_lock(pnode);
567825ba0f2Srobj for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
568825ba0f2Srobj nhp = topo_list_next(nhp)) {
569825ba0f2Srobj if (strcmp(nhp->th_name, name) == 0) {
570825ba0f2Srobj
571825ba0f2Srobj if (inst > nhp->th_range.tr_max ||
572a38fc4eaSRobert Johnston inst < nhp->th_range.tr_min) {
573a38fc4eaSRobert Johnston topo_node_rele(pnode);
574825ba0f2Srobj return (node_bind_seterror(mod, pnode, NULL,
575a38fc4eaSRobert Johnston B_TRUE, EMOD_NVL_INVAL));
576a38fc4eaSRobert Johnston }
577825ba0f2Srobj h = topo_node_hash(nhp, inst);
578a38fc4eaSRobert Johnston if (nhp->th_nodearr[h] != NULL) {
579a38fc4eaSRobert Johnston topo_node_rele(pnode);
580825ba0f2Srobj return (node_bind_seterror(mod, pnode, NULL,
581a38fc4eaSRobert Johnston B_TRUE, EMOD_NODE_BOUND));
582a38fc4eaSRobert Johnston } else
583825ba0f2Srobj break;
584825ba0f2Srobj
585825ba0f2Srobj }
586825ba0f2Srobj }
587a38fc4eaSRobert Johnston topo_node_unlock(pnode);
588825ba0f2Srobj
589a38fc4eaSRobert Johnston if (nhp == NULL) {
590a38fc4eaSRobert Johnston topo_node_rele(pnode);
591a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, NULL, B_FALSE,
592a38fc4eaSRobert Johnston EMOD_NODE_NOENT));
593a38fc4eaSRobert Johnston }
594a38fc4eaSRobert Johnston if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) {
595a38fc4eaSRobert Johnston topo_node_rele(pnode);
596a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, NULL, B_FALSE,
597a38fc4eaSRobert Johnston EMOD_NOMEM));
598a38fc4eaSRobert Johnston }
599825ba0f2Srobj
600825ba0f2Srobj (void) pthread_mutex_init(&node->tn_lock, NULL);
601825ba0f2Srobj
602825ba0f2Srobj node->tn_enum = mod;
603825ba0f2Srobj node->tn_hdl = mod->tm_hdl;
604825ba0f2Srobj node->tn_parent = pnode;
605825ba0f2Srobj node->tn_name = nhp->th_name;
606825ba0f2Srobj node->tn_instance = inst;
607825ba0f2Srobj node->tn_phash = nhp;
608825ba0f2Srobj node->tn_refs = 0;
609825ba0f2Srobj node->tn_fflags = TOPO_NODE_FACILITY;
610825ba0f2Srobj
611825ba0f2Srobj /* Ref count module that bound this node */
612825ba0f2Srobj topo_mod_hold(mod);
613825ba0f2Srobj
614a38fc4eaSRobert Johnston if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0) {
615a38fc4eaSRobert Johnston topo_node_rele(pnode);
616a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, err));
617a38fc4eaSRobert Johnston }
618a38fc4eaSRobert Johnston if (topo_mod_nvalloc(mod, &fnvl, NV_UNIQUE_NAME) < 0) {
619a38fc4eaSRobert Johnston topo_node_rele(pnode);
620a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE,
621a38fc4eaSRobert Johnston EMOD_NOMEM));
622a38fc4eaSRobert Johnston }
623825ba0f2Srobj if (nvlist_add_string(fnvl, FM_FMRI_FACILITY_NAME, name) != 0 ||
624825ba0f2Srobj nvlist_add_string(fnvl, FM_FMRI_FACILITY_TYPE, type) != 0) {
625825ba0f2Srobj nvlist_free(fnvl);
626a38fc4eaSRobert Johnston topo_node_rele(pnode);
627a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE,
628a38fc4eaSRobert Johnston EMOD_FMRI_NVL));
629825ba0f2Srobj }
630825ba0f2Srobj
631825ba0f2Srobj if (topo_node_resource(pnode, &pfmri, &err) < 0) {
632825ba0f2Srobj nvlist_free(fnvl);
633a38fc4eaSRobert Johnston topo_node_rele(pnode);
634a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, err));
635825ba0f2Srobj }
636825ba0f2Srobj
637825ba0f2Srobj if (nvlist_add_nvlist(pfmri, FM_FMRI_FACILITY, fnvl) != 0) {
638825ba0f2Srobj nvlist_free(fnvl);
639825ba0f2Srobj nvlist_free(pfmri);
640a38fc4eaSRobert Johnston topo_node_rele(pnode);
641a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE,
642a38fc4eaSRobert Johnston EMOD_FMRI_NVL));
643825ba0f2Srobj }
644825ba0f2Srobj
645825ba0f2Srobj nvlist_free(fnvl);
646825ba0f2Srobj
647825ba0f2Srobj if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
648825ba0f2Srobj TOPO_PROP_IMMUTABLE, pfmri, &err) < 0) {
649825ba0f2Srobj nvlist_free(pfmri);
650a38fc4eaSRobert Johnston topo_node_rele(pnode);
651a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, err));
652825ba0f2Srobj }
653825ba0f2Srobj
654825ba0f2Srobj nvlist_free(pfmri);
655825ba0f2Srobj
656825ba0f2Srobj topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
657825ba0f2Srobj "facility node bound %s=%s\n", type, node->tn_name);
658825ba0f2Srobj
659825ba0f2Srobj node->tn_state |= TOPO_NODE_BOUND;
660825ba0f2Srobj
661825ba0f2Srobj topo_node_hold(node);
662825ba0f2Srobj nhp->th_nodearr[h] = node;
663825ba0f2Srobj
664a38fc4eaSRobert Johnston topo_node_lock(pnode);
665a38fc4eaSRobert Johnston ++pnode->tn_refs;
666825ba0f2Srobj topo_node_unlock(pnode);
667a38fc4eaSRobert Johnston topo_node_rele(pnode);
668825ba0f2Srobj
669825ba0f2Srobj if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) {
670825ba0f2Srobj (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
671825ba0f2Srobj FM_FMRI_AUTH_PRODUCT, &err);
6729c94f155SCheng Sean Ye (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
6739c94f155SCheng Sean Ye FM_FMRI_AUTH_PRODUCT_SN, &err);
674825ba0f2Srobj (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
675825ba0f2Srobj FM_FMRI_AUTH_CHASSIS, &err);
676825ba0f2Srobj (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
677825ba0f2Srobj FM_FMRI_AUTH_SERVER, &err);
678825ba0f2Srobj }
679825ba0f2Srobj
680825ba0f2Srobj return (node);
681825ba0f2Srobj }
682825ba0f2Srobj
683825ba0f2Srobj int
topo_node_facility(topo_hdl_t * thp,tnode_t * node,const char * fac_type,uint32_t fac_subtype,topo_faclist_t * faclist,int * errp)684825ba0f2Srobj topo_node_facility(topo_hdl_t *thp, tnode_t *node, const char *fac_type,
685825ba0f2Srobj uint32_t fac_subtype, topo_faclist_t *faclist, int *errp)
686825ba0f2Srobj {
687825ba0f2Srobj tnode_t *tmp;
688a38fc4eaSRobert Johnston nvlist_t *rsrc, *fac;
689825ba0f2Srobj char *tmp_factype;
690825ba0f2Srobj uint32_t tmp_facsubtype;
691825ba0f2Srobj boolean_t list_empty = 1;
692825ba0f2Srobj topo_faclist_t *fac_ele;
693825ba0f2Srobj
694825ba0f2Srobj bzero(faclist, sizeof (topo_faclist_t));
695825ba0f2Srobj for (tmp = topo_child_first(node); tmp != NULL;
696825ba0f2Srobj tmp = topo_child_next(node, tmp)) {
697825ba0f2Srobj
698825ba0f2Srobj topo_node_hold(tmp);
699825ba0f2Srobj /*
700825ba0f2Srobj * If it's not a facility node, move on
701825ba0f2Srobj */
702825ba0f2Srobj if (topo_node_flags(tmp) != TOPO_NODE_FACILITY) {
703825ba0f2Srobj topo_node_rele(tmp);
704825ba0f2Srobj continue;
705825ba0f2Srobj }
706825ba0f2Srobj
707825ba0f2Srobj /*
708825ba0f2Srobj * Lookup whether the fac type is sensor or indicator and if
709825ba0f2Srobj * it's not the type we're looking for, move on
710825ba0f2Srobj */
711825ba0f2Srobj if (topo_node_resource(tmp, &rsrc, errp) != 0) {
712825ba0f2Srobj topo_dprintf(thp, TOPO_DBG_ERR,
713825ba0f2Srobj "Failed to get resource for node %s=%d (%s)\n",
714825ba0f2Srobj topo_node_name(node), topo_node_instance(node),
715825ba0f2Srobj topo_strerror(*errp));
716825ba0f2Srobj topo_node_rele(tmp);
717825ba0f2Srobj return (-1);
718825ba0f2Srobj }
719825ba0f2Srobj if ((nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0) ||
720825ba0f2Srobj (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE,
721825ba0f2Srobj &tmp_factype) != 0)) {
722825ba0f2Srobj
723f08344cbSEric Schrock nvlist_free(rsrc);
724825ba0f2Srobj topo_node_rele(tmp);
725825ba0f2Srobj return (-1);
726825ba0f2Srobj }
727f08344cbSEric Schrock
728825ba0f2Srobj if (strcmp(fac_type, tmp_factype) != 0) {
729825ba0f2Srobj topo_node_rele(tmp);
730e5dcf7beSRobert Johnston nvlist_free(rsrc);
731825ba0f2Srobj continue;
732825ba0f2Srobj }
733e5dcf7beSRobert Johnston nvlist_free(rsrc);
734825ba0f2Srobj
735825ba0f2Srobj /*
736825ba0f2Srobj * Finally, look up the subtype, which is a property in the
737825ba0f2Srobj * facility propgroup. If it's a match return a pointer to the
738825ba0f2Srobj * node. Otherwise, move on.
739825ba0f2Srobj */
740825ba0f2Srobj if (topo_prop_get_uint32(tmp, TOPO_PGROUP_FACILITY,
741825ba0f2Srobj TOPO_FACILITY_TYPE, &tmp_facsubtype, errp) != 0) {
742825ba0f2Srobj topo_node_rele(tmp);
743825ba0f2Srobj return (-1);
744825ba0f2Srobj }
745e5dcf7beSRobert Johnston if (fac_subtype == tmp_facsubtype ||
746e5dcf7beSRobert Johnston fac_subtype == TOPO_FAC_TYPE_ANY) {
747825ba0f2Srobj if ((fac_ele = topo_mod_zalloc(tmp->tn_enum,
748825ba0f2Srobj sizeof (topo_faclist_t))) == NULL) {
749825ba0f2Srobj *errp = ETOPO_NOMEM;
750f08344cbSEric Schrock topo_node_rele(tmp);
751825ba0f2Srobj return (-1);
752825ba0f2Srobj }
753825ba0f2Srobj fac_ele->tf_node = tmp;
754825ba0f2Srobj topo_list_append(&faclist->tf_list, fac_ele);
755825ba0f2Srobj list_empty = 0;
756825ba0f2Srobj }
757825ba0f2Srobj topo_node_rele(tmp);
758825ba0f2Srobj }
759825ba0f2Srobj
760825ba0f2Srobj if (list_empty) {
761825ba0f2Srobj *errp = ETOPO_FAC_NOENT;
762825ba0f2Srobj return (-1);
763825ba0f2Srobj }
764825ba0f2Srobj return (0);
765825ba0f2Srobj }
766825ba0f2Srobj
7677aec1d6eScindi void
topo_node_unbind(tnode_t * node)7687aec1d6eScindi topo_node_unbind(tnode_t *node)
7697aec1d6eScindi {
7707aec1d6eScindi if (node == NULL)
7717aec1d6eScindi return;
7727aec1d6eScindi
7737aec1d6eScindi topo_node_lock(node);
7747aec1d6eScindi if (!(node->tn_state & TOPO_NODE_BOUND)) {
7757aec1d6eScindi topo_node_unlock(node);
7767aec1d6eScindi return;
7777aec1d6eScindi }
7787aec1d6eScindi
7797aec1d6eScindi node->tn_state &= ~TOPO_NODE_BOUND;
7807aec1d6eScindi topo_node_unlock(node);
7817aec1d6eScindi
78212cc75c8Scindi topo_dprintf(node->tn_hdl, TOPO_DBG_MODSVC,
783*c5591576SRob Johnston "node unbound %s=%d refs = %d\n", node->tn_name,
78412cc75c8Scindi node->tn_instance, node->tn_refs);
78512cc75c8Scindi
7867aec1d6eScindi topo_node_rele(node);
7877aec1d6eScindi }
7887aec1d6eScindi
7897aec1d6eScindi /*ARGSUSED*/
7907aec1d6eScindi int
topo_node_present(tnode_t * node)7917aec1d6eScindi topo_node_present(tnode_t *node)
7927aec1d6eScindi {
7937aec1d6eScindi return (0);
7947aec1d6eScindi }
7957aec1d6eScindi
7967aec1d6eScindi /*ARGSUSED*/
7977aec1d6eScindi int
topo_node_contains(tnode_t * er,tnode_t * ee)7987aec1d6eScindi topo_node_contains(tnode_t *er, tnode_t *ee)
7997aec1d6eScindi {
8007aec1d6eScindi return (0);
8017aec1d6eScindi }
8027aec1d6eScindi
8037aec1d6eScindi /*ARGSUSED*/
8047aec1d6eScindi int
topo_node_unusable(tnode_t * node)8057aec1d6eScindi topo_node_unusable(tnode_t *node)
8067aec1d6eScindi {
8077aec1d6eScindi return (0);
8087aec1d6eScindi }
809c40d7343Scindi
810c40d7343Scindi topo_walk_t *
topo_node_walk_init(topo_hdl_t * thp,topo_mod_t * mod,tnode_t * node,int (* cb_f)(),void * pdata,int * errp)811c40d7343Scindi topo_node_walk_init(topo_hdl_t *thp, topo_mod_t *mod, tnode_t *node,
812c40d7343Scindi int (*cb_f)(), void *pdata, int *errp)
813c40d7343Scindi {
814c40d7343Scindi tnode_t *child;
815c40d7343Scindi topo_walk_t *wp;
816c40d7343Scindi
817c40d7343Scindi topo_node_hold(node);
818c40d7343Scindi
819c40d7343Scindi if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) {
820825ba0f2Srobj *errp = ETOPO_HDL_NOMEM;
821c40d7343Scindi topo_node_rele(node);
822c40d7343Scindi return (NULL);
823c40d7343Scindi }
824c40d7343Scindi
825c40d7343Scindi /*
826c40d7343Scindi * If this is the root of the scheme tree, start with the first
827c40d7343Scindi * child
828c40d7343Scindi */
829c40d7343Scindi topo_node_lock(node);
830c40d7343Scindi if (node->tn_state & TOPO_NODE_ROOT) {
831c40d7343Scindi if ((child = topo_child_first(node)) == NULL) {
832c40d7343Scindi /* Nothing to walk */
833c40d7343Scindi *errp = ETOPO_WALK_EMPTY;
834c40d7343Scindi topo_node_unlock(node);
835c40d7343Scindi topo_node_rele(node);
836c6765aabSeschrock topo_hdl_free(thp, wp, sizeof (topo_walk_t));
837c40d7343Scindi return (NULL);
838c40d7343Scindi }
839c40d7343Scindi topo_node_unlock(node);
840c40d7343Scindi topo_node_hold(child);
841c40d7343Scindi wp->tw_node = child;
842c40d7343Scindi } else {
843c40d7343Scindi topo_node_unlock(node);
84412cc75c8Scindi topo_node_hold(node); /* rele at walk end */
845c40d7343Scindi wp->tw_node = node;
846c40d7343Scindi }
847c40d7343Scindi
848c40d7343Scindi wp->tw_root = node;
849c40d7343Scindi wp->tw_cb = cb_f;
850c40d7343Scindi wp->tw_pdata = pdata;
851c40d7343Scindi wp->tw_thp = thp;
852c40d7343Scindi wp->tw_mod = mod;
853c40d7343Scindi
854c40d7343Scindi return (wp);
855c40d7343Scindi }
8561410cb93SJoshua M. Clulow
8571410cb93SJoshua M. Clulow /*
8581410cb93SJoshua M. Clulow * Walk the direct children of the given node.
8591410cb93SJoshua M. Clulow */
8601410cb93SJoshua M. Clulow int
topo_node_child_walk(topo_hdl_t * thp,tnode_t * pnode,topo_walk_cb_t cb_f,void * arg,int * errp)8611410cb93SJoshua M. Clulow topo_node_child_walk(topo_hdl_t *thp, tnode_t *pnode, topo_walk_cb_t cb_f,
8621410cb93SJoshua M. Clulow void *arg, int *errp)
8631410cb93SJoshua M. Clulow {
8641410cb93SJoshua M. Clulow int ret = TOPO_WALK_TERMINATE;
8651410cb93SJoshua M. Clulow tnode_t *cnode;
8661410cb93SJoshua M. Clulow
8671410cb93SJoshua M. Clulow topo_node_hold(pnode);
8681410cb93SJoshua M. Clulow
8691410cb93SJoshua M. Clulow /*
8701410cb93SJoshua M. Clulow * First Child:
8711410cb93SJoshua M. Clulow */
8721410cb93SJoshua M. Clulow topo_node_lock(pnode);
8731410cb93SJoshua M. Clulow cnode = topo_child_first(pnode);
8741410cb93SJoshua M. Clulow topo_node_unlock(pnode);
8751410cb93SJoshua M. Clulow
8761410cb93SJoshua M. Clulow if (cnode == NULL) {
8771410cb93SJoshua M. Clulow *errp = ETOPO_WALK_EMPTY;
8781410cb93SJoshua M. Clulow ret = TOPO_WALK_ERR;
8791410cb93SJoshua M. Clulow goto out;
8801410cb93SJoshua M. Clulow }
8811410cb93SJoshua M. Clulow
8821410cb93SJoshua M. Clulow while (cnode != NULL) {
8831410cb93SJoshua M. Clulow int iret;
8841410cb93SJoshua M. Clulow
8851410cb93SJoshua M. Clulow /*
8861410cb93SJoshua M. Clulow * Call the walker callback:
8871410cb93SJoshua M. Clulow */
8881410cb93SJoshua M. Clulow topo_node_hold(cnode);
8891410cb93SJoshua M. Clulow iret = cb_f(thp, cnode, arg);
8901410cb93SJoshua M. Clulow topo_node_rele(cnode);
8911410cb93SJoshua M. Clulow if (iret != TOPO_WALK_NEXT) {
8921410cb93SJoshua M. Clulow ret = iret;
8931410cb93SJoshua M. Clulow break;
8941410cb93SJoshua M. Clulow }
8951410cb93SJoshua M. Clulow
8961410cb93SJoshua M. Clulow /*
8971410cb93SJoshua M. Clulow * Next child:
8981410cb93SJoshua M. Clulow */
8991410cb93SJoshua M. Clulow topo_node_lock(pnode);
9001410cb93SJoshua M. Clulow cnode = topo_child_next(pnode, cnode);
9011410cb93SJoshua M. Clulow topo_node_unlock(pnode);
9021410cb93SJoshua M. Clulow }
9031410cb93SJoshua M. Clulow
9041410cb93SJoshua M. Clulow out:
9051410cb93SJoshua M. Clulow topo_node_rele(pnode);
9061410cb93SJoshua M. Clulow return (ret);
9071410cb93SJoshua M. Clulow }
9088abca89fSRob Johnston
9098abca89fSRob Johnston int
topo_node_occupied(tnode_t * node,boolean_t * is_occupied)9108abca89fSRob Johnston topo_node_occupied(tnode_t *node, boolean_t *is_occupied)
9118abca89fSRob Johnston {
9128abca89fSRob Johnston nvlist_t *out;
9138abca89fSRob Johnston int err;
9148abca89fSRob Johnston
9158abca89fSRob Johnston if (topo_method_invoke(node, TOPO_METH_OCCUPIED,
9168abca89fSRob Johnston TOPO_METH_OCCUPIED_VERSION, NULL, &out, &err) != 0) {
9178abca89fSRob Johnston return (err);
9188abca89fSRob Johnston }
9198abca89fSRob Johnston (void) nvlist_lookup_boolean_value(out, TOPO_METH_OCCUPIED_RET,
9208abca89fSRob Johnston is_occupied);
9218abca89fSRob Johnston
9228abca89fSRob Johnston nvlist_free(out);
9238abca89fSRob Johnston return (0);
9248abca89fSRob Johnston }
925