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 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Some topology creation routines may need to defer completing enumeration 29 * until after the entire PRI graph has been visited. This file includes 30 * the interfaces necessary to permit these routines to do this in a general 31 * way. 32 */ 33 34 #include <sys/types.h> 35 #include <sys/time.h> 36 #include <stddef.h> 37 #include <inttypes.h> 38 #include <strings.h> 39 #include <string.h> 40 #include <libuutil.h> 41 #include <libnvpair.h> 42 #include <sys/mdesc.h> 43 #include <fm/topo_mod.h> 44 #include <fm/topo_hc.h> 45 #include "pi_impl.h" 46 47 static uu_list_pool_t *defer_pool = NULL; 48 static uu_list_t *defer_list = NULL; 49 50 struct pi_defernode_s { 51 uu_list_node_t defer_node; 52 53 mde_cookie_t mde_node; /* MDE node index */ 54 tnode_t *t_parent; /* Parent topology node */ 55 tnode_t *t_node; /* Topo node associated with MDE node */ 56 void *private; /* Private data for defer routine */ 57 58 pi_deferenum_fn_t *func; /* Defered enumeration routine */ 59 }; 60 typedef struct pi_defernode_s pi_defernode_t; 61 62 /* Routines to handle the list of topology parents and mde_nodes */ 63 static int pi_deferlist_create(topo_mod_t *); 64 static int pi_deferlist_compare(const void *, const void *, void *); 65 66 67 /* 68 * Add a new routine to the list of deferred enumeration routines 69 */ 70 int 71 pi_defer_add(topo_mod_t *mod, mde_cookie_t mde_node, tnode_t *t_parent, 72 tnode_t *t_node, pi_deferenum_fn_t func, void *private) 73 { 74 int result; 75 uu_list_index_t idx; 76 pi_defernode_t *dnp; 77 78 if (defer_list == NULL) { 79 result = pi_deferlist_create(mod); 80 if (result != 0) { 81 return (result); 82 } 83 } 84 85 /* 86 * Create a data structure to store information about the node for 87 * which to defer enumeration. The defer_pool is created by the 88 * list creation routine, above. 89 */ 90 dnp = topo_mod_zalloc(mod, sizeof (pi_defernode_t)); 91 if (dnp == NULL) { 92 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 93 return (-1); 94 } 95 uu_list_node_init(dnp, &(dnp->defer_node), defer_pool); 96 97 dnp->mde_node = mde_node; 98 dnp->t_parent = t_parent; 99 dnp->t_node = t_node; 100 dnp->private = private; 101 dnp->func = func; 102 103 (void) uu_list_find(defer_list, dnp, NULL, &idx); 104 uu_list_insert(defer_list, dnp, idx); 105 106 return (0); 107 } 108 109 110 /* 111 * Execute the list of deferred enumeration routines, destroying the list as 112 * we go. 113 */ 114 int 115 pi_defer_exec(topo_mod_t *mod, md_t *mdp) 116 { 117 int result; 118 119 void *dvp; 120 pi_defernode_t *dp; 121 topo_instance_t inst; 122 mde_cookie_t mde_node; 123 tnode_t *t_parent; 124 tnode_t *t_node; 125 void *private; 126 char *hc_name; 127 128 pi_deferenum_fn_t *func; 129 130 topo_mod_dprintf(mod, "beginning deferred enumerator execution\n"); 131 if (defer_list == NULL) { 132 topo_mod_dprintf(mod, "no deferred enumerators. done.\n"); 133 return (0); 134 } 135 136 while ((dvp = uu_list_first(defer_list)) != NULL) { 137 /* Extract the necessary information from the defernode_t */ 138 dp = (pi_defernode_t *)dvp; 139 mde_node = dp->mde_node; 140 t_parent = dp->t_parent; 141 t_node = dp->t_node; 142 private = dp->private; 143 func = dp->func; 144 145 /* 146 * Remove the element from the list. Once we are done calling 147 * the routine we do not need it any more. 148 */ 149 uu_list_remove(defer_list, dvp); 150 uu_list_node_fini(dp, &(dp->defer_node), defer_pool); 151 topo_mod_free(mod, dp, sizeof (pi_defernode_t)); 152 153 /* Get the instance value from the mde node */ 154 if (pi_get_instance(mod, mdp, mde_node, &inst) != 0) { 155 topo_mod_dprintf(mod, "deferred node_0x%llx invalid\n", 156 (uint64_t)mde_node); 157 158 /* Move on to the next node */ 159 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 160 continue; 161 } 162 163 /* Get the hc name from the mde node */ 164 hc_name = pi_get_topo_hc_name(mod, mdp, mde_node); 165 if (hc_name == NULL) { 166 topo_mod_dprintf(mod, 167 "deferred node_0x%llx has invalid NULL hc_name\n", 168 (uint64_t)mde_node); 169 170 /* Move on to the next node */ 171 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 172 continue; 173 } 174 topo_mod_dprintf(mod, 175 "calling deferred enumerator for node_0x%llx\n", 176 (uint64_t)mde_node); 177 178 /* Call the deferred enumeration function */ 179 result = (func)(mod, mdp, mde_node, inst, t_parent, hc_name, 180 t_node, private); 181 if (result != 0) { 182 topo_mod_dprintf(mod, 183 "deferred enumeration for node_0x%llx failed\n", 184 (uint64_t)mde_node); 185 (void) topo_mod_seterrno(mod, EMOD_PARTIAL_ENUM); 186 } 187 188 /* Clean up from the deferred call */ 189 topo_mod_strfree(mod, hc_name); 190 } 191 topo_mod_dprintf(mod, "deferred enumeration completed.\n"); 192 193 uu_list_destroy(defer_list); 194 uu_list_pool_destroy(defer_pool); 195 defer_list = NULL; 196 defer_pool = NULL; 197 198 return (0); 199 } 200 201 202 static int 203 pi_deferlist_create(topo_mod_t *mod) 204 { 205 /* Initialize the uutil list structure */ 206 defer_pool = uu_list_pool_create("pi_defer_pool", 207 sizeof (pi_defernode_t), offsetof(pi_defernode_t, defer_node), 208 pi_deferlist_compare, 0); 209 if (defer_pool == NULL) { 210 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 211 return (-1); 212 } 213 defer_list = uu_list_create(defer_pool, NULL, 0); 214 if (defer_list == NULL) { 215 uu_list_pool_destroy(defer_pool); 216 defer_pool = NULL; 217 (void) topo_mod_seterrno(mod, EMOD_NOMEM); 218 return (-1); 219 } 220 221 return (0); 222 } 223 224 225 /* ARGSUSED */ 226 static int 227 pi_deferlist_compare(const void *l_arg, const void *r_arg, void *private) 228 { 229 pi_defernode_t *lp = (pi_defernode_t *)l_arg; 230 pi_defernode_t *rp = (pi_defernode_t *)r_arg; 231 232 if (lp->func != rp->func) { 233 return (1); 234 } 235 if (lp->t_parent != rp->t_parent) { 236 return (-1); 237 } 238 return (0); 239 } 240