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 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 2167aec1d6eScindi topo_node_lock(tnode_t *node) 2177aec1d6eScindi { 2187aec1d6eScindi (void) pthread_mutex_lock(&node->tn_lock); 2197aec1d6eScindi } 2207aec1d6eScindi 2217aec1d6eScindi void 2227aec1d6eScindi topo_node_unlock(tnode_t *node) 2237aec1d6eScindi { 2247aec1d6eScindi (void) pthread_mutex_unlock(&node->tn_lock); 2257aec1d6eScindi } 2267aec1d6eScindi 2277aec1d6eScindi void 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 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 * 2517aec1d6eScindi topo_node_name(tnode_t *node) 2527aec1d6eScindi { 2537aec1d6eScindi return (node->tn_name); 2547aec1d6eScindi } 2557aec1d6eScindi 2567aec1d6eScindi topo_instance_t 2577aec1d6eScindi topo_node_instance(tnode_t *node) 2587aec1d6eScindi { 2597aec1d6eScindi return (node->tn_instance); 2607aec1d6eScindi } 2617aec1d6eScindi 2624557a2a1Srobj tnode_t * 2634557a2a1Srobj topo_node_parent(tnode_t *node) 2644557a2a1Srobj { 2654557a2a1Srobj return (node->tn_parent); 2664557a2a1Srobj } 2674557a2a1Srobj 268*c5591576SRob Johnston topo_vertex_t * 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 275825ba0f2Srobj topo_node_flags(tnode_t *node) 276825ba0f2Srobj { 277825ba0f2Srobj return (node->tn_fflags); 278825ba0f2Srobj } 279825ba0f2Srobj 2800eb822a1Scindi void 2810eb822a1Scindi topo_node_setspecific(tnode_t *node, void *data) 2820eb822a1Scindi { 2830eb822a1Scindi node->tn_priv = data; 2840eb822a1Scindi } 2850eb822a1Scindi 2867aec1d6eScindi void * 2870eb822a1Scindi topo_node_getspecific(tnode_t *node) 2887aec1d6eScindi { 2897aec1d6eScindi return (node->tn_priv); 2907aec1d6eScindi } 2917aec1d6eScindi 2927aec1d6eScindi static int 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 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 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 * 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 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 * 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 * 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 * 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 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 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 7917aec1d6eScindi topo_node_present(tnode_t *node) 7927aec1d6eScindi { 7937aec1d6eScindi return (0); 7947aec1d6eScindi } 7957aec1d6eScindi 7967aec1d6eScindi /*ARGSUSED*/ 7977aec1d6eScindi int 7987aec1d6eScindi topo_node_contains(tnode_t *er, tnode_t *ee) 7997aec1d6eScindi { 8007aec1d6eScindi return (0); 8017aec1d6eScindi } 8027aec1d6eScindi 8037aec1d6eScindi /*ARGSUSED*/ 8047aec1d6eScindi int 8057aec1d6eScindi topo_node_unusable(tnode_t *node) 8067aec1d6eScindi { 8077aec1d6eScindi return (0); 8087aec1d6eScindi } 809c40d7343Scindi 810c40d7343Scindi topo_walk_t * 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 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 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