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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * DACF: device autoconfiguration support
31 * DACF provides a fast, lightweight policy engine for the I/O subsystem.
32 * This policy engine provides a mechanism for auto-configuring and
33 * auto-unconfiguring devices.
35 * After a device is attach(9E)ed, additional configuration may be needed in
36 * order to make the device available for use by the system. For example,
37 * STREAMS modules may need to be pushed atop the driver in order to create
38 * a STREAMS stack. If the device is to be removed from the system, these
39 * configuration operations need to be undone, and the device prepared for
42 * It is desirable to move the implementation of such policies outside of the
43 * kernel proper, since such operations are typically infrequent. To this end,
44 * DACF manages kernel modules in (module_path)/dacf directories. These adhere
45 * to the api defined in sys/dacf.h, and register sets of configuration
46 * operations. The kernel loads these modules when the operations they
47 * implement are needed, and can unload them at any time thereafter.
48 * Implementing configuration operations in external modules can also increase
51 * DACF provides a policy database which associates
53 * (device descr., kernel action) --> (configuration operation, parameters)
55 * - Device description is matching rule, for example:
56 * minor-nodetype="ddi_keyboard"
57 * - Kernel action is a reference to a dacf kernel hook.
58 * currently supported are "post-attach" and "pre-detach"
59 * - Configuration action is a reference to a module and a set of operations
60 * within the module, for example: consconfig:kbd_config
61 * - Parameters is a list of name="value" parameters to be passed to the
62 * configuration operation when invoked.
64 * The contents of the rules database are loaded from /etc/dacf.conf upon boot.
66 * DACF kernel hooks are comprised of a call into the rule-matching engine,
67 * using parameters from the hook in order find a matching rule. If one is
68 * found, the framework can invoke the configuration operation immediately, or
69 * defer doing so until later, by putting the rule on a 'reservation list.'
72 #include <sys/param.h>
73 #include <sys/modctl.h>
74 #include <sys/sysmacros.h>
76 #include <sys/cmn_err.h>
77 #include <sys/pathname.h>
78 #include <sys/ddi_impldefs.h>
79 #include <sys/sunddi.h>
80 #include <sys/autoconf.h>
81 #include <sys/modhash.h>
83 #include <sys/dacf_impl.h>
84 #include <sys/systm.h>
85 #include <sys/varargs.h>
86 #include <sys/debug.h>
88 #include <sys/fs/snode.h>
91 * Enumeration of the ops exported by the dacf framework.
93 * To add a new op to the framework, add it to this list, update dacf.h,
94 * (don't miss DACF_NUM_OPIDS) and modify dacf_rule_matrix.
97 typedef struct dacf_opmap
{
102 static dacf_opmap_t dacf_ops
[] = {
103 { "post-attach", DACF_OPID_POSTATTACH
},
104 { "pre-detach", DACF_OPID_PREDETACH
},
109 * Enumeration of the options exported by the dacf framework (currently none).
111 * To add a new option, add it to this array.
113 typedef struct dacf_opt
{
118 static dacf_opt_t dacf_options
[] = {
126 static char kmod_name
[] = "__kernel";
129 * Enumeration of the device specifiers exported by the dacf framework.
131 * To add a new devspec to the framework, add it to this list, update dacf.h,
132 * (don't miss DACF_NUM_DEVSPECS), modify dacf_rule_matrix, and modify
135 typedef struct dacf_ds
{
140 static dacf_ds_t dacf_devspecs
[] = {
141 { "minor-nodetype", DACF_DS_MIN_NT
},
142 { "driver-minorname", DACF_DS_DRV_MNAME
},
143 { "device-path", DACF_DS_DEV_PATH
},
147 mod_hash_t
*posta_mntype
, *posta_mname
, *posta_devname
; /* post-attach */
148 mod_hash_t
*pred_mntype
, *pred_mname
, *pred_devname
; /* pre-detach */
150 mod_hash_t
*dacf_module_hash
;
151 mod_hash_t
*dacf_info_hash
;
154 * This is the lookup table for the hash tables that dacf manages. Given an
155 * op id and devspec type, one can obtain the hash for that type of data.
157 mod_hash_t
**dacf_rule_matrix
[DACF_NUM_OPIDS
][DACF_NUM_DEVSPECS
] = {
158 { &posta_mntype
, &posta_mname
, &posta_devname
},
159 { &pred_mntype
, &pred_mname
, &pred_devname
},
163 kmutex_t dacf_module_lock
;
167 static dacf_rule_t
*dacf_rule_ctor(char *, char *, char *, dacf_opid_t
,
168 uint_t
, dacf_arg_t
*);
169 static mod_hash_t
*dacf_get_op_hash(dacf_opid_t
, dacf_devspec_t
);
170 static void dacf_rule_val_dtor(mod_hash_val_t
);
171 static void dacf_destroy_opsets(dacf_module_t
*module
);
172 static void dacf_opset_copy(dacf_opset_t
*dst
, dacf_opset_t
*src
);
173 static void dprintf(const char *, ...) __KPRINTFLIKE(1);
177 dprintf(const char *format
, ...)
180 char dp_buf
[256], *dpbp
;
181 if (dacfdebug
& DACF_DBG_MSGS
) {
182 va_start(alist
, format
);
184 * sprintf up the string that is 'dacf debug: <the message>'
186 (void) sprintf(dp_buf
, "dacf debug: ");
187 dpbp
= &(dp_buf
[strlen(dp_buf
)]);
188 (void) vsnprintf(dpbp
, sizeof (dp_buf
) - strlen(dp_buf
),
197 * initialize the dacf framework by creating the various hash tables.
205 mutex_enter(&dacf_lock
);
207 dprintf("dacf_init: creating hashmatrix\n");
211 * Sanity check that DACF_NUM_DEVSPECS and the devspecs are in sync
213 for (i
= 0; dacf_devspecs
[i
].name
!= NULL
; i
++)
215 ASSERT(i
== DACF_NUM_DEVSPECS
);
218 * Sanity check that DACF_NUM_OPIDS and the dacf_ops are in sync
220 for (i
= 0; dacf_ops
[i
].name
!= NULL
; i
++)
222 ASSERT(i
== DACF_NUM_OPIDS
);
225 for (i
= 0; i
< DACF_NUM_OPIDS
; i
++) {
226 for (j
= 0; j
< DACF_NUM_DEVSPECS
; j
++) {
227 if (dacf_rule_matrix
[i
][j
] == NULL
) {
231 * Set up a hash table with no key destructor. The
232 * keys are carried in the rule_t, so the val_dtor
233 * will take care of the key as well.
235 (void) snprintf(hbuf
, sizeof (hbuf
),
236 "dacf hashmatrix [%d][%d]", i
, j
);
237 *(dacf_rule_matrix
[i
][j
]) = mod_hash_create_extended(
238 hbuf
, /* hash name */
239 DACF_RULE_HASHSIZE
, /* # hash elems */
240 mod_hash_null_keydtor
, /* key dtor */
241 dacf_rule_val_dtor
, /* value dtor */
242 mod_hash_bystr
, NULL
, /* hash alg & data */
243 mod_hash_strkey_cmp
, /* key comparator */
248 dprintf("dacf_init: creating module_hash\n");
250 * dacf_module_hash stores the currently registered dacf modules
253 dacf_module_hash
= mod_hash_create_strhash("dacf module hash",
254 DACF_MODULE_HASHSIZE
, mod_hash_null_valdtor
);
256 dprintf("dacf_init: creating info_hash\n");
258 * dacf_info_hash stores pointers to data that modules can associate
259 * on a per minornode basis. The type of data stored is opaque to the
260 * framework-- thus there is no destructor supplied.
262 dacf_info_hash
= mod_hash_create_ptrhash("dacf info hash",
263 DACF_INFO_HASHSIZE
, mod_hash_null_valdtor
,
264 sizeof (struct ddi_minor_data
));
266 mutex_exit(&dacf_lock
);
269 * Register the '__kernel' module.
271 * These are operations that are provided by the kernel, not by a
272 * module. We just feed the framework a dacfsw structure; it will get
273 * marked as 'loaded' by dacf_module_register(), and will always be
276 (void) dacf_module_register(kmod_name
, &kmod_dacfsw
);
278 (void) read_dacf_binding_file(NULL
);
280 dprintf("dacf_init: dacf is ready\n");
285 * clear the dacf rule database. This is typically done in advance of
286 * rereading the dacf binding file.
292 ASSERT(MUTEX_HELD(&dacf_lock
));
294 for (i
= 0; i
< DACF_NUM_OPIDS
; i
++) {
295 for (j
= 0; j
< DACF_NUM_DEVSPECS
; j
++) {
296 if ((dacf_rule_matrix
[i
][j
] != NULL
) &&
297 (*(dacf_rule_matrix
[i
][j
]) != NULL
)) {
298 mod_hash_clear(*(dacf_rule_matrix
[i
][j
]));
306 * Create an entry in the dacf rule database.
307 * If 'module' is null, the kernel is the 'module'. (see dacf_rule_ctor()).
310 dacf_rule_insert(dacf_devspec_t devspec_type
, char *devspec_data
,
311 char *module
, char *opset
, dacf_opid_t opid
, uint_t opts
,
317 ASSERT(devspec_type
!= DACF_DS_ERROR
);
318 ASSERT(devspec_data
);
320 ASSERT(MUTEX_HELD(&dacf_lock
));
322 dprintf("dacf_rule_insert called: %s=\"%s\", %s:%s, %s\n",
323 dacf_devspec_to_str(devspec_type
), devspec_data
,
324 module
? module
: "[kernel]", opset
, dacf_opid_to_str(opid
));
327 * Fetch the hash table associated with this op-name and devspec-type.
328 * Some ops may not support all devspec-types, since they may be
329 * meaningless, so hash may be null.
331 hash
= dacf_get_op_hash(opid
, devspec_type
);
333 cmn_err(CE_WARN
, "!dacf dev-spec '%s' does not support op '%s'",
334 dacf_devspec_to_str(devspec_type
), dacf_opid_to_str(opid
));
339 * Allocate a rule and fill it in, take a hold on it.
341 rule
= dacf_rule_ctor(devspec_data
, module
, opset
, opid
, opts
,
343 dacf_rule_hold(rule
);
345 if (mod_hash_insert(hash
, (mod_hash_key_t
)rule
->r_devspec_data
,
346 (mod_hash_val_t
)rule
) != 0) {
348 * We failed, so release hold. This will cause the rule and
349 * associated data to get nuked.
351 dacf_rule_rele(rule
);
353 cmn_err(CE_WARN
, "!dacf rule %s='%s' %s:%s %s duplicates "
354 "another rule, ignored", dacf_devspec_to_str(devspec_type
),
355 devspec_data
, module
, opset
, dacf_opid_to_str(opid
));
363 * Allocate and fill out entries in a dacf_rule_t.
366 dacf_rule_ctor(char *device_spec
, char *module
, char *opset
, dacf_opid_t opid
,
367 uint_t opts
, dacf_arg_t
*op_args
)
372 rule
= kmem_alloc(sizeof (dacf_rule_t
), KM_SLEEP
);
375 * Fill in the entries
377 rule
->r_devspec_data
= kmem_alloc(strlen(device_spec
) + 1, KM_SLEEP
);
378 (void) strcpy(rule
->r_devspec_data
, device_spec
);
381 * If module is 'null' we set it to __kernel, meaning that this op
382 * is implemented by the kernel.
384 if (module
== NULL
) {
388 rule
->r_module
= kmem_alloc(strlen(module
) + 1, KM_SLEEP
);
389 (void) strcpy(rule
->r_module
, module
);
391 rule
->r_opset
= kmem_alloc(strlen(opset
) + 1, KM_SLEEP
);
392 (void) strcpy(rule
->r_opset
, opset
);
394 rule
->r_refs
= 0; /* no refs yet */
404 * dacf_arg_insert() should always succeed, since we're copying
405 * another (already duplicate-free) list.
407 (void) dacf_arg_insert(&rule
->r_args
, p
->arg_name
, p
->arg_val
);
415 * dacf_rule_val_dtor()
416 * This is the destructor for dacf_rule_t's in the rule database. It
417 * simply does a dacf_rule_rele() on the rule. This function will take
418 * care of destroying the rule if its ref count has dropped to 0.
421 dacf_rule_val_dtor(mod_hash_val_t val
)
423 ASSERT((void *)val
!= NULL
);
424 dacf_rule_rele((dacf_rule_t
*)val
);
428 * dacf_rule_destroy()
429 * destroy a dacf_rule_t
432 dacf_rule_destroy(dacf_rule_t
*rule
)
434 ASSERT(rule
->r_refs
== 0);
438 dacf_arglist_delete(&(rule
->r_args
));
439 kmem_free(rule
->r_devspec_data
, strlen(rule
->r_devspec_data
) + 1);
441 * Module may be null for a kernel-managed op-set
443 kmem_free(rule
->r_module
, strlen(rule
->r_module
) + 1);
444 kmem_free(rule
->r_opset
, strlen(rule
->r_opset
) + 1);
445 kmem_free(rule
, sizeof (dacf_rule_t
));
450 * dacf rules are ref-counted. This function increases the reference
454 dacf_rule_hold(dacf_rule_t
*rule
)
456 ASSERT(MUTEX_HELD(&dacf_lock
));
463 * drop the ref count on an rule, and destroy the rule if its
464 * ref count drops to 0.
467 dacf_rule_rele(dacf_rule_t
*rule
)
469 ASSERT(MUTEX_HELD(&dacf_lock
));
470 ASSERT(rule
->r_refs
> 0);
473 if (rule
->r_refs
== 0) {
474 dacf_rule_destroy(rule
);
480 * add an rule to a reservation list to be processed later.
483 dacf_rsrv_make(dacf_rsrvlist_t
*rsrv
, dacf_rule_t
*rule
, void *info
,
484 dacf_rsrvlist_t
**list
)
486 dacf_infohdl_t ihdl
= info
;
487 ASSERT(MUTEX_HELD(&dacf_lock
));
488 ASSERT(info
&& rule
&& list
);
491 * Bump the ref count on rule, so it won't get freed as long as it's on
492 * this reservation list.
494 dacf_rule_hold(rule
);
496 rsrv
->rsrv_rule
= rule
;
497 rsrv
->rsrv_ihdl
= ihdl
;
498 rsrv
->rsrv_result
= DDI_SUCCESS
;
499 rsrv
->rsrv_next
= *list
;
502 dprintf("dacf: reservation made\n");
507 * clear reservation list of operations of type 'op'
510 dacf_clr_rsrvs(dev_info_t
*devi
, dacf_opid_t op
)
512 dacf_process_rsrvs(&(DEVI(devi
)->devi_dacf_tasks
), op
, DACF_PROC_RELE
);
516 * dacf_process_rsrvs()
517 * iterate across a locked reservation list, processing each element
518 * which matches 'op' according to 'flags'.
520 * if DACF_PROC_INVOKE is specified, the elements that match 'op'
521 * will have their operations invoked. The return value from that
522 * operation is placed in the rsrv_result field of the dacf_rsrvlist_t
525 dacf_process_rsrvs(dacf_rsrvlist_t
**list
, dacf_opid_t op
, int flags
)
527 dacf_rsrvlist_t
*p
, *dp
;
528 dacf_rsrvlist_t
**prevptr
;
530 ASSERT(MUTEX_HELD(&dacf_lock
));
537 dprintf("dacf_process_rsrvs: opid = %d, flags = 0x%x\n", op
, flags
);
540 * Walk the list, finding rules whose opid's match op, and performing
541 * the work described by 'flags'.
544 for (p
= *list
; p
!= NULL
; ) {
546 if (p
->rsrv_rule
->r_opid
!= op
) {
547 prevptr
= &(p
->rsrv_next
);
552 if (flags
& DACF_PROC_INVOKE
) {
553 p
->rsrv_result
= dacf_op_invoke(p
->rsrv_rule
,
557 if (flags
& DACF_PROC_RELE
) {
558 *prevptr
= p
->rsrv_next
;
561 dacf_rule_rele(dp
->rsrv_rule
);
562 kmem_free(dp
, sizeof (dacf_rsrvlist_t
));
564 prevptr
= &(p
->rsrv_next
);
572 * Given an op name, (i.e. "post-attach" or "pre-detach") and a
573 * devspec-type, return the hash that represents that op indexed
577 dacf_get_op_hash(dacf_opid_t op
, dacf_devspec_t ds_type
)
579 ASSERT(op
<= DACF_NUM_OPIDS
&& op
> 0);
580 ASSERT(ds_type
<= DACF_NUM_DEVSPECS
&& ds_type
> 0);
583 * dacf_rule_matrix is an array of pointers to pointers to hashes.
585 if (dacf_rule_matrix
[op
- 1][ds_type
- 1] == NULL
) {
588 return (*(dacf_rule_matrix
[op
- 1][ds_type
- 1]));
593 * Create and insert an entry in an argument list.
594 * Returns -1 if the argument name is a duplicate of another already
595 * present in the hash.
598 dacf_arg_insert(dacf_arg_t
**list
, char *name
, char *val
)
603 * Don't allow duplicates.
605 for (arg
= *list
; arg
!= NULL
; arg
= arg
->arg_next
) {
606 if (strcmp(arg
->arg_name
, name
) == 0) {
611 arg
= kmem_alloc(sizeof (dacf_arg_t
), KM_SLEEP
);
612 arg
->arg_name
= kmem_alloc(strlen(name
) + 1, KM_SLEEP
);
613 (void) strcpy(arg
->arg_name
, name
);
614 arg
->arg_val
= kmem_alloc(strlen(val
) + 1, KM_SLEEP
);
615 (void) strcpy(arg
->arg_val
, val
);
617 arg
->arg_next
= *list
;
624 * dacf_arglist_delete()
625 * free all the elements of a list of dacf_arg_t's.
628 dacf_arglist_delete(dacf_arg_t
**list
)
630 dacf_arg_t
*arg
, *narg
;
632 while (arg
!= NULL
) {
633 narg
= arg
->arg_next
;
634 kmem_free(arg
->arg_name
, strlen(arg
->arg_name
) + 1);
635 kmem_free(arg
->arg_val
, strlen(arg
->arg_val
) + 1);
636 kmem_free(arg
, sizeof (dacf_arg_t
));
644 * Match a device-spec to a rule.
647 dacf_match(dacf_opid_t op
, dacf_devspec_t ds
, void *match_info
)
651 ASSERT(MUTEX_HELD(&dacf_lock
));
653 if (mod_hash_find(dacf_get_op_hash(op
, ds
), (mod_hash_key_t
)match_info
,
654 (mod_hash_val_t
*)&rule
) == 0) {
658 return (NULL
); /* Not Found */
662 * dacf_module_register()
663 * register a module with the framework. Use when a module gets loaded,
664 * or for the kernel to register a "virtual" module (i.e. a "module"
665 * which the kernel provides). Makes a copy of the interface description
666 * provided by the module.
669 dacf_module_register(char *mod_name
, struct dacfsw
*sw
)
673 dacf_module_t
*module
;
674 dacf_opset_t
*opsarray
;
680 if (sw
->dacf_rev
!= DACF_MODREV_1
) {
681 cmn_err(CE_WARN
, "dacf: module '%s' exports unsupported "
682 "version %d interface, not registered\n", mod_name
,
688 * count how many opsets are provided.
690 for (nelems
= 0; sw
->dacf_opsets
[nelems
].opset_name
!= NULL
; nelems
++)
693 dprintf("dacf_module_register: found %lu opsets\n", nelems
);
696 * Temporary: It's ok for the kernel dacf_sw to have no opsets, since
697 * we don't have any opsets to export yet (in NON-DEBUG).
699 if ((nelems
== 0) && (sw
!= &kmod_dacfsw
)) {
700 cmn_err(CE_WARN
, "dacf module %s exports no opsets, "
701 "not registered.\n", mod_name
);
706 * Look to see if the module has been previously registered with the
707 * framework. If so, we can fail with EBUSY.
709 if (mod_hash_find(dacf_module_hash
, (mod_hash_key_t
)mod_name
,
710 (mod_hash_val_t
)&module
) == 0) {
712 * See if it is loaded currently
714 rw_enter(&module
->dm_lock
, RW_WRITER
);
715 if (module
->dm_loaded
) {
716 rw_exit(&module
->dm_lock
);
717 cmn_err(CE_WARN
, "dacf module '%s' is "
718 "already registered.", mod_name
);
723 * This is the first time we've ever seen the module; stick
724 * it into the module hash. If that fails, we've had a
725 * race between two threads, both trying to insert the same
726 * new module. It's safe to stick the module into the
727 * hash only partly filled in, since dm_lock protects the
728 * structure, and we've got that write-locked.
730 module
= kmem_zalloc(sizeof (dacf_module_t
), KM_SLEEP
);
731 str
= kmem_alloc(strlen(mod_name
) + 1, KM_SLEEP
);
732 (void) strcpy(str
, mod_name
);
733 rw_enter(&module
->dm_lock
, RW_WRITER
);
735 if (mod_hash_insert(dacf_module_hash
, (mod_hash_key_t
)str
,
736 (mod_hash_val_t
)module
) != 0) {
737 rw_exit(&module
->dm_lock
);
738 kmem_free(str
, strlen(str
) + 1);
739 kmem_free(module
, sizeof (dacf_module_t
));
740 cmn_err(CE_WARN
, "dacf module '%s' is "
741 "already registered.", mod_name
);
746 * In either case (first time we've seen it or not), the module is
747 * not loaded, and we hold it write-locked.
749 ASSERT(RW_WRITE_HELD(&module
->dm_lock
));
752 * Alloc array of opsets for this module. Add one for the final
755 opsarray
= kmem_zalloc(sizeof (dacf_opset_t
) * (nelems
+ 1), KM_SLEEP
);
757 for (i
= 0; i
< nelems
; i
++) {
758 dacf_opset_copy(&(opsarray
[i
]), &(sw
->dacf_opsets
[i
]));
759 ASSERT(opsarray
[i
].opset_name
!= NULL
);
760 ASSERT(opsarray
[i
].opset_ops
!= NULL
);
762 opsarray
[nelems
].opset_name
= NULL
;
763 opsarray
[nelems
].opset_ops
= NULL
;
765 ASSERT(module
->dm_opsets
== NULL
); /* see dacf_destroy_opsets() */
766 module
->dm_opsets
= opsarray
;
768 if (dacfdebug
& DACF_DBG_MSGS
) {
769 dprintf("%s registered.\n", mod_name
);
770 for (i
= 0; i
< nelems
; i
++) {
771 dprintf("registered %s\n", opsarray
[i
].opset_name
);
775 module
->dm_loaded
= 1;
776 rw_exit(&module
->dm_lock
);
782 * dacf_module_unregister()
783 * remove a module from the framework, and free framework-allocated
787 dacf_module_unregister(char *mod_name
)
789 dacf_module_t
*module
;
792 * Can't unregister __kernel, since there is no real way to get it
793 * back-- Once it gets marked with dm_loaded == 0, the kernel will
794 * try to modload() if it is ever needed, which will fail utterly,
795 * and send op_invoke into a loop in it's modload logic
797 * If this is behavior is ever needed in the future, we can just
798 * add a flag indicating that this module is really a fake.
800 ASSERT(strcmp(mod_name
, kmod_name
) != 0);
802 dprintf("dacf_module_unregister: called for '%s'!\n", mod_name
);
805 * If NOAUL_DACF is set, or we try to get a write-lock on dm_lock and
806 * that fails, return EBUSY, and fail to unregister.
808 if (mod_hash_find(dacf_module_hash
, (mod_hash_key_t
)mod_name
,
809 (mod_hash_val_t
)&module
) == 0) {
810 if ((moddebug
& MODDEBUG_NOAUL_DACF
) ||
811 !rw_tryenter(&module
->dm_lock
, RW_WRITER
)) {
818 ASSERT(RW_WRITE_HELD(&module
->dm_lock
));
819 dacf_destroy_opsets(module
);
820 module
->dm_loaded
= 0;
821 rw_exit(&module
->dm_lock
);
826 * dacf_destroy_opsets()
827 * given a module, destroy all of it's associated op-sets.
830 dacf_destroy_opsets(dacf_module_t
*module
)
832 dacf_opset_t
*array
= module
->dm_opsets
;
837 ASSERT(RW_WRITE_HELD(&module
->dm_lock
));
838 ASSERT(module
->dm_loaded
== 1);
840 for (i
= 0; array
[i
].opset_name
!= NULL
; i
++) {
842 kmem_free(p
->opset_name
, strlen(p
->opset_name
) + 1);
844 * count nelems in opset_ops
846 for (nelems
= 0; ; nelems
++) {
847 if (p
->opset_ops
[nelems
].op_id
== DACF_OPID_END
) {
852 * Free the array of op ptrs.
854 kmem_free(p
->opset_ops
, sizeof (dacf_op_t
) * (nelems
+ 1));
858 * i has counted how big array is; +1 to account for the last element.
860 kmem_free(array
, (sizeof (dacf_opset_t
)) * (i
+ 1));
861 module
->dm_opsets
= NULL
;
866 * makes a copy of a dacf_opset_t.
869 dacf_opset_copy(dacf_opset_t
*dst
, dacf_opset_t
*src
)
874 dprintf("dacf_opset_copy: called\n");
876 dst
->opset_name
= kmem_alloc(strlen(src
->opset_name
) + 1, KM_SLEEP
);
877 (void) strcpy(dst
->opset_name
, src
->opset_name
);
879 dprintf("dacf_opset_copy: counting ops\n");
881 for (nelems
= 0; ; nelems
++) {
882 if ((src
->opset_ops
[nelems
].op_id
== DACF_OPID_END
) ||
883 (src
->opset_ops
[nelems
].op_func
== NULL
)) {
888 dprintf("dacf_opset_copy: found %lu ops\n", nelems
);
890 dst
->opset_ops
= kmem_alloc(sizeof (dacf_op_t
) * (nelems
+ 1),
893 dprintf("dacf_opset_copy: copying ops\n");
894 for (i
= 0; i
< nelems
; i
++) {
895 dst
->opset_ops
[i
].op_id
= src
->opset_ops
[i
].op_id
;
896 dst
->opset_ops
[i
].op_func
= src
->opset_ops
[i
].op_func
;
898 dst
->opset_ops
[nelems
].op_id
= DACF_OPID_END
;
899 dst
->opset_ops
[nelems
].op_func
= NULL
;
901 dprintf("dacf_opset_copy: done copying ops\n");
904 int dacf_modload_laps
= 0; /* just a diagnostic aid */
908 * Invoke a op in a opset in a module given the rule to invoke.
910 * If the return value of dacf_op_invoke is 0, then rval contains the
911 * return value of the _op_ being invoked. Otherwise, dacf_op_invoke's
912 * return value indicates why the op invocation failed.
915 dacf_op_invoke(dacf_rule_t
*rule
, dacf_infohdl_t info_hdl
, int flags
)
917 dacf_module_t
*module
;
918 dacf_opset_t
*opsarray
;
920 dacf_op_t
*op
= NULL
;
922 dacf_arghdl_t arg_hdl
;
927 ASSERT(MUTEX_HELD(&dacf_lock
));
929 op_id
= rule
->r_opid
;
930 dprintf("dacf_op_invoke: opid=%d\n", op_id
);
933 * Take laps, trying to load the dacf module. For the case of kernel-
934 * provided operations, __kernel will be found in the hash table, and
935 * no modload will be needed.
938 if (mod_hash_find(dacf_module_hash
,
939 (mod_hash_key_t
)rule
->r_module
,
940 (mod_hash_val_t
*)&module
) == 0) {
941 rw_enter(&module
->dm_lock
, RW_READER
);
943 * Found the module, and it is loaded.
945 if (module
->dm_loaded
!= 0) {
948 rw_exit(&module
->dm_lock
);
952 * If we're here, either: 1) it's not in the hash, or 2) it is,
953 * but dm_loaded is 0, meaning the module needs to be loaded.
955 dprintf("dacf_op_invoke: calling modload\n");
956 if (modload("dacf", rule
->r_module
) < 0) {
957 return (DACF_ERR_MOD_NOTFOUND
);
962 ASSERT(RW_READ_HELD(&module
->dm_lock
));
964 opsarray
= module
->dm_opsets
;
967 * Loop through the opsets exported by this module, and find the one
971 for (i
= 0; opsarray
[i
].opset_name
!= NULL
; i
++) {
972 if (strcmp(opsarray
[i
].opset_name
, rule
->r_opset
) == 0) {
973 opset
= &opsarray
[i
];
979 cmn_err(CE_WARN
, "!dacf: couldn't invoke op, opset '%s' not "
980 "found in module '%s'", rule
->r_opset
, rule
->r_module
);
981 rw_exit(&module
->dm_lock
);
982 return (DACF_ERR_OPSET_NOTFOUND
);
985 arg_hdl
= (dacf_arghdl_t
)rule
->r_args
;
988 * Call the appropriate routine in the target by looping across the
989 * ops until we find the one whose id matches opid.
992 for (i
= 0; opset
->opset_ops
[i
].op_id
!= DACF_OPID_END
; i
++) {
993 if (opset
->opset_ops
[i
].op_id
== op_id
) {
994 op
= &(opset
->opset_ops
[i
]);
1000 cmn_err(CE_WARN
, "!dacf: couldn't invoke op, op '%s' not found "
1001 "in opset '%s' in module '%s'", dacf_opid_to_str(op_id
),
1002 rule
->r_opset
, rule
->r_module
);
1003 rw_exit(&module
->dm_lock
);
1004 return (DACF_ERR_OP_NOTFOUND
);
1007 dprintf("dacf_op_invoke: found op, invoking...\n");
1010 * Drop dacf_lock here, so that op_func's that cause drivers to
1011 * get loaded don't wedge the system when they try to acquire dacf_lock
1014 * Mark that an invoke is happening to prevent recursive invokes
1016 dip
= ((struct ddi_minor_data
*)info_hdl
)->dip
;
1018 mutex_enter(&(DEVI(dip
)->devi_lock
));
1019 DEVI_SET_INVOKING_DACF(dip
);
1020 mutex_exit(&(DEVI(dip
)->devi_lock
));
1022 mutex_exit(&dacf_lock
);
1024 rval
= op
->op_func(info_hdl
, arg_hdl
, flags
);
1026 mutex_enter(&dacf_lock
);
1029 * Completed the invocation against module, so let go of it.
1031 mutex_enter(&(DEVI(dip
)->devi_lock
));
1032 DEVI_CLR_INVOKING_DACF(dip
);
1033 mutex_exit(&(DEVI(dip
)->devi_lock
));
1036 * Drop our r-lock on the module, now that we no longer need the module
1039 rw_exit(&module
->dm_lock
);
1041 if (rval
== DACF_SUCCESS
) {
1042 return (DACF_SUCCESS
);
1044 return (DACF_ERR_OP_FAILED
);
1049 * dacf_get_devspec()
1050 * given a devspec-type as a string, return a corresponding dacf_devspec_t
1053 dacf_get_devspec(char *name
)
1055 dacf_ds_t
*p
= &dacf_devspecs
[0];
1057 while (p
->name
!= NULL
) {
1058 if (strcmp(p
->name
, name
) == 0) {
1063 return (DACF_DS_ERROR
);
1067 * dacf_devspec_to_str()
1068 * given a dacf_devspec_t, return a pointer to the human readable string
1069 * representation of that device specifier.
1072 dacf_devspec_to_str(dacf_devspec_t ds
)
1074 dacf_ds_t
*p
= &dacf_devspecs
[0];
1076 while (p
->name
!= NULL
) {
1087 * given a op name, returns the corresponding dacf_opid_t.
1090 dacf_get_op(char *name
)
1092 dacf_opmap_t
*p
= &dacf_ops
[0];
1094 while (p
->name
!= NULL
) {
1095 if (strcmp(p
->name
, name
) == 0) {
1100 return (DACF_OPID_ERROR
);
1104 * dacf_opid_to_str()
1105 * given a dacf_opid_t, return the human-readable op-name.
1108 dacf_opid_to_str(dacf_opid_t tid
)
1110 dacf_opmap_t
*p
= &dacf_ops
[0];
1112 while (p
->name
!= NULL
) {
1123 * given an option specified as a string, add it to the bit-field of
1124 * options given. Returns -1 if the option is unrecognized.
1127 dacf_getopt(char *opt_str
, uint_t
*opts
)
1129 dacf_opt_t
*p
= &dacf_options
[0];
1132 * Look through the list for the option given
1134 while (p
->optname
!= NULL
) {
1135 if (strcmp(opt_str
, p
->optname
) == 0) {
1136 *opts
|= p
->optmask
;
1147 * This family of functions forms the dacf interface which is exported to
1148 * kernel/dacf modules. Modules _should_not_ use any dacf_* functions
1149 * presented above this point.
1151 * Note: These routines use a dacf_infohdl_t to struct ddi_minor_data * and
1152 * assume that the resulting pointer is not to an alias node. That is true
1153 * because dacf_op_invoke guarantees it by first resolving the alias.
1158 * given a dacf_infohdl_t, obtain the minor name of the device instance
1162 dacf_minor_name(dacf_infohdl_t info_hdl
)
1164 struct ddi_minor_data
*dmdp
= (struct ddi_minor_data
*)info_hdl
;
1166 return (dmdp
->ddm_name
);
1170 * dacf_minor_number()
1171 * given a dacf_infohdl_t, obtain the device minor number of the instance
1175 dacf_minor_number(dacf_infohdl_t info_hdl
)
1177 struct ddi_minor_data
*dmdp
= (struct ddi_minor_data
*)info_hdl
;
1179 return (getminor(dmdp
->ddm_dev
));
1184 * given a dacf_infohdl_t, obtain the dev_t of the instance being
1188 dacf_get_dev(dacf_infohdl_t info_hdl
)
1190 struct ddi_minor_data
*dmdp
= (struct ddi_minor_data
*)info_hdl
;
1192 return (dmdp
->ddm_dev
);
1196 * dacf_driver_name()
1197 * given a dacf_infohdl_t, obtain the device driver name of the device
1198 * instance being configured.
1201 dacf_driver_name(dacf_infohdl_t info_hdl
)
1203 struct ddi_minor_data
*dmdp
= (struct ddi_minor_data
*)info_hdl
;
1205 return (ddi_driver_name(dmdp
->dip
));
1209 * dacf_devinfo_node()
1210 * given a dacf_infohdl_t, obtain the dev_info_t of the device instance
1214 dacf_devinfo_node(dacf_infohdl_t info_hdl
)
1216 struct ddi_minor_data
*dmdp
= (struct ddi_minor_data
*)info_hdl
;
1223 * given the dacf_arghdl_t passed to a op and the name of an argument,
1224 * return the value of that argument.
1226 * returns NULL if the argument is not found.
1229 dacf_get_arg(dacf_arghdl_t arghdl
, char *arg_name
)
1231 dacf_arg_t
*arg_list
= (dacf_arg_t
*)arghdl
;
1234 while (arg_list
!= NULL
) {
1235 if (strcmp(arg_list
->arg_name
, arg_name
) == 0) {
1236 return (arg_list
->arg_val
);
1238 arg_list
= arg_list
->arg_next
;
1246 * associate instance-specific data with a device instance. Future
1247 * configuration ops invoked for this instance can retrieve this data using
1248 * dacf_retrieve_info() below. Modules are responsible for cleaning up
1249 * this data as appropriate, and should store NULL as the value of 'data'
1250 * when the data is no longer valid.
1253 dacf_store_info(dacf_infohdl_t info_hdl
, void *data
)
1255 struct ddi_minor_data
*dmdp
= (struct ddi_minor_data
*)info_hdl
;
1258 * If the client is 'storing NULL' we can represent that by blowing
1259 * the info entry out of the hash.
1262 (void) mod_hash_destroy(dacf_info_hash
, (mod_hash_key_t
)dmdp
);
1265 * mod_hash_replace can only fail on out of memory, but we sleep
1266 * for memory in this hash, so it is safe to ignore the retval.
1268 (void) mod_hash_replace(dacf_info_hash
, (mod_hash_key_t
)dmdp
,
1269 (mod_hash_val_t
)data
);
1274 * dacf_retrieve_info()
1275 * retrieve instance-specific data associated with a device instance.
1278 dacf_retrieve_info(dacf_infohdl_t info_hdl
)
1280 struct ddi_minor_data
*dmdp
= (struct ddi_minor_data
*)info_hdl
;
1283 if (mod_hash_find(dacf_info_hash
, (mod_hash_key_t
)dmdp
,
1284 (mod_hash_val_t
*)&data
) != 0) {
1293 * make a vnode for the specified dacf_infohdl_t.
1296 dacf_makevp(dacf_infohdl_t info_hdl
)
1298 struct ddi_minor_data
*dmdp
= (struct ddi_minor_data
*)info_hdl
;
1301 vp
= makespecvp(dmdp
->ddm_dev
, VCHR
);
1302 spec_assoc_vp_with_devi(vp
, dmdp
->dip
);