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