Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * Topology Trees
     28  *
     29  * Toplogy trees are instantiated for each builtin (FMRI) scheme specified
     30  * in topo_builtin.c.  Each ttree_t data structure contains the
     31  * skeleton of the topology tree (scheme, root node, and file information).
     32  * The root node of a topology does not represent any FMRI but rather serves
     33  * as the entry point for topology access interfaces.  The file information
     34  * provides a handle to access static .xml files that seed scheme-specifc
     35  * topologies
     36  *
     37  * Topology trees will remain unpopulated until topo_snap_hold() is called.
     38  * At that time, a ttree_t structure is allocated and added to the list
     39  * trees maintained in topo_hdl_t.  Builtin scheme-specific enumerators are
     40  * called upon to create nodes that represent FMRIs for resources present in the
     41  * system.  If a <scheme>-topology.xml file exists in a standard file
     42  * location, the file is used to seed the topology while the rest is
     43  * dynamically created by the builtin or helper enumerator modules.
     44  * For example, the 'hc' tree is enumerated by the hc enumerator (hc.c)
     45  * after the hc-topology.xml is read from /usr/platform/`uname -i`/lib/fm/topo,
     46  * /usr/platform/`uname -r`/lib/fm/topo, or /usr/lib/fm/topo.  Each node
     47  * is created with a properly formatted hc FMRI resource.
     48  *
     49  * Toplogy trees are released and deallocated when topo_snap_hold is called.
     50  * Upon return from topo_snap_rele(), all node resources are deallocated
     51  * and all that remains is the ttree_t structure containing the root node.
     52  */
     53 
     54 #include <pthread.h>
     55 #include <limits.h>
     56 #include <assert.h>
     57 #include <sys/param.h>
     58 #include <sys/systeminfo.h>
     59 #include <sys/utsname.h>
     60 
     61 #include <topo_alloc.h>
     62 #include <topo_error.h>
     63 #include <topo_file.h>
     64 #include <topo_module.h>
     65 #include <topo_string.h>
     66 #include <topo_subr.h>
     67 #include <topo_tree.h>
     68 
     69 static ttree_t *
     70 set_create_error(topo_hdl_t *thp, ttree_t *tp, int err)
     71 {
     72 	if (tp != NULL)
     73 		topo_tree_destroy(tp);
     74 
     75 	if (err != 0)
     76 		(void) topo_hdl_seterrno(thp, err);
     77 
     78 	return (NULL);
     79 }
     80 
     81 ttree_t *
     82 topo_tree_create(topo_hdl_t *thp, topo_mod_t *mod, const char *scheme)
     83 {
     84 	ttree_t *tp;
     85 	tnode_t *rp;
     86 
     87 	if ((tp = topo_mod_zalloc(mod, sizeof (ttree_t))) == NULL)
     88 		return (set_create_error(thp, NULL, ETOPO_NOMEM));
     89 
     90 	tp->tt_mod = mod;
     91 
     92 	if ((tp->tt_scheme = topo_mod_strdup(mod, scheme)) == NULL)
     93 		return (set_create_error(thp, tp, ETOPO_NOMEM));
     94 
     95 	/*
     96 	 * Initialize a private walker for internal use
     97 	 */
     98 	if ((tp->tt_walk = topo_mod_zalloc(mod, sizeof (topo_walk_t))) == NULL)
     99 		return (set_create_error(thp, tp, ETOPO_NOMEM));
    100 
    101 	/*
    102 	 * Create the root of this tree: LINKED but never BOUND
    103 	 */
    104 	if ((rp = topo_mod_zalloc(mod, sizeof (tnode_t))) == NULL)
    105 		return (set_create_error(thp, tp, 0)); /* th_errno set */
    106 
    107 	rp->tn_state = TOPO_NODE_ROOT | TOPO_NODE_INIT;
    108 	rp->tn_name = tp->tt_scheme;
    109 	rp->tn_instance = 0;
    110 	rp->tn_enum = mod;
    111 	rp->tn_hdl = thp;
    112 
    113 	topo_node_hold(rp);
    114 
    115 	tp->tt_walk->tw_root = rp;
    116 	tp->tt_walk->tw_thp = thp;
    117 
    118 	topo_mod_hold(mod); /* released when root node destroyed */
    119 
    120 	tp->tt_root = rp;
    121 
    122 	return (tp);
    123 }
    124 
    125 void
    126 topo_tree_destroy(ttree_t *tp)
    127 {
    128 	topo_mod_t *mod;
    129 
    130 	if (tp == NULL)
    131 		return;
    132 
    133 	mod = tp->tt_mod;
    134 	if (tp->tt_walk != NULL)
    135 		topo_mod_free(mod, tp->tt_walk, sizeof (topo_walk_t));
    136 
    137 	if (tp->tt_root != NULL) {
    138 		assert(tp->tt_root->tn_refs == 1);
    139 		topo_node_rele(tp->tt_root);
    140 	}
    141 	/*
    142 	 * Deallocate this last, because a pointer alias for tt_scheme
    143 	 * (stored in the root node's name field) may be used in
    144 	 * topo_node_rele().
    145 	 */
    146 	if (tp->tt_scheme != NULL)
    147 		topo_mod_strfree(mod, tp->tt_scheme);
    148 
    149 	topo_mod_free(mod, tp, sizeof (ttree_t));
    150 }
    151 
    152 static int
    153 topo_tree_enum(topo_hdl_t *thp, ttree_t *tp)
    154 {
    155 	int rv = 0;
    156 	char *pp;
    157 
    158 	/*
    159 	 * Attempt to enumerate the tree from a topology map in the
    160 	 * following order:
    161 	 *	<product-name>-<scheme>-topology
    162 	 *	<platform-name>-<scheme>-topology (uname -i)
    163 	 *	<machine-name>-<scheme>-topology (uname -m)
    164 	 *	<scheme>-topology
    165 	 *
    166 	 * Trim any SUNW, from the product or platform name
    167 	 * before loading file
    168 	 */
    169 	if (thp->th_product == NULL ||
    170 	    (pp = strchr(thp->th_product, ',')) == NULL)
    171 		pp = thp->th_product;
    172 	else
    173 		pp++;
    174 	if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root,
    175 	    pp, tp->tt_scheme, 0) < 0) {
    176 		if ((pp = strchr(thp->th_platform, ',')) == NULL)
    177 			pp = thp->th_platform;
    178 		else
    179 			pp++;
    180 
    181 		if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root,
    182 		    pp, tp->tt_scheme, 0) < 0) {
    183 			if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root,
    184 			    thp->th_machine, tp->tt_scheme, 0) < 0) {
    185 
    186 				if ((rv = topo_file_load(tp->tt_root->tn_enum,
    187 				    tp->tt_root, NULL, tp->tt_scheme, 0)) < 0) {
    188 					topo_dprintf(thp, TOPO_DBG_ERR, "no "
    189 					    "topology map found for the %s "
    190 					    "FMRI set\n", tp->tt_scheme);
    191 				}
    192 			}
    193 		}
    194 	}
    195 
    196 	if (rv != 0)
    197 		return (topo_hdl_seterrno(thp, ETOPO_ENUM_NOMAP));
    198 
    199 	return (0);
    200 }
    201 
    202 int
    203 topo_tree_enum_all(topo_hdl_t *thp)
    204 {
    205 	int err = 0;
    206 	ttree_t *tp;
    207 
    208 	for (tp = topo_list_next(&thp->th_trees); tp != NULL;
    209 	    tp = topo_list_next(tp)) {
    210 		err |= topo_tree_enum(thp, tp);
    211 	}
    212 
    213 	if (err != 0)
    214 		return (-1);
    215 	else
    216 		return (0);
    217 }
    218