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