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