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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <pthread.h> 29 #include <assert.h> 30 #include <errno.h> 31 #include <dirent.h> 32 #include <limits.h> 33 #include <alloca.h> 34 #include <unistd.h> 35 #include <stdio.h> 36 #include <strings.h> 37 38 #include <topo_mod.h> 39 40 #include <topo_error.h> 41 #include <topo_module.h> 42 #include <topo_subr.h> 43 #include <topo_tree.h> 44 45 topo_imethod_t * 46 topo_method_lookup(tnode_t *node, const char *name) 47 { 48 topo_imethod_t *mp; 49 50 for (mp = topo_list_next(&node->tn_methods); mp != NULL; 51 mp = topo_list_next(mp)) { 52 if (strcmp(name, mp->tim_name) == 0) { 53 topo_node_unlock(node); 54 return (mp); 55 } 56 } 57 58 return (NULL); 59 } 60 61 static void 62 topo_method_enter(topo_imethod_t *mp) 63 { 64 (void) pthread_mutex_lock(&mp->tim_lock); 65 66 while (mp->tim_busy != 0) 67 (void) pthread_cond_wait(&mp->tim_cv, &mp->tim_lock); 68 69 ++mp->tim_busy; 70 71 (void) pthread_mutex_unlock(&mp->tim_lock); 72 } 73 74 static void 75 topo_method_exit(topo_imethod_t *mp) 76 { 77 (void) pthread_mutex_lock(&mp->tim_lock); 78 --mp->tim_busy; 79 80 assert(mp->tim_busy == 0); 81 82 (void) pthread_cond_broadcast(&mp->tim_cv); 83 (void) pthread_mutex_unlock(&mp->tim_lock); 84 } 85 86 static int 87 set_methregister_error(topo_mod_t *mod, tnode_t *node, topo_imethod_t *mp, 88 int err) 89 { 90 if (mp != NULL) { 91 topo_list_delete(&node->tn_methods, mp); 92 if (mp->tim_name != NULL) 93 topo_mod_strfree(mod, mp->tim_name); 94 if (mp->tim_desc != NULL) 95 topo_mod_strfree(mod, mp->tim_desc); 96 97 topo_mod_free(mod, mp, sizeof (topo_imethod_t)); 98 } 99 100 topo_node_unlock(node); 101 102 topo_dprintf(mod->tm_hdl, TOPO_DBG_ERR, 103 "method registration failed for %s: %s\n", 104 mod->tm_name, topo_strerror(err)); 105 106 return (topo_mod_seterrno(mod, err)); 107 } 108 109 int 110 topo_method_register(topo_mod_t *mod, tnode_t *node, const topo_method_t *mp) 111 { 112 topo_imethod_t *imp; 113 const topo_method_t *meth; 114 115 /* 116 * Initialize module methods 117 */ 118 for (meth = &mp[0]; meth->tm_name != NULL; meth++) { 119 120 topo_node_lock(node); 121 if (topo_method_lookup(node, meth->tm_name) != NULL) { 122 topo_node_unlock(node); 123 continue; 124 } 125 126 if (meth->tm_stability < TOPO_STABILITY_INTERNAL || 127 meth->tm_stability > TOPO_STABILITY_MAX || 128 meth->tm_func == NULL) 129 return (set_methregister_error(mod, node, NULL, 130 ETOPO_METHOD_INVAL)); 131 132 imp = topo_mod_zalloc(mod, sizeof (topo_imethod_t)); 133 if (imp == NULL) 134 return (set_methregister_error(mod, node, imp, 135 ETOPO_METHOD_NOMEM)); 136 137 if ((imp->tim_name = topo_mod_strdup(mod, meth->tm_name)) 138 == NULL) 139 return (set_methregister_error(mod, node, imp, 140 ETOPO_METHOD_NOMEM)); 141 142 if ((imp->tim_desc = topo_mod_strdup(mod, meth->tm_desc)) 143 == NULL) 144 return (set_methregister_error(mod, node, imp, 145 ETOPO_METHOD_NOMEM)); 146 147 148 imp->tim_stability = meth->tm_stability; 149 imp->tim_version = meth->tm_version; 150 imp->tim_func = meth->tm_func; 151 imp->tim_mod = mod; 152 153 topo_list_append(&node->tn_methods, imp); 154 topo_node_unlock(node); 155 156 topo_dprintf(mod->tm_hdl, TOPO_DBG_MODSVC, 157 "registered module %s method " 158 "%s for %s=%d\n", mod->tm_name, imp->tim_name, 159 topo_node_name(node), topo_node_instance(node)); 160 161 } 162 163 return (0); 164 } 165 166 void 167 topo_method_unregister(topo_mod_t *mod, tnode_t *node, const char *name) 168 { 169 topo_imethod_t *mp; 170 171 topo_node_lock(node); 172 for (mp = topo_list_next(&node->tn_methods); mp != NULL; 173 mp = topo_list_next(mp)) { 174 if (strcmp(name, mp->tim_name) == 0) 175 break; 176 } 177 178 if (mp == NULL) { 179 topo_node_unlock(node); 180 return; 181 } 182 183 topo_list_delete(&node->tn_methods, mp); 184 topo_node_unlock(node); 185 186 if (mp->tim_name != NULL) 187 topo_mod_strfree(mod, mp->tim_name); 188 if (mp->tim_desc != NULL) 189 topo_mod_strfree(mod, mp->tim_desc); 190 191 topo_mod_free(mod, mp, sizeof (topo_imethod_t)); 192 } 193 194 void 195 topo_method_unregister_all(topo_mod_t *mod, tnode_t *node) 196 { 197 topo_imethod_t *mp; 198 199 topo_node_lock(node); 200 while ((mp = topo_list_next(&node->tn_methods)) != NULL) { 201 topo_list_delete(&node->tn_methods, mp); 202 if (mp->tim_name != NULL) 203 topo_mod_strfree(mod, mp->tim_name); 204 if (mp->tim_desc != NULL) 205 topo_mod_strfree(mod, mp->tim_desc); 206 topo_mod_free(mod, mp, sizeof (topo_imethod_t)); 207 } 208 topo_node_unlock(node); 209 } 210 211 212 int 213 topo_method_call(tnode_t *node, const char *method, 214 topo_version_t version, nvlist_t *in, nvlist_t **out, int *err) 215 { 216 int rc; 217 topo_imethod_t *mp; 218 219 for (mp = topo_list_next(&node->tn_methods); mp != NULL; 220 mp = topo_list_next(mp)) { 221 if (strcmp(method, mp->tim_name) != 0) 222 continue; 223 224 if (version < mp->tim_version) { 225 *err = ETOPO_METHOD_VERNEW; 226 return (-1); 227 } else if (version > mp->tim_version) { 228 *err = ETOPO_METHOD_VEROLD; 229 return (-1); 230 } 231 232 topo_method_enter(mp); 233 if ((rc = mp->tim_func(mp->tim_mod, node, version, in, out)) 234 < 0) { 235 if (mp->tim_mod->tm_errno == 0) 236 *err = ETOPO_METHOD_FAIL; 237 else 238 *err = mp->tim_mod->tm_errno; 239 } 240 topo_method_exit(mp); 241 242 return (rc); 243 244 } 245 246 *err = ETOPO_METHOD_NOTSUP; 247 return (-1); 248 } 249 250 int 251 topo_method_invoke(tnode_t *node, const char *method, 252 topo_version_t version, nvlist_t *in, nvlist_t **out, int *err) 253 { 254 int rc; 255 256 topo_node_hold(node); 257 rc = topo_method_call(node, method, version, in, out, err); 258 topo_node_rele(node); 259 260 return (rc); 261 } 262