xref: /illumos-gate/usr/src/lib/fm/topo/libtopo/common/topo_node.c (revision c40d7343efa60b18ad1ceb316eb337caeea79046)
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 /*
22*c40d7343Scindi  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237aec1d6eScindi  * Use is subject to license terms.
247aec1d6eScindi  */
257aec1d6eScindi 
267aec1d6eScindi #pragma ident	"%Z%%M%	%I%	%E% SMI"
277aec1d6eScindi 
287aec1d6eScindi /*
297aec1d6eScindi  * Topology Nodes
307aec1d6eScindi  *
317aec1d6eScindi  * Topology nodes, tnode_t, are data structures containing per-FMRI
327aec1d6eScindi  * information and are linked together to form the topology tree.
337aec1d6eScindi  * Nodes are created during the enumeration process of topo_snap_hold()
347aec1d6eScindi  * and destroyed during topo_snap_rele().  For the most part, tnode_t data
357aec1d6eScindi  * is read-only and no lock protection is required.  Nodes are
367aec1d6eScindi  * held in place during tree walk functions.  Tree walk functions
377aec1d6eScindi  * may access node data safely without locks.  The exception to this rule
387aec1d6eScindi  * is data associated with node properties (topo_prop.c).  Properties
397aec1d6eScindi  * may change at anytime and are protected by a per-property locking
407aec1d6eScindi  * strategy.
417aec1d6eScindi  *
42*c40d7343Scindi  * Enumerator plugin modules may also safely access topology nodes within their
43*c40d7343Scindi  * scope of operation: the parent node passed into the enumeration op or those
44*c40d7343Scindi  * nodes created by the enumerator.  Enumeration occurs only during
45*c40d7343Scindi  * topo_snap_hold() where a per-topo_hdl_t lock prevents multi-threaded access
46*c40d7343Scindi  * to the topology trees.
477aec1d6eScindi  *
48*c40d7343Scindi  * Enumerator method operation functions may safely access and change topology
49*c40d7343Scindi  * node property data, and contruct or destroy child nodes for the node
50*c40d7343Scindi  * on which the operation applies.  The method may also be called to destroy
51*c40d7343Scindi  * the node for which the method operation is called.  This permits
52*c40d7343Scindi  * dynamic topology tree snapshots and partial enumerations for branches that
53*c40d7343Scindi  * may not be needed right away.
547aec1d6eScindi  *
557aec1d6eScindi  * Node Interfaces
567aec1d6eScindi  *
57*c40d7343Scindi  * Nodes are created when an enumerator calls topo_node_bind().  Prior to
58*c40d7343Scindi  * calling topo_node_bind(), the enumerator should have reserved a range of
597aec1d6eScindi  * node instances with topo_node_range_create().  topo_node_range_create()
607aec1d6eScindi  * does not allocate any node resources but creates the infrastruture
617aec1d6eScindi  * required for a fully populated topology level.  This allows enumerators
627aec1d6eScindi  * reading from a <scheme>-topology.xml file to parse the file for a range
637aec1d6eScindi  * of resources before confirming the existence of a resource via a helper
647aec1d6eScindi  * plugin.  Only when the resource has been confirmed to exist should
657aec1d6eScindi  * the node be bound.
667aec1d6eScindi  *
67*c40d7343Scindi  * Node range and node linkage and unlinkage is performed during enumeration and
68*c40d7343Scindi  * method operations when it is safe to change node hash lists. Nodes and node
69*c40d7343Scindi  * ranges are deallocated when all references to the node have been released:
707aec1d6eScindi  * last walk completes and topo_snap_rele() is called.
717aec1d6eScindi  *
727aec1d6eScindi  * Node Hash/Ranges
737aec1d6eScindi  *
747aec1d6eScindi  * Each parent node may have one or more ranges of child nodes.  Each range
75*c40d7343Scindi  * is uniquely named and serves as a hash list of like sibling nodes with
767aec1d6eScindi  * different instance numbers.  A parent may have more than one node hash
777aec1d6eScindi  * (child range). If that is the case, the hash lists are strung together to
787aec1d6eScindi  * form sibling relationships between ranges.  Hash/Ranges are sparsely
797aec1d6eScindi  * populated with only nodes that have represented resources in the system.
80*c40d7343Scindi  *
81*c40d7343Scindi  *	_________________
82*c40d7343Scindi  *	|		|
83*c40d7343Scindi  *      |   tnode_t	|    -----------------------------
84*c40d7343Scindi  *      |      tn_phash ---> |  topo_nodehash_t          |
85*c40d7343Scindi  *      |     (children)|    |     th_nodearr (instances)|
86*c40d7343Scindi  *      -----------------    |     -------------------   |
87*c40d7343Scindi  *                           |  ---| 0 | 1  | ...| N |   |
88*c40d7343Scindi  *                           |  |  -------------------   |  -------------------
89*c40d7343Scindi  *                           |  |  th_list (siblings) ----->| topo_nodehash_t |
90*c40d7343Scindi  *                           |  |                        |  -------------------
91*c40d7343Scindi  *                           ---|-------------------------
92*c40d7343Scindi  *                              |
93*c40d7343Scindi  *                              v
94*c40d7343Scindi  *                           -----------
95*c40d7343Scindi  *                           | tnode_t |
96*c40d7343Scindi  *                           -----------
977aec1d6eScindi  */
987aec1d6eScindi 
997aec1d6eScindi #include <assert.h>
1007aec1d6eScindi #include <pthread.h>
1017aec1d6eScindi #include <strings.h>
1020eb822a1Scindi #include <sys/fm/protocol.h>
1037aec1d6eScindi #include <topo_alloc.h>
1047aec1d6eScindi #include <topo_error.h>
1050eb822a1Scindi #include <topo_method.h>
1060eb822a1Scindi #include <topo_subr.h>
1070eb822a1Scindi #include <topo_tree.h>
1080eb822a1Scindi 
1090eb822a1Scindi static topo_pgroup_info_t protocol_pgroup = {
1100eb822a1Scindi 	TOPO_PGROUP_PROTOCOL,
1110eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
1120eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
1130eb822a1Scindi 	1
1140eb822a1Scindi };
1150eb822a1Scindi 
1160eb822a1Scindi static const topo_pgroup_info_t auth_pgroup = {
1170eb822a1Scindi 	FM_FMRI_AUTHORITY,
1180eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
1190eb822a1Scindi 	TOPO_STABILITY_PRIVATE,
1200eb822a1Scindi 	1
1210eb822a1Scindi };
1227aec1d6eScindi 
1237aec1d6eScindi static void
1247aec1d6eScindi topo_node_destroy(tnode_t *node)
1257aec1d6eScindi {
1267aec1d6eScindi 	int i;
1277aec1d6eScindi 	tnode_t *pnode = node->tn_parent;
1287aec1d6eScindi 	topo_nodehash_t *nhp;
1297aec1d6eScindi 	topo_mod_t *hmod, *mod = node->tn_enum;
1307aec1d6eScindi 
1317aec1d6eScindi 	if (node == NULL)
1327aec1d6eScindi 		return;
1337aec1d6eScindi 
1347aec1d6eScindi 	assert(node->tn_refs == 0);
1357aec1d6eScindi 
1367aec1d6eScindi 	/*
1377aec1d6eScindi 	 * If not a root node, remove this node from the parent's node hash
1387aec1d6eScindi 	 */
1397aec1d6eScindi 
1407aec1d6eScindi 	if (!(node->tn_state & TOPO_NODE_ROOT)) {
1417aec1d6eScindi 		topo_node_lock(pnode);
1427aec1d6eScindi 
1437aec1d6eScindi 		nhp = node->tn_phash;
1447aec1d6eScindi 		for (i = 0; i < nhp->th_arrlen; i++) {
1457aec1d6eScindi 			if (node == nhp->th_nodearr[i]) {
1467aec1d6eScindi 				nhp->th_nodearr[i] = NULL;
1477aec1d6eScindi 
1487aec1d6eScindi 				/*
1497aec1d6eScindi 				 * Release hold on parent
1507aec1d6eScindi 				 */
1517aec1d6eScindi 				--pnode->tn_refs;
1527aec1d6eScindi 				if (pnode->tn_refs == 0)
1537aec1d6eScindi 					topo_node_destroy(pnode);
1547aec1d6eScindi 			}
1557aec1d6eScindi 		}
1567aec1d6eScindi 		topo_node_unlock(pnode);
1577aec1d6eScindi 	}
1587aec1d6eScindi 
1597aec1d6eScindi 	topo_node_unlock(node);
1607aec1d6eScindi 
1617aec1d6eScindi 	/*
1627aec1d6eScindi 	 * Allow enumerator to clean-up private data and then release
1637aec1d6eScindi 	 * ref count
1647aec1d6eScindi 	 */
1650eb822a1Scindi 	if (mod->tm_info->tmi_ops->tmo_release != NULL)
1660eb822a1Scindi 		mod->tm_info->tmi_ops->tmo_release(mod, node);
1677aec1d6eScindi 
1687aec1d6eScindi 	topo_method_unregister_all(mod, node);
1697aec1d6eScindi 
1707aec1d6eScindi 	/*
1717aec1d6eScindi 	 * Destroy all node hash lists
1727aec1d6eScindi 	 */
1737aec1d6eScindi 	while ((nhp = topo_list_next(&node->tn_children)) != NULL) {
1747aec1d6eScindi 		for (i = 0; i < nhp->th_arrlen; i++) {
1757aec1d6eScindi 			assert(nhp->th_nodearr[i] == NULL);
1767aec1d6eScindi 		}
1777aec1d6eScindi 		hmod = nhp->th_enum;
1787aec1d6eScindi 		topo_mod_strfree(hmod, nhp->th_name);
1797aec1d6eScindi 		topo_mod_free(hmod, nhp->th_nodearr,
1807aec1d6eScindi 		    nhp->th_arrlen * sizeof (tnode_t *));
1817aec1d6eScindi 		topo_list_delete(&node->tn_children, nhp);
1827aec1d6eScindi 		topo_mod_free(hmod, nhp, sizeof (topo_nodehash_t));
1837aec1d6eScindi 		topo_mod_rele(hmod);
1847aec1d6eScindi 	}
1857aec1d6eScindi 
1867aec1d6eScindi 	/*
1877aec1d6eScindi 	 * Destroy all property data structures, free the node and release
1887aec1d6eScindi 	 * the module that created it
1897aec1d6eScindi 	 */
1907aec1d6eScindi 	topo_pgroup_destroy_all(node);
1917aec1d6eScindi 	topo_mod_free(mod, node, sizeof (tnode_t));
1927aec1d6eScindi 	topo_mod_rele(mod);
1937aec1d6eScindi }
1947aec1d6eScindi 
1957aec1d6eScindi void
1967aec1d6eScindi topo_node_lock(tnode_t *node)
1977aec1d6eScindi {
1987aec1d6eScindi 	(void) pthread_mutex_lock(&node->tn_lock);
1997aec1d6eScindi }
2007aec1d6eScindi 
2017aec1d6eScindi void
2027aec1d6eScindi topo_node_unlock(tnode_t *node)
2037aec1d6eScindi {
2047aec1d6eScindi 	(void) pthread_mutex_unlock(&node->tn_lock);
2057aec1d6eScindi }
2067aec1d6eScindi 
2077aec1d6eScindi void
2087aec1d6eScindi topo_node_hold(tnode_t *node)
2097aec1d6eScindi {
2107aec1d6eScindi 	topo_node_lock(node);
2117aec1d6eScindi 	++node->tn_refs;
2127aec1d6eScindi 	topo_node_unlock(node);
2137aec1d6eScindi }
2147aec1d6eScindi 
2157aec1d6eScindi void
2167aec1d6eScindi topo_node_rele(tnode_t *node)
2177aec1d6eScindi {
2187aec1d6eScindi 	topo_node_lock(node);
2197aec1d6eScindi 	--node->tn_refs;
2207aec1d6eScindi 
2217aec1d6eScindi 	/*
2227aec1d6eScindi 	 * Ok to remove this node from the topo tree and destroy it
2237aec1d6eScindi 	 */
2247aec1d6eScindi 	if (node->tn_refs == 0)
2257aec1d6eScindi 		topo_node_destroy(node);
2267aec1d6eScindi 	else
2277aec1d6eScindi 		topo_node_unlock(node);
2287aec1d6eScindi }
2297aec1d6eScindi 
2307aec1d6eScindi char *
2317aec1d6eScindi topo_node_name(tnode_t *node)
2327aec1d6eScindi {
2337aec1d6eScindi 	return (node->tn_name);
2347aec1d6eScindi }
2357aec1d6eScindi 
2367aec1d6eScindi topo_instance_t
2377aec1d6eScindi topo_node_instance(tnode_t *node)
2387aec1d6eScindi {
2397aec1d6eScindi 	return (node->tn_instance);
2407aec1d6eScindi }
2417aec1d6eScindi 
2420eb822a1Scindi void
2430eb822a1Scindi topo_node_setspecific(tnode_t *node, void *data)
2440eb822a1Scindi {
2450eb822a1Scindi 	node->tn_priv = data;
2460eb822a1Scindi }
2470eb822a1Scindi 
2487aec1d6eScindi void *
2490eb822a1Scindi topo_node_getspecific(tnode_t *node)
2507aec1d6eScindi {
2517aec1d6eScindi 	return (node->tn_priv);
2527aec1d6eScindi }
2537aec1d6eScindi 
2547aec1d6eScindi static int
2557aec1d6eScindi node_create_seterror(topo_mod_t *mod, tnode_t *pnode, topo_nodehash_t *nhp,
2567aec1d6eScindi     int err)
2577aec1d6eScindi {
2587aec1d6eScindi 	topo_node_unlock(pnode);
2597aec1d6eScindi 
2600eb822a1Scindi 	topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to insert child:"
2617aec1d6eScindi 	    "%s\n", topo_strerror(err));
2627aec1d6eScindi 
2637aec1d6eScindi 	if (nhp != NULL) {
2647aec1d6eScindi 		if (nhp->th_name != NULL)
2657aec1d6eScindi 			topo_mod_strfree(mod, nhp->th_name);
2667aec1d6eScindi 		if (nhp->th_nodearr != NULL) {
2677aec1d6eScindi 			topo_mod_free(mod, nhp->th_nodearr,
2687aec1d6eScindi 			    nhp->th_arrlen * sizeof (tnode_t *));
2697aec1d6eScindi 		}
2707aec1d6eScindi 		topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
2717aec1d6eScindi 	}
2727aec1d6eScindi 
2737aec1d6eScindi 	return (topo_mod_seterrno(mod, err));
2747aec1d6eScindi }
2757aec1d6eScindi 
2767aec1d6eScindi int
2777aec1d6eScindi topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name,
2787aec1d6eScindi     topo_instance_t min, topo_instance_t max)
2797aec1d6eScindi {
2807aec1d6eScindi 	topo_nodehash_t *nhp;
2817aec1d6eScindi 
2827aec1d6eScindi 	topo_node_lock(pnode);
2837aec1d6eScindi 
2847aec1d6eScindi 	assert((pnode->tn_state & TOPO_NODE_BOUND) ||
2857aec1d6eScindi 	    (pnode->tn_state & TOPO_NODE_ROOT));
2867aec1d6eScindi 
2877aec1d6eScindi 	for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
2887aec1d6eScindi 	    nhp = topo_list_next(nhp)) {
2897aec1d6eScindi 		if (strcmp(nhp->th_name, name) == 0)
2907aec1d6eScindi 			return (node_create_seterror(mod, pnode, NULL,
2917aec1d6eScindi 			    ETOPO_NODE_DUP));
2927aec1d6eScindi 	}
2937aec1d6eScindi 
2947aec1d6eScindi 	if (min < 0 || max < min)
2957aec1d6eScindi 		return (node_create_seterror(mod, pnode, NULL,
2967aec1d6eScindi 		    ETOPO_NODE_INVAL));
2977aec1d6eScindi 
2987aec1d6eScindi 	if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL)
2997aec1d6eScindi 		return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM));
3007aec1d6eScindi 
3017aec1d6eScindi 	if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL)
3027aec1d6eScindi 		return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM));
3037aec1d6eScindi 
3047aec1d6eScindi 	nhp->th_arrlen = max - min + 1;
3057aec1d6eScindi 
3067aec1d6eScindi 	if ((nhp->th_nodearr = topo_mod_zalloc(mod,
3077aec1d6eScindi 	    nhp->th_arrlen * sizeof (tnode_t *))) == NULL)
3087aec1d6eScindi 		return (node_create_seterror(mod, pnode, nhp, ETOPO_NOMEM));
3097aec1d6eScindi 
3107aec1d6eScindi 	nhp->th_range.tr_min = min;
3117aec1d6eScindi 	nhp->th_range.tr_max = max;
3127aec1d6eScindi 	nhp->th_enum = mod;
3137aec1d6eScindi 	topo_mod_hold(mod);
3147aec1d6eScindi 
3157aec1d6eScindi 	/*
3167aec1d6eScindi 	 * Add these nodes to parent child list
3177aec1d6eScindi 	 */
3187aec1d6eScindi 	topo_list_append(&pnode->tn_children, nhp);
3197aec1d6eScindi 	topo_node_unlock(pnode);
3207aec1d6eScindi 
3210eb822a1Scindi 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
3220eb822a1Scindi 	    "created node range %s[%d-%d]\n", name, min, max);
3237aec1d6eScindi 
3247aec1d6eScindi 	return (0);
3257aec1d6eScindi }
3267aec1d6eScindi 
3277aec1d6eScindi void
3287aec1d6eScindi topo_node_range_destroy(tnode_t *pnode, const char *name)
3297aec1d6eScindi {
3307aec1d6eScindi 	int i;
3317aec1d6eScindi 	topo_nodehash_t *nhp;
3327aec1d6eScindi 	topo_mod_t *mod;
3337aec1d6eScindi 
3347aec1d6eScindi 	topo_node_lock(pnode);
3357aec1d6eScindi 	for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
3367aec1d6eScindi 	    nhp = topo_list_next(nhp)) {
3377aec1d6eScindi 		if (strcmp(nhp->th_name, name) == 0) {
3387aec1d6eScindi 			break;
3397aec1d6eScindi 		}
3407aec1d6eScindi 	}
3417aec1d6eScindi 
3427aec1d6eScindi 	if (nhp == NULL) {
3437aec1d6eScindi 		topo_node_unlock(pnode);
3447aec1d6eScindi 		return;
3457aec1d6eScindi 	}
3467aec1d6eScindi 
3477aec1d6eScindi 	topo_list_delete(&pnode->tn_children, nhp);
3487aec1d6eScindi 	topo_node_unlock(pnode);
3497aec1d6eScindi 
3507aec1d6eScindi 	/*
3517aec1d6eScindi 	 * Should be an empty node range
3527aec1d6eScindi 	 */
3537aec1d6eScindi 	for (i = 0; i < nhp->th_arrlen; i++) {
3547aec1d6eScindi 		topo_node_unbind(nhp->th_nodearr[i]);
3557aec1d6eScindi 	}
3567aec1d6eScindi 
3577aec1d6eScindi 	mod = nhp->th_enum;
3587aec1d6eScindi 	if (nhp->th_name != NULL)
3597aec1d6eScindi 		topo_mod_strfree(mod, nhp->th_name);
3607aec1d6eScindi 	if (nhp->th_nodearr != NULL) {
3617aec1d6eScindi 		topo_mod_free(mod, nhp->th_nodearr,
3627aec1d6eScindi 		    nhp->th_arrlen * sizeof (tnode_t *));
3637aec1d6eScindi 	}
3647aec1d6eScindi 	topo_mod_free(mod, nhp, sizeof (topo_nodehash_t));
3657aec1d6eScindi 	topo_mod_rele(mod);
3667aec1d6eScindi 
3677aec1d6eScindi }
3687aec1d6eScindi 
3697aec1d6eScindi tnode_t *
3707aec1d6eScindi topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst)
3717aec1d6eScindi {
3727aec1d6eScindi 	int h;
3737aec1d6eScindi 	tnode_t *node;
3747aec1d6eScindi 	topo_nodehash_t *nhp;
3757aec1d6eScindi 
3767aec1d6eScindi 	topo_node_lock(pnode);
3777aec1d6eScindi 	for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
3787aec1d6eScindi 	    nhp = topo_list_next(nhp)) {
3797aec1d6eScindi 		if (strcmp(nhp->th_name, name) == 0) {
3807aec1d6eScindi 
3817aec1d6eScindi 			if (inst > nhp->th_range.tr_max ||
3827aec1d6eScindi 			    inst < nhp->th_range.tr_min) {
3837aec1d6eScindi 				topo_node_unlock(pnode);
3847aec1d6eScindi 				return (NULL);
3857aec1d6eScindi 			}
3867aec1d6eScindi 
3877aec1d6eScindi 			h = topo_node_hash(nhp, inst);
3887aec1d6eScindi 			node = nhp->th_nodearr[h];
3897aec1d6eScindi 			topo_node_unlock(pnode);
3907aec1d6eScindi 			return (node);
3917aec1d6eScindi 		}
3927aec1d6eScindi 	}
3937aec1d6eScindi 	topo_node_unlock(pnode);
3947aec1d6eScindi 
3957aec1d6eScindi 	return (NULL);
3967aec1d6eScindi }
3977aec1d6eScindi 
3987aec1d6eScindi int
3997aec1d6eScindi topo_node_hash(topo_nodehash_t *nhp, topo_instance_t inst)
4007aec1d6eScindi {
4017aec1d6eScindi 	return (nhp->th_range.tr_max == 0 ?
4027aec1d6eScindi 	    nhp->th_range.tr_max : inst % (nhp->th_range.tr_max + 1));
4037aec1d6eScindi }
4047aec1d6eScindi 
4057aec1d6eScindi static tnode_t *
4067aec1d6eScindi node_bind_seterror(topo_mod_t *mod, tnode_t *pnode, tnode_t *node, int err)
4077aec1d6eScindi {
4087aec1d6eScindi 	topo_node_unlock(pnode);
4097aec1d6eScindi 
4107aec1d6eScindi 	(void) topo_mod_seterrno(mod, err);
4117aec1d6eScindi 
4127aec1d6eScindi 	if (node == NULL)
4137aec1d6eScindi 		return (NULL);
4147aec1d6eScindi 
4150eb822a1Scindi 	topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to bind %s=%d: "
4167aec1d6eScindi 	    "%s\n", (node->tn_name != NULL ? node->tn_name : "unknown"),
4177aec1d6eScindi 	    node->tn_instance, topo_strerror(err));
4187aec1d6eScindi 
4197aec1d6eScindi 	topo_node_lock(node); /* expected to be locked */
4207aec1d6eScindi 	topo_node_destroy(node);
4217aec1d6eScindi 
4227aec1d6eScindi 	return (NULL);
4237aec1d6eScindi }
4247aec1d6eScindi 
4257aec1d6eScindi tnode_t *
4267aec1d6eScindi topo_node_bind(topo_mod_t *mod, tnode_t *pnode, const char *name,
4270eb822a1Scindi     topo_instance_t inst, nvlist_t *fmri)
4287aec1d6eScindi {
4297aec1d6eScindi 	int h, err;
4307aec1d6eScindi 	tnode_t *node;
4317aec1d6eScindi 	topo_nodehash_t *nhp;
4327aec1d6eScindi 
4337aec1d6eScindi 	topo_node_lock(pnode);
4347aec1d6eScindi 	for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL;
4357aec1d6eScindi 	    nhp = topo_list_next(nhp)) {
4367aec1d6eScindi 		if (strcmp(nhp->th_name, name) == 0) {
4377aec1d6eScindi 
4387aec1d6eScindi 			if (inst > nhp->th_range.tr_max ||
4397aec1d6eScindi 			    inst < nhp->th_range.tr_min)
4407aec1d6eScindi 				return (node_bind_seterror(mod, pnode, NULL,
4417aec1d6eScindi 				    ETOPO_NODE_INVAL));
4427aec1d6eScindi 
4437aec1d6eScindi 			h = topo_node_hash(nhp, inst);
4447aec1d6eScindi 			if (nhp->th_nodearr[h] != NULL)
4457aec1d6eScindi 				return (node_bind_seterror(mod, pnode, NULL,
4467aec1d6eScindi 				    ETOPO_NODE_BOUND));
4477aec1d6eScindi 			else
4487aec1d6eScindi 				break;
4497aec1d6eScindi 
4507aec1d6eScindi 		}
4517aec1d6eScindi 	}
4527aec1d6eScindi 
4537aec1d6eScindi 	if (nhp == NULL)
4547aec1d6eScindi 		return (node_bind_seterror(mod, pnode, NULL, ETOPO_NODE_NOENT));
4557aec1d6eScindi 
4567aec1d6eScindi 	if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL)
4577aec1d6eScindi 		return (node_bind_seterror(mod, pnode, NULL, ETOPO_NOMEM));
4587aec1d6eScindi 
4597aec1d6eScindi 	(void) pthread_mutex_init(&node->tn_lock, NULL);
4607aec1d6eScindi 
4617aec1d6eScindi 	node->tn_enum = mod;
4627aec1d6eScindi 	node->tn_hdl = mod->tm_hdl;
4637aec1d6eScindi 	node->tn_parent = pnode;
4647aec1d6eScindi 	node->tn_name = nhp->th_name;
4657aec1d6eScindi 	node->tn_instance = inst;
4667aec1d6eScindi 	node->tn_phash = nhp;
4677aec1d6eScindi 	node->tn_refs = 0;
4687aec1d6eScindi 
4697aec1d6eScindi 	/* Ref count module that bound this node */
4707aec1d6eScindi 	topo_mod_hold(mod);
4717aec1d6eScindi 
4727aec1d6eScindi 	if (fmri == NULL)
4737aec1d6eScindi 		return (node_bind_seterror(mod, pnode, node, ETOPO_NODE_INVAL));
4747aec1d6eScindi 
4750eb822a1Scindi 	if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0)
4767aec1d6eScindi 		return (node_bind_seterror(mod, pnode, node, err));
4777aec1d6eScindi 
4787aec1d6eScindi 	if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE,
4790eb822a1Scindi 	    TOPO_PROP_IMMUTABLE, fmri, &err) < 0)
4807aec1d6eScindi 		return (node_bind_seterror(mod, pnode, node, err));
4817aec1d6eScindi 
4820eb822a1Scindi 	topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC,
4830eb822a1Scindi 	    "node bound %s=%d\n", node->tn_name, node->tn_instance);
4847aec1d6eScindi 
4857aec1d6eScindi 	node->tn_state |= TOPO_NODE_BOUND;
4867aec1d6eScindi 
4877aec1d6eScindi 	topo_node_hold(node);
4887aec1d6eScindi 	nhp->th_nodearr[h] = node;
4897aec1d6eScindi 	++pnode->tn_refs;
4907aec1d6eScindi 	topo_node_unlock(pnode);
4917aec1d6eScindi 
4920eb822a1Scindi 	if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) {
4930eb822a1Scindi 		(void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
4940eb822a1Scindi 		    FM_FMRI_AUTH_PRODUCT, &err);
4950eb822a1Scindi 		(void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
4960eb822a1Scindi 		    FM_FMRI_AUTH_CHASSIS, &err);
4970eb822a1Scindi 		(void) topo_prop_inherit(node, FM_FMRI_AUTHORITY,
4980eb822a1Scindi 		    FM_FMRI_AUTH_SERVER, &err);
4997aec1d6eScindi 	}
5007aec1d6eScindi 
5017aec1d6eScindi 	return (node);
5027aec1d6eScindi }
5037aec1d6eScindi 
5047aec1d6eScindi void
5057aec1d6eScindi topo_node_unbind(tnode_t *node)
5067aec1d6eScindi {
5077aec1d6eScindi 	if (node == NULL)
5087aec1d6eScindi 		return;
5097aec1d6eScindi 
5107aec1d6eScindi 	topo_node_lock(node);
5117aec1d6eScindi 	if (!(node->tn_state & TOPO_NODE_BOUND)) {
5127aec1d6eScindi 		topo_node_unlock(node);
5137aec1d6eScindi 		return;
5147aec1d6eScindi 	}
5157aec1d6eScindi 
5167aec1d6eScindi 	node->tn_state &= ~TOPO_NODE_BOUND;
5177aec1d6eScindi 	topo_node_unlock(node);
5187aec1d6eScindi 
5197aec1d6eScindi 	topo_node_rele(node);
5207aec1d6eScindi }
5217aec1d6eScindi 
5227aec1d6eScindi /*ARGSUSED*/
5237aec1d6eScindi int
5247aec1d6eScindi topo_node_present(tnode_t *node)
5257aec1d6eScindi {
5267aec1d6eScindi 	return (0);
5277aec1d6eScindi }
5287aec1d6eScindi 
5297aec1d6eScindi /*ARGSUSED*/
5307aec1d6eScindi int
5317aec1d6eScindi topo_node_contains(tnode_t *er, tnode_t *ee)
5327aec1d6eScindi {
5337aec1d6eScindi 	return (0);
5347aec1d6eScindi }
5357aec1d6eScindi 
5367aec1d6eScindi /*ARGSUSED*/
5377aec1d6eScindi int
5387aec1d6eScindi topo_node_unusable(tnode_t *node)
5397aec1d6eScindi {
5407aec1d6eScindi 	return (0);
5417aec1d6eScindi }
542*c40d7343Scindi 
543*c40d7343Scindi topo_walk_t *
544*c40d7343Scindi topo_node_walk_init(topo_hdl_t *thp, topo_mod_t *mod, tnode_t *node,
545*c40d7343Scindi     int (*cb_f)(), void *pdata, int *errp)
546*c40d7343Scindi {
547*c40d7343Scindi 	tnode_t *child;
548*c40d7343Scindi 	topo_walk_t *wp;
549*c40d7343Scindi 
550*c40d7343Scindi 	topo_node_hold(node);
551*c40d7343Scindi 
552*c40d7343Scindi 	if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) {
553*c40d7343Scindi 		*errp = ETOPO_NOMEM;
554*c40d7343Scindi 		topo_node_rele(node);
555*c40d7343Scindi 		return (NULL);
556*c40d7343Scindi 	}
557*c40d7343Scindi 
558*c40d7343Scindi 	/*
559*c40d7343Scindi 	 * If this is the root of the scheme tree, start with the first
560*c40d7343Scindi 	 * child
561*c40d7343Scindi 	 */
562*c40d7343Scindi 	topo_node_lock(node);
563*c40d7343Scindi 	if (node->tn_state & TOPO_NODE_ROOT) {
564*c40d7343Scindi 		if ((child = topo_child_first(node)) == NULL) {
565*c40d7343Scindi 			/* Nothing to walk */
566*c40d7343Scindi 			*errp = ETOPO_WALK_EMPTY;
567*c40d7343Scindi 			topo_node_unlock(node);
568*c40d7343Scindi 			topo_node_rele(node);
569*c40d7343Scindi 			return (NULL);
570*c40d7343Scindi 		}
571*c40d7343Scindi 		topo_node_unlock(node);
572*c40d7343Scindi 		topo_node_hold(child);
573*c40d7343Scindi 		wp->tw_node = child;
574*c40d7343Scindi 	} else {
575*c40d7343Scindi 		topo_node_unlock(node);
576*c40d7343Scindi 		topo_node_hold(child);
577*c40d7343Scindi 		wp->tw_node = node;
578*c40d7343Scindi 	}
579*c40d7343Scindi 
580*c40d7343Scindi 	wp->tw_root = node;
581*c40d7343Scindi 	wp->tw_cb = cb_f;
582*c40d7343Scindi 	wp->tw_pdata = pdata;
583*c40d7343Scindi 	wp->tw_thp = thp;
584*c40d7343Scindi 	wp->tw_mod = mod;
585*c40d7343Scindi 
586*c40d7343Scindi 	return (wp);
587*c40d7343Scindi }
588