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