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 ((pp = strchr(thp->th_product, ',')) == NULL) 170 pp = thp->th_product; 171 else 172 pp++; 173 if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root, 174 pp, tp->tt_scheme, 0) < 0) { 175 if ((pp = strchr(thp->th_platform, ',')) == NULL) 176 pp = thp->th_platform; 177 else 178 pp++; 179 180 if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root, 181 pp, tp->tt_scheme, 0) < 0) { 182 if (topo_file_load(tp->tt_root->tn_enum, tp->tt_root, 183 thp->th_machine, tp->tt_scheme, 0) < 0) { 184 185 if ((rv = topo_file_load(tp->tt_root->tn_enum, 186 tp->tt_root, NULL, tp->tt_scheme, 0)) < 0) { 187 topo_dprintf(thp, TOPO_DBG_ERR, "no " 188 "topology map found for the %s " 189 "FMRI set\n", tp->tt_scheme); 190 } 191 } 192 } 193 } 194 195 if (rv != 0) 196 return (topo_hdl_seterrno(thp, ETOPO_ENUM_NOMAP)); 197 198 return (0); 199 } 200 201 int 202 topo_tree_enum_all(topo_hdl_t *thp) 203 { 204 int err = 0; 205 ttree_t *tp; 206 207 for (tp = topo_list_next(&thp->th_trees); tp != NULL; 208 tp = topo_list_next(tp)) { 209 err |= topo_tree_enum(thp, tp); 210 } 211 212 if (err != 0) 213 return (-1); 214 else 215 return (0); 216 } 217