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*f6e214c7SGavin Maltby * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 237aec1d6eScindi */ 247aec1d6eScindi 257aec1d6eScindi /* 267aec1d6eScindi * Topology Nodes 277aec1d6eScindi * 287aec1d6eScindi * Topology nodes, tnode_t, are data structures containing per-FMRI 297aec1d6eScindi * information and are linked together to form the topology tree. 307aec1d6eScindi * Nodes are created during the enumeration process of topo_snap_hold() 317aec1d6eScindi * and destroyed during topo_snap_rele(). For the most part, tnode_t data 327aec1d6eScindi * is read-only and no lock protection is required. Nodes are 337aec1d6eScindi * held in place during tree walk functions. Tree walk functions 347aec1d6eScindi * may access node data safely without locks. The exception to this rule 357aec1d6eScindi * is data associated with node properties (topo_prop.c). Properties 367aec1d6eScindi * may change at anytime and are protected by a per-property locking 377aec1d6eScindi * strategy. 387aec1d6eScindi * 39c40d7343Scindi * Enumerator plugin modules may also safely access topology nodes within their 40c40d7343Scindi * scope of operation: the parent node passed into the enumeration op or those 41c40d7343Scindi * nodes created by the enumerator. Enumeration occurs only during 42c40d7343Scindi * topo_snap_hold() where a per-topo_hdl_t lock prevents multi-threaded access 43c40d7343Scindi * to the topology trees. 447aec1d6eScindi * 45c40d7343Scindi * Enumerator method operation functions may safely access and change topology 46c40d7343Scindi * node property data, and contruct or destroy child nodes for the node 47c40d7343Scindi * on which the operation applies. The method may also be called to destroy 48c40d7343Scindi * the node for which the method operation is called. This permits 49c40d7343Scindi * dynamic topology tree snapshots and partial enumerations for branches that 50c40d7343Scindi * may not be needed right away. 517aec1d6eScindi * 527aec1d6eScindi * Node Interfaces 537aec1d6eScindi * 54c40d7343Scindi * Nodes are created when an enumerator calls topo_node_bind(). Prior to 55c40d7343Scindi * calling topo_node_bind(), the enumerator should have reserved a range of 567aec1d6eScindi * node instances with topo_node_range_create(). topo_node_range_create() 577aec1d6eScindi * does not allocate any node resources but creates the infrastruture 587aec1d6eScindi * required for a fully populated topology level. This allows enumerators 597aec1d6eScindi * reading from a <scheme>-topology.xml file to parse the file for a range 607aec1d6eScindi * of resources before confirming the existence of a resource via a helper 617aec1d6eScindi * plugin. Only when the resource has been confirmed to exist should 627aec1d6eScindi * the node be bound. 637aec1d6eScindi * 64c40d7343Scindi * Node range and node linkage and unlinkage is performed during enumeration and 65c40d7343Scindi * method operations when it is safe to change node hash lists. Nodes and node 66c40d7343Scindi * ranges are deallocated when all references to the node have been released: 677aec1d6eScindi * last walk completes and topo_snap_rele() is called. 687aec1d6eScindi * 697aec1d6eScindi * Node Hash/Ranges 707aec1d6eScindi * 717aec1d6eScindi * Each parent node may have one or more ranges of child nodes. Each range 72c40d7343Scindi * is uniquely named and serves as a hash list of like sibling nodes with 737aec1d6eScindi * different instance numbers. A parent may have more than one node hash 747aec1d6eScindi * (child range). If that is the case, the hash lists are strung together to 757aec1d6eScindi * form sibling relationships between ranges. Hash/Ranges are sparsely 767aec1d6eScindi * populated with only nodes that have represented resources in the system. 77c40d7343Scindi * 78c40d7343Scindi * _________________ 79c40d7343Scindi * | | 80c40d7343Scindi * | tnode_t | ----------------------------- 81c40d7343Scindi * | tn_phash ---> | topo_nodehash_t | 82c40d7343Scindi * | (children)| | th_nodearr (instances)| 83c40d7343Scindi * ----------------- | ------------------- | 84c40d7343Scindi * | ---| 0 | 1 | ...| N | | 85c40d7343Scindi * | | ------------------- | ------------------- 86c40d7343Scindi * | | th_list (siblings) ----->| topo_nodehash_t | 87c40d7343Scindi * | | | ------------------- 88c40d7343Scindi * ---|------------------------- 89c40d7343Scindi * | 90c40d7343Scindi * v 91c40d7343Scindi * ----------- 92c40d7343Scindi * | tnode_t | 93c40d7343Scindi * ----------- 94825ba0f2Srobj * 95825ba0f2Srobj * Facility Nodes 96825ba0f2Srobj * 97825ba0f2Srobj * Facility nodes are always leaf nodes in the topology and represent a FMRI 98825ba0f2Srobj * sensor or indicator facility for the path to which it is connected. 99825ba0f2Srobj * Facility nodes are bound to the topology with topo_node_facbind() and 100825ba0f2Srobj * unbound with topo_node_unbind(). 1017aec1d6eScindi */ 1027aec1d6eScindi 1037aec1d6eScindi #include <assert.h> 1047aec1d6eScindi #include <pthread.h> 1057aec1d6eScindi #include <strings.h> 1060eb822a1Scindi #include <sys/fm/protocol.h> 1077aec1d6eScindi #include <topo_alloc.h> 1087aec1d6eScindi #include <topo_error.h> 109825ba0f2Srobj #include <topo_list.h> 1100eb822a1Scindi #include <topo_method.h> 1110eb822a1Scindi #include <topo_subr.h> 1120eb822a1Scindi #include <topo_tree.h> 1130eb822a1Scindi 1140eb822a1Scindi static topo_pgroup_info_t protocol_pgroup = { 1150eb822a1Scindi TOPO_PGROUP_PROTOCOL, 1160eb822a1Scindi TOPO_STABILITY_PRIVATE, 1170eb822a1Scindi TOPO_STABILITY_PRIVATE, 1180eb822a1Scindi 1 1190eb822a1Scindi }; 1200eb822a1Scindi 1210eb822a1Scindi static const topo_pgroup_info_t auth_pgroup = { 1220eb822a1Scindi FM_FMRI_AUTHORITY, 1230eb822a1Scindi TOPO_STABILITY_PRIVATE, 1240eb822a1Scindi TOPO_STABILITY_PRIVATE, 1250eb822a1Scindi 1 1260eb822a1Scindi }; 1277aec1d6eScindi 1287aec1d6eScindi static void 1297aec1d6eScindi topo_node_destroy(tnode_t *node) 1307aec1d6eScindi { 1317aec1d6eScindi int i; 1327aec1d6eScindi tnode_t *pnode = node->tn_parent; 1337aec1d6eScindi topo_nodehash_t *nhp; 1347aec1d6eScindi topo_mod_t *hmod, *mod = node->tn_enum; 1357aec1d6eScindi 1367aec1d6eScindi if (node == NULL) 1377aec1d6eScindi return; 1387aec1d6eScindi 13912cc75c8Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, "destroying node %s=%d\n", 14012cc75c8Scindi topo_node_name(node), topo_node_instance(node)); 14112cc75c8Scindi 1427aec1d6eScindi assert(node->tn_refs == 0); 1437aec1d6eScindi 1447aec1d6eScindi /* 1457aec1d6eScindi * If not a root node, remove this node from the parent's node hash 1467aec1d6eScindi */ 1477aec1d6eScindi 1487aec1d6eScindi if (!(node->tn_state & TOPO_NODE_ROOT)) { 1497aec1d6eScindi topo_node_lock(pnode); 1507aec1d6eScindi 1517aec1d6eScindi nhp = node->tn_phash; 1527aec1d6eScindi for (i = 0; i < nhp->th_arrlen; i++) { 1537aec1d6eScindi if (node == nhp->th_nodearr[i]) { 1547aec1d6eScindi nhp->th_nodearr[i] = NULL; 1557aec1d6eScindi 1567aec1d6eScindi /* 1577aec1d6eScindi * Release hold on parent 1587aec1d6eScindi */ 1597aec1d6eScindi --pnode->tn_refs; 1607aec1d6eScindi if (pnode->tn_refs == 0) 1617aec1d6eScindi topo_node_destroy(pnode); 1627aec1d6eScindi } 1637aec1d6eScindi } 1647aec1d6eScindi topo_node_unlock(pnode); 1657aec1d6eScindi } 1667aec1d6eScindi 1677aec1d6eScindi topo_node_unlock(node); 1687aec1d6eScindi 1697aec1d6eScindi /* 1707aec1d6eScindi * Allow enumerator to clean-up private data and then release 1717aec1d6eScindi * ref count 1727aec1d6eScindi */ 1730eb822a1Scindi if (mod->tm_info->tmi_ops->tmo_release != NULL) 1740eb822a1Scindi mod->tm_info->tmi_ops->tmo_release(mod, node); 1757aec1d6eScindi 1767aec1d6eScindi topo_method_unregister_all(mod, node); 1777aec1d6eScindi 1787aec1d6eScindi /* 1797aec1d6eScindi * Destroy all node hash lists 1807aec1d6eScindi */ 1817aec1d6eScindi while ((nhp = topo_list_next(&node->tn_children)) != NULL) { 1827aec1d6eScindi for (i = 0; i < nhp->th_arrlen; i++) { 1837aec1d6eScindi assert(nhp->th_nodearr[i] == NULL); 1847aec1d6eScindi } 1857aec1d6eScindi hmod = nhp->th_enum; 1867aec1d6eScindi topo_mod_strfree(hmod, nhp->th_name); 1877aec1d6eScindi topo_mod_free(hmod, nhp->th_nodearr, 1887aec1d6eScindi nhp->th_arrlen * sizeof (tnode_t *)); 1897aec1d6eScindi topo_list_delete(&node->tn_children, nhp); 1907aec1d6eScindi topo_mod_free(hmod, nhp, sizeof (topo_nodehash_t)); 1917aec1d6eScindi topo_mod_rele(hmod); 1927aec1d6eScindi } 1937aec1d6eScindi 1947aec1d6eScindi /* 1957aec1d6eScindi * Destroy all property data structures, free the node and release 1967aec1d6eScindi * the module that created it 1977aec1d6eScindi */ 1987aec1d6eScindi topo_pgroup_destroy_all(node); 1997aec1d6eScindi topo_mod_free(mod, node, sizeof (tnode_t)); 2007aec1d6eScindi topo_mod_rele(mod); 2017aec1d6eScindi } 2027aec1d6eScindi 2037aec1d6eScindi void 2047aec1d6eScindi topo_node_lock(tnode_t *node) 2057aec1d6eScindi { 2067aec1d6eScindi (void) pthread_mutex_lock(&node->tn_lock); 2077aec1d6eScindi } 2087aec1d6eScindi 2097aec1d6eScindi void 2107aec1d6eScindi topo_node_unlock(tnode_t *node) 2117aec1d6eScindi { 2127aec1d6eScindi (void) pthread_mutex_unlock(&node->tn_lock); 2137aec1d6eScindi } 2147aec1d6eScindi 2157aec1d6eScindi void 2167aec1d6eScindi topo_node_hold(tnode_t *node) 2177aec1d6eScindi { 2187aec1d6eScindi topo_node_lock(node); 2197aec1d6eScindi ++node->tn_refs; 2207aec1d6eScindi topo_node_unlock(node); 2217aec1d6eScindi } 2227aec1d6eScindi 2237aec1d6eScindi void 2247aec1d6eScindi topo_node_rele(tnode_t *node) 2257aec1d6eScindi { 2267aec1d6eScindi topo_node_lock(node); 2277aec1d6eScindi --node->tn_refs; 2287aec1d6eScindi 2297aec1d6eScindi /* 2307aec1d6eScindi * Ok to remove this node from the topo tree and destroy it 2317aec1d6eScindi */ 2327aec1d6eScindi if (node->tn_refs == 0) 2337aec1d6eScindi topo_node_destroy(node); 2347aec1d6eScindi else 2357aec1d6eScindi topo_node_unlock(node); 2367aec1d6eScindi } 2377aec1d6eScindi 2387aec1d6eScindi char * 2397aec1d6eScindi topo_node_name(tnode_t *node) 2407aec1d6eScindi { 2417aec1d6eScindi return (node->tn_name); 2427aec1d6eScindi } 2437aec1d6eScindi 2447aec1d6eScindi topo_instance_t 2457aec1d6eScindi topo_node_instance(tnode_t *node) 2467aec1d6eScindi { 2477aec1d6eScindi return (node->tn_instance); 2487aec1d6eScindi } 2497aec1d6eScindi 2504557a2a1Srobj tnode_t * 2514557a2a1Srobj topo_node_parent(tnode_t *node) 2524557a2a1Srobj { 2534557a2a1Srobj return (node->tn_parent); 2544557a2a1Srobj } 2554557a2a1Srobj 256825ba0f2Srobj int 257825ba0f2Srobj topo_node_flags(tnode_t *node) 258825ba0f2Srobj { 259825ba0f2Srobj return (node->tn_fflags); 260825ba0f2Srobj } 261825ba0f2Srobj 2620eb822a1Scindi void 2630eb822a1Scindi topo_node_setspecific(tnode_t *node, void *data) 2640eb822a1Scindi { 2650eb822a1Scindi node->tn_priv = data; 2660eb822a1Scindi } 2670eb822a1Scindi 2687aec1d6eScindi void * 2690eb822a1Scindi topo_node_getspecific(tnode_t *node) 2707aec1d6eScindi { 2717aec1d6eScindi return (node->tn_priv); 2727aec1d6eScindi } 2737aec1d6eScindi 2747aec1d6eScindi static int 2757aec1d6eScindi node_create_seterror(topo_mod_t *mod, tnode_t *pnode, topo_nodehash_t *nhp, 2767aec1d6eScindi int err) 2777aec1d6eScindi { 2787aec1d6eScindi topo_node_unlock(pnode); 2797aec1d6eScindi 2800eb822a1Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to insert child:" 2817aec1d6eScindi "%s\n", topo_strerror(err)); 2827aec1d6eScindi 2837aec1d6eScindi if (nhp != NULL) { 2847aec1d6eScindi if (nhp->th_name != NULL) 2857aec1d6eScindi topo_mod_strfree(mod, nhp->th_name); 2867aec1d6eScindi if (nhp->th_nodearr != NULL) { 2877aec1d6eScindi topo_mod_free(mod, nhp->th_nodearr, 2887aec1d6eScindi nhp->th_arrlen * sizeof (tnode_t *)); 2897aec1d6eScindi } 2907aec1d6eScindi topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); 2917aec1d6eScindi } 2927aec1d6eScindi 2937aec1d6eScindi return (topo_mod_seterrno(mod, err)); 2947aec1d6eScindi } 2957aec1d6eScindi 2967aec1d6eScindi int 2977aec1d6eScindi topo_node_range_create(topo_mod_t *mod, tnode_t *pnode, const char *name, 2987aec1d6eScindi topo_instance_t min, topo_instance_t max) 2997aec1d6eScindi { 3007aec1d6eScindi topo_nodehash_t *nhp; 3017aec1d6eScindi 3027aec1d6eScindi topo_node_lock(pnode); 3037aec1d6eScindi 3047aec1d6eScindi assert((pnode->tn_state & TOPO_NODE_BOUND) || 3057aec1d6eScindi (pnode->tn_state & TOPO_NODE_ROOT)); 3067aec1d6eScindi 3077aec1d6eScindi for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 3087aec1d6eScindi nhp = topo_list_next(nhp)) { 3097aec1d6eScindi if (strcmp(nhp->th_name, name) == 0) 3107aec1d6eScindi return (node_create_seterror(mod, pnode, NULL, 311825ba0f2Srobj EMOD_NODE_DUP)); 3127aec1d6eScindi } 3137aec1d6eScindi 3147aec1d6eScindi if (min < 0 || max < min) 3157aec1d6eScindi return (node_create_seterror(mod, pnode, NULL, 316825ba0f2Srobj EMOD_NODE_RANGE)); 3177aec1d6eScindi 3187aec1d6eScindi if ((nhp = topo_mod_zalloc(mod, sizeof (topo_nodehash_t))) == NULL) 319825ba0f2Srobj return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 3207aec1d6eScindi 3217aec1d6eScindi if ((nhp->th_name = topo_mod_strdup(mod, name)) == NULL) 322825ba0f2Srobj return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 3237aec1d6eScindi 3247aec1d6eScindi nhp->th_arrlen = max - min + 1; 3257aec1d6eScindi 3267aec1d6eScindi if ((nhp->th_nodearr = topo_mod_zalloc(mod, 3277aec1d6eScindi nhp->th_arrlen * sizeof (tnode_t *))) == NULL) 328825ba0f2Srobj return (node_create_seterror(mod, pnode, nhp, EMOD_NOMEM)); 3297aec1d6eScindi 3307aec1d6eScindi nhp->th_range.tr_min = min; 3317aec1d6eScindi nhp->th_range.tr_max = max; 3327aec1d6eScindi nhp->th_enum = mod; 3337aec1d6eScindi topo_mod_hold(mod); 3347aec1d6eScindi 3357aec1d6eScindi /* 3367aec1d6eScindi * Add these nodes to parent child list 3377aec1d6eScindi */ 3387aec1d6eScindi topo_list_append(&pnode->tn_children, nhp); 3397aec1d6eScindi topo_node_unlock(pnode); 3407aec1d6eScindi 3410eb822a1Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 3420eb822a1Scindi "created node range %s[%d-%d]\n", name, min, max); 3437aec1d6eScindi 3447aec1d6eScindi return (0); 3457aec1d6eScindi } 3467aec1d6eScindi 3477aec1d6eScindi void 3487aec1d6eScindi topo_node_range_destroy(tnode_t *pnode, const char *name) 3497aec1d6eScindi { 3507aec1d6eScindi int i; 3517aec1d6eScindi topo_nodehash_t *nhp; 3527aec1d6eScindi topo_mod_t *mod; 3537aec1d6eScindi 3547aec1d6eScindi topo_node_lock(pnode); 3557aec1d6eScindi for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 3567aec1d6eScindi nhp = topo_list_next(nhp)) { 3577aec1d6eScindi if (strcmp(nhp->th_name, name) == 0) { 3587aec1d6eScindi break; 3597aec1d6eScindi } 3607aec1d6eScindi } 3617aec1d6eScindi 3627aec1d6eScindi if (nhp == NULL) { 3637aec1d6eScindi topo_node_unlock(pnode); 3647aec1d6eScindi return; 3657aec1d6eScindi } 3667aec1d6eScindi 36712cc75c8Scindi for (i = 0; i < nhp->th_arrlen; i++) 36812cc75c8Scindi assert(nhp->th_nodearr[i] == NULL); 36912cc75c8Scindi 3707aec1d6eScindi topo_list_delete(&pnode->tn_children, nhp); 3717aec1d6eScindi topo_node_unlock(pnode); 3727aec1d6eScindi 3737aec1d6eScindi mod = nhp->th_enum; 3747aec1d6eScindi if (nhp->th_name != NULL) 3757aec1d6eScindi topo_mod_strfree(mod, nhp->th_name); 3767aec1d6eScindi if (nhp->th_nodearr != NULL) { 3777aec1d6eScindi topo_mod_free(mod, nhp->th_nodearr, 3787aec1d6eScindi nhp->th_arrlen * sizeof (tnode_t *)); 3797aec1d6eScindi } 3807aec1d6eScindi topo_mod_free(mod, nhp, sizeof (topo_nodehash_t)); 3817aec1d6eScindi topo_mod_rele(mod); 3827aec1d6eScindi 3837aec1d6eScindi } 3847aec1d6eScindi 3857aec1d6eScindi tnode_t * 3867aec1d6eScindi topo_node_lookup(tnode_t *pnode, const char *name, topo_instance_t inst) 3877aec1d6eScindi { 3887aec1d6eScindi int h; 3897aec1d6eScindi tnode_t *node; 3907aec1d6eScindi topo_nodehash_t *nhp; 3917aec1d6eScindi 392*f6e214c7SGavin Maltby topo_dprintf(pnode->tn_hdl, TOPO_DBG_MODSVC, 393*f6e214c7SGavin Maltby "topo_node_lookup: looking for '%s' instance %d\n", name, inst); 394*f6e214c7SGavin Maltby 3957aec1d6eScindi topo_node_lock(pnode); 3967aec1d6eScindi for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 3977aec1d6eScindi nhp = topo_list_next(nhp)) { 3987aec1d6eScindi if (strcmp(nhp->th_name, name) == 0) { 3997aec1d6eScindi 4007aec1d6eScindi if (inst > nhp->th_range.tr_max || 4017aec1d6eScindi inst < nhp->th_range.tr_min) { 4027aec1d6eScindi topo_node_unlock(pnode); 4037aec1d6eScindi return (NULL); 4047aec1d6eScindi } 4057aec1d6eScindi 4067aec1d6eScindi h = topo_node_hash(nhp, inst); 4077aec1d6eScindi node = nhp->th_nodearr[h]; 4087aec1d6eScindi topo_node_unlock(pnode); 4097aec1d6eScindi return (node); 4107aec1d6eScindi } 4117aec1d6eScindi } 4127aec1d6eScindi topo_node_unlock(pnode); 4137aec1d6eScindi 4147aec1d6eScindi return (NULL); 4157aec1d6eScindi } 4167aec1d6eScindi 4177aec1d6eScindi int 4187aec1d6eScindi topo_node_hash(topo_nodehash_t *nhp, topo_instance_t inst) 4197aec1d6eScindi { 42020c794b3Sgavinm return ((inst - nhp->th_range.tr_min) % nhp->th_arrlen); 4217aec1d6eScindi } 4227aec1d6eScindi 4237aec1d6eScindi static tnode_t * 424a38fc4eaSRobert Johnston node_bind_seterror(topo_mod_t *mod, tnode_t *pnode, tnode_t *node, 425a38fc4eaSRobert Johnston boolean_t pnode_locked, int err) 4267aec1d6eScindi { 427a38fc4eaSRobert Johnston if (pnode_locked) 428a38fc4eaSRobert Johnston topo_node_unlock(pnode); 4297aec1d6eScindi 4307aec1d6eScindi (void) topo_mod_seterrno(mod, err); 4317aec1d6eScindi 4327aec1d6eScindi if (node == NULL) 4337aec1d6eScindi return (NULL); 4347aec1d6eScindi 4350eb822a1Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, "unable to bind %s=%d: " 4367aec1d6eScindi "%s\n", (node->tn_name != NULL ? node->tn_name : "unknown"), 4377aec1d6eScindi node->tn_instance, topo_strerror(err)); 4387aec1d6eScindi 4397aec1d6eScindi topo_node_lock(node); /* expected to be locked */ 4407aec1d6eScindi topo_node_destroy(node); 4417aec1d6eScindi 4427aec1d6eScindi return (NULL); 4437aec1d6eScindi } 4447aec1d6eScindi 4457aec1d6eScindi tnode_t * 4467aec1d6eScindi topo_node_bind(topo_mod_t *mod, tnode_t *pnode, const char *name, 4470eb822a1Scindi topo_instance_t inst, nvlist_t *fmri) 4487aec1d6eScindi { 4497aec1d6eScindi int h, err; 4507aec1d6eScindi tnode_t *node; 4517aec1d6eScindi topo_nodehash_t *nhp; 4527aec1d6eScindi 4537aec1d6eScindi topo_node_lock(pnode); 4547aec1d6eScindi for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 4557aec1d6eScindi nhp = topo_list_next(nhp)) { 4567aec1d6eScindi if (strcmp(nhp->th_name, name) == 0) { 4577aec1d6eScindi 4587aec1d6eScindi if (inst > nhp->th_range.tr_max || 4597aec1d6eScindi inst < nhp->th_range.tr_min) 4607aec1d6eScindi return (node_bind_seterror(mod, pnode, NULL, 461a38fc4eaSRobert Johnston B_TRUE, EMOD_NODE_RANGE)); 4627aec1d6eScindi 4637aec1d6eScindi h = topo_node_hash(nhp, inst); 4647aec1d6eScindi if (nhp->th_nodearr[h] != NULL) 4657aec1d6eScindi return (node_bind_seterror(mod, pnode, NULL, 466a38fc4eaSRobert Johnston B_TRUE, EMOD_NODE_BOUND)); 4677aec1d6eScindi else 4687aec1d6eScindi break; 4697aec1d6eScindi 4707aec1d6eScindi } 4717aec1d6eScindi } 4727aec1d6eScindi 4737aec1d6eScindi if (nhp == NULL) 474a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, NULL, B_TRUE, 475a38fc4eaSRobert Johnston EMOD_NODE_NOENT)); 4767aec1d6eScindi 4777aec1d6eScindi if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) 478a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, NULL, B_TRUE, 479a38fc4eaSRobert Johnston EMOD_NOMEM)); 4807aec1d6eScindi 4817aec1d6eScindi (void) pthread_mutex_init(&node->tn_lock, NULL); 4827aec1d6eScindi 4837aec1d6eScindi node->tn_enum = mod; 4847aec1d6eScindi node->tn_hdl = mod->tm_hdl; 4857aec1d6eScindi node->tn_parent = pnode; 4867aec1d6eScindi node->tn_name = nhp->th_name; 4877aec1d6eScindi node->tn_instance = inst; 4887aec1d6eScindi node->tn_phash = nhp; 4897aec1d6eScindi node->tn_refs = 0; 4907aec1d6eScindi 4917aec1d6eScindi /* Ref count module that bound this node */ 4927aec1d6eScindi topo_mod_hold(mod); 4937aec1d6eScindi 4947aec1d6eScindi if (fmri == NULL) 495a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_TRUE, 496a38fc4eaSRobert Johnston EMOD_NVL_INVAL)); 4977aec1d6eScindi 4980eb822a1Scindi if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0) 499a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_TRUE, err)); 5007aec1d6eScindi 5017aec1d6eScindi if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE, 5020eb822a1Scindi TOPO_PROP_IMMUTABLE, fmri, &err) < 0) 503a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_TRUE, err)); 5047aec1d6eScindi 5050eb822a1Scindi topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 50612cc75c8Scindi "node bound %s=%d/%s=%d\n", topo_node_name(pnode), 50712cc75c8Scindi topo_node_instance(pnode), node->tn_name, node->tn_instance); 5087aec1d6eScindi 5097aec1d6eScindi node->tn_state |= TOPO_NODE_BOUND; 5107aec1d6eScindi 5117aec1d6eScindi topo_node_hold(node); 5127aec1d6eScindi nhp->th_nodearr[h] = node; 5137aec1d6eScindi ++pnode->tn_refs; 514825ba0f2Srobj 5157aec1d6eScindi topo_node_unlock(pnode); 5167aec1d6eScindi 5170eb822a1Scindi if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) { 5180eb822a1Scindi (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 5190eb822a1Scindi FM_FMRI_AUTH_PRODUCT, &err); 5209c94f155SCheng Sean Ye (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 5219c94f155SCheng Sean Ye FM_FMRI_AUTH_PRODUCT_SN, &err); 5220eb822a1Scindi (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 5230eb822a1Scindi FM_FMRI_AUTH_CHASSIS, &err); 5240eb822a1Scindi (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 5250eb822a1Scindi FM_FMRI_AUTH_SERVER, &err); 5267aec1d6eScindi } 5277aec1d6eScindi 5287aec1d6eScindi return (node); 5297aec1d6eScindi } 5307aec1d6eScindi 531825ba0f2Srobj tnode_t * 532825ba0f2Srobj topo_node_facbind(topo_mod_t *mod, tnode_t *pnode, const char *name, 533825ba0f2Srobj const char *type) 534825ba0f2Srobj { 535825ba0f2Srobj int h, err; 536825ba0f2Srobj tnode_t *node; 537825ba0f2Srobj topo_nodehash_t *nhp; 538825ba0f2Srobj topo_instance_t inst = 0; 539825ba0f2Srobj nvlist_t *pfmri, *fnvl; 540825ba0f2Srobj 541825ba0f2Srobj /* 542825ba0f2Srobj * Create a single entry range for this facility 543825ba0f2Srobj */ 544825ba0f2Srobj if (topo_node_range_create(mod, pnode, name, 0, 0) < 0) 545825ba0f2Srobj return (NULL); /* mod errno set */ 546825ba0f2Srobj 547a38fc4eaSRobert Johnston topo_node_hold(pnode); 548825ba0f2Srobj topo_node_lock(pnode); 549825ba0f2Srobj for (nhp = topo_list_next(&pnode->tn_children); nhp != NULL; 550825ba0f2Srobj nhp = topo_list_next(nhp)) { 551825ba0f2Srobj if (strcmp(nhp->th_name, name) == 0) { 552825ba0f2Srobj 553825ba0f2Srobj if (inst > nhp->th_range.tr_max || 554a38fc4eaSRobert Johnston inst < nhp->th_range.tr_min) { 555a38fc4eaSRobert Johnston topo_node_rele(pnode); 556825ba0f2Srobj return (node_bind_seterror(mod, pnode, NULL, 557a38fc4eaSRobert Johnston B_TRUE, EMOD_NVL_INVAL)); 558a38fc4eaSRobert Johnston } 559825ba0f2Srobj h = topo_node_hash(nhp, inst); 560a38fc4eaSRobert Johnston if (nhp->th_nodearr[h] != NULL) { 561a38fc4eaSRobert Johnston topo_node_rele(pnode); 562825ba0f2Srobj return (node_bind_seterror(mod, pnode, NULL, 563a38fc4eaSRobert Johnston B_TRUE, EMOD_NODE_BOUND)); 564a38fc4eaSRobert Johnston } else 565825ba0f2Srobj break; 566825ba0f2Srobj 567825ba0f2Srobj } 568825ba0f2Srobj } 569a38fc4eaSRobert Johnston topo_node_unlock(pnode); 570825ba0f2Srobj 571a38fc4eaSRobert Johnston if (nhp == NULL) { 572a38fc4eaSRobert Johnston topo_node_rele(pnode); 573a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, NULL, B_FALSE, 574a38fc4eaSRobert Johnston EMOD_NODE_NOENT)); 575a38fc4eaSRobert Johnston } 576a38fc4eaSRobert Johnston if ((node = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL) { 577a38fc4eaSRobert Johnston topo_node_rele(pnode); 578a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, NULL, B_FALSE, 579a38fc4eaSRobert Johnston EMOD_NOMEM)); 580a38fc4eaSRobert Johnston } 581825ba0f2Srobj 582825ba0f2Srobj (void) pthread_mutex_init(&node->tn_lock, NULL); 583825ba0f2Srobj 584825ba0f2Srobj node->tn_enum = mod; 585825ba0f2Srobj node->tn_hdl = mod->tm_hdl; 586825ba0f2Srobj node->tn_parent = pnode; 587825ba0f2Srobj node->tn_name = nhp->th_name; 588825ba0f2Srobj node->tn_instance = inst; 589825ba0f2Srobj node->tn_phash = nhp; 590825ba0f2Srobj node->tn_refs = 0; 591825ba0f2Srobj node->tn_fflags = TOPO_NODE_FACILITY; 592825ba0f2Srobj 593825ba0f2Srobj /* Ref count module that bound this node */ 594825ba0f2Srobj topo_mod_hold(mod); 595825ba0f2Srobj 596a38fc4eaSRobert Johnston if (topo_pgroup_create(node, &protocol_pgroup, &err) < 0) { 597a38fc4eaSRobert Johnston topo_node_rele(pnode); 598a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 599a38fc4eaSRobert Johnston } 600a38fc4eaSRobert Johnston if (topo_mod_nvalloc(mod, &fnvl, NV_UNIQUE_NAME) < 0) { 601a38fc4eaSRobert Johnston topo_node_rele(pnode); 602a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, 603a38fc4eaSRobert Johnston EMOD_NOMEM)); 604a38fc4eaSRobert Johnston } 605825ba0f2Srobj if (nvlist_add_string(fnvl, FM_FMRI_FACILITY_NAME, name) != 0 || 606825ba0f2Srobj nvlist_add_string(fnvl, FM_FMRI_FACILITY_TYPE, type) != 0) { 607825ba0f2Srobj nvlist_free(fnvl); 608a38fc4eaSRobert Johnston topo_node_rele(pnode); 609a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, 610a38fc4eaSRobert Johnston EMOD_FMRI_NVL)); 611825ba0f2Srobj } 612825ba0f2Srobj 613825ba0f2Srobj if (topo_node_resource(pnode, &pfmri, &err) < 0) { 614825ba0f2Srobj nvlist_free(fnvl); 615a38fc4eaSRobert Johnston topo_node_rele(pnode); 616a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 617825ba0f2Srobj } 618825ba0f2Srobj 619825ba0f2Srobj if (nvlist_add_nvlist(pfmri, FM_FMRI_FACILITY, fnvl) != 0) { 620825ba0f2Srobj nvlist_free(fnvl); 621825ba0f2Srobj nvlist_free(pfmri); 622a38fc4eaSRobert Johnston topo_node_rele(pnode); 623a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, 624a38fc4eaSRobert Johnston EMOD_FMRI_NVL)); 625825ba0f2Srobj } 626825ba0f2Srobj 627825ba0f2Srobj nvlist_free(fnvl); 628825ba0f2Srobj 629825ba0f2Srobj if (topo_prop_set_fmri(node, TOPO_PGROUP_PROTOCOL, TOPO_PROP_RESOURCE, 630825ba0f2Srobj TOPO_PROP_IMMUTABLE, pfmri, &err) < 0) { 631825ba0f2Srobj nvlist_free(pfmri); 632a38fc4eaSRobert Johnston topo_node_rele(pnode); 633a38fc4eaSRobert Johnston return (node_bind_seterror(mod, pnode, node, B_FALSE, err)); 634825ba0f2Srobj } 635825ba0f2Srobj 636825ba0f2Srobj nvlist_free(pfmri); 637825ba0f2Srobj 638825ba0f2Srobj topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 639825ba0f2Srobj "facility node bound %s=%s\n", type, node->tn_name); 640825ba0f2Srobj 641825ba0f2Srobj node->tn_state |= TOPO_NODE_BOUND; 642825ba0f2Srobj 643825ba0f2Srobj topo_node_hold(node); 644825ba0f2Srobj nhp->th_nodearr[h] = node; 645825ba0f2Srobj 646a38fc4eaSRobert Johnston topo_node_lock(pnode); 647a38fc4eaSRobert Johnston ++pnode->tn_refs; 648825ba0f2Srobj topo_node_unlock(pnode); 649a38fc4eaSRobert Johnston topo_node_rele(pnode); 650825ba0f2Srobj 651825ba0f2Srobj if (topo_pgroup_create(node, &auth_pgroup, &err) == 0) { 652825ba0f2Srobj (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 653825ba0f2Srobj FM_FMRI_AUTH_PRODUCT, &err); 6549c94f155SCheng Sean Ye (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 6559c94f155SCheng Sean Ye FM_FMRI_AUTH_PRODUCT_SN, &err); 656825ba0f2Srobj (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 657825ba0f2Srobj FM_FMRI_AUTH_CHASSIS, &err); 658825ba0f2Srobj (void) topo_prop_inherit(node, FM_FMRI_AUTHORITY, 659825ba0f2Srobj FM_FMRI_AUTH_SERVER, &err); 660825ba0f2Srobj } 661825ba0f2Srobj 662825ba0f2Srobj return (node); 663825ba0f2Srobj } 664825ba0f2Srobj 665825ba0f2Srobj int 666825ba0f2Srobj topo_node_facility(topo_hdl_t *thp, tnode_t *node, const char *fac_type, 667825ba0f2Srobj uint32_t fac_subtype, topo_faclist_t *faclist, int *errp) 668825ba0f2Srobj { 669825ba0f2Srobj tnode_t *tmp; 670a38fc4eaSRobert Johnston nvlist_t *rsrc, *fac; 671825ba0f2Srobj char *tmp_factype; 672825ba0f2Srobj uint32_t tmp_facsubtype; 673825ba0f2Srobj boolean_t list_empty = 1; 674825ba0f2Srobj topo_faclist_t *fac_ele; 675825ba0f2Srobj 676825ba0f2Srobj bzero(faclist, sizeof (topo_faclist_t)); 677825ba0f2Srobj for (tmp = topo_child_first(node); tmp != NULL; 678825ba0f2Srobj tmp = topo_child_next(node, tmp)) { 679825ba0f2Srobj 680825ba0f2Srobj topo_node_hold(tmp); 681825ba0f2Srobj /* 682825ba0f2Srobj * If it's not a facility node, move on 683825ba0f2Srobj */ 684825ba0f2Srobj if (topo_node_flags(tmp) != TOPO_NODE_FACILITY) { 685825ba0f2Srobj topo_node_rele(tmp); 686825ba0f2Srobj continue; 687825ba0f2Srobj } 688825ba0f2Srobj 689825ba0f2Srobj /* 690825ba0f2Srobj * Lookup whether the fac type is sensor or indicator and if 691825ba0f2Srobj * it's not the type we're looking for, move on 692825ba0f2Srobj */ 693825ba0f2Srobj if (topo_node_resource(tmp, &rsrc, errp) != 0) { 694825ba0f2Srobj topo_dprintf(thp, TOPO_DBG_ERR, 695825ba0f2Srobj "Failed to get resource for node %s=%d (%s)\n", 696825ba0f2Srobj topo_node_name(node), topo_node_instance(node), 697825ba0f2Srobj topo_strerror(*errp)); 698825ba0f2Srobj topo_node_rele(tmp); 699825ba0f2Srobj return (-1); 700825ba0f2Srobj } 701825ba0f2Srobj if ((nvlist_lookup_nvlist(rsrc, "facility", &fac) != 0) || 702825ba0f2Srobj (nvlist_lookup_string(fac, FM_FMRI_FACILITY_TYPE, 703825ba0f2Srobj &tmp_factype) != 0)) { 704825ba0f2Srobj 705f08344cbSEric Schrock nvlist_free(rsrc); 706825ba0f2Srobj topo_node_rele(tmp); 707825ba0f2Srobj return (-1); 708825ba0f2Srobj } 709f08344cbSEric Schrock 710825ba0f2Srobj if (strcmp(fac_type, tmp_factype) != 0) { 711825ba0f2Srobj topo_node_rele(tmp); 712e5dcf7beSRobert Johnston nvlist_free(rsrc); 713825ba0f2Srobj continue; 714825ba0f2Srobj } 715e5dcf7beSRobert Johnston nvlist_free(rsrc); 716825ba0f2Srobj 717825ba0f2Srobj /* 718825ba0f2Srobj * Finally, look up the subtype, which is a property in the 719825ba0f2Srobj * facility propgroup. If it's a match return a pointer to the 720825ba0f2Srobj * node. Otherwise, move on. 721825ba0f2Srobj */ 722825ba0f2Srobj if (topo_prop_get_uint32(tmp, TOPO_PGROUP_FACILITY, 723825ba0f2Srobj TOPO_FACILITY_TYPE, &tmp_facsubtype, errp) != 0) { 724825ba0f2Srobj topo_node_rele(tmp); 725825ba0f2Srobj return (-1); 726825ba0f2Srobj } 727e5dcf7beSRobert Johnston if (fac_subtype == tmp_facsubtype || 728e5dcf7beSRobert Johnston fac_subtype == TOPO_FAC_TYPE_ANY) { 729825ba0f2Srobj if ((fac_ele = topo_mod_zalloc(tmp->tn_enum, 730825ba0f2Srobj sizeof (topo_faclist_t))) == NULL) { 731825ba0f2Srobj *errp = ETOPO_NOMEM; 732f08344cbSEric Schrock topo_node_rele(tmp); 733825ba0f2Srobj return (-1); 734825ba0f2Srobj } 735825ba0f2Srobj fac_ele->tf_node = tmp; 736825ba0f2Srobj topo_list_append(&faclist->tf_list, fac_ele); 737825ba0f2Srobj list_empty = 0; 738825ba0f2Srobj } 739825ba0f2Srobj topo_node_rele(tmp); 740825ba0f2Srobj } 741825ba0f2Srobj 742825ba0f2Srobj if (list_empty) { 743825ba0f2Srobj *errp = ETOPO_FAC_NOENT; 744825ba0f2Srobj return (-1); 745825ba0f2Srobj } 746825ba0f2Srobj return (0); 747825ba0f2Srobj } 748825ba0f2Srobj 7497aec1d6eScindi void 7507aec1d6eScindi topo_node_unbind(tnode_t *node) 7517aec1d6eScindi { 7527aec1d6eScindi if (node == NULL) 7537aec1d6eScindi return; 7547aec1d6eScindi 7557aec1d6eScindi topo_node_lock(node); 7567aec1d6eScindi if (!(node->tn_state & TOPO_NODE_BOUND)) { 7577aec1d6eScindi topo_node_unlock(node); 7587aec1d6eScindi return; 7597aec1d6eScindi } 7607aec1d6eScindi 7617aec1d6eScindi node->tn_state &= ~TOPO_NODE_BOUND; 7627aec1d6eScindi topo_node_unlock(node); 7637aec1d6eScindi 76412cc75c8Scindi topo_dprintf(node->tn_hdl, TOPO_DBG_MODSVC, 76512cc75c8Scindi "node unbound %s=%d/%s=%d refs = %d\n", 76612cc75c8Scindi topo_node_name(node->tn_parent), 76712cc75c8Scindi topo_node_instance(node->tn_parent), node->tn_name, 76812cc75c8Scindi node->tn_instance, node->tn_refs); 76912cc75c8Scindi 7707aec1d6eScindi topo_node_rele(node); 7717aec1d6eScindi } 7727aec1d6eScindi 7737aec1d6eScindi /*ARGSUSED*/ 7747aec1d6eScindi int 7757aec1d6eScindi topo_node_present(tnode_t *node) 7767aec1d6eScindi { 7777aec1d6eScindi return (0); 7787aec1d6eScindi } 7797aec1d6eScindi 7807aec1d6eScindi /*ARGSUSED*/ 7817aec1d6eScindi int 7827aec1d6eScindi topo_node_contains(tnode_t *er, tnode_t *ee) 7837aec1d6eScindi { 7847aec1d6eScindi return (0); 7857aec1d6eScindi } 7867aec1d6eScindi 7877aec1d6eScindi /*ARGSUSED*/ 7887aec1d6eScindi int 7897aec1d6eScindi topo_node_unusable(tnode_t *node) 7907aec1d6eScindi { 7917aec1d6eScindi return (0); 7927aec1d6eScindi } 793c40d7343Scindi 794c40d7343Scindi topo_walk_t * 795c40d7343Scindi topo_node_walk_init(topo_hdl_t *thp, topo_mod_t *mod, tnode_t *node, 796c40d7343Scindi int (*cb_f)(), void *pdata, int *errp) 797c40d7343Scindi { 798c40d7343Scindi tnode_t *child; 799c40d7343Scindi topo_walk_t *wp; 800c40d7343Scindi 801c40d7343Scindi topo_node_hold(node); 802c40d7343Scindi 803c40d7343Scindi if ((wp = topo_hdl_zalloc(thp, sizeof (topo_walk_t))) == NULL) { 804825ba0f2Srobj *errp = ETOPO_HDL_NOMEM; 805c40d7343Scindi topo_node_rele(node); 806c40d7343Scindi return (NULL); 807c40d7343Scindi } 808c40d7343Scindi 809c40d7343Scindi /* 810c40d7343Scindi * If this is the root of the scheme tree, start with the first 811c40d7343Scindi * child 812c40d7343Scindi */ 813c40d7343Scindi topo_node_lock(node); 814c40d7343Scindi if (node->tn_state & TOPO_NODE_ROOT) { 815c40d7343Scindi if ((child = topo_child_first(node)) == NULL) { 816c40d7343Scindi /* Nothing to walk */ 817c40d7343Scindi *errp = ETOPO_WALK_EMPTY; 818c40d7343Scindi topo_node_unlock(node); 819c40d7343Scindi topo_node_rele(node); 820c6765aabSeschrock topo_hdl_free(thp, wp, sizeof (topo_walk_t)); 821c40d7343Scindi return (NULL); 822c40d7343Scindi } 823c40d7343Scindi topo_node_unlock(node); 824c40d7343Scindi topo_node_hold(child); 825c40d7343Scindi wp->tw_node = child; 826c40d7343Scindi } else { 827c40d7343Scindi topo_node_unlock(node); 82812cc75c8Scindi topo_node_hold(node); /* rele at walk end */ 829c40d7343Scindi wp->tw_node = node; 830c40d7343Scindi } 831c40d7343Scindi 832c40d7343Scindi wp->tw_root = node; 833c40d7343Scindi wp->tw_cb = cb_f; 834c40d7343Scindi wp->tw_pdata = pdata; 835c40d7343Scindi wp->tw_thp = thp; 836c40d7343Scindi wp->tw_mod = mod; 837c40d7343Scindi 838c40d7343Scindi return (wp); 839c40d7343Scindi } 840