uts: make emu10k non-verbose
[unleashed.git] / kernel / os / dacf.c
blobadabf9a0739aa75142f2fb2e5f59d3500ec9ade4
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * DACF: device autoconfiguration support
29 * DACF provides a fast, lightweight policy engine for the I/O subsystem.
30 * This policy engine provides a mechanism for auto-configuring and
31 * auto-unconfiguring devices.
33 * After a device is attach(9E)ed, additional configuration may be needed in
34 * order to make the device available for use by the system. For example,
35 * STREAMS modules may need to be pushed atop the driver in order to create
36 * a STREAMS stack. If the device is to be removed from the system, these
37 * configuration operations need to be undone, and the device prepared for
38 * detach(9E).
40 * It is desirable to move the implementation of such policies outside of the
41 * kernel proper, since such operations are typically infrequent. To this end,
42 * DACF manages kernel modules in (module_path)/dacf directories. These adhere
43 * to the api defined in sys/dacf.h, and register sets of configuration
44 * operations. The kernel loads these modules when the operations they
45 * implement are needed, and can unload them at any time thereafter.
46 * Implementing configuration operations in external modules can also increase
47 * code reuse.
49 * DACF provides a policy database which associates
51 * (device descr., kernel action) --> (configuration operation, parameters)
53 * - Device description is matching rule, for example:
54 * minor-nodetype="ddi_keyboard"
55 * - Kernel action is a reference to a dacf kernel hook.
56 * currently supported are "post-attach" and "pre-detach"
57 * - Configuration action is a reference to a module and a set of operations
58 * within the module, for example: consconfig:kbd_config
59 * - Parameters is a list of name="value" parameters to be passed to the
60 * configuration operation when invoked.
62 * The contents of the rules database are loaded from /etc/dacf.conf upon boot.
64 * DACF kernel hooks are comprised of a call into the rule-matching engine,
65 * using parameters from the hook in order find a matching rule. If one is
66 * found, the framework can invoke the configuration operation immediately, or
67 * defer doing so until later, by putting the rule on a 'reservation list.'
70 #include <sys/param.h>
71 #include <sys/modctl.h>
72 #include <sys/sysmacros.h>
73 #include <sys/kmem.h>
74 #include <sys/cmn_err.h>
75 #include <sys/pathname.h>
76 #include <sys/ddi_impldefs.h>
77 #include <sys/sunddi.h>
78 #include <sys/autoconf.h>
79 #include <sys/modhash.h>
80 #include <sys/dacf.h>
81 #include <sys/dacf_impl.h>
82 #include <sys/systm.h>
83 #include <sys/varargs.h>
84 #include <sys/debug.h>
85 #include <sys/log.h>
86 #include <sys/fs/snode.h>
89 * Enumeration of the ops exported by the dacf framework.
91 * To add a new op to the framework, add it to this list, update dacf.h,
92 * (don't miss DACF_NUM_OPIDS) and modify dacf_rule_matrix.
95 typedef struct dacf_opmap {
96 const char *name;
97 dacf_opid_t id;
98 } dacf_opmap_t;
100 static dacf_opmap_t dacf_ops[] = {
101 { "post-attach", DACF_OPID_POSTATTACH },
102 { "pre-detach", DACF_OPID_PREDETACH },
103 { NULL, 0 },
107 * Enumeration of the options exported by the dacf framework (currently none).
109 * To add a new option, add it to this array.
111 typedef struct dacf_opt {
112 const char *optname;
113 uint_t optmask;
114 } dacf_opt_t;
116 static dacf_opt_t dacf_options[] = {
117 #ifdef DEBUG
118 { "testopt", 1 },
119 { "testopt2", 2 },
120 #endif
121 { NULL, 0 },
124 static char kmod_name[] = "__kernel";
127 * Enumeration of the device specifiers exported by the dacf framework.
129 * To add a new devspec to the framework, add it to this list, update dacf.h,
130 * (don't miss DACF_NUM_DEVSPECS), modify dacf_rule_matrix, and modify
131 * dacf_match().
133 typedef struct dacf_ds {
134 const char *name;
135 dacf_devspec_t id;
136 } dacf_ds_t;
138 static dacf_ds_t dacf_devspecs[] = {
139 { "minor-nodetype", DACF_DS_MIN_NT },
140 { "driver-minorname", DACF_DS_DRV_MNAME },
141 { "device-path", DACF_DS_DEV_PATH },
142 { NULL, 0},
145 mod_hash_t *posta_mntype, *posta_mname, *posta_devname; /* post-attach */
146 mod_hash_t *pred_mntype, *pred_mname, *pred_devname; /* pre-detach */
148 mod_hash_t *dacf_module_hash;
149 mod_hash_t *dacf_info_hash;
152 * This is the lookup table for the hash tables that dacf manages. Given an
153 * op id and devspec type, one can obtain the hash for that type of data.
155 mod_hash_t **dacf_rule_matrix[DACF_NUM_OPIDS][DACF_NUM_DEVSPECS] = {
156 { &posta_mntype, &posta_mname, &posta_devname },
157 { &pred_mntype, &pred_mname, &pred_devname },
160 kmutex_t dacf_lock;
161 kmutex_t dacf_module_lock;
163 int dacfdebug = 0;
165 static dacf_rule_t *dacf_rule_ctor(char *, char *, char *, dacf_opid_t,
166 uint_t, dacf_arg_t *);
167 static mod_hash_t *dacf_get_op_hash(dacf_opid_t, dacf_devspec_t);
168 static void dacf_rule_val_dtor(mod_hash_val_t);
169 static void dacf_destroy_opsets(dacf_module_t *module);
170 static void dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src);
171 static void dprintf(const char *, ...) __KPRINTFLIKE(1);
173 /*PRINTFLIKE1*/
174 static void
175 dprintf(const char *format, ...)
177 va_list alist;
178 char dp_buf[256], *dpbp;
179 if (dacfdebug & DACF_DBG_MSGS) {
180 va_start(alist, format);
182 * sprintf up the string that is 'dacf debug: <the message>'
184 (void) sprintf(dp_buf, "dacf debug: ");
185 dpbp = &(dp_buf[strlen(dp_buf)]);
186 (void) vsnprintf(dpbp, sizeof (dp_buf) - strlen(dp_buf),
187 format, alist);
188 printf(dp_buf);
189 va_end(alist);
194 * dacf_init()
195 * initialize the dacf framework by creating the various hash tables.
197 void
198 dacf_init()
200 int i, j;
201 char hbuf[40];
203 mutex_enter(&dacf_lock);
205 dprintf("dacf_init: creating hashmatrix\n");
207 #ifdef DEBUG
209 * Sanity check that DACF_NUM_DEVSPECS and the devspecs are in sync
211 for (i = 0; dacf_devspecs[i].name != NULL; i++)
212 continue;
213 ASSERT(i == DACF_NUM_DEVSPECS);
216 * Sanity check that DACF_NUM_OPIDS and the dacf_ops are in sync
218 for (i = 0; dacf_ops[i].name != NULL; i++)
219 continue;
220 ASSERT(i == DACF_NUM_OPIDS);
221 #endif
223 for (i = 0; i < DACF_NUM_OPIDS; i++) {
224 for (j = 0; j < DACF_NUM_DEVSPECS; j++) {
225 if (dacf_rule_matrix[i][j] == NULL) {
226 continue;
229 * Set up a hash table with no key destructor. The
230 * keys are carried in the rule_t, so the val_dtor
231 * will take care of the key as well.
233 (void) snprintf(hbuf, sizeof (hbuf),
234 "dacf hashmatrix [%d][%d]", i, j);
235 *(dacf_rule_matrix[i][j]) = mod_hash_create_extended(
236 hbuf, /* hash name */
237 DACF_RULE_HASHSIZE, /* # hash elems */
238 mod_hash_null_keydtor, /* key dtor */
239 dacf_rule_val_dtor, /* value dtor */
240 mod_hash_bystr, NULL, /* hash alg & data */
241 mod_hash_strkey_cmp, /* key comparator */
242 KM_SLEEP);
246 dprintf("dacf_init: creating module_hash\n");
248 * dacf_module_hash stores the currently registered dacf modules
249 * by name.
251 dacf_module_hash = mod_hash_create_strhash("dacf module hash",
252 DACF_MODULE_HASHSIZE, mod_hash_null_valdtor);
254 dprintf("dacf_init: creating info_hash\n");
256 * dacf_info_hash stores pointers to data that modules can associate
257 * on a per minornode basis. The type of data stored is opaque to the
258 * framework-- thus there is no destructor supplied.
260 dacf_info_hash = mod_hash_create_ptrhash("dacf info hash",
261 DACF_INFO_HASHSIZE, mod_hash_null_valdtor,
262 sizeof (struct ddi_minor_data));
264 mutex_exit(&dacf_lock);
267 * Register the '__kernel' module.
269 * These are operations that are provided by the kernel, not by a
270 * module. We just feed the framework a dacfsw structure; it will get
271 * marked as 'loaded' by dacf_module_register(), and will always be
272 * available.
274 (void) dacf_module_register(kmod_name, &kmod_dacfsw);
276 (void) read_dacf_binding_file(NULL);
278 dprintf("dacf_init: dacf is ready\n");
282 * dacf_clear_rules()
283 * clear the dacf rule database. This is typically done in advance of
284 * rereading the dacf binding file.
286 void
287 dacf_clear_rules()
289 int i, j;
290 ASSERT(MUTEX_HELD(&dacf_lock));
292 for (i = 0; i < DACF_NUM_OPIDS; i++) {
293 for (j = 0; j < DACF_NUM_DEVSPECS; j++) {
294 if ((dacf_rule_matrix[i][j] != NULL) &&
295 (*(dacf_rule_matrix[i][j]) != NULL)) {
296 mod_hash_clear(*(dacf_rule_matrix[i][j]));
303 * dacf_rule_insert()
304 * Create an entry in the dacf rule database.
305 * If 'module' is null, the kernel is the 'module'. (see dacf_rule_ctor()).
308 dacf_rule_insert(dacf_devspec_t devspec_type, char *devspec_data,
309 char *module, char *opset, dacf_opid_t opid, uint_t opts,
310 dacf_arg_t *op_args)
312 dacf_rule_t *rule;
313 mod_hash_t *hash;
315 ASSERT(devspec_type != DACF_DS_ERROR);
316 ASSERT(devspec_data);
317 ASSERT(opset);
318 ASSERT(MUTEX_HELD(&dacf_lock));
320 dprintf("dacf_rule_insert called: %s=\"%s\", %s:%s, %s\n",
321 dacf_devspec_to_str(devspec_type), devspec_data,
322 module ? module : "[kernel]", opset, dacf_opid_to_str(opid));
325 * Fetch the hash table associated with this op-name and devspec-type.
326 * Some ops may not support all devspec-types, since they may be
327 * meaningless, so hash may be null.
329 hash = dacf_get_op_hash(opid, devspec_type);
330 if (hash == NULL) {
331 cmn_err(CE_WARN, "!dacf dev-spec '%s' does not support op '%s'",
332 dacf_devspec_to_str(devspec_type), dacf_opid_to_str(opid));
333 return (-1);
337 * Allocate a rule and fill it in, take a hold on it.
339 rule = dacf_rule_ctor(devspec_data, module, opset, opid, opts,
340 op_args);
341 dacf_rule_hold(rule);
343 if (mod_hash_insert(hash, (mod_hash_key_t)rule->r_devspec_data,
344 (mod_hash_val_t)rule) != 0) {
346 * We failed, so release hold. This will cause the rule and
347 * associated data to get nuked.
349 dacf_rule_rele(rule);
351 cmn_err(CE_WARN, "!dacf rule %s='%s' %s:%s %s duplicates "
352 "another rule, ignored", dacf_devspec_to_str(devspec_type),
353 devspec_data, module, opset, dacf_opid_to_str(opid));
354 return (-1);
356 return (0);
360 * dacf_rule_ctor()
361 * Allocate and fill out entries in a dacf_rule_t.
363 static dacf_rule_t *
364 dacf_rule_ctor(char *device_spec, char *module, char *opset, dacf_opid_t opid,
365 uint_t opts, dacf_arg_t *op_args)
367 dacf_rule_t *rule;
368 dacf_arg_t *p;
370 rule = kmem_alloc(sizeof (dacf_rule_t), KM_SLEEP);
373 * Fill in the entries
375 rule->r_devspec_data = kmem_alloc(strlen(device_spec) + 1, KM_SLEEP);
376 (void) strcpy(rule->r_devspec_data, device_spec);
379 * If module is 'null' we set it to __kernel, meaning that this op
380 * is implemented by the kernel.
382 if (module == NULL) {
383 module = kmod_name;
386 rule->r_module = kmem_alloc(strlen(module) + 1, KM_SLEEP);
387 (void) strcpy(rule->r_module, module);
389 rule->r_opset = kmem_alloc(strlen(opset) + 1, KM_SLEEP);
390 (void) strcpy(rule->r_opset, opset);
392 rule->r_refs = 0; /* no refs yet */
393 rule->r_opts = opts;
394 rule->r_opid = opid;
396 rule->r_args = NULL;
397 p = op_args;
398 while (p != NULL) {
399 ASSERT(p->arg_name);
400 ASSERT(p->arg_val);
402 * dacf_arg_insert() should always succeed, since we're copying
403 * another (already duplicate-free) list.
405 (void) dacf_arg_insert(&rule->r_args, p->arg_name, p->arg_val);
406 p = p->arg_next;
409 return (rule);
413 * dacf_rule_val_dtor()
414 * This is the destructor for dacf_rule_t's in the rule database. It
415 * simply does a dacf_rule_rele() on the rule. This function will take
416 * care of destroying the rule if its ref count has dropped to 0.
418 static void
419 dacf_rule_val_dtor(mod_hash_val_t val)
421 ASSERT((void *)val != NULL);
422 dacf_rule_rele((dacf_rule_t *)val);
426 * dacf_rule_destroy()
427 * destroy a dacf_rule_t
429 void
430 dacf_rule_destroy(dacf_rule_t *rule)
432 ASSERT(rule->r_refs == 0);
434 * Free arguments.
436 dacf_arglist_delete(&(rule->r_args));
437 kmem_free(rule->r_devspec_data, strlen(rule->r_devspec_data) + 1);
439 * Module may be null for a kernel-managed op-set
441 kmem_free(rule->r_module, strlen(rule->r_module) + 1);
442 kmem_free(rule->r_opset, strlen(rule->r_opset) + 1);
443 kmem_free(rule, sizeof (dacf_rule_t));
447 * dacf_rule_hold()
448 * dacf rules are ref-counted. This function increases the reference
449 * count on an rule.
451 void
452 dacf_rule_hold(dacf_rule_t *rule)
454 ASSERT(MUTEX_HELD(&dacf_lock));
456 rule->r_refs++;
460 * dacf_rule_rele()
461 * drop the ref count on an rule, and destroy the rule if its
462 * ref count drops to 0.
464 void
465 dacf_rule_rele(dacf_rule_t *rule)
467 ASSERT(MUTEX_HELD(&dacf_lock));
468 ASSERT(rule->r_refs > 0);
470 rule->r_refs--;
471 if (rule->r_refs == 0) {
472 dacf_rule_destroy(rule);
477 * dacf_rsrv_make()
478 * add an rule to a reservation list to be processed later.
480 void
481 dacf_rsrv_make(dacf_rsrvlist_t *rsrv, dacf_rule_t *rule, void *info,
482 dacf_rsrvlist_t **list)
484 dacf_infohdl_t ihdl = info;
485 ASSERT(MUTEX_HELD(&dacf_lock));
486 ASSERT(info && rule && list);
489 * Bump the ref count on rule, so it won't get freed as long as it's on
490 * this reservation list.
492 dacf_rule_hold(rule);
494 rsrv->rsrv_rule = rule;
495 rsrv->rsrv_ihdl = ihdl;
496 rsrv->rsrv_result = DDI_SUCCESS;
497 rsrv->rsrv_next = *list;
498 *list = rsrv;
500 dprintf("dacf: reservation made\n");
504 * dacf_clr_rsrvs()
505 * clear reservation list of operations of type 'op'
507 void
508 dacf_clr_rsrvs(dev_info_t *devi, dacf_opid_t op)
510 dacf_process_rsrvs(&(DEVI(devi)->devi_dacf_tasks), op, DACF_PROC_RELE);
514 * dacf_process_rsrvs()
515 * iterate across a locked reservation list, processing each element
516 * which matches 'op' according to 'flags'.
518 * if DACF_PROC_INVOKE is specified, the elements that match 'op'
519 * will have their operations invoked. The return value from that
520 * operation is placed in the rsrv_result field of the dacf_rsrvlist_t
522 void
523 dacf_process_rsrvs(dacf_rsrvlist_t **list, dacf_opid_t op, int flags)
525 dacf_rsrvlist_t *p, *dp;
526 dacf_rsrvlist_t **prevptr;
528 ASSERT(MUTEX_HELD(&dacf_lock));
529 ASSERT(list);
530 ASSERT(flags != 0);
532 if (*list == NULL)
533 return;
535 dprintf("dacf_process_rsrvs: opid = %d, flags = 0x%x\n", op, flags);
538 * Walk the list, finding rules whose opid's match op, and performing
539 * the work described by 'flags'.
541 prevptr = list;
542 for (p = *list; p != NULL; ) {
544 if (p->rsrv_rule->r_opid != op) {
545 prevptr = &(p->rsrv_next);
546 p = p->rsrv_next;
547 continue;
550 if (flags & DACF_PROC_INVOKE) {
551 p->rsrv_result = dacf_op_invoke(p->rsrv_rule,
552 p->rsrv_ihdl, 0);
555 if (flags & DACF_PROC_RELE) {
556 *prevptr = p->rsrv_next;
557 dp = p;
558 p = p->rsrv_next;
559 dacf_rule_rele(dp->rsrv_rule);
560 kmem_free(dp, sizeof (dacf_rsrvlist_t));
561 } else {
562 prevptr = &(p->rsrv_next);
563 p = p->rsrv_next;
569 * dacf_get_op_hash()
570 * Given an op name, (i.e. "post-attach" or "pre-detach") and a
571 * devspec-type, return the hash that represents that op indexed
572 * by that devspec.
574 static mod_hash_t *
575 dacf_get_op_hash(dacf_opid_t op, dacf_devspec_t ds_type)
577 ASSERT(op <= DACF_NUM_OPIDS && op > 0);
578 ASSERT(ds_type <= DACF_NUM_DEVSPECS && ds_type > 0);
581 * dacf_rule_matrix is an array of pointers to pointers to hashes.
583 if (dacf_rule_matrix[op - 1][ds_type - 1] == NULL) {
584 return (NULL);
586 return (*(dacf_rule_matrix[op - 1][ds_type - 1]));
590 * dacf_arg_insert()
591 * Create and insert an entry in an argument list.
592 * Returns -1 if the argument name is a duplicate of another already
593 * present in the hash.
596 dacf_arg_insert(dacf_arg_t **list, char *name, char *val)
598 dacf_arg_t *arg;
601 * Don't allow duplicates.
603 for (arg = *list; arg != NULL; arg = arg->arg_next) {
604 if (strcmp(arg->arg_name, name) == 0) {
605 return (-1);
609 arg = kmem_alloc(sizeof (dacf_arg_t), KM_SLEEP);
610 arg->arg_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
611 (void) strcpy(arg->arg_name, name);
612 arg->arg_val = kmem_alloc(strlen(val) + 1, KM_SLEEP);
613 (void) strcpy(arg->arg_val, val);
615 arg->arg_next = *list;
616 *list = arg;
618 return (0);
622 * dacf_arglist_delete()
623 * free all the elements of a list of dacf_arg_t's.
625 void
626 dacf_arglist_delete(dacf_arg_t **list)
628 dacf_arg_t *arg, *narg;
629 arg = *list;
630 while (arg != NULL) {
631 narg = arg->arg_next;
632 kmem_free(arg->arg_name, strlen(arg->arg_name) + 1);
633 kmem_free(arg->arg_val, strlen(arg->arg_val) + 1);
634 kmem_free(arg, sizeof (dacf_arg_t));
635 arg = narg;
637 *list = NULL;
641 * dacf_match()
642 * Match a device-spec to a rule.
644 dacf_rule_t *
645 dacf_match(dacf_opid_t op, dacf_devspec_t ds, void *match_info)
647 dacf_rule_t *rule;
649 ASSERT(MUTEX_HELD(&dacf_lock));
651 if (mod_hash_find(dacf_get_op_hash(op, ds), (mod_hash_key_t)match_info,
652 (mod_hash_val_t *)&rule) == 0) {
653 return (rule);
656 return (NULL); /* Not Found */
660 * dacf_module_register()
661 * register a module with the framework. Use when a module gets loaded,
662 * or for the kernel to register a "virtual" module (i.e. a "module"
663 * which the kernel provides). Makes a copy of the interface description
664 * provided by the module.
667 dacf_module_register(char *mod_name, struct dacfsw *sw)
669 char *str;
670 size_t i, nelems;
671 dacf_module_t *module;
672 dacf_opset_t *opsarray;
674 if (sw == NULL) {
675 return (EINVAL);
678 if (sw->dacf_rev != DACF_MODREV_1) {
679 cmn_err(CE_WARN, "dacf: module '%s' exports unsupported "
680 "version %d interface, not registered\n", mod_name,
681 sw->dacf_rev);
682 return (EINVAL);
686 * count how many opsets are provided.
688 for (nelems = 0; sw->dacf_opsets[nelems].opset_name != NULL; nelems++)
691 dprintf("dacf_module_register: found %lu opsets\n", nelems);
694 * Temporary: It's ok for the kernel dacf_sw to have no opsets, since
695 * we don't have any opsets to export yet (in NON-DEBUG).
697 if ((nelems == 0) && (sw != &kmod_dacfsw)) {
698 cmn_err(CE_WARN, "dacf module %s exports no opsets, "
699 "not registered.\n", mod_name);
700 return (EINVAL);
704 * Look to see if the module has been previously registered with the
705 * framework. If so, we can fail with EBUSY.
707 if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name,
708 (mod_hash_val_t)&module) == 0) {
710 * See if it is loaded currently
712 rw_enter(&module->dm_lock, RW_WRITER);
713 if (module->dm_loaded) {
714 rw_exit(&module->dm_lock);
715 cmn_err(CE_WARN, "dacf module '%s' is "
716 "already registered.", mod_name);
717 return (EBUSY);
719 } else {
721 * This is the first time we've ever seen the module; stick
722 * it into the module hash. If that fails, we've had a
723 * race between two threads, both trying to insert the same
724 * new module. It's safe to stick the module into the
725 * hash only partly filled in, since dm_lock protects the
726 * structure, and we've got that write-locked.
728 module = kmem_zalloc(sizeof (dacf_module_t), KM_SLEEP);
729 str = kmem_alloc(strlen(mod_name) + 1, KM_SLEEP);
730 (void) strcpy(str, mod_name);
731 rw_enter(&module->dm_lock, RW_WRITER);
733 if (mod_hash_insert(dacf_module_hash, (mod_hash_key_t)str,
734 (mod_hash_val_t)module) != 0) {
735 rw_exit(&module->dm_lock);
736 kmem_free(str, strlen(str) + 1);
737 kmem_free(module, sizeof (dacf_module_t));
738 cmn_err(CE_WARN, "dacf module '%s' is "
739 "already registered.", mod_name);
740 return (EBUSY);
744 * In either case (first time we've seen it or not), the module is
745 * not loaded, and we hold it write-locked.
747 ASSERT(RW_WRITE_HELD(&module->dm_lock));
750 * Alloc array of opsets for this module. Add one for the final
751 * NULL entry
753 opsarray = kmem_zalloc(sizeof (dacf_opset_t) * (nelems + 1), KM_SLEEP);
755 for (i = 0; i < nelems; i++) {
756 dacf_opset_copy(&(opsarray[i]), &(sw->dacf_opsets[i]));
757 ASSERT(opsarray[i].opset_name != NULL);
758 ASSERT(opsarray[i].opset_ops != NULL);
760 opsarray[nelems].opset_name = NULL;
761 opsarray[nelems].opset_ops = NULL;
763 ASSERT(module->dm_opsets == NULL); /* see dacf_destroy_opsets() */
764 module->dm_opsets = opsarray;
766 if (dacfdebug & DACF_DBG_MSGS) {
767 dprintf("%s registered.\n", mod_name);
768 for (i = 0; i < nelems; i++) {
769 dprintf("registered %s\n", opsarray[i].opset_name);
773 module->dm_loaded = 1;
774 rw_exit(&module->dm_lock);
776 return (0);
780 * dacf_module_unregister()
781 * remove a module from the framework, and free framework-allocated
782 * resources.
785 dacf_module_unregister(char *mod_name)
787 dacf_module_t *module;
790 * Can't unregister __kernel, since there is no real way to get it
791 * back-- Once it gets marked with dm_loaded == 0, the kernel will
792 * try to modload() if it is ever needed, which will fail utterly,
793 * and send op_invoke into a loop in it's modload logic
795 * If this is behavior is ever needed in the future, we can just
796 * add a flag indicating that this module is really a fake.
798 ASSERT(strcmp(mod_name, kmod_name) != 0);
800 dprintf("dacf_module_unregister: called for '%s'!\n", mod_name);
803 * If NOAUL_DACF is set, or we try to get a write-lock on dm_lock and
804 * that fails, return EBUSY, and fail to unregister.
806 if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name,
807 (mod_hash_val_t)&module) == 0) {
808 if ((moddebug & MODDEBUG_NOAUL_DACF) ||
809 !rw_tryenter(&module->dm_lock, RW_WRITER)) {
810 return (EBUSY);
812 } else {
813 return (EINVAL);
816 ASSERT(RW_WRITE_HELD(&module->dm_lock));
817 dacf_destroy_opsets(module);
818 module->dm_loaded = 0;
819 rw_exit(&module->dm_lock);
820 return (0);
824 * dacf_destroy_opsets()
825 * given a module, destroy all of it's associated op-sets.
827 static void
828 dacf_destroy_opsets(dacf_module_t *module)
830 dacf_opset_t *array = module->dm_opsets;
831 dacf_opset_t *p;
832 int i;
833 size_t nelems;
835 ASSERT(RW_WRITE_HELD(&module->dm_lock));
836 ASSERT(module->dm_loaded == 1);
838 for (i = 0; array[i].opset_name != NULL; i++) {
839 p = &(array[i]);
840 kmem_free(p->opset_name, strlen(p->opset_name) + 1);
842 * count nelems in opset_ops
844 for (nelems = 0; ; nelems++) {
845 if (p->opset_ops[nelems].op_id == DACF_OPID_END) {
846 break;
850 * Free the array of op ptrs.
852 kmem_free(p->opset_ops, sizeof (dacf_op_t) * (nelems + 1));
856 * i has counted how big array is; +1 to account for the last element.
858 kmem_free(array, (sizeof (dacf_opset_t)) * (i + 1));
859 module->dm_opsets = NULL;
863 * dacf_opset_copy()
864 * makes a copy of a dacf_opset_t.
866 static void
867 dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src)
869 size_t nelems, i;
870 ASSERT(src && dst);
872 dprintf("dacf_opset_copy: called\n");
874 dst->opset_name = kmem_alloc(strlen(src->opset_name) + 1, KM_SLEEP);
875 (void) strcpy(dst->opset_name, src->opset_name);
877 dprintf("dacf_opset_copy: counting ops\n");
879 for (nelems = 0; ; nelems++) {
880 if ((src->opset_ops[nelems].op_id == DACF_OPID_END) ||
881 (src->opset_ops[nelems].op_func == NULL)) {
882 break;
886 dprintf("dacf_opset_copy: found %lu ops\n", nelems);
888 dst->opset_ops = kmem_alloc(sizeof (dacf_op_t) * (nelems + 1),
889 KM_SLEEP);
891 dprintf("dacf_opset_copy: copying ops\n");
892 for (i = 0; i < nelems; i++) {
893 dst->opset_ops[i].op_id = src->opset_ops[i].op_id;
894 dst->opset_ops[i].op_func = src->opset_ops[i].op_func;
896 dst->opset_ops[nelems].op_id = DACF_OPID_END;
897 dst->opset_ops[nelems].op_func = NULL;
899 dprintf("dacf_opset_copy: done copying ops\n");
902 int dacf_modload_laps = 0; /* just a diagnostic aid */
905 * dacf_op_invoke()
906 * Invoke a op in a opset in a module given the rule to invoke.
908 * If the return value of dacf_op_invoke is 0, then rval contains the
909 * return value of the _op_ being invoked. Otherwise, dacf_op_invoke's
910 * return value indicates why the op invocation failed.
913 dacf_op_invoke(dacf_rule_t *rule, dacf_infohdl_t info_hdl, int flags)
915 dacf_module_t *module;
916 dacf_opset_t *opsarray;
917 dacf_opset_t *opset;
918 dacf_op_t *op = NULL;
919 dacf_opid_t op_id;
920 dacf_arghdl_t arg_hdl;
921 dev_info_t *dip;
922 int i, rval = -1;
924 ASSERT(rule);
925 ASSERT(MUTEX_HELD(&dacf_lock));
927 op_id = rule->r_opid;
928 dprintf("dacf_op_invoke: opid=%d\n", op_id);
931 * Take laps, trying to load the dacf module. For the case of kernel-
932 * provided operations, __kernel will be found in the hash table, and
933 * no modload will be needed.
935 for (;;) {
936 if (mod_hash_find(dacf_module_hash,
937 (mod_hash_key_t)rule->r_module,
938 (mod_hash_val_t *)&module) == 0) {
939 rw_enter(&module->dm_lock, RW_READER);
941 * Found the module, and it is loaded.
943 if (module->dm_loaded != 0) {
944 break;
946 rw_exit(&module->dm_lock);
950 * If we're here, either: 1) it's not in the hash, or 2) it is,
951 * but dm_loaded is 0, meaning the module needs to be loaded.
953 dprintf("dacf_op_invoke: calling modload\n");
954 if (modload("dacf", rule->r_module) < 0) {
955 return (DACF_ERR_MOD_NOTFOUND);
957 dacf_modload_laps++;
960 ASSERT(RW_READ_HELD(&module->dm_lock));
962 opsarray = module->dm_opsets;
965 * Loop through the opsets exported by this module, and find the one
966 * we care about.
968 opset = NULL;
969 for (i = 0; opsarray[i].opset_name != NULL; i++) {
970 if (strcmp(opsarray[i].opset_name, rule->r_opset) == 0) {
971 opset = &opsarray[i];
972 break;
976 if (opset == NULL) {
977 cmn_err(CE_WARN, "!dacf: couldn't invoke op, opset '%s' not "
978 "found in module '%s'", rule->r_opset, rule->r_module);
979 rw_exit(&module->dm_lock);
980 return (DACF_ERR_OPSET_NOTFOUND);
983 arg_hdl = (dacf_arghdl_t)rule->r_args;
986 * Call the appropriate routine in the target by looping across the
987 * ops until we find the one whose id matches opid.
989 op = NULL;
990 for (i = 0; opset->opset_ops[i].op_id != DACF_OPID_END; i++) {
991 if (opset->opset_ops[i].op_id == op_id) {
992 op = &(opset->opset_ops[i]);
993 break;
997 if (op == NULL) {
998 cmn_err(CE_WARN, "!dacf: couldn't invoke op, op '%s' not found "
999 "in opset '%s' in module '%s'", dacf_opid_to_str(op_id),
1000 rule->r_opset, rule->r_module);
1001 rw_exit(&module->dm_lock);
1002 return (DACF_ERR_OP_NOTFOUND);
1005 dprintf("dacf_op_invoke: found op, invoking...\n");
1008 * Drop dacf_lock here, so that op_func's that cause drivers to
1009 * get loaded don't wedge the system when they try to acquire dacf_lock
1010 * to do matching.
1012 * Mark that an invoke is happening to prevent recursive invokes
1014 dip = ((struct ddi_minor_data *)info_hdl)->dip;
1016 mutex_enter(&(DEVI(dip)->devi_lock));
1017 DEVI_SET_INVOKING_DACF(dip);
1018 mutex_exit(&(DEVI(dip)->devi_lock));
1020 mutex_exit(&dacf_lock);
1022 rval = op->op_func(info_hdl, arg_hdl, flags);
1024 mutex_enter(&dacf_lock);
1027 * Completed the invocation against module, so let go of it.
1029 mutex_enter(&(DEVI(dip)->devi_lock));
1030 DEVI_CLR_INVOKING_DACF(dip);
1031 mutex_exit(&(DEVI(dip)->devi_lock));
1034 * Drop our r-lock on the module, now that we no longer need the module
1035 * to stay loaded.
1037 rw_exit(&module->dm_lock);
1039 if (rval == DACF_SUCCESS) {
1040 return (DACF_SUCCESS);
1041 } else {
1042 return (DACF_ERR_OP_FAILED);
1047 * dacf_get_devspec()
1048 * given a devspec-type as a string, return a corresponding dacf_devspec_t
1050 dacf_devspec_t
1051 dacf_get_devspec(char *name)
1053 dacf_ds_t *p = &dacf_devspecs[0];
1055 while (p->name != NULL) {
1056 if (strcmp(p->name, name) == 0) {
1057 return (p->id);
1059 p++;
1061 return (DACF_DS_ERROR);
1065 * dacf_devspec_to_str()
1066 * given a dacf_devspec_t, return a pointer to the human readable string
1067 * representation of that device specifier.
1069 const char *
1070 dacf_devspec_to_str(dacf_devspec_t ds)
1072 dacf_ds_t *p = &dacf_devspecs[0];
1074 while (p->name != NULL) {
1075 if (p->id == ds) {
1076 return (p->name);
1078 p++;
1080 return (NULL);
1084 * dacf_get_op()
1085 * given a op name, returns the corresponding dacf_opid_t.
1087 dacf_opid_t
1088 dacf_get_op(char *name)
1090 dacf_opmap_t *p = &dacf_ops[0];
1092 while (p->name != NULL) {
1093 if (strcmp(p->name, name) == 0) {
1094 return (p->id);
1096 p++;
1098 return (DACF_OPID_ERROR);
1102 * dacf_opid_to_str()
1103 * given a dacf_opid_t, return the human-readable op-name.
1105 const char *
1106 dacf_opid_to_str(dacf_opid_t tid)
1108 dacf_opmap_t *p = &dacf_ops[0];
1110 while (p->name != NULL) {
1111 if (p->id == tid) {
1112 return (p->name);
1114 p++;
1116 return (NULL);
1120 * dacf_getopt()
1121 * given an option specified as a string, add it to the bit-field of
1122 * options given. Returns -1 if the option is unrecognized.
1125 dacf_getopt(char *opt_str, uint_t *opts)
1127 dacf_opt_t *p = &dacf_options[0];
1130 * Look through the list for the option given
1132 while (p->optname != NULL) {
1133 if (strcmp(opt_str, p->optname) == 0) {
1134 *opts |= p->optmask;
1135 return (0);
1137 p++;
1139 return (-1);
1145 * This family of functions forms the dacf interface which is exported to
1146 * kernel/dacf modules. Modules _should_not_ use any dacf_* functions
1147 * presented above this point.
1149 * Note: These routines use a dacf_infohdl_t to struct ddi_minor_data * and
1150 * assume that the resulting pointer is not to an alias node. That is true
1151 * because dacf_op_invoke guarantees it by first resolving the alias.
1155 * dacf_minor_name()
1156 * given a dacf_infohdl_t, obtain the minor name of the device instance
1157 * being configured.
1159 const char *
1160 dacf_minor_name(dacf_infohdl_t info_hdl)
1162 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1164 return (dmdp->ddm_name);
1168 * dacf_minor_number()
1169 * given a dacf_infohdl_t, obtain the device minor number of the instance
1170 * being configured.
1172 minor_t
1173 dacf_minor_number(dacf_infohdl_t info_hdl)
1175 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1177 return (getminor(dmdp->ddm_dev));
1181 * dacf_get_dev()
1182 * given a dacf_infohdl_t, obtain the dev_t of the instance being
1183 * configured.
1185 dev_t
1186 dacf_get_dev(dacf_infohdl_t info_hdl)
1188 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1190 return (dmdp->ddm_dev);
1194 * dacf_driver_name()
1195 * given a dacf_infohdl_t, obtain the device driver name of the device
1196 * instance being configured.
1198 const char *
1199 dacf_driver_name(dacf_infohdl_t info_hdl)
1201 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1203 return (ddi_driver_name(dmdp->dip));
1207 * dacf_devinfo_node()
1208 * given a dacf_infohdl_t, obtain the dev_info_t of the device instance
1209 * being configured.
1211 dev_info_t *
1212 dacf_devinfo_node(dacf_infohdl_t info_hdl)
1214 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1216 return (dmdp->dip);
1220 * dacf_get_arg()
1221 * given the dacf_arghdl_t passed to a op and the name of an argument,
1222 * return the value of that argument.
1224 * returns NULL if the argument is not found.
1226 const char *
1227 dacf_get_arg(dacf_arghdl_t arghdl, char *arg_name)
1229 dacf_arg_t *arg_list = (dacf_arg_t *)arghdl;
1230 ASSERT(arg_name);
1232 while (arg_list != NULL) {
1233 if (strcmp(arg_list->arg_name, arg_name) == 0) {
1234 return (arg_list->arg_val);
1236 arg_list = arg_list->arg_next;
1239 return (NULL);
1243 * dacf_store_info()
1244 * associate instance-specific data with a device instance. Future
1245 * configuration ops invoked for this instance can retrieve this data using
1246 * dacf_retrieve_info() below. Modules are responsible for cleaning up
1247 * this data as appropriate, and should store NULL as the value of 'data'
1248 * when the data is no longer valid.
1250 void
1251 dacf_store_info(dacf_infohdl_t info_hdl, void *data)
1253 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1256 * If the client is 'storing NULL' we can represent that by blowing
1257 * the info entry out of the hash.
1259 if (data == NULL) {
1260 (void) mod_hash_destroy(dacf_info_hash, (mod_hash_key_t)dmdp);
1261 } else {
1263 * mod_hash_replace can only fail on out of memory, but we sleep
1264 * for memory in this hash, so it is safe to ignore the retval.
1266 (void) mod_hash_replace(dacf_info_hash, (mod_hash_key_t)dmdp,
1267 (mod_hash_val_t)data);
1272 * dacf_retrieve_info()
1273 * retrieve instance-specific data associated with a device instance.
1275 void *
1276 dacf_retrieve_info(dacf_infohdl_t info_hdl)
1278 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1279 void *data;
1281 if (mod_hash_find(dacf_info_hash, (mod_hash_key_t)dmdp,
1282 (mod_hash_val_t *)&data) != 0) {
1283 return (NULL);
1286 return (data);
1290 * dacf_makevp()
1291 * make a vnode for the specified dacf_infohdl_t.
1293 struct vnode *
1294 dacf_makevp(dacf_infohdl_t info_hdl)
1296 struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1297 struct vnode *vp;
1299 vp = makespecvp(dmdp->ddm_dev, VCHR);
1300 spec_assoc_vp_with_devi(vp, dmdp->dip);
1301 return (vp);