1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * DACF: device autoconfiguration support 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * DACF provides a fast, lightweight policy engine for the I/O subsystem. 33*0Sstevel@tonic-gate * This policy engine provides a mechanism for auto-configuring and 34*0Sstevel@tonic-gate * auto-unconfiguring devices. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * After a device is attach(9E)ed, additional configuration may be needed in 37*0Sstevel@tonic-gate * order to make the device available for use by the system. For example, 38*0Sstevel@tonic-gate * STREAMS modules may need to be pushed atop the driver in order to create 39*0Sstevel@tonic-gate * a STREAMS stack. If the device is to be removed from the system, these 40*0Sstevel@tonic-gate * configuration operations need to be undone, and the device prepared for 41*0Sstevel@tonic-gate * detach(9E). 42*0Sstevel@tonic-gate * 43*0Sstevel@tonic-gate * It is desirable to move the implementation of such policies outside of the 44*0Sstevel@tonic-gate * kernel proper, since such operations are typically infrequent. To this end, 45*0Sstevel@tonic-gate * DACF manages kernel modules in (module_path)/dacf directories. These adhere 46*0Sstevel@tonic-gate * to the api defined in sys/dacf.h, and register sets of configuration 47*0Sstevel@tonic-gate * operations. The kernel loads these modules when the operations they 48*0Sstevel@tonic-gate * implement are needed, and can unload them at any time thereafter. 49*0Sstevel@tonic-gate * Implementing configuration operations in external modules can also increase 50*0Sstevel@tonic-gate * code reuse. 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * DACF provides a policy database which associates 53*0Sstevel@tonic-gate * 54*0Sstevel@tonic-gate * (device descr., kernel action) --> (configuration operation, parameters) 55*0Sstevel@tonic-gate * 56*0Sstevel@tonic-gate * - Device description is matching rule, for example: 57*0Sstevel@tonic-gate * minor-nodetype="ddi_keyboard" 58*0Sstevel@tonic-gate * - Kernel action is a reference to a dacf kernel hook. 59*0Sstevel@tonic-gate * currently supported are "post-attach" and "pre-detach" 60*0Sstevel@tonic-gate * - Configuration action is a reference to a module and a set of operations 61*0Sstevel@tonic-gate * within the module, for example: consconfig:kbd_config 62*0Sstevel@tonic-gate * - Parameters is a list of name="value" parameters to be passed to the 63*0Sstevel@tonic-gate * configuration operation when invoked. 64*0Sstevel@tonic-gate * 65*0Sstevel@tonic-gate * The contents of the rules database are loaded from /etc/dacf.conf upon boot. 66*0Sstevel@tonic-gate * 67*0Sstevel@tonic-gate * DACF kernel hooks are comprised of a call into the rule-matching engine, 68*0Sstevel@tonic-gate * using parameters from the hook in order find a matching rule. If one is 69*0Sstevel@tonic-gate * found, the framework can invoke the configuration operation immediately, or 70*0Sstevel@tonic-gate * defer doing so until later, by putting the rule on a 'reservation list.' 71*0Sstevel@tonic-gate */ 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate #include <sys/param.h> 74*0Sstevel@tonic-gate #include <sys/modctl.h> 75*0Sstevel@tonic-gate #include <sys/sysmacros.h> 76*0Sstevel@tonic-gate #include <sys/kmem.h> 77*0Sstevel@tonic-gate #include <sys/cmn_err.h> 78*0Sstevel@tonic-gate #include <sys/pathname.h> 79*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 80*0Sstevel@tonic-gate #include <sys/sunddi.h> 81*0Sstevel@tonic-gate #include <sys/autoconf.h> 82*0Sstevel@tonic-gate #include <sys/modhash.h> 83*0Sstevel@tonic-gate #include <sys/dacf.h> 84*0Sstevel@tonic-gate #include <sys/dacf_impl.h> 85*0Sstevel@tonic-gate #include <sys/systm.h> 86*0Sstevel@tonic-gate #include <sys/varargs.h> 87*0Sstevel@tonic-gate #include <sys/debug.h> 88*0Sstevel@tonic-gate #include <sys/log.h> 89*0Sstevel@tonic-gate #include <sys/fs/snode.h> 90*0Sstevel@tonic-gate 91*0Sstevel@tonic-gate /* 92*0Sstevel@tonic-gate * Enumeration of the ops exported by the dacf framework. 93*0Sstevel@tonic-gate * 94*0Sstevel@tonic-gate * To add a new op to the framework, add it to this list, update dacf.h, 95*0Sstevel@tonic-gate * (don't miss DACF_NUM_OPIDS) and modify dacf_rule_matrix. 96*0Sstevel@tonic-gate * 97*0Sstevel@tonic-gate */ 98*0Sstevel@tonic-gate typedef struct dacf_opmap { 99*0Sstevel@tonic-gate const char *name; 100*0Sstevel@tonic-gate dacf_opid_t id; 101*0Sstevel@tonic-gate } dacf_opmap_t; 102*0Sstevel@tonic-gate 103*0Sstevel@tonic-gate static dacf_opmap_t dacf_ops[] = { 104*0Sstevel@tonic-gate { "post-attach", DACF_OPID_POSTATTACH }, 105*0Sstevel@tonic-gate { "pre-detach", DACF_OPID_PREDETACH }, 106*0Sstevel@tonic-gate { NULL, 0 }, 107*0Sstevel@tonic-gate }; 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate /* 110*0Sstevel@tonic-gate * Enumeration of the options exported by the dacf framework (currently none). 111*0Sstevel@tonic-gate * 112*0Sstevel@tonic-gate * To add a new option, add it to this array. 113*0Sstevel@tonic-gate */ 114*0Sstevel@tonic-gate typedef struct dacf_opt { 115*0Sstevel@tonic-gate const char *optname; 116*0Sstevel@tonic-gate uint_t optmask; 117*0Sstevel@tonic-gate } dacf_opt_t; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate static dacf_opt_t dacf_options[] = { 120*0Sstevel@tonic-gate #ifdef DEBUG 121*0Sstevel@tonic-gate { "testopt", 1 }, 122*0Sstevel@tonic-gate { "testopt2", 2 }, 123*0Sstevel@tonic-gate #endif 124*0Sstevel@tonic-gate { NULL, 0 }, 125*0Sstevel@tonic-gate }; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate static char kmod_name[] = "__kernel"; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate /* 130*0Sstevel@tonic-gate * Enumeration of the device specifiers exported by the dacf framework. 131*0Sstevel@tonic-gate * 132*0Sstevel@tonic-gate * To add a new devspec to the framework, add it to this list, update dacf.h, 133*0Sstevel@tonic-gate * (don't miss DACF_NUM_DEVSPECS), modify dacf_rule_matrix, and modify 134*0Sstevel@tonic-gate * dacf_match(). 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate typedef struct dacf_ds { 137*0Sstevel@tonic-gate const char *name; 138*0Sstevel@tonic-gate dacf_devspec_t id; 139*0Sstevel@tonic-gate } dacf_ds_t; 140*0Sstevel@tonic-gate 141*0Sstevel@tonic-gate static dacf_ds_t dacf_devspecs[] = { 142*0Sstevel@tonic-gate { "minor-nodetype", DACF_DS_MIN_NT }, 143*0Sstevel@tonic-gate { "driver-minorname", DACF_DS_DRV_MNAME }, 144*0Sstevel@tonic-gate { "device-path", DACF_DS_DEV_PATH }, 145*0Sstevel@tonic-gate { NULL, NULL }, 146*0Sstevel@tonic-gate }; 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate mod_hash_t *posta_mntype, *posta_mname, *posta_devname; /* post-attach */ 149*0Sstevel@tonic-gate mod_hash_t *pred_mntype, *pred_mname, *pred_devname; /* pre-detach */ 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate mod_hash_t *dacf_module_hash; 152*0Sstevel@tonic-gate mod_hash_t *dacf_info_hash; 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gate /* 155*0Sstevel@tonic-gate * This is the lookup table for the hash tables that dacf manages. Given an 156*0Sstevel@tonic-gate * op id and devspec type, one can obtain the hash for that type of data. 157*0Sstevel@tonic-gate */ 158*0Sstevel@tonic-gate mod_hash_t **dacf_rule_matrix[DACF_NUM_OPIDS][DACF_NUM_DEVSPECS] = { 159*0Sstevel@tonic-gate { &posta_mntype, &posta_mname, &posta_devname }, 160*0Sstevel@tonic-gate { &pred_mntype, &pred_mname, &pred_devname }, 161*0Sstevel@tonic-gate }; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate kmutex_t dacf_lock; 164*0Sstevel@tonic-gate kmutex_t dacf_module_lock; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate int dacfdebug = 0; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate static dacf_rule_t *dacf_rule_ctor(char *, char *, char *, dacf_opid_t, 169*0Sstevel@tonic-gate uint_t, dacf_arg_t *); 170*0Sstevel@tonic-gate static mod_hash_t *dacf_get_op_hash(dacf_opid_t, dacf_devspec_t); 171*0Sstevel@tonic-gate static void dacf_rule_val_dtor(mod_hash_val_t); 172*0Sstevel@tonic-gate static void dacf_destroy_opsets(dacf_module_t *module); 173*0Sstevel@tonic-gate static void dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src); 174*0Sstevel@tonic-gate static void dprintf(const char *, ...) __KPRINTFLIKE(1); 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate /*PRINTFLIKE1*/ 177*0Sstevel@tonic-gate static void 178*0Sstevel@tonic-gate dprintf(const char *format, ...) 179*0Sstevel@tonic-gate { 180*0Sstevel@tonic-gate va_list alist; 181*0Sstevel@tonic-gate char dp_buf[256], *dpbp; 182*0Sstevel@tonic-gate if (dacfdebug & DACF_DBG_MSGS) { 183*0Sstevel@tonic-gate va_start(alist, format); 184*0Sstevel@tonic-gate /* 185*0Sstevel@tonic-gate * sprintf up the string that is 'dacf debug: <the message>' 186*0Sstevel@tonic-gate */ 187*0Sstevel@tonic-gate (void) sprintf(dp_buf, "dacf debug: "); 188*0Sstevel@tonic-gate dpbp = &(dp_buf[strlen(dp_buf)]); 189*0Sstevel@tonic-gate (void) vsnprintf(dpbp, sizeof (dp_buf) - strlen(dp_buf), 190*0Sstevel@tonic-gate format, alist); 191*0Sstevel@tonic-gate printf(dp_buf); 192*0Sstevel@tonic-gate va_end(alist); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate /* 197*0Sstevel@tonic-gate * dacf_init() 198*0Sstevel@tonic-gate * initialize the dacf framework by creating the various hash tables. 199*0Sstevel@tonic-gate */ 200*0Sstevel@tonic-gate void 201*0Sstevel@tonic-gate dacf_init() 202*0Sstevel@tonic-gate { 203*0Sstevel@tonic-gate int i, j; 204*0Sstevel@tonic-gate char hbuf[40]; 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate mutex_enter(&dacf_lock); 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate dprintf("dacf_init: creating hashmatrix\n"); 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate #ifdef DEBUG 211*0Sstevel@tonic-gate /* 212*0Sstevel@tonic-gate * Sanity check that DACF_NUM_DEVSPECS and the devspecs are in sync 213*0Sstevel@tonic-gate */ 214*0Sstevel@tonic-gate for (i = 0; dacf_devspecs[i].name != NULL; i++) 215*0Sstevel@tonic-gate continue; 216*0Sstevel@tonic-gate ASSERT(i == DACF_NUM_DEVSPECS); 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate /* 219*0Sstevel@tonic-gate * Sanity check that DACF_NUM_OPIDS and the dacf_ops are in sync 220*0Sstevel@tonic-gate */ 221*0Sstevel@tonic-gate for (i = 0; dacf_ops[i].name != NULL; i++) 222*0Sstevel@tonic-gate continue; 223*0Sstevel@tonic-gate ASSERT(i == DACF_NUM_OPIDS); 224*0Sstevel@tonic-gate #endif 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate for (i = 0; i < DACF_NUM_OPIDS; i++) { 227*0Sstevel@tonic-gate for (j = 0; j < DACF_NUM_DEVSPECS; j++) { 228*0Sstevel@tonic-gate if (dacf_rule_matrix[i][j] == NULL) { 229*0Sstevel@tonic-gate continue; 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate /* 232*0Sstevel@tonic-gate * Set up a hash table with no key destructor. The 233*0Sstevel@tonic-gate * keys are carried in the rule_t, so the val_dtor 234*0Sstevel@tonic-gate * will take care of the key as well. 235*0Sstevel@tonic-gate */ 236*0Sstevel@tonic-gate (void) snprintf(hbuf, sizeof (hbuf), 237*0Sstevel@tonic-gate "dacf hashmatrix [%d][%d]", i, j); 238*0Sstevel@tonic-gate *(dacf_rule_matrix[i][j]) = mod_hash_create_extended( 239*0Sstevel@tonic-gate hbuf, /* hash name */ 240*0Sstevel@tonic-gate DACF_RULE_HASHSIZE, /* # hash elems */ 241*0Sstevel@tonic-gate mod_hash_null_keydtor, /* key dtor */ 242*0Sstevel@tonic-gate dacf_rule_val_dtor, /* value dtor */ 243*0Sstevel@tonic-gate mod_hash_bystr, NULL, /* hash alg & data */ 244*0Sstevel@tonic-gate mod_hash_strkey_cmp, /* key comparator */ 245*0Sstevel@tonic-gate KM_SLEEP); 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate dprintf("dacf_init: creating module_hash\n"); 250*0Sstevel@tonic-gate /* 251*0Sstevel@tonic-gate * dacf_module_hash stores the currently registered dacf modules 252*0Sstevel@tonic-gate * by name. 253*0Sstevel@tonic-gate */ 254*0Sstevel@tonic-gate dacf_module_hash = mod_hash_create_strhash("dacf module hash", 255*0Sstevel@tonic-gate DACF_MODULE_HASHSIZE, mod_hash_null_valdtor); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate dprintf("dacf_init: creating info_hash\n"); 258*0Sstevel@tonic-gate /* 259*0Sstevel@tonic-gate * dacf_info_hash stores pointers to data that modules can associate 260*0Sstevel@tonic-gate * on a per minornode basis. The type of data stored is opaque to the 261*0Sstevel@tonic-gate * framework-- thus there is no destructor supplied. 262*0Sstevel@tonic-gate */ 263*0Sstevel@tonic-gate dacf_info_hash = mod_hash_create_ptrhash("dacf info hash", 264*0Sstevel@tonic-gate DACF_INFO_HASHSIZE, mod_hash_null_valdtor, 265*0Sstevel@tonic-gate sizeof (struct ddi_minor_data)); 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate mutex_exit(&dacf_lock); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate /* 270*0Sstevel@tonic-gate * Register the '__kernel' module. 271*0Sstevel@tonic-gate * 272*0Sstevel@tonic-gate * These are operations that are provided by the kernel, not by a 273*0Sstevel@tonic-gate * module. We just feed the framework a dacfsw structure; it will get 274*0Sstevel@tonic-gate * marked as 'loaded' by dacf_module_register(), and will always be 275*0Sstevel@tonic-gate * available. 276*0Sstevel@tonic-gate */ 277*0Sstevel@tonic-gate (void) dacf_module_register(kmod_name, &kmod_dacfsw); 278*0Sstevel@tonic-gate 279*0Sstevel@tonic-gate (void) read_dacf_binding_file(NULL); 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate dprintf("dacf_init: dacf is ready\n"); 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate /* 285*0Sstevel@tonic-gate * dacf_clear_rules() 286*0Sstevel@tonic-gate * clear the dacf rule database. This is typically done in advance of 287*0Sstevel@tonic-gate * rereading the dacf binding file. 288*0Sstevel@tonic-gate */ 289*0Sstevel@tonic-gate void 290*0Sstevel@tonic-gate dacf_clear_rules() 291*0Sstevel@tonic-gate { 292*0Sstevel@tonic-gate int i, j; 293*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate for (i = 0; i < DACF_NUM_OPIDS; i++) { 296*0Sstevel@tonic-gate for (j = 0; j < DACF_NUM_DEVSPECS; j++) { 297*0Sstevel@tonic-gate if ((dacf_rule_matrix[i][j] != NULL) && 298*0Sstevel@tonic-gate (*(dacf_rule_matrix[i][j]) != NULL)) { 299*0Sstevel@tonic-gate mod_hash_clear(*(dacf_rule_matrix[i][j])); 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate /* 306*0Sstevel@tonic-gate * dacf_rule_insert() 307*0Sstevel@tonic-gate * Create an entry in the dacf rule database. 308*0Sstevel@tonic-gate * If 'module' is null, the kernel is the 'module'. (see dacf_rule_ctor()). 309*0Sstevel@tonic-gate */ 310*0Sstevel@tonic-gate int 311*0Sstevel@tonic-gate dacf_rule_insert(dacf_devspec_t devspec_type, char *devspec_data, 312*0Sstevel@tonic-gate char *module, char *opset, dacf_opid_t opid, uint_t opts, 313*0Sstevel@tonic-gate dacf_arg_t *op_args) 314*0Sstevel@tonic-gate { 315*0Sstevel@tonic-gate dacf_rule_t *rule; 316*0Sstevel@tonic-gate mod_hash_t *hash; 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate ASSERT(devspec_type != DACF_DS_ERROR); 319*0Sstevel@tonic-gate ASSERT(devspec_data); 320*0Sstevel@tonic-gate ASSERT(opset); 321*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate dprintf("dacf_rule_insert called: %s=\"%s\", %s:%s, %s\n", 324*0Sstevel@tonic-gate dacf_devspec_to_str(devspec_type), devspec_data, 325*0Sstevel@tonic-gate module ? module : "[kernel]", opset, dacf_opid_to_str(opid)); 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gate /* 328*0Sstevel@tonic-gate * Fetch the hash table associated with this op-name and devspec-type. 329*0Sstevel@tonic-gate * Some ops may not support all devspec-types, since they may be 330*0Sstevel@tonic-gate * meaningless, so hash may be null. 331*0Sstevel@tonic-gate */ 332*0Sstevel@tonic-gate hash = dacf_get_op_hash(opid, devspec_type); 333*0Sstevel@tonic-gate if (hash == NULL) { 334*0Sstevel@tonic-gate cmn_err(CE_WARN, "!dacf dev-spec '%s' does not support op '%s'", 335*0Sstevel@tonic-gate dacf_devspec_to_str(devspec_type), dacf_opid_to_str(opid)); 336*0Sstevel@tonic-gate return (-1); 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate /* 340*0Sstevel@tonic-gate * Allocate a rule and fill it in, take a hold on it. 341*0Sstevel@tonic-gate */ 342*0Sstevel@tonic-gate rule = dacf_rule_ctor(devspec_data, module, opset, opid, opts, 343*0Sstevel@tonic-gate op_args); 344*0Sstevel@tonic-gate dacf_rule_hold(rule); 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate if (mod_hash_insert(hash, (mod_hash_key_t)rule->r_devspec_data, 347*0Sstevel@tonic-gate (mod_hash_val_t)rule) != 0) { 348*0Sstevel@tonic-gate /* 349*0Sstevel@tonic-gate * We failed, so release hold. This will cause the rule and 350*0Sstevel@tonic-gate * associated data to get nuked. 351*0Sstevel@tonic-gate */ 352*0Sstevel@tonic-gate dacf_rule_rele(rule); 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gate cmn_err(CE_WARN, "!dacf rule %s='%s' %s:%s %s duplicates " 355*0Sstevel@tonic-gate "another rule, ignored", dacf_devspec_to_str(devspec_type), 356*0Sstevel@tonic-gate devspec_data, module, opset, dacf_opid_to_str(opid)); 357*0Sstevel@tonic-gate return (-1); 358*0Sstevel@tonic-gate } 359*0Sstevel@tonic-gate return (0); 360*0Sstevel@tonic-gate } 361*0Sstevel@tonic-gate 362*0Sstevel@tonic-gate /* 363*0Sstevel@tonic-gate * dacf_rule_ctor() 364*0Sstevel@tonic-gate * Allocate and fill out entries in a dacf_rule_t. 365*0Sstevel@tonic-gate */ 366*0Sstevel@tonic-gate static dacf_rule_t * 367*0Sstevel@tonic-gate dacf_rule_ctor(char *device_spec, char *module, char *opset, dacf_opid_t opid, 368*0Sstevel@tonic-gate uint_t opts, dacf_arg_t *op_args) 369*0Sstevel@tonic-gate { 370*0Sstevel@tonic-gate dacf_rule_t *rule; 371*0Sstevel@tonic-gate dacf_arg_t *p; 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate rule = kmem_alloc(sizeof (dacf_rule_t), KM_SLEEP); 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate /* 376*0Sstevel@tonic-gate * Fill in the entries 377*0Sstevel@tonic-gate */ 378*0Sstevel@tonic-gate rule->r_devspec_data = kmem_alloc(strlen(device_spec) + 1, KM_SLEEP); 379*0Sstevel@tonic-gate (void) strcpy(rule->r_devspec_data, device_spec); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate /* 382*0Sstevel@tonic-gate * If module is 'null' we set it to __kernel, meaning that this op 383*0Sstevel@tonic-gate * is implemented by the kernel. 384*0Sstevel@tonic-gate */ 385*0Sstevel@tonic-gate if (module == NULL) { 386*0Sstevel@tonic-gate module = kmod_name; 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate rule->r_module = kmem_alloc(strlen(module) + 1, KM_SLEEP); 390*0Sstevel@tonic-gate (void) strcpy(rule->r_module, module); 391*0Sstevel@tonic-gate 392*0Sstevel@tonic-gate rule->r_opset = kmem_alloc(strlen(opset) + 1, KM_SLEEP); 393*0Sstevel@tonic-gate (void) strcpy(rule->r_opset, opset); 394*0Sstevel@tonic-gate 395*0Sstevel@tonic-gate rule->r_refs = 0; /* no refs yet */ 396*0Sstevel@tonic-gate rule->r_opts = opts; 397*0Sstevel@tonic-gate rule->r_opid = opid; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate rule->r_args = NULL; 400*0Sstevel@tonic-gate p = op_args; 401*0Sstevel@tonic-gate while (p != NULL) { 402*0Sstevel@tonic-gate ASSERT(p->arg_name); 403*0Sstevel@tonic-gate ASSERT(p->arg_val); 404*0Sstevel@tonic-gate /* 405*0Sstevel@tonic-gate * dacf_arg_insert() should always succeed, since we're copying 406*0Sstevel@tonic-gate * another (already duplicate-free) list. 407*0Sstevel@tonic-gate */ 408*0Sstevel@tonic-gate (void) dacf_arg_insert(&rule->r_args, p->arg_name, p->arg_val); 409*0Sstevel@tonic-gate p = p->arg_next; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate 412*0Sstevel@tonic-gate return (rule); 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * dacf_rule_val_dtor() 417*0Sstevel@tonic-gate * This is the destructor for dacf_rule_t's in the rule database. It 418*0Sstevel@tonic-gate * simply does a dacf_rule_rele() on the rule. This function will take 419*0Sstevel@tonic-gate * care of destroying the rule if its ref count has dropped to 0. 420*0Sstevel@tonic-gate */ 421*0Sstevel@tonic-gate static void 422*0Sstevel@tonic-gate dacf_rule_val_dtor(mod_hash_val_t val) 423*0Sstevel@tonic-gate { 424*0Sstevel@tonic-gate ASSERT((void *)val != NULL); 425*0Sstevel@tonic-gate dacf_rule_rele((dacf_rule_t *)val); 426*0Sstevel@tonic-gate } 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate /* 429*0Sstevel@tonic-gate * dacf_rule_destroy() 430*0Sstevel@tonic-gate * destroy a dacf_rule_t 431*0Sstevel@tonic-gate */ 432*0Sstevel@tonic-gate void 433*0Sstevel@tonic-gate dacf_rule_destroy(dacf_rule_t *rule) 434*0Sstevel@tonic-gate { 435*0Sstevel@tonic-gate ASSERT(rule->r_refs == 0); 436*0Sstevel@tonic-gate /* 437*0Sstevel@tonic-gate * Free arguments. 438*0Sstevel@tonic-gate */ 439*0Sstevel@tonic-gate dacf_arglist_delete(&(rule->r_args)); 440*0Sstevel@tonic-gate kmem_free(rule->r_devspec_data, strlen(rule->r_devspec_data) + 1); 441*0Sstevel@tonic-gate /* 442*0Sstevel@tonic-gate * Module may be null for a kernel-managed op-set 443*0Sstevel@tonic-gate */ 444*0Sstevel@tonic-gate kmem_free(rule->r_module, strlen(rule->r_module) + 1); 445*0Sstevel@tonic-gate kmem_free(rule->r_opset, strlen(rule->r_opset) + 1); 446*0Sstevel@tonic-gate kmem_free(rule, sizeof (dacf_rule_t)); 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* 450*0Sstevel@tonic-gate * dacf_rule_hold() 451*0Sstevel@tonic-gate * dacf rules are ref-counted. This function increases the reference 452*0Sstevel@tonic-gate * count on an rule. 453*0Sstevel@tonic-gate */ 454*0Sstevel@tonic-gate void 455*0Sstevel@tonic-gate dacf_rule_hold(dacf_rule_t *rule) 456*0Sstevel@tonic-gate { 457*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate rule->r_refs++; 460*0Sstevel@tonic-gate } 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate /* 463*0Sstevel@tonic-gate * dacf_rule_rele() 464*0Sstevel@tonic-gate * drop the ref count on an rule, and destroy the rule if its 465*0Sstevel@tonic-gate * ref count drops to 0. 466*0Sstevel@tonic-gate */ 467*0Sstevel@tonic-gate void 468*0Sstevel@tonic-gate dacf_rule_rele(dacf_rule_t *rule) 469*0Sstevel@tonic-gate { 470*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 471*0Sstevel@tonic-gate ASSERT(rule->r_refs > 0); 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate rule->r_refs--; 474*0Sstevel@tonic-gate if (rule->r_refs == 0) { 475*0Sstevel@tonic-gate dacf_rule_destroy(rule); 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate /* 480*0Sstevel@tonic-gate * dacf_rsrv_make() 481*0Sstevel@tonic-gate * add an rule to a reservation list to be processed later. 482*0Sstevel@tonic-gate */ 483*0Sstevel@tonic-gate void 484*0Sstevel@tonic-gate dacf_rsrv_make(dacf_rsrvlist_t *rsrv, dacf_rule_t *rule, void *info, 485*0Sstevel@tonic-gate dacf_rsrvlist_t **list) 486*0Sstevel@tonic-gate { 487*0Sstevel@tonic-gate dacf_infohdl_t ihdl = info; 488*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 489*0Sstevel@tonic-gate ASSERT(info && rule && list); 490*0Sstevel@tonic-gate 491*0Sstevel@tonic-gate /* 492*0Sstevel@tonic-gate * Bump the ref count on rule, so it won't get freed as long as it's on 493*0Sstevel@tonic-gate * this reservation list. 494*0Sstevel@tonic-gate */ 495*0Sstevel@tonic-gate dacf_rule_hold(rule); 496*0Sstevel@tonic-gate 497*0Sstevel@tonic-gate rsrv->rsrv_rule = rule; 498*0Sstevel@tonic-gate rsrv->rsrv_ihdl = ihdl; 499*0Sstevel@tonic-gate rsrv->rsrv_result = DDI_SUCCESS; 500*0Sstevel@tonic-gate rsrv->rsrv_next = *list; 501*0Sstevel@tonic-gate *list = rsrv; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate dprintf("dacf: reservation made\n"); 504*0Sstevel@tonic-gate } 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate /* 507*0Sstevel@tonic-gate * dacf_clr_rsrvs() 508*0Sstevel@tonic-gate * clear reservation list of operations of type 'op' 509*0Sstevel@tonic-gate */ 510*0Sstevel@tonic-gate void 511*0Sstevel@tonic-gate dacf_clr_rsrvs(dev_info_t *devi, dacf_opid_t op) 512*0Sstevel@tonic-gate { 513*0Sstevel@tonic-gate dacf_process_rsrvs(&(DEVI(devi)->devi_dacf_tasks), op, DACF_PROC_RELE); 514*0Sstevel@tonic-gate } 515*0Sstevel@tonic-gate 516*0Sstevel@tonic-gate /* 517*0Sstevel@tonic-gate * dacf_process_rsrvs() 518*0Sstevel@tonic-gate * iterate across a locked reservation list, processing each element 519*0Sstevel@tonic-gate * which matches 'op' according to 'flags'. 520*0Sstevel@tonic-gate * 521*0Sstevel@tonic-gate * if DACF_PROC_INVOKE is specified, the elements that match 'op' 522*0Sstevel@tonic-gate * will have their operations invoked. The return value from that 523*0Sstevel@tonic-gate * operation is placed in the rsrv_result field of the dacf_rsrvlist_t 524*0Sstevel@tonic-gate */ 525*0Sstevel@tonic-gate void 526*0Sstevel@tonic-gate dacf_process_rsrvs(dacf_rsrvlist_t **list, dacf_opid_t op, int flags) 527*0Sstevel@tonic-gate { 528*0Sstevel@tonic-gate dacf_rsrvlist_t *p, *dp; 529*0Sstevel@tonic-gate dacf_rsrvlist_t **prevptr; 530*0Sstevel@tonic-gate 531*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 532*0Sstevel@tonic-gate ASSERT(list); 533*0Sstevel@tonic-gate ASSERT(flags != 0); 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate if (*list == NULL) 536*0Sstevel@tonic-gate return; 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate dprintf("dacf_process_rsrvs: opid = %d, flags = 0x%x\n", op, flags); 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate /* 541*0Sstevel@tonic-gate * Walk the list, finding rules whose opid's match op, and performing 542*0Sstevel@tonic-gate * the work described by 'flags'. 543*0Sstevel@tonic-gate */ 544*0Sstevel@tonic-gate prevptr = list; 545*0Sstevel@tonic-gate for (p = *list; p != NULL; ) { 546*0Sstevel@tonic-gate 547*0Sstevel@tonic-gate if (p->rsrv_rule->r_opid != op) { 548*0Sstevel@tonic-gate prevptr = &(p->rsrv_next); 549*0Sstevel@tonic-gate p = p->rsrv_next; 550*0Sstevel@tonic-gate continue; 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate if (flags & DACF_PROC_INVOKE) { 554*0Sstevel@tonic-gate p->rsrv_result = dacf_op_invoke(p->rsrv_rule, 555*0Sstevel@tonic-gate p->rsrv_ihdl, 0); 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate if (flags & DACF_PROC_RELE) { 559*0Sstevel@tonic-gate *prevptr = p->rsrv_next; 560*0Sstevel@tonic-gate dp = p; 561*0Sstevel@tonic-gate p = p->rsrv_next; 562*0Sstevel@tonic-gate dacf_rule_rele(dp->rsrv_rule); 563*0Sstevel@tonic-gate kmem_free(dp, sizeof (dacf_rsrvlist_t)); 564*0Sstevel@tonic-gate } else { 565*0Sstevel@tonic-gate prevptr = &(p->rsrv_next); 566*0Sstevel@tonic-gate p = p->rsrv_next; 567*0Sstevel@tonic-gate } 568*0Sstevel@tonic-gate } 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate 571*0Sstevel@tonic-gate /* 572*0Sstevel@tonic-gate * dacf_get_op_hash() 573*0Sstevel@tonic-gate * Given an op name, (i.e. "post-attach" or "pre-detach") and a 574*0Sstevel@tonic-gate * devspec-type, return the hash that represents that op indexed 575*0Sstevel@tonic-gate * by that devspec. 576*0Sstevel@tonic-gate */ 577*0Sstevel@tonic-gate static mod_hash_t * 578*0Sstevel@tonic-gate dacf_get_op_hash(dacf_opid_t op, dacf_devspec_t ds_type) 579*0Sstevel@tonic-gate { 580*0Sstevel@tonic-gate ASSERT(op <= DACF_NUM_OPIDS && op > 0); 581*0Sstevel@tonic-gate ASSERT(ds_type <= DACF_NUM_DEVSPECS && ds_type > 0); 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate /* 584*0Sstevel@tonic-gate * dacf_rule_matrix is an array of pointers to pointers to hashes. 585*0Sstevel@tonic-gate */ 586*0Sstevel@tonic-gate if (dacf_rule_matrix[op - 1][ds_type - 1] == NULL) { 587*0Sstevel@tonic-gate return (NULL); 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate return (*(dacf_rule_matrix[op - 1][ds_type - 1])); 590*0Sstevel@tonic-gate } 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* 593*0Sstevel@tonic-gate * dacf_arg_insert() 594*0Sstevel@tonic-gate * Create and insert an entry in an argument list. 595*0Sstevel@tonic-gate * Returns -1 if the argument name is a duplicate of another already 596*0Sstevel@tonic-gate * present in the hash. 597*0Sstevel@tonic-gate */ 598*0Sstevel@tonic-gate int 599*0Sstevel@tonic-gate dacf_arg_insert(dacf_arg_t **list, char *name, char *val) 600*0Sstevel@tonic-gate { 601*0Sstevel@tonic-gate dacf_arg_t *arg; 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate /* 604*0Sstevel@tonic-gate * Don't allow duplicates. 605*0Sstevel@tonic-gate */ 606*0Sstevel@tonic-gate for (arg = *list; arg != NULL; arg = arg->arg_next) { 607*0Sstevel@tonic-gate if (strcmp(arg->arg_name, name) == 0) { 608*0Sstevel@tonic-gate return (-1); 609*0Sstevel@tonic-gate } 610*0Sstevel@tonic-gate } 611*0Sstevel@tonic-gate 612*0Sstevel@tonic-gate arg = kmem_alloc(sizeof (dacf_arg_t), KM_SLEEP); 613*0Sstevel@tonic-gate arg->arg_name = kmem_alloc(strlen(name) + 1, KM_SLEEP); 614*0Sstevel@tonic-gate (void) strcpy(arg->arg_name, name); 615*0Sstevel@tonic-gate arg->arg_val = kmem_alloc(strlen(val) + 1, KM_SLEEP); 616*0Sstevel@tonic-gate (void) strcpy(arg->arg_val, val); 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate arg->arg_next = *list; 619*0Sstevel@tonic-gate *list = arg; 620*0Sstevel@tonic-gate 621*0Sstevel@tonic-gate return (0); 622*0Sstevel@tonic-gate } 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate /* 625*0Sstevel@tonic-gate * dacf_arglist_delete() 626*0Sstevel@tonic-gate * free all the elements of a list of dacf_arg_t's. 627*0Sstevel@tonic-gate */ 628*0Sstevel@tonic-gate void 629*0Sstevel@tonic-gate dacf_arglist_delete(dacf_arg_t **list) 630*0Sstevel@tonic-gate { 631*0Sstevel@tonic-gate dacf_arg_t *arg, *narg; 632*0Sstevel@tonic-gate arg = *list; 633*0Sstevel@tonic-gate while (arg != NULL) { 634*0Sstevel@tonic-gate narg = arg->arg_next; 635*0Sstevel@tonic-gate kmem_free(arg->arg_name, strlen(arg->arg_name) + 1); 636*0Sstevel@tonic-gate kmem_free(arg->arg_val, strlen(arg->arg_val) + 1); 637*0Sstevel@tonic-gate kmem_free(arg, sizeof (dacf_arg_t)); 638*0Sstevel@tonic-gate arg = narg; 639*0Sstevel@tonic-gate } 640*0Sstevel@tonic-gate *list = NULL; 641*0Sstevel@tonic-gate } 642*0Sstevel@tonic-gate 643*0Sstevel@tonic-gate /* 644*0Sstevel@tonic-gate * dacf_match() 645*0Sstevel@tonic-gate * Match a device-spec to a rule. 646*0Sstevel@tonic-gate */ 647*0Sstevel@tonic-gate dacf_rule_t * 648*0Sstevel@tonic-gate dacf_match(dacf_opid_t op, dacf_devspec_t ds, void *match_info) 649*0Sstevel@tonic-gate { 650*0Sstevel@tonic-gate dacf_rule_t *rule; 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate if (mod_hash_find(dacf_get_op_hash(op, ds), (mod_hash_key_t)match_info, 655*0Sstevel@tonic-gate (mod_hash_val_t *)&rule) == 0) { 656*0Sstevel@tonic-gate return (rule); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate return (NULL); /* Not Found */ 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate /* 663*0Sstevel@tonic-gate * dacf_module_register() 664*0Sstevel@tonic-gate * register a module with the framework. Use when a module gets loaded, 665*0Sstevel@tonic-gate * or for the kernel to register a "virtual" module (i.e. a "module" 666*0Sstevel@tonic-gate * which the kernel provides). Makes a copy of the interface description 667*0Sstevel@tonic-gate * provided by the module. 668*0Sstevel@tonic-gate */ 669*0Sstevel@tonic-gate int 670*0Sstevel@tonic-gate dacf_module_register(char *mod_name, struct dacfsw *sw) 671*0Sstevel@tonic-gate { 672*0Sstevel@tonic-gate char *str; 673*0Sstevel@tonic-gate size_t i, nelems; 674*0Sstevel@tonic-gate dacf_module_t *module; 675*0Sstevel@tonic-gate dacf_opset_t *opsarray; 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate if (sw == NULL) { 678*0Sstevel@tonic-gate return (EINVAL); 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate if (sw->dacf_rev != DACF_MODREV_1) { 682*0Sstevel@tonic-gate cmn_err(CE_WARN, "dacf: module '%s' exports unsupported " 683*0Sstevel@tonic-gate "version %d interface, not registered\n", mod_name, 684*0Sstevel@tonic-gate sw->dacf_rev); 685*0Sstevel@tonic-gate return (EINVAL); 686*0Sstevel@tonic-gate } 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate /* 689*0Sstevel@tonic-gate * count how many opsets are provided. 690*0Sstevel@tonic-gate */ 691*0Sstevel@tonic-gate for (nelems = 0; sw->dacf_opsets[nelems].opset_name != NULL; nelems++) 692*0Sstevel@tonic-gate ; 693*0Sstevel@tonic-gate 694*0Sstevel@tonic-gate dprintf("dacf_module_register: found %lu opsets\n", nelems); 695*0Sstevel@tonic-gate 696*0Sstevel@tonic-gate /* 697*0Sstevel@tonic-gate * Temporary: It's ok for the kernel dacf_sw to have no opsets, since 698*0Sstevel@tonic-gate * we don't have any opsets to export yet (in NON-DEBUG). 699*0Sstevel@tonic-gate */ 700*0Sstevel@tonic-gate if ((nelems == 0) && (sw != &kmod_dacfsw)) { 701*0Sstevel@tonic-gate cmn_err(CE_WARN, "dacf module %s exports no opsets, " 702*0Sstevel@tonic-gate "not registered.\n", mod_name); 703*0Sstevel@tonic-gate return (EINVAL); 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate /* 707*0Sstevel@tonic-gate * Look to see if the module has been previously registered with the 708*0Sstevel@tonic-gate * framework. If so, we can fail with EBUSY. 709*0Sstevel@tonic-gate */ 710*0Sstevel@tonic-gate if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name, 711*0Sstevel@tonic-gate (mod_hash_val_t)&module) == 0) { 712*0Sstevel@tonic-gate /* 713*0Sstevel@tonic-gate * See if it is loaded currently 714*0Sstevel@tonic-gate */ 715*0Sstevel@tonic-gate rw_enter(&module->dm_lock, RW_WRITER); 716*0Sstevel@tonic-gate if (module->dm_loaded) { 717*0Sstevel@tonic-gate rw_exit(&module->dm_lock); 718*0Sstevel@tonic-gate cmn_err(CE_WARN, "dacf module '%s' is " 719*0Sstevel@tonic-gate "already registered.", mod_name); 720*0Sstevel@tonic-gate return (EBUSY); 721*0Sstevel@tonic-gate } 722*0Sstevel@tonic-gate } else { 723*0Sstevel@tonic-gate /* 724*0Sstevel@tonic-gate * This is the first time we've ever seen the module; stick 725*0Sstevel@tonic-gate * it into the module hash. If that fails, we've had a 726*0Sstevel@tonic-gate * race between two threads, both trying to insert the same 727*0Sstevel@tonic-gate * new module. It's safe to stick the module into the 728*0Sstevel@tonic-gate * hash only partly filled in, since dm_lock protects the 729*0Sstevel@tonic-gate * structure, and we've got that write-locked. 730*0Sstevel@tonic-gate */ 731*0Sstevel@tonic-gate module = kmem_zalloc(sizeof (dacf_module_t), KM_SLEEP); 732*0Sstevel@tonic-gate str = kmem_alloc(strlen(mod_name) + 1, KM_SLEEP); 733*0Sstevel@tonic-gate (void) strcpy(str, mod_name); 734*0Sstevel@tonic-gate rw_enter(&module->dm_lock, RW_WRITER); 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate if (mod_hash_insert(dacf_module_hash, (mod_hash_key_t)str, 737*0Sstevel@tonic-gate (mod_hash_val_t)module) != 0) { 738*0Sstevel@tonic-gate rw_exit(&module->dm_lock); 739*0Sstevel@tonic-gate kmem_free(str, strlen(str) + 1); 740*0Sstevel@tonic-gate kmem_free(module, sizeof (dacf_module_t)); 741*0Sstevel@tonic-gate cmn_err(CE_WARN, "dacf module '%s' is " 742*0Sstevel@tonic-gate "already registered.", mod_name); 743*0Sstevel@tonic-gate return (EBUSY); 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate } 746*0Sstevel@tonic-gate /* 747*0Sstevel@tonic-gate * In either case (first time we've seen it or not), the module is 748*0Sstevel@tonic-gate * not loaded, and we hold it write-locked. 749*0Sstevel@tonic-gate */ 750*0Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&module->dm_lock)); 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate /* 753*0Sstevel@tonic-gate * Alloc array of opsets for this module. Add one for the final 754*0Sstevel@tonic-gate * NULL entry 755*0Sstevel@tonic-gate */ 756*0Sstevel@tonic-gate opsarray = kmem_zalloc(sizeof (dacf_opset_t) * (nelems + 1), KM_SLEEP); 757*0Sstevel@tonic-gate 758*0Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 759*0Sstevel@tonic-gate dacf_opset_copy(&(opsarray[i]), &(sw->dacf_opsets[i])); 760*0Sstevel@tonic-gate ASSERT(opsarray[i].opset_name != NULL); 761*0Sstevel@tonic-gate ASSERT(opsarray[i].opset_ops != NULL); 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate opsarray[nelems].opset_name = NULL; 764*0Sstevel@tonic-gate opsarray[nelems].opset_ops = NULL; 765*0Sstevel@tonic-gate 766*0Sstevel@tonic-gate ASSERT(module->dm_opsets == NULL); /* see dacf_destroy_opsets() */ 767*0Sstevel@tonic-gate module->dm_opsets = opsarray; 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate if (dacfdebug & DACF_DBG_MSGS) { 770*0Sstevel@tonic-gate dprintf("%s registered.\n", mod_name); 771*0Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 772*0Sstevel@tonic-gate dprintf("registered %s\n", opsarray[i].opset_name); 773*0Sstevel@tonic-gate } 774*0Sstevel@tonic-gate } 775*0Sstevel@tonic-gate 776*0Sstevel@tonic-gate module->dm_loaded = 1; 777*0Sstevel@tonic-gate rw_exit(&module->dm_lock); 778*0Sstevel@tonic-gate 779*0Sstevel@tonic-gate return (0); 780*0Sstevel@tonic-gate } 781*0Sstevel@tonic-gate 782*0Sstevel@tonic-gate /* 783*0Sstevel@tonic-gate * dacf_module_unregister() 784*0Sstevel@tonic-gate * remove a module from the framework, and free framework-allocated 785*0Sstevel@tonic-gate * resources. 786*0Sstevel@tonic-gate */ 787*0Sstevel@tonic-gate int 788*0Sstevel@tonic-gate dacf_module_unregister(char *mod_name) 789*0Sstevel@tonic-gate { 790*0Sstevel@tonic-gate dacf_module_t *module; 791*0Sstevel@tonic-gate 792*0Sstevel@tonic-gate /* 793*0Sstevel@tonic-gate * Can't unregister __kernel, since there is no real way to get it 794*0Sstevel@tonic-gate * back-- Once it gets marked with dm_loaded == 0, the kernel will 795*0Sstevel@tonic-gate * try to modload() if it is ever needed, which will fail utterly, 796*0Sstevel@tonic-gate * and send op_invoke into a loop in it's modload logic 797*0Sstevel@tonic-gate * 798*0Sstevel@tonic-gate * If this is behavior is ever needed in the future, we can just 799*0Sstevel@tonic-gate * add a flag indicating that this module is really a fake. 800*0Sstevel@tonic-gate */ 801*0Sstevel@tonic-gate ASSERT(strcmp(mod_name, kmod_name) != 0); 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate dprintf("dacf_module_unregister: called for '%s'!\n", mod_name); 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate /* 806*0Sstevel@tonic-gate * If NOAUL_DACF is set, or we try to get a write-lock on dm_lock and 807*0Sstevel@tonic-gate * that fails, return EBUSY, and fail to unregister. 808*0Sstevel@tonic-gate */ 809*0Sstevel@tonic-gate if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name, 810*0Sstevel@tonic-gate (mod_hash_val_t)&module) == 0) { 811*0Sstevel@tonic-gate if ((moddebug & MODDEBUG_NOAUL_DACF) || 812*0Sstevel@tonic-gate !rw_tryenter(&module->dm_lock, RW_WRITER)) { 813*0Sstevel@tonic-gate return (EBUSY); 814*0Sstevel@tonic-gate } 815*0Sstevel@tonic-gate } else { 816*0Sstevel@tonic-gate return (EINVAL); 817*0Sstevel@tonic-gate } 818*0Sstevel@tonic-gate 819*0Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&module->dm_lock)); 820*0Sstevel@tonic-gate dacf_destroy_opsets(module); 821*0Sstevel@tonic-gate module->dm_loaded = 0; 822*0Sstevel@tonic-gate rw_exit(&module->dm_lock); 823*0Sstevel@tonic-gate return (0); 824*0Sstevel@tonic-gate } 825*0Sstevel@tonic-gate 826*0Sstevel@tonic-gate /* 827*0Sstevel@tonic-gate * dacf_destroy_opsets() 828*0Sstevel@tonic-gate * given a module, destroy all of it's associated op-sets. 829*0Sstevel@tonic-gate */ 830*0Sstevel@tonic-gate static void 831*0Sstevel@tonic-gate dacf_destroy_opsets(dacf_module_t *module) 832*0Sstevel@tonic-gate { 833*0Sstevel@tonic-gate dacf_opset_t *array = module->dm_opsets; 834*0Sstevel@tonic-gate dacf_opset_t *p; 835*0Sstevel@tonic-gate int i; 836*0Sstevel@tonic-gate size_t nelems; 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&module->dm_lock)); 839*0Sstevel@tonic-gate ASSERT(module->dm_loaded == 1); 840*0Sstevel@tonic-gate 841*0Sstevel@tonic-gate for (i = 0; array[i].opset_name != NULL; i++) { 842*0Sstevel@tonic-gate p = &(array[i]); 843*0Sstevel@tonic-gate kmem_free(p->opset_name, strlen(p->opset_name) + 1); 844*0Sstevel@tonic-gate /* 845*0Sstevel@tonic-gate * count nelems in opset_ops 846*0Sstevel@tonic-gate */ 847*0Sstevel@tonic-gate for (nelems = 0; ; nelems++) { 848*0Sstevel@tonic-gate if (p->opset_ops[nelems].op_id == DACF_OPID_END) { 849*0Sstevel@tonic-gate break; 850*0Sstevel@tonic-gate } 851*0Sstevel@tonic-gate } 852*0Sstevel@tonic-gate /* 853*0Sstevel@tonic-gate * Free the array of op ptrs. 854*0Sstevel@tonic-gate */ 855*0Sstevel@tonic-gate kmem_free(p->opset_ops, sizeof (dacf_op_t) * (nelems + 1)); 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate /* 859*0Sstevel@tonic-gate * i has counted how big array is; +1 to account for the last element. 860*0Sstevel@tonic-gate */ 861*0Sstevel@tonic-gate kmem_free(array, (sizeof (dacf_opset_t)) * (i + 1)); 862*0Sstevel@tonic-gate module->dm_opsets = NULL; 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate /* 866*0Sstevel@tonic-gate * dacf_opset_copy() 867*0Sstevel@tonic-gate * makes a copy of a dacf_opset_t. 868*0Sstevel@tonic-gate */ 869*0Sstevel@tonic-gate static void 870*0Sstevel@tonic-gate dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src) 871*0Sstevel@tonic-gate { 872*0Sstevel@tonic-gate size_t nelems, i; 873*0Sstevel@tonic-gate ASSERT(src && dst); 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate dprintf("dacf_opset_copy: called\n"); 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate dst->opset_name = kmem_alloc(strlen(src->opset_name) + 1, KM_SLEEP); 878*0Sstevel@tonic-gate (void) strcpy(dst->opset_name, src->opset_name); 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate dprintf("dacf_opset_copy: counting ops\n"); 881*0Sstevel@tonic-gate 882*0Sstevel@tonic-gate for (nelems = 0; ; nelems++) { 883*0Sstevel@tonic-gate if ((src->opset_ops[nelems].op_id == DACF_OPID_END) || 884*0Sstevel@tonic-gate (src->opset_ops[nelems].op_func == NULL)) { 885*0Sstevel@tonic-gate break; 886*0Sstevel@tonic-gate } 887*0Sstevel@tonic-gate } 888*0Sstevel@tonic-gate 889*0Sstevel@tonic-gate dprintf("dacf_opset_copy: found %lu ops\n", nelems); 890*0Sstevel@tonic-gate 891*0Sstevel@tonic-gate dst->opset_ops = kmem_alloc(sizeof (dacf_op_t) * (nelems + 1), 892*0Sstevel@tonic-gate KM_SLEEP); 893*0Sstevel@tonic-gate 894*0Sstevel@tonic-gate dprintf("dacf_opset_copy: copying ops\n"); 895*0Sstevel@tonic-gate for (i = 0; i < nelems; i++) { 896*0Sstevel@tonic-gate dst->opset_ops[i].op_id = src->opset_ops[i].op_id; 897*0Sstevel@tonic-gate dst->opset_ops[i].op_func = src->opset_ops[i].op_func; 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate dst->opset_ops[nelems].op_id = DACF_OPID_END; 900*0Sstevel@tonic-gate dst->opset_ops[nelems].op_func = NULL; 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate dprintf("dacf_opset_copy: done copying ops\n"); 903*0Sstevel@tonic-gate } 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate int dacf_modload_laps = 0; /* just a diagnostic aid */ 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate /* 908*0Sstevel@tonic-gate * dacf_op_invoke() 909*0Sstevel@tonic-gate * Invoke a op in a opset in a module given the rule to invoke. 910*0Sstevel@tonic-gate * 911*0Sstevel@tonic-gate * If the return value of dacf_op_invoke is 0, then rval contains the 912*0Sstevel@tonic-gate * return value of the _op_ being invoked. Otherwise, dacf_op_invoke's 913*0Sstevel@tonic-gate * return value indicates why the op invocation failed. 914*0Sstevel@tonic-gate */ 915*0Sstevel@tonic-gate int 916*0Sstevel@tonic-gate dacf_op_invoke(dacf_rule_t *rule, dacf_infohdl_t info_hdl, int flags) 917*0Sstevel@tonic-gate { 918*0Sstevel@tonic-gate dacf_module_t *module; 919*0Sstevel@tonic-gate dacf_opset_t *opsarray; 920*0Sstevel@tonic-gate dacf_opset_t *opset; 921*0Sstevel@tonic-gate dacf_op_t *op = NULL; 922*0Sstevel@tonic-gate dacf_opid_t op_id; 923*0Sstevel@tonic-gate dacf_arghdl_t arg_hdl; 924*0Sstevel@tonic-gate dev_info_t *dip; 925*0Sstevel@tonic-gate int i, rval = -1; 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate ASSERT(rule); 928*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&dacf_lock)); 929*0Sstevel@tonic-gate 930*0Sstevel@tonic-gate op_id = rule->r_opid; 931*0Sstevel@tonic-gate dprintf("dacf_op_invoke: opid=%d\n", op_id); 932*0Sstevel@tonic-gate 933*0Sstevel@tonic-gate /* 934*0Sstevel@tonic-gate * Take laps, trying to load the dacf module. For the case of kernel- 935*0Sstevel@tonic-gate * provided operations, __kernel will be found in the hash table, and 936*0Sstevel@tonic-gate * no modload will be needed. 937*0Sstevel@tonic-gate */ 938*0Sstevel@tonic-gate for (;;) { 939*0Sstevel@tonic-gate if (mod_hash_find(dacf_module_hash, 940*0Sstevel@tonic-gate (mod_hash_key_t)rule->r_module, 941*0Sstevel@tonic-gate (mod_hash_val_t *)&module) == 0) { 942*0Sstevel@tonic-gate rw_enter(&module->dm_lock, RW_READER); 943*0Sstevel@tonic-gate /* 944*0Sstevel@tonic-gate * Found the module, and it is loaded. 945*0Sstevel@tonic-gate */ 946*0Sstevel@tonic-gate if (module->dm_loaded != 0) { 947*0Sstevel@tonic-gate break; 948*0Sstevel@tonic-gate } 949*0Sstevel@tonic-gate rw_exit(&module->dm_lock); 950*0Sstevel@tonic-gate } 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate /* 953*0Sstevel@tonic-gate * If we're here, either: 1) it's not in the hash, or 2) it is, 954*0Sstevel@tonic-gate * but dm_loaded is 0, meaning the module needs to be loaded. 955*0Sstevel@tonic-gate */ 956*0Sstevel@tonic-gate dprintf("dacf_op_invoke: calling modload\n"); 957*0Sstevel@tonic-gate if (modload("dacf", rule->r_module) < 0) { 958*0Sstevel@tonic-gate return (DACF_ERR_MOD_NOTFOUND); 959*0Sstevel@tonic-gate } 960*0Sstevel@tonic-gate dacf_modload_laps++; 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate 963*0Sstevel@tonic-gate ASSERT(RW_READ_HELD(&module->dm_lock)); 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate opsarray = module->dm_opsets; 966*0Sstevel@tonic-gate 967*0Sstevel@tonic-gate /* 968*0Sstevel@tonic-gate * Loop through the opsets exported by this module, and find the one 969*0Sstevel@tonic-gate * we care about. 970*0Sstevel@tonic-gate */ 971*0Sstevel@tonic-gate opset = NULL; 972*0Sstevel@tonic-gate for (i = 0; opsarray[i].opset_name != NULL; i++) { 973*0Sstevel@tonic-gate if (strcmp(opsarray[i].opset_name, rule->r_opset) == 0) { 974*0Sstevel@tonic-gate opset = &opsarray[i]; 975*0Sstevel@tonic-gate break; 976*0Sstevel@tonic-gate } 977*0Sstevel@tonic-gate } 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate if (opset == NULL) { 980*0Sstevel@tonic-gate cmn_err(CE_WARN, "!dacf: couldn't invoke op, opset '%s' not " 981*0Sstevel@tonic-gate "found in module '%s'", rule->r_opset, rule->r_module); 982*0Sstevel@tonic-gate rw_exit(&module->dm_lock); 983*0Sstevel@tonic-gate return (DACF_ERR_OPSET_NOTFOUND); 984*0Sstevel@tonic-gate } 985*0Sstevel@tonic-gate 986*0Sstevel@tonic-gate arg_hdl = (dacf_arghdl_t)rule->r_args; 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate /* 989*0Sstevel@tonic-gate * Call the appropriate routine in the target by looping across the 990*0Sstevel@tonic-gate * ops until we find the one whose id matches opid. 991*0Sstevel@tonic-gate */ 992*0Sstevel@tonic-gate op = NULL; 993*0Sstevel@tonic-gate for (i = 0; opset->opset_ops[i].op_id != DACF_OPID_END; i++) { 994*0Sstevel@tonic-gate if (opset->opset_ops[i].op_id == op_id) { 995*0Sstevel@tonic-gate op = &(opset->opset_ops[i]); 996*0Sstevel@tonic-gate break; 997*0Sstevel@tonic-gate } 998*0Sstevel@tonic-gate } 999*0Sstevel@tonic-gate 1000*0Sstevel@tonic-gate if (op == NULL) { 1001*0Sstevel@tonic-gate cmn_err(CE_WARN, "!dacf: couldn't invoke op, op '%s' not found " 1002*0Sstevel@tonic-gate "in opset '%s' in module '%s'", dacf_opid_to_str(op_id), 1003*0Sstevel@tonic-gate rule->r_opset, rule->r_module); 1004*0Sstevel@tonic-gate rw_exit(&module->dm_lock); 1005*0Sstevel@tonic-gate return (DACF_ERR_OP_NOTFOUND); 1006*0Sstevel@tonic-gate } 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate dprintf("dacf_op_invoke: found op, invoking...\n"); 1009*0Sstevel@tonic-gate 1010*0Sstevel@tonic-gate /* 1011*0Sstevel@tonic-gate * Drop dacf_lock here, so that op_func's that cause drivers to 1012*0Sstevel@tonic-gate * get loaded don't wedge the system when they try to acquire dacf_lock 1013*0Sstevel@tonic-gate * to do matching. 1014*0Sstevel@tonic-gate * 1015*0Sstevel@tonic-gate * Mark that an invoke is happening to prevent recursive invokes 1016*0Sstevel@tonic-gate */ 1017*0Sstevel@tonic-gate dip = ((struct ddi_minor_data *)info_hdl)->dip; 1018*0Sstevel@tonic-gate 1019*0Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 1020*0Sstevel@tonic-gate DEVI_SET_INVOKING_DACF(dip); 1021*0Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 1022*0Sstevel@tonic-gate 1023*0Sstevel@tonic-gate mutex_exit(&dacf_lock); 1024*0Sstevel@tonic-gate 1025*0Sstevel@tonic-gate rval = op->op_func(info_hdl, arg_hdl, flags); 1026*0Sstevel@tonic-gate 1027*0Sstevel@tonic-gate mutex_enter(&dacf_lock); 1028*0Sstevel@tonic-gate 1029*0Sstevel@tonic-gate /* 1030*0Sstevel@tonic-gate * Completed the invocation against module, so let go of it. 1031*0Sstevel@tonic-gate */ 1032*0Sstevel@tonic-gate mutex_enter(&(DEVI(dip)->devi_lock)); 1033*0Sstevel@tonic-gate DEVI_CLR_INVOKING_DACF(dip); 1034*0Sstevel@tonic-gate mutex_exit(&(DEVI(dip)->devi_lock)); 1035*0Sstevel@tonic-gate 1036*0Sstevel@tonic-gate /* 1037*0Sstevel@tonic-gate * Drop our r-lock on the module, now that we no longer need the module 1038*0Sstevel@tonic-gate * to stay loaded. 1039*0Sstevel@tonic-gate */ 1040*0Sstevel@tonic-gate rw_exit(&module->dm_lock); 1041*0Sstevel@tonic-gate 1042*0Sstevel@tonic-gate if (rval == DACF_SUCCESS) { 1043*0Sstevel@tonic-gate return (DACF_SUCCESS); 1044*0Sstevel@tonic-gate } else { 1045*0Sstevel@tonic-gate return (DACF_ERR_OP_FAILED); 1046*0Sstevel@tonic-gate } 1047*0Sstevel@tonic-gate } 1048*0Sstevel@tonic-gate 1049*0Sstevel@tonic-gate /* 1050*0Sstevel@tonic-gate * dacf_get_devspec() 1051*0Sstevel@tonic-gate * given a devspec-type as a string, return a corresponding dacf_devspec_t 1052*0Sstevel@tonic-gate */ 1053*0Sstevel@tonic-gate dacf_devspec_t 1054*0Sstevel@tonic-gate dacf_get_devspec(char *name) 1055*0Sstevel@tonic-gate { 1056*0Sstevel@tonic-gate dacf_ds_t *p = &dacf_devspecs[0]; 1057*0Sstevel@tonic-gate 1058*0Sstevel@tonic-gate while (p->name != NULL) { 1059*0Sstevel@tonic-gate if (strcmp(p->name, name) == 0) { 1060*0Sstevel@tonic-gate return (p->id); 1061*0Sstevel@tonic-gate } 1062*0Sstevel@tonic-gate p++; 1063*0Sstevel@tonic-gate } 1064*0Sstevel@tonic-gate return (DACF_DS_ERROR); 1065*0Sstevel@tonic-gate } 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate /* 1068*0Sstevel@tonic-gate * dacf_devspec_to_str() 1069*0Sstevel@tonic-gate * given a dacf_devspec_t, return a pointer to the human readable string 1070*0Sstevel@tonic-gate * representation of that device specifier. 1071*0Sstevel@tonic-gate */ 1072*0Sstevel@tonic-gate const char * 1073*0Sstevel@tonic-gate dacf_devspec_to_str(dacf_devspec_t ds) 1074*0Sstevel@tonic-gate { 1075*0Sstevel@tonic-gate dacf_ds_t *p = &dacf_devspecs[0]; 1076*0Sstevel@tonic-gate 1077*0Sstevel@tonic-gate while (p->name != NULL) { 1078*0Sstevel@tonic-gate if (p->id == ds) { 1079*0Sstevel@tonic-gate return (p->name); 1080*0Sstevel@tonic-gate } 1081*0Sstevel@tonic-gate p++; 1082*0Sstevel@tonic-gate } 1083*0Sstevel@tonic-gate return (NULL); 1084*0Sstevel@tonic-gate } 1085*0Sstevel@tonic-gate 1086*0Sstevel@tonic-gate /* 1087*0Sstevel@tonic-gate * dacf_get_op() 1088*0Sstevel@tonic-gate * given a op name, returns the corresponding dacf_opid_t. 1089*0Sstevel@tonic-gate */ 1090*0Sstevel@tonic-gate dacf_opid_t 1091*0Sstevel@tonic-gate dacf_get_op(char *name) 1092*0Sstevel@tonic-gate { 1093*0Sstevel@tonic-gate dacf_opmap_t *p = &dacf_ops[0]; 1094*0Sstevel@tonic-gate 1095*0Sstevel@tonic-gate while (p->name != NULL) { 1096*0Sstevel@tonic-gate if (strcmp(p->name, name) == 0) { 1097*0Sstevel@tonic-gate return (p->id); 1098*0Sstevel@tonic-gate } 1099*0Sstevel@tonic-gate p++; 1100*0Sstevel@tonic-gate } 1101*0Sstevel@tonic-gate return (DACF_OPID_ERROR); 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate 1104*0Sstevel@tonic-gate /* 1105*0Sstevel@tonic-gate * dacf_opid_to_str() 1106*0Sstevel@tonic-gate * given a dacf_opid_t, return the human-readable op-name. 1107*0Sstevel@tonic-gate */ 1108*0Sstevel@tonic-gate const char * 1109*0Sstevel@tonic-gate dacf_opid_to_str(dacf_opid_t tid) 1110*0Sstevel@tonic-gate { 1111*0Sstevel@tonic-gate dacf_opmap_t *p = &dacf_ops[0]; 1112*0Sstevel@tonic-gate 1113*0Sstevel@tonic-gate while (p->name != NULL) { 1114*0Sstevel@tonic-gate if (p->id == tid) { 1115*0Sstevel@tonic-gate return (p->name); 1116*0Sstevel@tonic-gate } 1117*0Sstevel@tonic-gate p++; 1118*0Sstevel@tonic-gate } 1119*0Sstevel@tonic-gate return (NULL); 1120*0Sstevel@tonic-gate } 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gate /* 1123*0Sstevel@tonic-gate * dacf_getopt() 1124*0Sstevel@tonic-gate * given an option specified as a string, add it to the bit-field of 1125*0Sstevel@tonic-gate * options given. Returns -1 if the option is unrecognized. 1126*0Sstevel@tonic-gate */ 1127*0Sstevel@tonic-gate int 1128*0Sstevel@tonic-gate dacf_getopt(char *opt_str, uint_t *opts) 1129*0Sstevel@tonic-gate { 1130*0Sstevel@tonic-gate dacf_opt_t *p = &dacf_options[0]; 1131*0Sstevel@tonic-gate 1132*0Sstevel@tonic-gate /* 1133*0Sstevel@tonic-gate * Look through the list for the option given 1134*0Sstevel@tonic-gate */ 1135*0Sstevel@tonic-gate while (p->optname != NULL) { 1136*0Sstevel@tonic-gate if (strcmp(opt_str, p->optname) == 0) { 1137*0Sstevel@tonic-gate *opts |= p->optmask; 1138*0Sstevel@tonic-gate return (0); 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate p++; 1141*0Sstevel@tonic-gate } 1142*0Sstevel@tonic-gate return (-1); 1143*0Sstevel@tonic-gate } 1144*0Sstevel@tonic-gate 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate 1147*0Sstevel@tonic-gate /* 1148*0Sstevel@tonic-gate * This family of functions forms the dacf interface which is exported to 1149*0Sstevel@tonic-gate * kernel/dacf modules. Modules _should_not_ use any dacf_* functions 1150*0Sstevel@tonic-gate * presented above this point. 1151*0Sstevel@tonic-gate * 1152*0Sstevel@tonic-gate * Note: These routines use a dacf_infohdl_t to struct ddi_minor_data * and 1153*0Sstevel@tonic-gate * assume that the resulting pointer is not to an alias node. That is true 1154*0Sstevel@tonic-gate * because dacf_op_invoke guarantees it by first resolving the alias. 1155*0Sstevel@tonic-gate */ 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate /* 1158*0Sstevel@tonic-gate * dacf_minor_name() 1159*0Sstevel@tonic-gate * given a dacf_infohdl_t, obtain the minor name of the device instance 1160*0Sstevel@tonic-gate * being configured. 1161*0Sstevel@tonic-gate */ 1162*0Sstevel@tonic-gate const char * 1163*0Sstevel@tonic-gate dacf_minor_name(dacf_infohdl_t info_hdl) 1164*0Sstevel@tonic-gate { 1165*0Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate return (dmdp->ddm_name); 1168*0Sstevel@tonic-gate } 1169*0Sstevel@tonic-gate 1170*0Sstevel@tonic-gate /* 1171*0Sstevel@tonic-gate * dacf_minor_number() 1172*0Sstevel@tonic-gate * given a dacf_infohdl_t, obtain the device minor number of the instance 1173*0Sstevel@tonic-gate * being configured. 1174*0Sstevel@tonic-gate */ 1175*0Sstevel@tonic-gate minor_t 1176*0Sstevel@tonic-gate dacf_minor_number(dacf_infohdl_t info_hdl) 1177*0Sstevel@tonic-gate { 1178*0Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate return (getminor(dmdp->ddm_dev)); 1181*0Sstevel@tonic-gate } 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate /* 1184*0Sstevel@tonic-gate * dacf_driver_name() 1185*0Sstevel@tonic-gate * given a dacf_infohdl_t, obtain the device driver name of the device 1186*0Sstevel@tonic-gate * instance being configured. 1187*0Sstevel@tonic-gate */ 1188*0Sstevel@tonic-gate const char * 1189*0Sstevel@tonic-gate dacf_driver_name(dacf_infohdl_t info_hdl) 1190*0Sstevel@tonic-gate { 1191*0Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate return (ddi_driver_name(dmdp->dip)); 1194*0Sstevel@tonic-gate } 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate /* 1197*0Sstevel@tonic-gate * dacf_devinfo_node() 1198*0Sstevel@tonic-gate * given a dacf_infohdl_t, obtain the dev_info_t of the device instance 1199*0Sstevel@tonic-gate * being configured. 1200*0Sstevel@tonic-gate */ 1201*0Sstevel@tonic-gate dev_info_t * 1202*0Sstevel@tonic-gate dacf_devinfo_node(dacf_infohdl_t info_hdl) 1203*0Sstevel@tonic-gate { 1204*0Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1205*0Sstevel@tonic-gate 1206*0Sstevel@tonic-gate return (dmdp->dip); 1207*0Sstevel@tonic-gate } 1208*0Sstevel@tonic-gate 1209*0Sstevel@tonic-gate /* 1210*0Sstevel@tonic-gate * dacf_get_arg() 1211*0Sstevel@tonic-gate * given the dacf_arghdl_t passed to a op and the name of an argument, 1212*0Sstevel@tonic-gate * return the value of that argument. 1213*0Sstevel@tonic-gate * 1214*0Sstevel@tonic-gate * returns NULL if the argument is not found. 1215*0Sstevel@tonic-gate */ 1216*0Sstevel@tonic-gate const char * 1217*0Sstevel@tonic-gate dacf_get_arg(dacf_arghdl_t arghdl, char *arg_name) 1218*0Sstevel@tonic-gate { 1219*0Sstevel@tonic-gate dacf_arg_t *arg_list = (dacf_arg_t *)arghdl; 1220*0Sstevel@tonic-gate ASSERT(arg_name); 1221*0Sstevel@tonic-gate 1222*0Sstevel@tonic-gate while (arg_list != NULL) { 1223*0Sstevel@tonic-gate if (strcmp(arg_list->arg_name, arg_name) == 0) { 1224*0Sstevel@tonic-gate return (arg_list->arg_val); 1225*0Sstevel@tonic-gate } 1226*0Sstevel@tonic-gate arg_list = arg_list->arg_next; 1227*0Sstevel@tonic-gate } 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate return (NULL); 1230*0Sstevel@tonic-gate } 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate /* 1233*0Sstevel@tonic-gate * dacf_store_info() 1234*0Sstevel@tonic-gate * associate instance-specific data with a device instance. Future 1235*0Sstevel@tonic-gate * configuration ops invoked for this instance can retrieve this data using 1236*0Sstevel@tonic-gate * dacf_retrieve_info() below. Modules are responsible for cleaning up 1237*0Sstevel@tonic-gate * this data as appropriate, and should store NULL as the value of 'data' 1238*0Sstevel@tonic-gate * when the data is no longer valid. 1239*0Sstevel@tonic-gate */ 1240*0Sstevel@tonic-gate void 1241*0Sstevel@tonic-gate dacf_store_info(dacf_infohdl_t info_hdl, void *data) 1242*0Sstevel@tonic-gate { 1243*0Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1244*0Sstevel@tonic-gate 1245*0Sstevel@tonic-gate /* 1246*0Sstevel@tonic-gate * If the client is 'storing NULL' we can represent that by blowing 1247*0Sstevel@tonic-gate * the info entry out of the hash. 1248*0Sstevel@tonic-gate */ 1249*0Sstevel@tonic-gate if (data == NULL) { 1250*0Sstevel@tonic-gate (void) mod_hash_destroy(dacf_info_hash, (mod_hash_key_t)dmdp); 1251*0Sstevel@tonic-gate } else { 1252*0Sstevel@tonic-gate /* 1253*0Sstevel@tonic-gate * mod_hash_replace can only fail on out of memory, but we sleep 1254*0Sstevel@tonic-gate * for memory in this hash, so it is safe to ignore the retval. 1255*0Sstevel@tonic-gate */ 1256*0Sstevel@tonic-gate (void) mod_hash_replace(dacf_info_hash, (mod_hash_key_t)dmdp, 1257*0Sstevel@tonic-gate (mod_hash_val_t)data); 1258*0Sstevel@tonic-gate } 1259*0Sstevel@tonic-gate } 1260*0Sstevel@tonic-gate 1261*0Sstevel@tonic-gate /* 1262*0Sstevel@tonic-gate * dacf_retrieve_info() 1263*0Sstevel@tonic-gate * retrieve instance-specific data associated with a device instance. 1264*0Sstevel@tonic-gate */ 1265*0Sstevel@tonic-gate void * 1266*0Sstevel@tonic-gate dacf_retrieve_info(dacf_infohdl_t info_hdl) 1267*0Sstevel@tonic-gate { 1268*0Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1269*0Sstevel@tonic-gate void *data; 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate if (mod_hash_find(dacf_info_hash, (mod_hash_key_t)dmdp, 1272*0Sstevel@tonic-gate (mod_hash_val_t *)&data) != 0) { 1273*0Sstevel@tonic-gate return (NULL); 1274*0Sstevel@tonic-gate } 1275*0Sstevel@tonic-gate 1276*0Sstevel@tonic-gate return (data); 1277*0Sstevel@tonic-gate } 1278*0Sstevel@tonic-gate 1279*0Sstevel@tonic-gate /* 1280*0Sstevel@tonic-gate * dacf_makevp() 1281*0Sstevel@tonic-gate * make a vnode for the specified dacf_infohdl_t. 1282*0Sstevel@tonic-gate */ 1283*0Sstevel@tonic-gate struct vnode * 1284*0Sstevel@tonic-gate dacf_makevp(dacf_infohdl_t info_hdl) 1285*0Sstevel@tonic-gate { 1286*0Sstevel@tonic-gate struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl; 1287*0Sstevel@tonic-gate struct vnode *vp; 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate vp = makespecvp(dmdp->ddm_dev, VCHR); 1290*0Sstevel@tonic-gate spec_assoc_vp_with_devi(vp, dmdp->dip); 1291*0Sstevel@tonic-gate return (vp); 1292*0Sstevel@tonic-gate } 1293