xref: /onnv-gate/usr/src/uts/common/os/dacf.c (revision 5895:f251acdd9bdc)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*5895Syz147064  * Common Development and Distribution License (the "License").
6*5895Syz147064  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*5895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * DACF: device autoconfiguration support
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * DACF provides a fast, lightweight policy engine for the I/O subsystem.
320Sstevel@tonic-gate  * This policy engine provides a mechanism for auto-configuring and
330Sstevel@tonic-gate  * auto-unconfiguring devices.
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * After a device is attach(9E)ed, additional configuration may be needed in
360Sstevel@tonic-gate  * order to make the device available for use by the system.  For example,
370Sstevel@tonic-gate  * STREAMS modules may need to be pushed atop the driver in order to create
380Sstevel@tonic-gate  * a STREAMS stack.  If the device is to be removed from the system, these
390Sstevel@tonic-gate  * configuration operations need to be undone, and the device prepared for
400Sstevel@tonic-gate  * detach(9E).
410Sstevel@tonic-gate  *
420Sstevel@tonic-gate  * It is desirable to move the implementation of such policies outside of the
430Sstevel@tonic-gate  * kernel proper, since such operations are typically infrequent.  To this end,
440Sstevel@tonic-gate  * DACF manages kernel modules in (module_path)/dacf directories.  These adhere
450Sstevel@tonic-gate  * to the api defined in sys/dacf.h, and register sets of configuration
460Sstevel@tonic-gate  * operations.  The kernel loads these modules when the operations they
470Sstevel@tonic-gate  * implement are needed, and can unload them at any time thereafter.
480Sstevel@tonic-gate  * Implementing configuration operations in external modules can also increase
490Sstevel@tonic-gate  * code reuse.
500Sstevel@tonic-gate  *
510Sstevel@tonic-gate  * DACF provides a policy database which associates
520Sstevel@tonic-gate  *
530Sstevel@tonic-gate  *   (device descr., kernel action) --> (configuration operation, parameters)
540Sstevel@tonic-gate  *
550Sstevel@tonic-gate  * - Device description is matching rule, for example:
560Sstevel@tonic-gate  * 	minor-nodetype="ddi_keyboard"
570Sstevel@tonic-gate  * - Kernel action is a reference to a dacf kernel hook.
580Sstevel@tonic-gate  *      currently supported are "post-attach" and "pre-detach"
590Sstevel@tonic-gate  * - Configuration action is a reference to a module and a set of operations
600Sstevel@tonic-gate  *      within the module, for example:  consconfig:kbd_config
610Sstevel@tonic-gate  * - Parameters is a list of name="value" parameters to be passed to the
620Sstevel@tonic-gate  *      configuration operation when invoked.
630Sstevel@tonic-gate  *
640Sstevel@tonic-gate  * The contents of the rules database are loaded from /etc/dacf.conf upon boot.
650Sstevel@tonic-gate  *
660Sstevel@tonic-gate  * DACF kernel hooks are comprised of a call into the rule-matching engine,
670Sstevel@tonic-gate  * using parameters from the hook in order find a matching rule.  If one is
680Sstevel@tonic-gate  * found, the framework can invoke the configuration operation immediately, or
690Sstevel@tonic-gate  * defer doing so until later, by putting the rule on a 'reservation list.'
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate #include <sys/param.h>
730Sstevel@tonic-gate #include <sys/modctl.h>
740Sstevel@tonic-gate #include <sys/sysmacros.h>
750Sstevel@tonic-gate #include <sys/kmem.h>
760Sstevel@tonic-gate #include <sys/cmn_err.h>
770Sstevel@tonic-gate #include <sys/pathname.h>
780Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
790Sstevel@tonic-gate #include <sys/sunddi.h>
800Sstevel@tonic-gate #include <sys/autoconf.h>
810Sstevel@tonic-gate #include <sys/modhash.h>
820Sstevel@tonic-gate #include <sys/dacf.h>
830Sstevel@tonic-gate #include <sys/dacf_impl.h>
840Sstevel@tonic-gate #include <sys/systm.h>
850Sstevel@tonic-gate #include <sys/varargs.h>
860Sstevel@tonic-gate #include <sys/debug.h>
870Sstevel@tonic-gate #include <sys/log.h>
880Sstevel@tonic-gate #include <sys/fs/snode.h>
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  * Enumeration of the ops exported by the dacf framework.
920Sstevel@tonic-gate  *
930Sstevel@tonic-gate  * To add a new op to the framework, add it to this list, update dacf.h,
940Sstevel@tonic-gate  * (don't miss DACF_NUM_OPIDS) and modify dacf_rule_matrix.
950Sstevel@tonic-gate  *
960Sstevel@tonic-gate  */
970Sstevel@tonic-gate typedef struct dacf_opmap {
980Sstevel@tonic-gate 	const char *name;
990Sstevel@tonic-gate 	dacf_opid_t id;
1000Sstevel@tonic-gate } dacf_opmap_t;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static dacf_opmap_t dacf_ops[] = {
1030Sstevel@tonic-gate 	{ "post-attach",	DACF_OPID_POSTATTACH		},
1040Sstevel@tonic-gate 	{ "pre-detach",		DACF_OPID_PREDETACH		},
1050Sstevel@tonic-gate 	{ NULL,			0				},
1060Sstevel@tonic-gate };
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * Enumeration of the options exported by the dacf framework (currently none).
1100Sstevel@tonic-gate  *
1110Sstevel@tonic-gate  * To add a new option, add it to this array.
1120Sstevel@tonic-gate  */
1130Sstevel@tonic-gate typedef struct dacf_opt {
1140Sstevel@tonic-gate 	const char *optname;
1150Sstevel@tonic-gate 	uint_t optmask;
1160Sstevel@tonic-gate } dacf_opt_t;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate static dacf_opt_t dacf_options[] = {
1190Sstevel@tonic-gate #ifdef DEBUG
1200Sstevel@tonic-gate 	{ "testopt", 		1		},
1210Sstevel@tonic-gate 	{ "testopt2", 		2		},
1220Sstevel@tonic-gate #endif
1230Sstevel@tonic-gate 	{ NULL, 		0		},
1240Sstevel@tonic-gate };
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate static char kmod_name[] = "__kernel";
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate /*
1290Sstevel@tonic-gate  * Enumeration of the device specifiers exported by the dacf framework.
1300Sstevel@tonic-gate  *
1310Sstevel@tonic-gate  * To add a new devspec to the framework, add it to this list, update dacf.h,
1320Sstevel@tonic-gate  * (don't miss DACF_NUM_DEVSPECS), modify dacf_rule_matrix, and modify
1330Sstevel@tonic-gate  * dacf_match().
1340Sstevel@tonic-gate  */
1350Sstevel@tonic-gate typedef struct dacf_ds {
1360Sstevel@tonic-gate 	const char *name;
1370Sstevel@tonic-gate 	dacf_devspec_t id;
1380Sstevel@tonic-gate } dacf_ds_t;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate static dacf_ds_t dacf_devspecs[] = {
1410Sstevel@tonic-gate 	{ "minor-nodetype", 	DACF_DS_MIN_NT 		},
1420Sstevel@tonic-gate 	{ "driver-minorname", 	DACF_DS_DRV_MNAME	},
1430Sstevel@tonic-gate 	{ "device-path",	DACF_DS_DEV_PATH	},
1440Sstevel@tonic-gate 	{ NULL,			NULL			},
1450Sstevel@tonic-gate };
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate mod_hash_t *posta_mntype, *posta_mname, *posta_devname;	/* post-attach */
1480Sstevel@tonic-gate mod_hash_t *pred_mntype, *pred_mname, *pred_devname;	/* pre-detach */
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate mod_hash_t *dacf_module_hash;
1510Sstevel@tonic-gate mod_hash_t *dacf_info_hash;
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * This is the lookup table for the hash tables that dacf manages.  Given an
1550Sstevel@tonic-gate  * op id and devspec type, one can obtain the hash for that type of data.
1560Sstevel@tonic-gate  */
1570Sstevel@tonic-gate mod_hash_t **dacf_rule_matrix[DACF_NUM_OPIDS][DACF_NUM_DEVSPECS] = {
1580Sstevel@tonic-gate 	{ &posta_mntype, 	&posta_mname,	&posta_devname	},
1590Sstevel@tonic-gate 	{ &pred_mntype,		&pred_mname,	&pred_devname	},
1600Sstevel@tonic-gate };
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate kmutex_t dacf_lock;
1630Sstevel@tonic-gate kmutex_t dacf_module_lock;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate int dacfdebug = 0;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate static dacf_rule_t *dacf_rule_ctor(char *, char *, char *, dacf_opid_t,
1680Sstevel@tonic-gate     uint_t, dacf_arg_t *);
1690Sstevel@tonic-gate static mod_hash_t *dacf_get_op_hash(dacf_opid_t, dacf_devspec_t);
1700Sstevel@tonic-gate static void dacf_rule_val_dtor(mod_hash_val_t);
1710Sstevel@tonic-gate static void dacf_destroy_opsets(dacf_module_t *module);
1720Sstevel@tonic-gate static void dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src);
1730Sstevel@tonic-gate static void dprintf(const char *, ...) __KPRINTFLIKE(1);
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate /*PRINTFLIKE1*/
1760Sstevel@tonic-gate static void
dprintf(const char * format,...)1770Sstevel@tonic-gate dprintf(const char *format, ...)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate 	va_list alist;
1800Sstevel@tonic-gate 	char dp_buf[256], *dpbp;
1810Sstevel@tonic-gate 	if (dacfdebug & DACF_DBG_MSGS) {
1820Sstevel@tonic-gate 		va_start(alist, format);
1830Sstevel@tonic-gate 		/*
1840Sstevel@tonic-gate 		 * sprintf up the string that is 'dacf debug: <the message>'
1850Sstevel@tonic-gate 		 */
1860Sstevel@tonic-gate 		(void) sprintf(dp_buf, "dacf debug: ");
1870Sstevel@tonic-gate 		dpbp = &(dp_buf[strlen(dp_buf)]);
1880Sstevel@tonic-gate 		(void) vsnprintf(dpbp, sizeof (dp_buf) - strlen(dp_buf),
1890Sstevel@tonic-gate 		    format, alist);
1900Sstevel@tonic-gate 		printf(dp_buf);
1910Sstevel@tonic-gate 		va_end(alist);
1920Sstevel@tonic-gate 	}
1930Sstevel@tonic-gate }
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate /*
1960Sstevel@tonic-gate  * dacf_init()
1970Sstevel@tonic-gate  * 	initialize the dacf framework by creating the various hash tables.
1980Sstevel@tonic-gate  */
1990Sstevel@tonic-gate void
dacf_init()2000Sstevel@tonic-gate dacf_init()
2010Sstevel@tonic-gate {
2020Sstevel@tonic-gate 	int i, j;
2030Sstevel@tonic-gate 	char hbuf[40];
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	mutex_enter(&dacf_lock);
2060Sstevel@tonic-gate 
2070Sstevel@tonic-gate 	dprintf("dacf_init: creating hashmatrix\n");
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate #ifdef DEBUG
2100Sstevel@tonic-gate 	/*
2110Sstevel@tonic-gate 	 * Sanity check that DACF_NUM_DEVSPECS and the devspecs are in sync
2120Sstevel@tonic-gate 	 */
2130Sstevel@tonic-gate 	for (i = 0; dacf_devspecs[i].name != NULL; i++)
2140Sstevel@tonic-gate 		continue;
2150Sstevel@tonic-gate 	ASSERT(i == DACF_NUM_DEVSPECS);
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	/*
2180Sstevel@tonic-gate 	 * Sanity check that DACF_NUM_OPIDS and the dacf_ops are in sync
2190Sstevel@tonic-gate 	 */
2200Sstevel@tonic-gate 	for (i = 0; dacf_ops[i].name != NULL; i++)
2210Sstevel@tonic-gate 		continue;
2220Sstevel@tonic-gate 	ASSERT(i == DACF_NUM_OPIDS);
2230Sstevel@tonic-gate #endif
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	for (i = 0; i < DACF_NUM_OPIDS; i++) {
2260Sstevel@tonic-gate 		for (j = 0; j < DACF_NUM_DEVSPECS; j++) {
2270Sstevel@tonic-gate 			if (dacf_rule_matrix[i][j] == NULL) {
2280Sstevel@tonic-gate 				continue;
2290Sstevel@tonic-gate 			}
2300Sstevel@tonic-gate 			/*
2310Sstevel@tonic-gate 			 * Set up a hash table with no key destructor.  The
2320Sstevel@tonic-gate 			 * keys are carried in the rule_t, so the val_dtor
2330Sstevel@tonic-gate 			 * will take care of the key as well.
2340Sstevel@tonic-gate 			 */
2350Sstevel@tonic-gate 			(void) snprintf(hbuf, sizeof (hbuf),
2360Sstevel@tonic-gate 			    "dacf hashmatrix [%d][%d]", i, j);
2370Sstevel@tonic-gate 			*(dacf_rule_matrix[i][j]) = mod_hash_create_extended(
2380Sstevel@tonic-gate 			    hbuf,			/* hash name */
2390Sstevel@tonic-gate 			    DACF_RULE_HASHSIZE,		/* # hash elems */
2400Sstevel@tonic-gate 			    mod_hash_null_keydtor,	/* key dtor */
2410Sstevel@tonic-gate 			    dacf_rule_val_dtor,		/* value dtor */
2420Sstevel@tonic-gate 			    mod_hash_bystr, NULL, 	/* hash alg & data */
2430Sstevel@tonic-gate 			    mod_hash_strkey_cmp,	/* key comparator */
2440Sstevel@tonic-gate 			    KM_SLEEP);
2450Sstevel@tonic-gate 		}
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	dprintf("dacf_init: creating module_hash\n");
2490Sstevel@tonic-gate 	/*
2500Sstevel@tonic-gate 	 * dacf_module_hash stores the currently registered dacf modules
2510Sstevel@tonic-gate 	 * by name.
2520Sstevel@tonic-gate 	 */
2530Sstevel@tonic-gate 	dacf_module_hash = mod_hash_create_strhash("dacf module hash",
2540Sstevel@tonic-gate 	    DACF_MODULE_HASHSIZE, mod_hash_null_valdtor);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	dprintf("dacf_init: creating info_hash\n");
2570Sstevel@tonic-gate 	/*
2580Sstevel@tonic-gate 	 * dacf_info_hash stores pointers to data that modules can associate
2590Sstevel@tonic-gate 	 * on a per minornode basis.  The type of data stored is opaque to the
2600Sstevel@tonic-gate 	 * framework-- thus there is no destructor supplied.
2610Sstevel@tonic-gate 	 */
2620Sstevel@tonic-gate 	dacf_info_hash = mod_hash_create_ptrhash("dacf info hash",
2630Sstevel@tonic-gate 	    DACF_INFO_HASHSIZE, mod_hash_null_valdtor,
2640Sstevel@tonic-gate 	    sizeof (struct ddi_minor_data));
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	mutex_exit(&dacf_lock);
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	/*
2690Sstevel@tonic-gate 	 * Register the '__kernel' module.
2700Sstevel@tonic-gate 	 *
2710Sstevel@tonic-gate 	 * These are operations that are provided by the kernel, not by a
2720Sstevel@tonic-gate 	 * module.  We just feed the framework a dacfsw structure; it will get
2730Sstevel@tonic-gate 	 * marked as 'loaded' by dacf_module_register(), and will always be
2740Sstevel@tonic-gate 	 * available.
2750Sstevel@tonic-gate 	 */
2760Sstevel@tonic-gate 	(void) dacf_module_register(kmod_name, &kmod_dacfsw);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	(void) read_dacf_binding_file(NULL);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	dprintf("dacf_init: dacf is ready\n");
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * dacf_clear_rules()
2850Sstevel@tonic-gate  * 	clear the dacf rule database.  This is typically done in advance of
2860Sstevel@tonic-gate  * 	rereading the dacf binding file.
2870Sstevel@tonic-gate  */
2880Sstevel@tonic-gate void
dacf_clear_rules()2890Sstevel@tonic-gate dacf_clear_rules()
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	int i, j;
2920Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dacf_lock));
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	for (i = 0; i < DACF_NUM_OPIDS; i++) {
2950Sstevel@tonic-gate 		for (j = 0; j < DACF_NUM_DEVSPECS; j++) {
2960Sstevel@tonic-gate 			if ((dacf_rule_matrix[i][j] != NULL) &&
2970Sstevel@tonic-gate 			    (*(dacf_rule_matrix[i][j]) != NULL)) {
2980Sstevel@tonic-gate 				mod_hash_clear(*(dacf_rule_matrix[i][j]));
2990Sstevel@tonic-gate 			}
3000Sstevel@tonic-gate 		}
3010Sstevel@tonic-gate 	}
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate  * dacf_rule_insert()
3060Sstevel@tonic-gate  *	Create an entry in the dacf rule database.
3070Sstevel@tonic-gate  *	If 'module' is null, the kernel is the 'module'. (see dacf_rule_ctor()).
3080Sstevel@tonic-gate  */
3090Sstevel@tonic-gate int
dacf_rule_insert(dacf_devspec_t devspec_type,char * devspec_data,char * module,char * opset,dacf_opid_t opid,uint_t opts,dacf_arg_t * op_args)3100Sstevel@tonic-gate dacf_rule_insert(dacf_devspec_t devspec_type, char *devspec_data,
3110Sstevel@tonic-gate     char *module, char *opset, dacf_opid_t opid, uint_t opts,
3120Sstevel@tonic-gate     dacf_arg_t *op_args)
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate 	dacf_rule_t *rule;
3150Sstevel@tonic-gate 	mod_hash_t *hash;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	ASSERT(devspec_type != DACF_DS_ERROR);
3180Sstevel@tonic-gate 	ASSERT(devspec_data);
3190Sstevel@tonic-gate 	ASSERT(opset);
3200Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dacf_lock));
3210Sstevel@tonic-gate 
3220Sstevel@tonic-gate 	dprintf("dacf_rule_insert called: %s=\"%s\", %s:%s, %s\n",
3230Sstevel@tonic-gate 	    dacf_devspec_to_str(devspec_type), devspec_data,
3240Sstevel@tonic-gate 	    module ? module : "[kernel]", opset, dacf_opid_to_str(opid));
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	/*
3270Sstevel@tonic-gate 	 * Fetch the hash table associated with this op-name and devspec-type.
3280Sstevel@tonic-gate 	 * Some ops may not support all devspec-types, since they may be
3290Sstevel@tonic-gate 	 * meaningless, so hash may be null.
3300Sstevel@tonic-gate 	 */
3310Sstevel@tonic-gate 	hash = dacf_get_op_hash(opid, devspec_type);
3320Sstevel@tonic-gate 	if (hash == NULL) {
3330Sstevel@tonic-gate 		cmn_err(CE_WARN, "!dacf dev-spec '%s' does not support op '%s'",
3340Sstevel@tonic-gate 		    dacf_devspec_to_str(devspec_type), dacf_opid_to_str(opid));
3350Sstevel@tonic-gate 		return (-1);
3360Sstevel@tonic-gate 	}
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/*
3390Sstevel@tonic-gate 	 * Allocate a rule  and fill it in, take a hold on it.
3400Sstevel@tonic-gate 	 */
3410Sstevel@tonic-gate 	rule = dacf_rule_ctor(devspec_data, module, opset, opid, opts,
3420Sstevel@tonic-gate 	    op_args);
3430Sstevel@tonic-gate 	dacf_rule_hold(rule);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	if (mod_hash_insert(hash, (mod_hash_key_t)rule->r_devspec_data,
3460Sstevel@tonic-gate 	    (mod_hash_val_t)rule) != 0) {
3470Sstevel@tonic-gate 		/*
3480Sstevel@tonic-gate 		 * We failed, so release hold.  This will cause the rule and
3490Sstevel@tonic-gate 		 * associated data to get nuked.
3500Sstevel@tonic-gate 		 */
3510Sstevel@tonic-gate 		dacf_rule_rele(rule);
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 		cmn_err(CE_WARN, "!dacf rule %s='%s' %s:%s %s duplicates "
3540Sstevel@tonic-gate 		    "another rule, ignored", dacf_devspec_to_str(devspec_type),
3550Sstevel@tonic-gate 		    devspec_data, module, opset, dacf_opid_to_str(opid));
3560Sstevel@tonic-gate 		return (-1);
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 	return (0);
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate /*
3620Sstevel@tonic-gate  * dacf_rule_ctor()
3630Sstevel@tonic-gate  * 	Allocate and fill out entries in a dacf_rule_t.
3640Sstevel@tonic-gate  */
3650Sstevel@tonic-gate static dacf_rule_t *
dacf_rule_ctor(char * device_spec,char * module,char * opset,dacf_opid_t opid,uint_t opts,dacf_arg_t * op_args)3660Sstevel@tonic-gate dacf_rule_ctor(char *device_spec, char *module, char *opset, dacf_opid_t opid,
3670Sstevel@tonic-gate     uint_t opts, dacf_arg_t *op_args)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate 	dacf_rule_t *rule;
3700Sstevel@tonic-gate 	dacf_arg_t *p;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	rule = kmem_alloc(sizeof (dacf_rule_t), KM_SLEEP);
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	/*
3750Sstevel@tonic-gate 	 * Fill in the entries
3760Sstevel@tonic-gate 	 */
3770Sstevel@tonic-gate 	rule->r_devspec_data = kmem_alloc(strlen(device_spec) + 1, KM_SLEEP);
3780Sstevel@tonic-gate 	(void) strcpy(rule->r_devspec_data, device_spec);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	/*
3810Sstevel@tonic-gate 	 * If module is 'null' we set it to __kernel, meaning that this op
3820Sstevel@tonic-gate 	 * is implemented by the kernel.
3830Sstevel@tonic-gate 	 */
3840Sstevel@tonic-gate 	if (module == NULL) {
3850Sstevel@tonic-gate 		module = kmod_name;
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	rule->r_module = kmem_alloc(strlen(module) + 1, KM_SLEEP);
3890Sstevel@tonic-gate 	(void) strcpy(rule->r_module, module);
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	rule->r_opset = kmem_alloc(strlen(opset) + 1, KM_SLEEP);
3920Sstevel@tonic-gate 	(void) strcpy(rule->r_opset, opset);
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	rule->r_refs = 0;	/* no refs yet */
3950Sstevel@tonic-gate 	rule->r_opts = opts;
3960Sstevel@tonic-gate 	rule->r_opid = opid;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	rule->r_args = NULL;
3990Sstevel@tonic-gate 	p = op_args;
4000Sstevel@tonic-gate 	while (p != NULL) {
4010Sstevel@tonic-gate 		ASSERT(p->arg_name);
4020Sstevel@tonic-gate 		ASSERT(p->arg_val);
4030Sstevel@tonic-gate 		/*
4040Sstevel@tonic-gate 		 * dacf_arg_insert() should always succeed, since we're copying
4050Sstevel@tonic-gate 		 * another (already duplicate-free) list.
4060Sstevel@tonic-gate 		 */
4070Sstevel@tonic-gate 		(void) dacf_arg_insert(&rule->r_args, p->arg_name, p->arg_val);
4080Sstevel@tonic-gate 		p = p->arg_next;
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	return (rule);
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate /*
4150Sstevel@tonic-gate  * dacf_rule_val_dtor()
4160Sstevel@tonic-gate  * 	This is the destructor for dacf_rule_t's in the rule database.  It
4170Sstevel@tonic-gate  * 	simply does a dacf_rule_rele() on the rule.  This function will take
4180Sstevel@tonic-gate  * 	care of destroying the rule if its ref count has dropped to 0.
4190Sstevel@tonic-gate  */
4200Sstevel@tonic-gate static void
dacf_rule_val_dtor(mod_hash_val_t val)4210Sstevel@tonic-gate dacf_rule_val_dtor(mod_hash_val_t val)
4220Sstevel@tonic-gate {
4230Sstevel@tonic-gate 	ASSERT((void *)val != NULL);
4240Sstevel@tonic-gate 	dacf_rule_rele((dacf_rule_t *)val);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate  * dacf_rule_destroy()
4290Sstevel@tonic-gate  * 	destroy a dacf_rule_t
4300Sstevel@tonic-gate  */
4310Sstevel@tonic-gate void
dacf_rule_destroy(dacf_rule_t * rule)4320Sstevel@tonic-gate dacf_rule_destroy(dacf_rule_t *rule)
4330Sstevel@tonic-gate {
4340Sstevel@tonic-gate 	ASSERT(rule->r_refs == 0);
4350Sstevel@tonic-gate 	/*
4360Sstevel@tonic-gate 	 * Free arguments.
4370Sstevel@tonic-gate 	 */
4380Sstevel@tonic-gate 	dacf_arglist_delete(&(rule->r_args));
4390Sstevel@tonic-gate 	kmem_free(rule->r_devspec_data, strlen(rule->r_devspec_data) + 1);
4400Sstevel@tonic-gate 	/*
4410Sstevel@tonic-gate 	 * Module may be null for a kernel-managed op-set
4420Sstevel@tonic-gate 	 */
4430Sstevel@tonic-gate 	kmem_free(rule->r_module, strlen(rule->r_module) + 1);
4440Sstevel@tonic-gate 	kmem_free(rule->r_opset, strlen(rule->r_opset) + 1);
4450Sstevel@tonic-gate 	kmem_free(rule, sizeof (dacf_rule_t));
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate /*
4490Sstevel@tonic-gate  * dacf_rule_hold()
4500Sstevel@tonic-gate  * 	dacf rules are ref-counted.  This function increases the reference
4510Sstevel@tonic-gate  * 	count on an rule.
4520Sstevel@tonic-gate  */
4530Sstevel@tonic-gate void
dacf_rule_hold(dacf_rule_t * rule)4540Sstevel@tonic-gate dacf_rule_hold(dacf_rule_t *rule)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dacf_lock));
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	rule->r_refs++;
4590Sstevel@tonic-gate }
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate /*
4620Sstevel@tonic-gate  * dacf_rule_rele()
4630Sstevel@tonic-gate  * 	drop the ref count on an rule, and destroy the rule if its
4640Sstevel@tonic-gate  * 	ref count drops to 0.
4650Sstevel@tonic-gate  */
4660Sstevel@tonic-gate void
dacf_rule_rele(dacf_rule_t * rule)4670Sstevel@tonic-gate dacf_rule_rele(dacf_rule_t *rule)
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dacf_lock));
4700Sstevel@tonic-gate 	ASSERT(rule->r_refs > 0);
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	rule->r_refs--;
4730Sstevel@tonic-gate 	if (rule->r_refs == 0) {
4740Sstevel@tonic-gate 		dacf_rule_destroy(rule);
4750Sstevel@tonic-gate 	}
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate /*
4790Sstevel@tonic-gate  * dacf_rsrv_make()
4800Sstevel@tonic-gate  * 	add an rule to a reservation list to be processed later.
4810Sstevel@tonic-gate  */
4820Sstevel@tonic-gate void
dacf_rsrv_make(dacf_rsrvlist_t * rsrv,dacf_rule_t * rule,void * info,dacf_rsrvlist_t ** list)4830Sstevel@tonic-gate dacf_rsrv_make(dacf_rsrvlist_t *rsrv, dacf_rule_t *rule, void *info,
4840Sstevel@tonic-gate     dacf_rsrvlist_t **list)
4850Sstevel@tonic-gate {
4860Sstevel@tonic-gate 	dacf_infohdl_t ihdl = info;
4870Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dacf_lock));
4880Sstevel@tonic-gate 	ASSERT(info && rule && list);
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate 	/*
4910Sstevel@tonic-gate 	 * Bump the ref count on rule, so it won't get freed as long as it's on
4920Sstevel@tonic-gate 	 * this reservation list.
4930Sstevel@tonic-gate 	 */
4940Sstevel@tonic-gate 	dacf_rule_hold(rule);
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	rsrv->rsrv_rule = rule;
4970Sstevel@tonic-gate 	rsrv->rsrv_ihdl = ihdl;
4980Sstevel@tonic-gate 	rsrv->rsrv_result = DDI_SUCCESS;
4990Sstevel@tonic-gate 	rsrv->rsrv_next = *list;
5000Sstevel@tonic-gate 	*list = rsrv;
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	dprintf("dacf: reservation made\n");
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate /*
5060Sstevel@tonic-gate  * dacf_clr_rsrvs()
5070Sstevel@tonic-gate  * 	clear reservation list of operations of type 'op'
5080Sstevel@tonic-gate  */
5090Sstevel@tonic-gate void
dacf_clr_rsrvs(dev_info_t * devi,dacf_opid_t op)5100Sstevel@tonic-gate dacf_clr_rsrvs(dev_info_t *devi, dacf_opid_t op)
5110Sstevel@tonic-gate {
5120Sstevel@tonic-gate 	dacf_process_rsrvs(&(DEVI(devi)->devi_dacf_tasks), op, DACF_PROC_RELE);
5130Sstevel@tonic-gate }
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate /*
5160Sstevel@tonic-gate  * dacf_process_rsrvs()
5170Sstevel@tonic-gate  * 	iterate across a locked reservation list, processing each element
5180Sstevel@tonic-gate  * 	which matches 'op' according to 'flags'.
5190Sstevel@tonic-gate  *
5200Sstevel@tonic-gate  * 	if DACF_PROC_INVOKE is specified, the elements that match 'op'
5210Sstevel@tonic-gate  * 	will have their operations invoked.  The return value from that
5220Sstevel@tonic-gate  * 	operation is placed in the rsrv_result field of the dacf_rsrvlist_t
5230Sstevel@tonic-gate  */
5240Sstevel@tonic-gate void
dacf_process_rsrvs(dacf_rsrvlist_t ** list,dacf_opid_t op,int flags)5250Sstevel@tonic-gate dacf_process_rsrvs(dacf_rsrvlist_t **list, dacf_opid_t op, int flags)
5260Sstevel@tonic-gate {
5270Sstevel@tonic-gate 	dacf_rsrvlist_t *p, *dp;
5280Sstevel@tonic-gate 	dacf_rsrvlist_t **prevptr;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dacf_lock));
5310Sstevel@tonic-gate 	ASSERT(list);
5320Sstevel@tonic-gate 	ASSERT(flags != 0);
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	if (*list == NULL)
5350Sstevel@tonic-gate 		return;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 	dprintf("dacf_process_rsrvs: opid = %d, flags = 0x%x\n", op, flags);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	/*
5400Sstevel@tonic-gate 	 * Walk the list, finding rules whose opid's match op, and performing
5410Sstevel@tonic-gate 	 * the work described by 'flags'.
5420Sstevel@tonic-gate 	 */
5430Sstevel@tonic-gate 	prevptr = list;
5440Sstevel@tonic-gate 	for (p = *list; p != NULL; ) {
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 		if (p->rsrv_rule->r_opid != op) {
5470Sstevel@tonic-gate 			prevptr = &(p->rsrv_next);
5480Sstevel@tonic-gate 			p = p->rsrv_next;
5490Sstevel@tonic-gate 			continue;
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		if (flags & DACF_PROC_INVOKE) {
5530Sstevel@tonic-gate 			p->rsrv_result = dacf_op_invoke(p->rsrv_rule,
5540Sstevel@tonic-gate 			    p->rsrv_ihdl, 0);
5550Sstevel@tonic-gate 		}
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 		if (flags & DACF_PROC_RELE) {
5580Sstevel@tonic-gate 			*prevptr = p->rsrv_next;
5590Sstevel@tonic-gate 			dp = p;
5600Sstevel@tonic-gate 			p = p->rsrv_next;
5610Sstevel@tonic-gate 			dacf_rule_rele(dp->rsrv_rule);
5620Sstevel@tonic-gate 			kmem_free(dp, sizeof (dacf_rsrvlist_t));
5630Sstevel@tonic-gate 		} else {
5640Sstevel@tonic-gate 			prevptr = &(p->rsrv_next);
5650Sstevel@tonic-gate 			p = p->rsrv_next;
5660Sstevel@tonic-gate 		}
5670Sstevel@tonic-gate 	}
5680Sstevel@tonic-gate }
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate  * dacf_get_op_hash()
5720Sstevel@tonic-gate  * 	Given an op name, (i.e. "post-attach" or "pre-detach") and a
5730Sstevel@tonic-gate  * 	devspec-type, return the hash that represents that op indexed
5740Sstevel@tonic-gate  * 	by that devspec.
5750Sstevel@tonic-gate  */
5760Sstevel@tonic-gate static mod_hash_t *
dacf_get_op_hash(dacf_opid_t op,dacf_devspec_t ds_type)5770Sstevel@tonic-gate dacf_get_op_hash(dacf_opid_t op, dacf_devspec_t ds_type)
5780Sstevel@tonic-gate {
5790Sstevel@tonic-gate 	ASSERT(op <= DACF_NUM_OPIDS && op > 0);
5800Sstevel@tonic-gate 	ASSERT(ds_type <= DACF_NUM_DEVSPECS && ds_type > 0);
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	/*
5830Sstevel@tonic-gate 	 * dacf_rule_matrix is an array of pointers to pointers to hashes.
5840Sstevel@tonic-gate 	 */
5850Sstevel@tonic-gate 	if (dacf_rule_matrix[op - 1][ds_type - 1] == NULL) {
5860Sstevel@tonic-gate 		return (NULL);
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 	return (*(dacf_rule_matrix[op - 1][ds_type - 1]));
5890Sstevel@tonic-gate }
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate /*
5920Sstevel@tonic-gate  * dacf_arg_insert()
5930Sstevel@tonic-gate  * 	Create and insert an entry in an argument list.
5940Sstevel@tonic-gate  * 	Returns -1 if the argument name is a duplicate of another already
5950Sstevel@tonic-gate  * 	present in the hash.
5960Sstevel@tonic-gate  */
5970Sstevel@tonic-gate int
dacf_arg_insert(dacf_arg_t ** list,char * name,char * val)5980Sstevel@tonic-gate dacf_arg_insert(dacf_arg_t **list, char *name, char *val)
5990Sstevel@tonic-gate {
6000Sstevel@tonic-gate 	dacf_arg_t *arg;
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	/*
6030Sstevel@tonic-gate 	 * Don't allow duplicates.
6040Sstevel@tonic-gate 	 */
6050Sstevel@tonic-gate 	for (arg = *list; arg != NULL; arg = arg->arg_next) {
6060Sstevel@tonic-gate 		if (strcmp(arg->arg_name, name) == 0) {
6070Sstevel@tonic-gate 			return (-1);
6080Sstevel@tonic-gate 		}
6090Sstevel@tonic-gate 	}
6100Sstevel@tonic-gate 
6110Sstevel@tonic-gate 	arg = kmem_alloc(sizeof (dacf_arg_t), KM_SLEEP);
6120Sstevel@tonic-gate 	arg->arg_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
6130Sstevel@tonic-gate 	(void) strcpy(arg->arg_name, name);
6140Sstevel@tonic-gate 	arg->arg_val = kmem_alloc(strlen(val) + 1, KM_SLEEP);
6150Sstevel@tonic-gate 	(void) strcpy(arg->arg_val, val);
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	arg->arg_next = *list;
6180Sstevel@tonic-gate 	*list = arg;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	return (0);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate /*
6240Sstevel@tonic-gate  * dacf_arglist_delete()
6250Sstevel@tonic-gate  * 	free all the elements of a list of dacf_arg_t's.
6260Sstevel@tonic-gate  */
6270Sstevel@tonic-gate void
dacf_arglist_delete(dacf_arg_t ** list)6280Sstevel@tonic-gate dacf_arglist_delete(dacf_arg_t **list)
6290Sstevel@tonic-gate {
6300Sstevel@tonic-gate 	dacf_arg_t *arg, *narg;
6310Sstevel@tonic-gate 	arg = *list;
6320Sstevel@tonic-gate 	while (arg != NULL) {
6330Sstevel@tonic-gate 		narg = arg->arg_next;
6340Sstevel@tonic-gate 		kmem_free(arg->arg_name, strlen(arg->arg_name) + 1);
6350Sstevel@tonic-gate 		kmem_free(arg->arg_val, strlen(arg->arg_val) + 1);
6360Sstevel@tonic-gate 		kmem_free(arg, sizeof (dacf_arg_t));
6370Sstevel@tonic-gate 		arg = narg;
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate 	*list = NULL;
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate /*
6430Sstevel@tonic-gate  * dacf_match()
6440Sstevel@tonic-gate  * 	Match a device-spec to a rule.
6450Sstevel@tonic-gate  */
6460Sstevel@tonic-gate dacf_rule_t *
dacf_match(dacf_opid_t op,dacf_devspec_t ds,void * match_info)6470Sstevel@tonic-gate dacf_match(dacf_opid_t op, dacf_devspec_t ds, void *match_info)
6480Sstevel@tonic-gate {
6490Sstevel@tonic-gate 	dacf_rule_t *rule;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dacf_lock));
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	if (mod_hash_find(dacf_get_op_hash(op, ds), (mod_hash_key_t)match_info,
6540Sstevel@tonic-gate 	    (mod_hash_val_t *)&rule) == 0) {
6550Sstevel@tonic-gate 		return (rule);
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate 	return (NULL);	/* Not Found */
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate /*
6620Sstevel@tonic-gate  * dacf_module_register()
6630Sstevel@tonic-gate  * 	register a module with the framework.  Use when a module gets loaded,
6640Sstevel@tonic-gate  * 	or for the kernel to register a "virtual" module (i.e. a "module"
6650Sstevel@tonic-gate  * 	which the kernel provides).  Makes a copy of the interface description
6660Sstevel@tonic-gate  * 	provided by the module.
6670Sstevel@tonic-gate  */
6680Sstevel@tonic-gate int
dacf_module_register(char * mod_name,struct dacfsw * sw)6690Sstevel@tonic-gate dacf_module_register(char *mod_name, struct dacfsw *sw)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	char *str;
6720Sstevel@tonic-gate 	size_t i, nelems;
6730Sstevel@tonic-gate 	dacf_module_t *module;
6740Sstevel@tonic-gate 	dacf_opset_t *opsarray;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	if (sw == NULL) {
6770Sstevel@tonic-gate 		return (EINVAL);
6780Sstevel@tonic-gate 	}
6790Sstevel@tonic-gate 
6800Sstevel@tonic-gate 	if (sw->dacf_rev != DACF_MODREV_1) {
6810Sstevel@tonic-gate 		cmn_err(CE_WARN, "dacf: module '%s' exports unsupported "
6820Sstevel@tonic-gate 		    "version %d interface, not registered\n", mod_name,
6830Sstevel@tonic-gate 		    sw->dacf_rev);
6840Sstevel@tonic-gate 		return (EINVAL);
6850Sstevel@tonic-gate 	}
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	/*
6880Sstevel@tonic-gate 	 * count how many opsets are provided.
6890Sstevel@tonic-gate 	 */
6900Sstevel@tonic-gate 	for (nelems = 0; sw->dacf_opsets[nelems].opset_name != NULL; nelems++)
6910Sstevel@tonic-gate 		;
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	dprintf("dacf_module_register: found %lu opsets\n", nelems);
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	/*
6960Sstevel@tonic-gate 	 * Temporary: It's ok for the kernel dacf_sw to have no opsets, since
6970Sstevel@tonic-gate 	 * we don't have any opsets to export yet (in NON-DEBUG).
6980Sstevel@tonic-gate 	 */
6990Sstevel@tonic-gate 	if ((nelems == 0) && (sw != &kmod_dacfsw)) {
7000Sstevel@tonic-gate 		cmn_err(CE_WARN, "dacf module %s exports no opsets, "
7010Sstevel@tonic-gate 		    "not registered.\n", mod_name);
7020Sstevel@tonic-gate 		return (EINVAL);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/*
7060Sstevel@tonic-gate 	 * Look to see if the module has been previously registered with the
7070Sstevel@tonic-gate 	 * framework.  If so, we can fail with EBUSY.
7080Sstevel@tonic-gate 	 */
7090Sstevel@tonic-gate 	if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name,
7100Sstevel@tonic-gate 	    (mod_hash_val_t)&module) == 0) {
7110Sstevel@tonic-gate 		/*
7120Sstevel@tonic-gate 		 * See if it is loaded currently
7130Sstevel@tonic-gate 		 */
7140Sstevel@tonic-gate 		rw_enter(&module->dm_lock, RW_WRITER);
7150Sstevel@tonic-gate 		if (module->dm_loaded) {
7160Sstevel@tonic-gate 			rw_exit(&module->dm_lock);
7170Sstevel@tonic-gate 			cmn_err(CE_WARN, "dacf module '%s' is "
7180Sstevel@tonic-gate 			    "already registered.", mod_name);
7190Sstevel@tonic-gate 			return (EBUSY);
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 	} else {
7220Sstevel@tonic-gate 		/*
7230Sstevel@tonic-gate 		 * This is the first time we've ever seen the module; stick
7240Sstevel@tonic-gate 		 * it into the module hash.  If that fails, we've had a
7250Sstevel@tonic-gate 		 * race between two threads, both trying to insert the same
7260Sstevel@tonic-gate 		 * new module.  It's safe to stick the module into the
7270Sstevel@tonic-gate 		 * hash only partly filled in, since dm_lock protects the
7280Sstevel@tonic-gate 		 * structure, and we've got that write-locked.
7290Sstevel@tonic-gate 		 */
7300Sstevel@tonic-gate 		module = kmem_zalloc(sizeof (dacf_module_t), KM_SLEEP);
7310Sstevel@tonic-gate 		str = kmem_alloc(strlen(mod_name) + 1, KM_SLEEP);
7320Sstevel@tonic-gate 		(void) strcpy(str, mod_name);
7330Sstevel@tonic-gate 		rw_enter(&module->dm_lock, RW_WRITER);
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 		if (mod_hash_insert(dacf_module_hash, (mod_hash_key_t)str,
7360Sstevel@tonic-gate 		    (mod_hash_val_t)module) != 0) {
7370Sstevel@tonic-gate 			rw_exit(&module->dm_lock);
7380Sstevel@tonic-gate 			kmem_free(str, strlen(str) + 1);
7390Sstevel@tonic-gate 			kmem_free(module, sizeof (dacf_module_t));
7400Sstevel@tonic-gate 			cmn_err(CE_WARN, "dacf module '%s' is "
7410Sstevel@tonic-gate 			    "already registered.", mod_name);
7420Sstevel@tonic-gate 			return (EBUSY);
7430Sstevel@tonic-gate 		}
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 	/*
7460Sstevel@tonic-gate 	 * In either case (first time we've seen it or not), the module is
7470Sstevel@tonic-gate 	 * not loaded, and we hold it write-locked.
7480Sstevel@tonic-gate 	 */
7490Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&module->dm_lock));
7500Sstevel@tonic-gate 
7510Sstevel@tonic-gate 	/*
7520Sstevel@tonic-gate 	 * Alloc array of opsets for this module.  Add one for the final
7530Sstevel@tonic-gate 	 * NULL entry
7540Sstevel@tonic-gate 	 */
7550Sstevel@tonic-gate 	opsarray = kmem_zalloc(sizeof (dacf_opset_t) * (nelems + 1), KM_SLEEP);
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	for (i = 0; i < nelems; i++) {
7580Sstevel@tonic-gate 		dacf_opset_copy(&(opsarray[i]), &(sw->dacf_opsets[i]));
7590Sstevel@tonic-gate 		ASSERT(opsarray[i].opset_name != NULL);
7600Sstevel@tonic-gate 		ASSERT(opsarray[i].opset_ops != NULL);
7610Sstevel@tonic-gate 	}
7620Sstevel@tonic-gate 	opsarray[nelems].opset_name = NULL;
7630Sstevel@tonic-gate 	opsarray[nelems].opset_ops = NULL;
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	ASSERT(module->dm_opsets == NULL);	/* see dacf_destroy_opsets() */
7660Sstevel@tonic-gate 	module->dm_opsets = opsarray;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	if (dacfdebug & DACF_DBG_MSGS) {
7690Sstevel@tonic-gate 		dprintf("%s registered.\n", mod_name);
7700Sstevel@tonic-gate 		for (i = 0; i < nelems; i++) {
7710Sstevel@tonic-gate 			dprintf("registered %s\n", opsarray[i].opset_name);
7720Sstevel@tonic-gate 		}
7730Sstevel@tonic-gate 	}
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	module->dm_loaded = 1;
7760Sstevel@tonic-gate 	rw_exit(&module->dm_lock);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	return (0);
7790Sstevel@tonic-gate }
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate /*
7820Sstevel@tonic-gate  * dacf_module_unregister()
7830Sstevel@tonic-gate  * 	remove a module from the framework, and free framework-allocated
7840Sstevel@tonic-gate  * 	resources.
7850Sstevel@tonic-gate  */
7860Sstevel@tonic-gate int
dacf_module_unregister(char * mod_name)7870Sstevel@tonic-gate dacf_module_unregister(char *mod_name)
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate 	dacf_module_t *module;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	/*
7920Sstevel@tonic-gate 	 * Can't unregister __kernel, since there is no real way to get it
7930Sstevel@tonic-gate 	 * back-- Once it gets marked with dm_loaded == 0, the kernel will
7940Sstevel@tonic-gate 	 * try to modload() if it is ever needed, which will fail utterly,
7950Sstevel@tonic-gate 	 * and send op_invoke into a loop in it's modload logic
7960Sstevel@tonic-gate 	 *
7970Sstevel@tonic-gate 	 * If this is behavior is ever needed in the future, we can just
7980Sstevel@tonic-gate 	 * add a flag indicating that this module is really a fake.
7990Sstevel@tonic-gate 	 */
8000Sstevel@tonic-gate 	ASSERT(strcmp(mod_name, kmod_name) != 0);
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate 	dprintf("dacf_module_unregister: called for '%s'!\n", mod_name);
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	/*
8050Sstevel@tonic-gate 	 * If NOAUL_DACF is set, or we try to get a write-lock on dm_lock and
8060Sstevel@tonic-gate 	 * that fails, return EBUSY, and fail to unregister.
8070Sstevel@tonic-gate 	 */
8080Sstevel@tonic-gate 	if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name,
8090Sstevel@tonic-gate 	    (mod_hash_val_t)&module) == 0) {
8100Sstevel@tonic-gate 		if ((moddebug & MODDEBUG_NOAUL_DACF) ||
8110Sstevel@tonic-gate 		    !rw_tryenter(&module->dm_lock, RW_WRITER)) {
8120Sstevel@tonic-gate 			return (EBUSY);
8130Sstevel@tonic-gate 		}
8140Sstevel@tonic-gate 	} else {
8150Sstevel@tonic-gate 		return (EINVAL);
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&module->dm_lock));
8190Sstevel@tonic-gate 	dacf_destroy_opsets(module);
8200Sstevel@tonic-gate 	module->dm_loaded = 0;
8210Sstevel@tonic-gate 	rw_exit(&module->dm_lock);
8220Sstevel@tonic-gate 	return (0);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate /*
8260Sstevel@tonic-gate  * dacf_destroy_opsets()
8270Sstevel@tonic-gate  * 	given a module, destroy all of it's associated op-sets.
8280Sstevel@tonic-gate  */
8290Sstevel@tonic-gate static void
dacf_destroy_opsets(dacf_module_t * module)8300Sstevel@tonic-gate dacf_destroy_opsets(dacf_module_t *module)
8310Sstevel@tonic-gate {
8320Sstevel@tonic-gate 	dacf_opset_t *array = module->dm_opsets;
8330Sstevel@tonic-gate 	dacf_opset_t *p;
8340Sstevel@tonic-gate 	int i;
8350Sstevel@tonic-gate 	size_t nelems;
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&module->dm_lock));
8380Sstevel@tonic-gate 	ASSERT(module->dm_loaded == 1);
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	for (i = 0; array[i].opset_name != NULL; i++) {
8410Sstevel@tonic-gate 		p = &(array[i]);
8420Sstevel@tonic-gate 		kmem_free(p->opset_name, strlen(p->opset_name) + 1);
8430Sstevel@tonic-gate 		/*
8440Sstevel@tonic-gate 		 * count nelems in opset_ops
8450Sstevel@tonic-gate 		 */
8460Sstevel@tonic-gate 		for (nelems = 0; ; nelems++) {
8470Sstevel@tonic-gate 			if (p->opset_ops[nelems].op_id == DACF_OPID_END) {
8480Sstevel@tonic-gate 				break;
8490Sstevel@tonic-gate 			}
8500Sstevel@tonic-gate 		}
8510Sstevel@tonic-gate 		/*
8520Sstevel@tonic-gate 		 * Free the array of op ptrs.
8530Sstevel@tonic-gate 		 */
8540Sstevel@tonic-gate 		kmem_free(p->opset_ops, sizeof (dacf_op_t) * (nelems + 1));
8550Sstevel@tonic-gate 	}
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	/*
8580Sstevel@tonic-gate 	 * i has counted how big array is; +1 to account for the last element.
8590Sstevel@tonic-gate 	 */
8600Sstevel@tonic-gate 	kmem_free(array, (sizeof (dacf_opset_t)) * (i + 1));
8610Sstevel@tonic-gate 	module->dm_opsets = NULL;
8620Sstevel@tonic-gate }
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate /*
8650Sstevel@tonic-gate  * dacf_opset_copy()
8660Sstevel@tonic-gate  * 	makes a copy of a dacf_opset_t.
8670Sstevel@tonic-gate  */
8680Sstevel@tonic-gate static void
dacf_opset_copy(dacf_opset_t * dst,dacf_opset_t * src)8690Sstevel@tonic-gate dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src)
8700Sstevel@tonic-gate {
8710Sstevel@tonic-gate 	size_t nelems, i;
8720Sstevel@tonic-gate 	ASSERT(src && dst);
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	dprintf("dacf_opset_copy: called\n");
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	dst->opset_name = kmem_alloc(strlen(src->opset_name) + 1, KM_SLEEP);
8770Sstevel@tonic-gate 	(void) strcpy(dst->opset_name, src->opset_name);
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	dprintf("dacf_opset_copy: counting ops\n");
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	for (nelems = 0; ; nelems++) {
8820Sstevel@tonic-gate 		if ((src->opset_ops[nelems].op_id == DACF_OPID_END) ||
8830Sstevel@tonic-gate 		    (src->opset_ops[nelems].op_func == NULL)) {
8840Sstevel@tonic-gate 			break;
8850Sstevel@tonic-gate 		}
8860Sstevel@tonic-gate 	}
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	dprintf("dacf_opset_copy: found %lu ops\n", nelems);
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	dst->opset_ops = kmem_alloc(sizeof (dacf_op_t) * (nelems + 1),
8910Sstevel@tonic-gate 	    KM_SLEEP);
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 	dprintf("dacf_opset_copy: copying ops\n");
8940Sstevel@tonic-gate 	for (i = 0; i < nelems; i++) {
8950Sstevel@tonic-gate 		dst->opset_ops[i].op_id = src->opset_ops[i].op_id;
8960Sstevel@tonic-gate 		dst->opset_ops[i].op_func = src->opset_ops[i].op_func;
8970Sstevel@tonic-gate 	}
8980Sstevel@tonic-gate 	dst->opset_ops[nelems].op_id = DACF_OPID_END;
8990Sstevel@tonic-gate 	dst->opset_ops[nelems].op_func = NULL;
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 	dprintf("dacf_opset_copy: done copying ops\n");
9020Sstevel@tonic-gate }
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate int dacf_modload_laps = 0;	/* just a diagnostic aid */
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate /*
9070Sstevel@tonic-gate  * dacf_op_invoke()
9080Sstevel@tonic-gate  *	Invoke a op in a opset in a module given the rule to invoke.
9090Sstevel@tonic-gate  *
9100Sstevel@tonic-gate  *	If the return value of dacf_op_invoke is 0, then rval contains the
9110Sstevel@tonic-gate  *	return value of the _op_ being invoked. Otherwise, dacf_op_invoke's
9120Sstevel@tonic-gate  *	return value indicates why the op invocation failed.
9130Sstevel@tonic-gate  */
9140Sstevel@tonic-gate int
dacf_op_invoke(dacf_rule_t * rule,dacf_infohdl_t info_hdl,int flags)9150Sstevel@tonic-gate dacf_op_invoke(dacf_rule_t *rule, dacf_infohdl_t info_hdl, int flags)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate 	dacf_module_t *module;
9180Sstevel@tonic-gate 	dacf_opset_t *opsarray;
9190Sstevel@tonic-gate 	dacf_opset_t *opset;
9200Sstevel@tonic-gate 	dacf_op_t *op = NULL;
9210Sstevel@tonic-gate 	dacf_opid_t op_id;
9220Sstevel@tonic-gate 	dacf_arghdl_t arg_hdl;
9230Sstevel@tonic-gate 	dev_info_t *dip;
9240Sstevel@tonic-gate 	int i, rval = -1;
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 	ASSERT(rule);
9270Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dacf_lock));
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 	op_id = rule->r_opid;
9300Sstevel@tonic-gate 	dprintf("dacf_op_invoke: opid=%d\n", op_id);
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 	/*
9330Sstevel@tonic-gate 	 * Take laps, trying to load the dacf module.  For the case of kernel-
9340Sstevel@tonic-gate 	 * provided operations, __kernel will be found in the hash table, and
9350Sstevel@tonic-gate 	 * no modload will be needed.
9360Sstevel@tonic-gate 	 */
9370Sstevel@tonic-gate 	for (;;) {
9380Sstevel@tonic-gate 		if (mod_hash_find(dacf_module_hash,
9390Sstevel@tonic-gate 		    (mod_hash_key_t)rule->r_module,
9400Sstevel@tonic-gate 		    (mod_hash_val_t *)&module) == 0) {
9410Sstevel@tonic-gate 			rw_enter(&module->dm_lock, RW_READER);
9420Sstevel@tonic-gate 			/*
9430Sstevel@tonic-gate 			 * Found the module, and it is loaded.
9440Sstevel@tonic-gate 			 */
9450Sstevel@tonic-gate 			if (module->dm_loaded != 0) {
9460Sstevel@tonic-gate 				break;
9470Sstevel@tonic-gate 			}
9480Sstevel@tonic-gate 			rw_exit(&module->dm_lock);
9490Sstevel@tonic-gate 		}
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 		/*
9520Sstevel@tonic-gate 		 * If we're here, either: 1) it's not in the hash, or 2) it is,
9530Sstevel@tonic-gate 		 * but dm_loaded is 0, meaning the module needs to be loaded.
9540Sstevel@tonic-gate 		 */
9550Sstevel@tonic-gate 		dprintf("dacf_op_invoke: calling modload\n");
9560Sstevel@tonic-gate 		if (modload("dacf", rule->r_module) < 0) {
9570Sstevel@tonic-gate 			return (DACF_ERR_MOD_NOTFOUND);
9580Sstevel@tonic-gate 		}
9590Sstevel@tonic-gate 		dacf_modload_laps++;
9600Sstevel@tonic-gate 	}
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 	ASSERT(RW_READ_HELD(&module->dm_lock));
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	opsarray = module->dm_opsets;
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	/*
9670Sstevel@tonic-gate 	 * Loop through the opsets exported by this module, and find the one
9680Sstevel@tonic-gate 	 * we care about.
9690Sstevel@tonic-gate 	 */
9700Sstevel@tonic-gate 	opset = NULL;
9710Sstevel@tonic-gate 	for (i = 0; opsarray[i].opset_name != NULL; i++) {
9720Sstevel@tonic-gate 		if (strcmp(opsarray[i].opset_name, rule->r_opset) == 0) {
9730Sstevel@tonic-gate 			opset = &opsarray[i];
9740Sstevel@tonic-gate 			break;
9750Sstevel@tonic-gate 		}
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	if (opset == NULL) {
9790Sstevel@tonic-gate 		cmn_err(CE_WARN, "!dacf: couldn't invoke op, opset '%s' not "
9800Sstevel@tonic-gate 		    "found in module '%s'", rule->r_opset, rule->r_module);
9810Sstevel@tonic-gate 		rw_exit(&module->dm_lock);
9820Sstevel@tonic-gate 		return (DACF_ERR_OPSET_NOTFOUND);
9830Sstevel@tonic-gate 	}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	arg_hdl = (dacf_arghdl_t)rule->r_args;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	/*
9880Sstevel@tonic-gate 	 * Call the appropriate routine in the target by looping across the
9890Sstevel@tonic-gate 	 * ops until we find the one whose id matches opid.
9900Sstevel@tonic-gate 	 */
9910Sstevel@tonic-gate 	op = NULL;
9920Sstevel@tonic-gate 	for (i = 0; opset->opset_ops[i].op_id != DACF_OPID_END; i++) {
9930Sstevel@tonic-gate 		if (opset->opset_ops[i].op_id == op_id) {
9940Sstevel@tonic-gate 			op = &(opset->opset_ops[i]);
9950Sstevel@tonic-gate 			break;
9960Sstevel@tonic-gate 		}
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	if (op == NULL) {
10000Sstevel@tonic-gate 		cmn_err(CE_WARN, "!dacf: couldn't invoke op, op '%s' not found "
10010Sstevel@tonic-gate 		    "in opset '%s' in module '%s'", dacf_opid_to_str(op_id),
10020Sstevel@tonic-gate 		    rule->r_opset, rule->r_module);
10030Sstevel@tonic-gate 		rw_exit(&module->dm_lock);
10040Sstevel@tonic-gate 		return (DACF_ERR_OP_NOTFOUND);
10050Sstevel@tonic-gate 	}
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	dprintf("dacf_op_invoke: found op, invoking...\n");
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	/*
10100Sstevel@tonic-gate 	 * Drop dacf_lock here, so that op_func's that cause drivers to
10110Sstevel@tonic-gate 	 * get loaded don't wedge the system when they try to acquire dacf_lock
10120Sstevel@tonic-gate 	 * to do matching.
10130Sstevel@tonic-gate 	 *
10140Sstevel@tonic-gate 	 * Mark that an invoke is happening to prevent recursive invokes
10150Sstevel@tonic-gate 	 */
10160Sstevel@tonic-gate 	dip = ((struct ddi_minor_data *)info_hdl)->dip;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
10190Sstevel@tonic-gate 	DEVI_SET_INVOKING_DACF(dip);
10200Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	mutex_exit(&dacf_lock);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	rval = op->op_func(info_hdl, arg_hdl, flags);
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	mutex_enter(&dacf_lock);
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 	/*
10290Sstevel@tonic-gate 	 * Completed the invocation against module, so let go of it.
10300Sstevel@tonic-gate 	 */
10310Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
10320Sstevel@tonic-gate 	DEVI_CLR_INVOKING_DACF(dip);
10330Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	/*
10360Sstevel@tonic-gate 	 * Drop our r-lock on the module, now that we no longer need the module
10370Sstevel@tonic-gate 	 * to stay loaded.
10380Sstevel@tonic-gate 	 */
10390Sstevel@tonic-gate 	rw_exit(&module->dm_lock);
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 	if (rval == DACF_SUCCESS) {
10420Sstevel@tonic-gate 		return (DACF_SUCCESS);
10430Sstevel@tonic-gate 	} else {
10440Sstevel@tonic-gate 		return (DACF_ERR_OP_FAILED);
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate }
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate /*
10490Sstevel@tonic-gate  * dacf_get_devspec()
10500Sstevel@tonic-gate  * 	given a devspec-type as a string, return a corresponding dacf_devspec_t
10510Sstevel@tonic-gate  */
10520Sstevel@tonic-gate dacf_devspec_t
dacf_get_devspec(char * name)10530Sstevel@tonic-gate dacf_get_devspec(char *name)
10540Sstevel@tonic-gate {
10550Sstevel@tonic-gate 	dacf_ds_t *p = &dacf_devspecs[0];
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	while (p->name != NULL) {
10580Sstevel@tonic-gate 		if (strcmp(p->name, name) == 0) {
10590Sstevel@tonic-gate 			return (p->id);
10600Sstevel@tonic-gate 		}
10610Sstevel@tonic-gate 		p++;
10620Sstevel@tonic-gate 	}
10630Sstevel@tonic-gate 	return (DACF_DS_ERROR);
10640Sstevel@tonic-gate }
10650Sstevel@tonic-gate 
10660Sstevel@tonic-gate /*
10670Sstevel@tonic-gate  * dacf_devspec_to_str()
10680Sstevel@tonic-gate  * 	given a dacf_devspec_t, return a pointer to the human readable string
10690Sstevel@tonic-gate  * 	representation of that device specifier.
10700Sstevel@tonic-gate  */
10710Sstevel@tonic-gate const char *
dacf_devspec_to_str(dacf_devspec_t ds)10720Sstevel@tonic-gate dacf_devspec_to_str(dacf_devspec_t ds)
10730Sstevel@tonic-gate {
10740Sstevel@tonic-gate 	dacf_ds_t *p = &dacf_devspecs[0];
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	while (p->name != NULL) {
10770Sstevel@tonic-gate 		if (p->id == ds) {
10780Sstevel@tonic-gate 			return (p->name);
10790Sstevel@tonic-gate 		}
10800Sstevel@tonic-gate 		p++;
10810Sstevel@tonic-gate 	}
10820Sstevel@tonic-gate 	return (NULL);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate  * dacf_get_op()
10870Sstevel@tonic-gate  * 	given a op name, returns the corresponding dacf_opid_t.
10880Sstevel@tonic-gate  */
10890Sstevel@tonic-gate dacf_opid_t
dacf_get_op(char * name)10900Sstevel@tonic-gate dacf_get_op(char *name)
10910Sstevel@tonic-gate {
10920Sstevel@tonic-gate 	dacf_opmap_t *p = &dacf_ops[0];
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	while (p->name != NULL) {
10950Sstevel@tonic-gate 		if (strcmp(p->name, name) == 0) {
10960Sstevel@tonic-gate 			return (p->id);
10970Sstevel@tonic-gate 		}
10980Sstevel@tonic-gate 		p++;
10990Sstevel@tonic-gate 	}
11000Sstevel@tonic-gate 	return (DACF_OPID_ERROR);
11010Sstevel@tonic-gate }
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate /*
11040Sstevel@tonic-gate  * dacf_opid_to_str()
11050Sstevel@tonic-gate  * 	given a dacf_opid_t, return the human-readable op-name.
11060Sstevel@tonic-gate  */
11070Sstevel@tonic-gate const char *
dacf_opid_to_str(dacf_opid_t tid)11080Sstevel@tonic-gate dacf_opid_to_str(dacf_opid_t tid)
11090Sstevel@tonic-gate {
11100Sstevel@tonic-gate 	dacf_opmap_t *p = &dacf_ops[0];
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	while (p->name != NULL) {
11130Sstevel@tonic-gate 		if (p->id == tid) {
11140Sstevel@tonic-gate 			return (p->name);
11150Sstevel@tonic-gate 		}
11160Sstevel@tonic-gate 		p++;
11170Sstevel@tonic-gate 	}
11180Sstevel@tonic-gate 	return (NULL);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate 
11210Sstevel@tonic-gate /*
11220Sstevel@tonic-gate  * dacf_getopt()
11230Sstevel@tonic-gate  * 	given an option specified as a string, add it to the bit-field of
11240Sstevel@tonic-gate  * 	options given.  Returns -1 if the option is unrecognized.
11250Sstevel@tonic-gate  */
11260Sstevel@tonic-gate int
dacf_getopt(char * opt_str,uint_t * opts)11270Sstevel@tonic-gate dacf_getopt(char *opt_str, uint_t *opts)
11280Sstevel@tonic-gate {
11290Sstevel@tonic-gate 	dacf_opt_t *p = &dacf_options[0];
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	/*
11320Sstevel@tonic-gate 	 * Look through the list for the option given
11330Sstevel@tonic-gate 	 */
11340Sstevel@tonic-gate 	while (p->optname != NULL) {
11350Sstevel@tonic-gate 		if (strcmp(opt_str, p->optname) == 0) {
11360Sstevel@tonic-gate 			*opts |= p->optmask;
11370Sstevel@tonic-gate 			return (0);
11380Sstevel@tonic-gate 		}
11390Sstevel@tonic-gate 		p++;
11400Sstevel@tonic-gate 	}
11410Sstevel@tonic-gate 	return (-1);
11420Sstevel@tonic-gate }
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate /*
11470Sstevel@tonic-gate  * This family of functions forms the dacf interface which is exported to
11480Sstevel@tonic-gate  * kernel/dacf modules.  Modules _should_not_ use any dacf_* functions
11490Sstevel@tonic-gate  * presented above this point.
11500Sstevel@tonic-gate  *
11510Sstevel@tonic-gate  * Note: These routines use a dacf_infohdl_t to struct ddi_minor_data * and
11520Sstevel@tonic-gate  * assume that the resulting pointer is not to an alias node.  That is true
11530Sstevel@tonic-gate  * because dacf_op_invoke guarantees it by first resolving the alias.
11540Sstevel@tonic-gate  */
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate /*
11570Sstevel@tonic-gate  * dacf_minor_name()
11580Sstevel@tonic-gate  * 	given a dacf_infohdl_t, obtain the minor name of the device instance
11590Sstevel@tonic-gate  * 	being configured.
11600Sstevel@tonic-gate  */
11610Sstevel@tonic-gate const char *
dacf_minor_name(dacf_infohdl_t info_hdl)11620Sstevel@tonic-gate dacf_minor_name(dacf_infohdl_t info_hdl)
11630Sstevel@tonic-gate {
11640Sstevel@tonic-gate 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	return (dmdp->ddm_name);
11670Sstevel@tonic-gate }
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate /*
11700Sstevel@tonic-gate  * dacf_minor_number()
11710Sstevel@tonic-gate  * 	given a dacf_infohdl_t, obtain the device minor number of the instance
11720Sstevel@tonic-gate  * 	being configured.
11730Sstevel@tonic-gate  */
11740Sstevel@tonic-gate minor_t
dacf_minor_number(dacf_infohdl_t info_hdl)11750Sstevel@tonic-gate dacf_minor_number(dacf_infohdl_t info_hdl)
11760Sstevel@tonic-gate {
11770Sstevel@tonic-gate 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	return (getminor(dmdp->ddm_dev));
11800Sstevel@tonic-gate }
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate /*
1183*5895Syz147064  * dacf_get_dev()
1184*5895Syz147064  *	given a dacf_infohdl_t, obtain the dev_t of the instance being
1185*5895Syz147064  *	configured.
1186*5895Syz147064  */
1187*5895Syz147064 dev_t
dacf_get_dev(dacf_infohdl_t info_hdl)1188*5895Syz147064 dacf_get_dev(dacf_infohdl_t info_hdl)
1189*5895Syz147064 {
1190*5895Syz147064 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1191*5895Syz147064 
1192*5895Syz147064 	return (dmdp->ddm_dev);
1193*5895Syz147064 }
1194*5895Syz147064 
1195*5895Syz147064 /*
11960Sstevel@tonic-gate  * dacf_driver_name()
11970Sstevel@tonic-gate  * 	given a dacf_infohdl_t, obtain the device driver name of the device
11980Sstevel@tonic-gate  * 	instance being configured.
11990Sstevel@tonic-gate  */
12000Sstevel@tonic-gate const char *
dacf_driver_name(dacf_infohdl_t info_hdl)12010Sstevel@tonic-gate dacf_driver_name(dacf_infohdl_t info_hdl)
12020Sstevel@tonic-gate {
12030Sstevel@tonic-gate 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
12040Sstevel@tonic-gate 
12050Sstevel@tonic-gate 	return (ddi_driver_name(dmdp->dip));
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate /*
12090Sstevel@tonic-gate  * dacf_devinfo_node()
12100Sstevel@tonic-gate  * 	given a dacf_infohdl_t, obtain the dev_info_t of the device instance
12110Sstevel@tonic-gate  * 	being configured.
12120Sstevel@tonic-gate  */
12130Sstevel@tonic-gate dev_info_t *
dacf_devinfo_node(dacf_infohdl_t info_hdl)12140Sstevel@tonic-gate dacf_devinfo_node(dacf_infohdl_t info_hdl)
12150Sstevel@tonic-gate {
12160Sstevel@tonic-gate 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	return (dmdp->dip);
12190Sstevel@tonic-gate }
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate /*
12220Sstevel@tonic-gate  * dacf_get_arg()
12230Sstevel@tonic-gate  * 	given the dacf_arghdl_t passed to a op and the name of an argument,
12240Sstevel@tonic-gate  * 	return the value of that argument.
12250Sstevel@tonic-gate  *
12260Sstevel@tonic-gate  * 	returns NULL if the argument is not found.
12270Sstevel@tonic-gate  */
12280Sstevel@tonic-gate const char *
dacf_get_arg(dacf_arghdl_t arghdl,char * arg_name)12290Sstevel@tonic-gate dacf_get_arg(dacf_arghdl_t arghdl, char *arg_name)
12300Sstevel@tonic-gate {
12310Sstevel@tonic-gate 	dacf_arg_t *arg_list = (dacf_arg_t *)arghdl;
12320Sstevel@tonic-gate 	ASSERT(arg_name);
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	while (arg_list != NULL) {
12350Sstevel@tonic-gate 		if (strcmp(arg_list->arg_name, arg_name) == 0) {
12360Sstevel@tonic-gate 			return (arg_list->arg_val);
12370Sstevel@tonic-gate 		}
12380Sstevel@tonic-gate 		arg_list = arg_list->arg_next;
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	return (NULL);
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate /*
12450Sstevel@tonic-gate  * dacf_store_info()
12460Sstevel@tonic-gate  * 	associate instance-specific data with a device instance.  Future
12470Sstevel@tonic-gate  * 	configuration ops invoked for this instance can retrieve this data using
12480Sstevel@tonic-gate  * 	dacf_retrieve_info() below.  Modules are responsible for cleaning up
12490Sstevel@tonic-gate  * 	this data as appropriate, and should store NULL as the value of 'data'
12500Sstevel@tonic-gate  * 	when the data is no longer valid.
12510Sstevel@tonic-gate  */
12520Sstevel@tonic-gate void
dacf_store_info(dacf_infohdl_t info_hdl,void * data)12530Sstevel@tonic-gate dacf_store_info(dacf_infohdl_t info_hdl, void *data)
12540Sstevel@tonic-gate {
12550Sstevel@tonic-gate 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
12560Sstevel@tonic-gate 
12570Sstevel@tonic-gate 	/*
12580Sstevel@tonic-gate 	 * If the client is 'storing NULL' we can represent that by blowing
12590Sstevel@tonic-gate 	 * the info entry out of the hash.
12600Sstevel@tonic-gate 	 */
12610Sstevel@tonic-gate 	if (data == NULL) {
12620Sstevel@tonic-gate 		(void) mod_hash_destroy(dacf_info_hash, (mod_hash_key_t)dmdp);
12630Sstevel@tonic-gate 	} else {
12640Sstevel@tonic-gate 		/*
12650Sstevel@tonic-gate 		 * mod_hash_replace can only fail on out of memory, but we sleep
12660Sstevel@tonic-gate 		 * for memory in this hash, so it is safe to ignore the retval.
12670Sstevel@tonic-gate 		 */
12680Sstevel@tonic-gate 		(void) mod_hash_replace(dacf_info_hash, (mod_hash_key_t)dmdp,
12690Sstevel@tonic-gate 		    (mod_hash_val_t)data);
12700Sstevel@tonic-gate 	}
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate /*
12740Sstevel@tonic-gate  * dacf_retrieve_info()
12750Sstevel@tonic-gate  * 	retrieve instance-specific data associated with a device instance.
12760Sstevel@tonic-gate  */
12770Sstevel@tonic-gate void *
dacf_retrieve_info(dacf_infohdl_t info_hdl)12780Sstevel@tonic-gate dacf_retrieve_info(dacf_infohdl_t info_hdl)
12790Sstevel@tonic-gate {
12800Sstevel@tonic-gate 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
12810Sstevel@tonic-gate 	void *data;
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate 	if (mod_hash_find(dacf_info_hash, (mod_hash_key_t)dmdp,
1284*5895Syz147064 	    (mod_hash_val_t *)&data) != 0) {
12850Sstevel@tonic-gate 		return (NULL);
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	return (data);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate  * dacf_makevp()
12930Sstevel@tonic-gate  * 	make a vnode for the specified dacf_infohdl_t.
12940Sstevel@tonic-gate  */
12950Sstevel@tonic-gate struct vnode *
dacf_makevp(dacf_infohdl_t info_hdl)12960Sstevel@tonic-gate dacf_makevp(dacf_infohdl_t info_hdl)
12970Sstevel@tonic-gate {
12980Sstevel@tonic-gate 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
12990Sstevel@tonic-gate 	struct vnode	*vp;
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	vp = makespecvp(dmdp->ddm_dev, VCHR);
13020Sstevel@tonic-gate 	spec_assoc_vp_with_devi(vp, dmdp->dip);
13030Sstevel@tonic-gate 	return (vp);
13040Sstevel@tonic-gate }
1305