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