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