xref: /illumos-gate/usr/src/uts/common/os/dacf.c (revision 7bcaeddb)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * DACF: device autoconfiguration support
28  *
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.
32  *
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).
39  *
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.
48  *
49  * DACF provides a policy database which associates
50  *
51  *   (device descr., kernel action) --> (configuration operation, parameters)
52  *
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.
61  *
62  * The contents of the rules database are loaded from /etc/dacf.conf upon boot.
63  *
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.'
68  */
69 
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>
87 
88 /*
89  * Enumeration of the ops exported by the dacf framework.
90  *
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.
93  *
94  */
95 typedef struct dacf_opmap {
96 	const char *name;
97 	dacf_opid_t id;
98 } dacf_opmap_t;
99 
100 static dacf_opmap_t dacf_ops[] = {
101 	{ "post-attach",	DACF_OPID_POSTATTACH		},
102 	{ "pre-detach",		DACF_OPID_PREDETACH		},
103 	{ NULL,			0				},
104 };
105 
106 /*
107  * Enumeration of the options exported by the dacf framework (currently none).
108  *
109  * To add a new option, add it to this array.
110  */
111 typedef struct dacf_opt {
112 	const char *optname;
113 	uint_t optmask;
114 } dacf_opt_t;
115 
116 static dacf_opt_t dacf_options[] = {
117 #ifdef DEBUG
118 	{ "testopt", 		1		},
119 	{ "testopt2", 		2		},
120 #endif
121 	{ NULL, 		0		},
122 };
123 
124 static char kmod_name[] = "__kernel";
125 
126 /*
127  * Enumeration of the device specifiers exported by the dacf framework.
128  *
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().
132  */
133 typedef struct dacf_ds {
134 	const char *name;
135 	dacf_devspec_t id;
136 } dacf_ds_t;
137 
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,			DACF_DS_ERROR		},
143 };
144 
145 mod_hash_t *posta_mntype, *posta_mname, *posta_devname;	/* post-attach */
146 mod_hash_t *pred_mntype, *pred_mname, *pred_devname;	/* pre-detach */
147 
148 mod_hash_t *dacf_module_hash;
149 mod_hash_t *dacf_info_hash;
150 
151 /*
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.
154  */
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	},
158 };
159 
160 kmutex_t dacf_lock;
161 kmutex_t dacf_module_lock;
162 
163 int dacfdebug = 0;
164 
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);
172 
173 /*PRINTFLIKE1*/
174 static void
dprintf(const char * format,...)175 dprintf(const char *format, ...)
176 {
177 	va_list alist;
178 	char dp_buf[256], *dpbp;
179 	if (dacfdebug & DACF_DBG_MSGS) {
180 		va_start(alist, format);
181 		/*
182 		 * sprintf up the string that is 'dacf debug: <the message>'
183 		 */
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);
190 	}
191 }
192 
193 /*
194  * dacf_init()
195  * 	initialize the dacf framework by creating the various hash tables.
196  */
197 void
dacf_init()198 dacf_init()
199 {
200 	int i, j;
201 	char hbuf[40];
202 
203 	mutex_enter(&dacf_lock);
204 
205 	dprintf("dacf_init: creating hashmatrix\n");
206 
207 #ifdef DEBUG
208 	/*
209 	 * Sanity check that DACF_NUM_DEVSPECS and the devspecs are in sync
210 	 */
211 	for (i = 0; dacf_devspecs[i].name != NULL; i++)
212 		continue;
213 	ASSERT(i == DACF_NUM_DEVSPECS);
214 
215 	/*
216 	 * Sanity check that DACF_NUM_OPIDS and the dacf_ops are in sync
217 	 */
218 	for (i = 0; dacf_ops[i].name != NULL; i++)
219 		continue;
220 	ASSERT(i == DACF_NUM_OPIDS);
221 #endif
222 
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;
227 			}
228 			/*
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.
232 			 */
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);
243 		}
244 	}
245 
246 	dprintf("dacf_init: creating module_hash\n");
247 	/*
248 	 * dacf_module_hash stores the currently registered dacf modules
249 	 * by name.
250 	 */
251 	dacf_module_hash = mod_hash_create_strhash("dacf module hash",
252 	    DACF_MODULE_HASHSIZE, mod_hash_null_valdtor);
253 
254 	dprintf("dacf_init: creating info_hash\n");
255 	/*
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.
259 	 */
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));
263 
264 	mutex_exit(&dacf_lock);
265 
266 	/*
267 	 * Register the '__kernel' module.
268 	 *
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.
273 	 */
274 	(void) dacf_module_register(kmod_name, &kmod_dacfsw);
275 
276 	(void) read_dacf_binding_file(NULL);
277 
278 	dprintf("dacf_init: dacf is ready\n");
279 }
280 
281 /*
282  * dacf_clear_rules()
283  * 	clear the dacf rule database.  This is typically done in advance of
284  * 	rereading the dacf binding file.
285  */
286 void
dacf_clear_rules()287 dacf_clear_rules()
288 {
289 	int i, j;
290 	ASSERT(MUTEX_HELD(&dacf_lock));
291 
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]));
297 			}
298 		}
299 	}
300 }
301 
302 /*
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()).
306  */
307 int
dacf_rule_insert(dacf_devspec_t devspec_type,char * devspec_data,char * module,char * opset,dacf_opid_t opid,uint_t opts,dacf_arg_t * op_args)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)
311 {
312 	dacf_rule_t *rule;
313 	mod_hash_t *hash;
314 
315 	ASSERT(devspec_type != DACF_DS_ERROR);
316 	ASSERT(devspec_data);
317 	ASSERT(opset);
318 	ASSERT(MUTEX_HELD(&dacf_lock));
319 
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));
323 
324 	/*
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.
328 	 */
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);
334 	}
335 
336 	/*
337 	 * Allocate a rule  and fill it in, take a hold on it.
338 	 */
339 	rule = dacf_rule_ctor(devspec_data, module, opset, opid, opts,
340 	    op_args);
341 	dacf_rule_hold(rule);
342 
343 	if (mod_hash_insert(hash, (mod_hash_key_t)rule->r_devspec_data,
344 	    (mod_hash_val_t)rule) != 0) {
345 		/*
346 		 * We failed, so release hold.  This will cause the rule and
347 		 * associated data to get nuked.
348 		 */
349 		dacf_rule_rele(rule);
350 
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);
355 	}
356 	return (0);
357 }
358 
359 /*
360  * dacf_rule_ctor()
361  * 	Allocate and fill out entries in a dacf_rule_t.
362  */
363 static dacf_rule_t *
dacf_rule_ctor(char * device_spec,char * module,char * opset,dacf_opid_t opid,uint_t opts,dacf_arg_t * op_args)364 dacf_rule_ctor(char *device_spec, char *module, char *opset, dacf_opid_t opid,
365     uint_t opts, dacf_arg_t *op_args)
366 {
367 	dacf_rule_t *rule;
368 	dacf_arg_t *p;
369 
370 	rule = kmem_alloc(sizeof (dacf_rule_t), KM_SLEEP);
371 
372 	/*
373 	 * Fill in the entries
374 	 */
375 	rule->r_devspec_data = kmem_alloc(strlen(device_spec) + 1, KM_SLEEP);
376 	(void) strcpy(rule->r_devspec_data, device_spec);
377 
378 	/*
379 	 * If module is 'null' we set it to __kernel, meaning that this op
380 	 * is implemented by the kernel.
381 	 */
382 	if (module == NULL) {
383 		module = kmod_name;
384 	}
385 
386 	rule->r_module = kmem_alloc(strlen(module) + 1, KM_SLEEP);
387 	(void) strcpy(rule->r_module, module);
388 
389 	rule->r_opset = kmem_alloc(strlen(opset) + 1, KM_SLEEP);
390 	(void) strcpy(rule->r_opset, opset);
391 
392 	rule->r_refs = 0;	/* no refs yet */
393 	rule->r_opts = opts;
394 	rule->r_opid = opid;
395 
396 	rule->r_args = NULL;
397 	p = op_args;
398 	while (p != NULL) {
399 		ASSERT(p->arg_name);
400 		ASSERT(p->arg_val);
401 		/*
402 		 * dacf_arg_insert() should always succeed, since we're copying
403 		 * another (already duplicate-free) list.
404 		 */
405 		(void) dacf_arg_insert(&rule->r_args, p->arg_name, p->arg_val);
406 		p = p->arg_next;
407 	}
408 
409 	return (rule);
410 }
411 
412 /*
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.
417  */
418 static void
dacf_rule_val_dtor(mod_hash_val_t val)419 dacf_rule_val_dtor(mod_hash_val_t val)
420 {
421 	ASSERT((void *)val != NULL);
422 	dacf_rule_rele((dacf_rule_t *)val);
423 }
424 
425 /*
426  * dacf_rule_destroy()
427  * 	destroy a dacf_rule_t
428  */
429 void
dacf_rule_destroy(dacf_rule_t * rule)430 dacf_rule_destroy(dacf_rule_t *rule)
431 {
432 	ASSERT(rule->r_refs == 0);
433 	/*
434 	 * Free arguments.
435 	 */
436 	dacf_arglist_delete(&(rule->r_args));
437 	kmem_free(rule->r_devspec_data, strlen(rule->r_devspec_data) + 1);
438 	/*
439 	 * Module may be null for a kernel-managed op-set
440 	 */
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));
444 }
445 
446 /*
447  * dacf_rule_hold()
448  * 	dacf rules are ref-counted.  This function increases the reference
449  * 	count on an rule.
450  */
451 void
dacf_rule_hold(dacf_rule_t * rule)452 dacf_rule_hold(dacf_rule_t *rule)
453 {
454 	ASSERT(MUTEX_HELD(&dacf_lock));
455 
456 	rule->r_refs++;
457 }
458 
459 /*
460  * dacf_rule_rele()
461  * 	drop the ref count on an rule, and destroy the rule if its
462  * 	ref count drops to 0.
463  */
464 void
dacf_rule_rele(dacf_rule_t * rule)465 dacf_rule_rele(dacf_rule_t *rule)
466 {
467 	ASSERT(MUTEX_HELD(&dacf_lock));
468 	ASSERT(rule->r_refs > 0);
469 
470 	rule->r_refs--;
471 	if (rule->r_refs == 0) {
472 		dacf_rule_destroy(rule);
473 	}
474 }
475 
476 /*
477  * dacf_rsrv_make()
478  * 	add an rule to a reservation list to be processed later.
479  */
480 void
dacf_rsrv_make(dacf_rsrvlist_t * rsrv,dacf_rule_t * rule,void * info,dacf_rsrvlist_t ** list)481 dacf_rsrv_make(dacf_rsrvlist_t *rsrv, dacf_rule_t *rule, void *info,
482     dacf_rsrvlist_t **list)
483 {
484 	dacf_infohdl_t ihdl = info;
485 	ASSERT(MUTEX_HELD(&dacf_lock));
486 	ASSERT(info && rule && list);
487 
488 	/*
489 	 * Bump the ref count on rule, so it won't get freed as long as it's on
490 	 * this reservation list.
491 	 */
492 	dacf_rule_hold(rule);
493 
494 	rsrv->rsrv_rule = rule;
495 	rsrv->rsrv_ihdl = ihdl;
496 	rsrv->rsrv_result = DDI_SUCCESS;
497 	rsrv->rsrv_next = *list;
498 	*list = rsrv;
499 
500 	dprintf("dacf: reservation made\n");
501 }
502 
503 /*
504  * dacf_clr_rsrvs()
505  * 	clear reservation list of operations of type 'op'
506  */
507 void
dacf_clr_rsrvs(dev_info_t * devi,dacf_opid_t op)508 dacf_clr_rsrvs(dev_info_t *devi, dacf_opid_t op)
509 {
510 	dacf_process_rsrvs(&(DEVI(devi)->devi_dacf_tasks), op, DACF_PROC_RELE);
511 }
512 
513 /*
514  * dacf_process_rsrvs()
515  * 	iterate across a locked reservation list, processing each element
516  * 	which matches 'op' according to 'flags'.
517  *
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
521  */
522 void
dacf_process_rsrvs(dacf_rsrvlist_t ** list,dacf_opid_t op,int flags)523 dacf_process_rsrvs(dacf_rsrvlist_t **list, dacf_opid_t op, int flags)
524 {
525 	dacf_rsrvlist_t *p, *dp;
526 	dacf_rsrvlist_t **prevptr;
527 
528 	ASSERT(MUTEX_HELD(&dacf_lock));
529 	ASSERT(list);
530 	ASSERT(flags != 0);
531 
532 	if (*list == NULL)
533 		return;
534 
535 	dprintf("dacf_process_rsrvs: opid = %d, flags = 0x%x\n", op, flags);
536 
537 	/*
538 	 * Walk the list, finding rules whose opid's match op, and performing
539 	 * the work described by 'flags'.
540 	 */
541 	prevptr = list;
542 	for (p = *list; p != NULL; ) {
543 
544 		if (p->rsrv_rule->r_opid != op) {
545 			prevptr = &(p->rsrv_next);
546 			p = p->rsrv_next;
547 			continue;
548 		}
549 
550 		if (flags & DACF_PROC_INVOKE) {
551 			p->rsrv_result = dacf_op_invoke(p->rsrv_rule,
552 			    p->rsrv_ihdl, 0);
553 		}
554 
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;
564 		}
565 	}
566 }
567 
568 /*
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.
573  */
574 static mod_hash_t *
dacf_get_op_hash(dacf_opid_t op,dacf_devspec_t ds_type)575 dacf_get_op_hash(dacf_opid_t op, dacf_devspec_t ds_type)
576 {
577 	ASSERT(op <= DACF_NUM_OPIDS && op > 0);
578 	ASSERT(ds_type <= DACF_NUM_DEVSPECS && ds_type > 0);
579 
580 	/*
581 	 * dacf_rule_matrix is an array of pointers to pointers to hashes.
582 	 */
583 	if (dacf_rule_matrix[op - 1][ds_type - 1] == NULL) {
584 		return (NULL);
585 	}
586 	return (*(dacf_rule_matrix[op - 1][ds_type - 1]));
587 }
588 
589 /*
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.
594  */
595 int
dacf_arg_insert(dacf_arg_t ** list,char * name,char * val)596 dacf_arg_insert(dacf_arg_t **list, char *name, char *val)
597 {
598 	dacf_arg_t *arg;
599 
600 	/*
601 	 * Don't allow duplicates.
602 	 */
603 	for (arg = *list; arg != NULL; arg = arg->arg_next) {
604 		if (strcmp(arg->arg_name, name) == 0) {
605 			return (-1);
606 		}
607 	}
608 
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);
614 
615 	arg->arg_next = *list;
616 	*list = arg;
617 
618 	return (0);
619 }
620 
621 /*
622  * dacf_arglist_delete()
623  * 	free all the elements of a list of dacf_arg_t's.
624  */
625 void
dacf_arglist_delete(dacf_arg_t ** list)626 dacf_arglist_delete(dacf_arg_t **list)
627 {
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;
636 	}
637 	*list = NULL;
638 }
639 
640 /*
641  * dacf_match()
642  * 	Match a device-spec to a rule.
643  */
644 dacf_rule_t *
dacf_match(dacf_opid_t op,dacf_devspec_t ds,const void * match_info)645 dacf_match(dacf_opid_t op, dacf_devspec_t ds, const void *match_info)
646 {
647 	dacf_rule_t *rule;
648 
649 	ASSERT(MUTEX_HELD(&dacf_lock));
650 
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);
654 	}
655 
656 	return (NULL);	/* Not Found */
657 }
658 
659 /*
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.
665  */
666 int
dacf_module_register(char * mod_name,struct dacfsw * sw)667 dacf_module_register(char *mod_name, struct dacfsw *sw)
668 {
669 	char *str;
670 	size_t i, nelems;
671 	dacf_module_t *module;
672 	dacf_opset_t *opsarray;
673 
674 	if (sw == NULL) {
675 		return (EINVAL);
676 	}
677 
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);
683 	}
684 
685 	/*
686 	 * count how many opsets are provided.
687 	 */
688 	for (nelems = 0; sw->dacf_opsets[nelems].opset_name != NULL; nelems++)
689 		;
690 
691 	dprintf("dacf_module_register: found %lu opsets\n", nelems);
692 
693 	/*
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).
696 	 */
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);
701 	}
702 
703 	/*
704 	 * Look to see if the module has been previously registered with the
705 	 * framework.  If so, we can fail with EBUSY.
706 	 */
707 	if (mod_hash_find(dacf_module_hash, (mod_hash_key_t)mod_name,
708 	    (mod_hash_val_t)&module) == 0) {
709 		/*
710 		 * See if it is loaded currently
711 		 */
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);
718 		}
719 	} else {
720 		/*
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.
727 		 */
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);
732 
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);
741 		}
742 	}
743 	/*
744 	 * In either case (first time we've seen it or not), the module is
745 	 * not loaded, and we hold it write-locked.
746 	 */
747 	ASSERT(RW_WRITE_HELD(&module->dm_lock));
748 
749 	/*
750 	 * Alloc array of opsets for this module.  Add one for the final
751 	 * NULL entry
752 	 */
753 	opsarray = kmem_zalloc(sizeof (dacf_opset_t) * (nelems + 1), KM_SLEEP);
754 
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);
759 	}
760 	opsarray[nelems].opset_name = NULL;
761 	opsarray[nelems].opset_ops = NULL;
762 
763 	ASSERT(module->dm_opsets == NULL);	/* see dacf_destroy_opsets() */
764 	module->dm_opsets = opsarray;
765 
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);
770 		}
771 	}
772 
773 	module->dm_loaded = 1;
774 	rw_exit(&module->dm_lock);
775 
776 	return (0);
777 }
778 
779 /*
780  * dacf_module_unregister()
781  * 	remove a module from the framework, and free framework-allocated
782  * 	resources.
783  */
784 int
dacf_module_unregister(char * mod_name)785 dacf_module_unregister(char *mod_name)
786 {
787 	dacf_module_t *module;
788 
789 	/*
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
794 	 *
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.
797 	 */
798 	ASSERT(strcmp(mod_name, kmod_name) != 0);
799 
800 	dprintf("dacf_module_unregister: called for '%s'!\n", mod_name);
801 
802 	/*
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.
805 	 */
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);
811 		}
812 	} else {
813 		return (EINVAL);
814 	}
815 
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);
821 }
822 
823 /*
824  * dacf_destroy_opsets()
825  * 	given a module, destroy all of it's associated op-sets.
826  */
827 static void
dacf_destroy_opsets(dacf_module_t * module)828 dacf_destroy_opsets(dacf_module_t *module)
829 {
830 	dacf_opset_t *array = module->dm_opsets;
831 	dacf_opset_t *p;
832 	int i;
833 	size_t nelems;
834 
835 	ASSERT(RW_WRITE_HELD(&module->dm_lock));
836 	ASSERT(module->dm_loaded == 1);
837 
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);
841 		/*
842 		 * count nelems in opset_ops
843 		 */
844 		for (nelems = 0; ; nelems++) {
845 			if (p->opset_ops[nelems].op_id == DACF_OPID_END) {
846 				break;
847 			}
848 		}
849 		/*
850 		 * Free the array of op ptrs.
851 		 */
852 		kmem_free(p->opset_ops, sizeof (dacf_op_t) * (nelems + 1));
853 	}
854 
855 	/*
856 	 * i has counted how big array is; +1 to account for the last element.
857 	 */
858 	kmem_free(array, (sizeof (dacf_opset_t)) * (i + 1));
859 	module->dm_opsets = NULL;
860 }
861 
862 /*
863  * dacf_opset_copy()
864  * 	makes a copy of a dacf_opset_t.
865  */
866 static void
dacf_opset_copy(dacf_opset_t * dst,dacf_opset_t * src)867 dacf_opset_copy(dacf_opset_t *dst, dacf_opset_t *src)
868 {
869 	size_t nelems, i;
870 	ASSERT(src && dst);
871 
872 	dprintf("dacf_opset_copy: called\n");
873 
874 	dst->opset_name = kmem_alloc(strlen(src->opset_name) + 1, KM_SLEEP);
875 	(void) strcpy(dst->opset_name, src->opset_name);
876 
877 	dprintf("dacf_opset_copy: counting ops\n");
878 
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;
883 		}
884 	}
885 
886 	dprintf("dacf_opset_copy: found %lu ops\n", nelems);
887 
888 	dst->opset_ops = kmem_alloc(sizeof (dacf_op_t) * (nelems + 1),
889 	    KM_SLEEP);
890 
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;
895 	}
896 	dst->opset_ops[nelems].op_id = DACF_OPID_END;
897 	dst->opset_ops[nelems].op_func = NULL;
898 
899 	dprintf("dacf_opset_copy: done copying ops\n");
900 }
901 
902 int dacf_modload_laps = 0;	/* just a diagnostic aid */
903 
904 /*
905  * dacf_op_invoke()
906  *	Invoke a op in a opset in a module given the rule to invoke.
907  *
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.
911  */
912 int
dacf_op_invoke(dacf_rule_t * rule,dacf_infohdl_t info_hdl,int flags)913 dacf_op_invoke(dacf_rule_t *rule, dacf_infohdl_t info_hdl, int flags)
914 {
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;
923 
924 	ASSERT(rule);
925 	ASSERT(MUTEX_HELD(&dacf_lock));
926 
927 	op_id = rule->r_opid;
928 	dprintf("dacf_op_invoke: opid=%d\n", op_id);
929 
930 	/*
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.
934 	 */
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);
940 			/*
941 			 * Found the module, and it is loaded.
942 			 */
943 			if (module->dm_loaded != 0) {
944 				break;
945 			}
946 			rw_exit(&module->dm_lock);
947 		}
948 
949 		/*
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.
952 		 */
953 		dprintf("dacf_op_invoke: calling modload\n");
954 		if (modload("dacf", rule->r_module) < 0) {
955 			return (DACF_ERR_MOD_NOTFOUND);
956 		}
957 		dacf_modload_laps++;
958 	}
959 
960 	ASSERT(RW_READ_HELD(&module->dm_lock));
961 
962 	opsarray = module->dm_opsets;
963 
964 	/*
965 	 * Loop through the opsets exported by this module, and find the one
966 	 * we care about.
967 	 */
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;
973 		}
974 	}
975 
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);
981 	}
982 
983 	arg_hdl = (dacf_arghdl_t)rule->r_args;
984 
985 	/*
986 	 * Call the appropriate routine in the target by looping across the
987 	 * ops until we find the one whose id matches opid.
988 	 */
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;
994 		}
995 	}
996 
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);
1003 	}
1004 
1005 	dprintf("dacf_op_invoke: found op, invoking...\n");
1006 
1007 	/*
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.
1011 	 *
1012 	 * Mark that an invoke is happening to prevent recursive invokes
1013 	 */
1014 	dip = ((struct ddi_minor_data *)info_hdl)->dip;
1015 
1016 	mutex_enter(&(DEVI(dip)->devi_lock));
1017 	DEVI_SET_INVOKING_DACF(dip);
1018 	mutex_exit(&(DEVI(dip)->devi_lock));
1019 
1020 	mutex_exit(&dacf_lock);
1021 
1022 	rval = op->op_func(info_hdl, arg_hdl, flags);
1023 
1024 	mutex_enter(&dacf_lock);
1025 
1026 	/*
1027 	 * Completed the invocation against module, so let go of it.
1028 	 */
1029 	mutex_enter(&(DEVI(dip)->devi_lock));
1030 	DEVI_CLR_INVOKING_DACF(dip);
1031 	mutex_exit(&(DEVI(dip)->devi_lock));
1032 
1033 	/*
1034 	 * Drop our r-lock on the module, now that we no longer need the module
1035 	 * to stay loaded.
1036 	 */
1037 	rw_exit(&module->dm_lock);
1038 
1039 	if (rval == DACF_SUCCESS) {
1040 		return (DACF_SUCCESS);
1041 	} else {
1042 		return (DACF_ERR_OP_FAILED);
1043 	}
1044 }
1045 
1046 /*
1047  * dacf_get_devspec()
1048  * 	given a devspec-type as a string, return a corresponding dacf_devspec_t
1049  */
1050 dacf_devspec_t
dacf_get_devspec(char * name)1051 dacf_get_devspec(char *name)
1052 {
1053 	dacf_ds_t *p = &dacf_devspecs[0];
1054 
1055 	while (p->name != NULL) {
1056 		if (strcmp(p->name, name) == 0) {
1057 			return (p->id);
1058 		}
1059 		p++;
1060 	}
1061 	return (DACF_DS_ERROR);
1062 }
1063 
1064 /*
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.
1068  */
1069 const char *
dacf_devspec_to_str(dacf_devspec_t ds)1070 dacf_devspec_to_str(dacf_devspec_t ds)
1071 {
1072 	dacf_ds_t *p = &dacf_devspecs[0];
1073 
1074 	while (p->name != NULL) {
1075 		if (p->id == ds) {
1076 			return (p->name);
1077 		}
1078 		p++;
1079 	}
1080 	return (NULL);
1081 }
1082 
1083 /*
1084  * dacf_get_op()
1085  * 	given a op name, returns the corresponding dacf_opid_t.
1086  */
1087 dacf_opid_t
dacf_get_op(char * name)1088 dacf_get_op(char *name)
1089 {
1090 	dacf_opmap_t *p = &dacf_ops[0];
1091 
1092 	while (p->name != NULL) {
1093 		if (strcmp(p->name, name) == 0) {
1094 			return (p->id);
1095 		}
1096 		p++;
1097 	}
1098 	return (DACF_OPID_ERROR);
1099 }
1100 
1101 /*
1102  * dacf_opid_to_str()
1103  * 	given a dacf_opid_t, return the human-readable op-name.
1104  */
1105 const char *
dacf_opid_to_str(dacf_opid_t tid)1106 dacf_opid_to_str(dacf_opid_t tid)
1107 {
1108 	dacf_opmap_t *p = &dacf_ops[0];
1109 
1110 	while (p->name != NULL) {
1111 		if (p->id == tid) {
1112 			return (p->name);
1113 		}
1114 		p++;
1115 	}
1116 	return (NULL);
1117 }
1118 
1119 /*
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.
1123  */
1124 int
dacf_getopt(char * opt_str,uint_t * opts)1125 dacf_getopt(char *opt_str, uint_t *opts)
1126 {
1127 	dacf_opt_t *p = &dacf_options[0];
1128 
1129 	/*
1130 	 * Look through the list for the option given
1131 	 */
1132 	while (p->optname != NULL) {
1133 		if (strcmp(opt_str, p->optname) == 0) {
1134 			*opts |= p->optmask;
1135 			return (0);
1136 		}
1137 		p++;
1138 	}
1139 	return (-1);
1140 }
1141 
1142 
1143 
1144 /*
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.
1148  *
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.
1152  */
1153 
1154 /*
1155  * dacf_minor_name()
1156  * 	given a dacf_infohdl_t, obtain the minor name of the device instance
1157  * 	being configured.
1158  */
1159 const char *
dacf_minor_name(dacf_infohdl_t info_hdl)1160 dacf_minor_name(dacf_infohdl_t info_hdl)
1161 {
1162 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1163 
1164 	return (dmdp->ddm_name);
1165 }
1166 
1167 /*
1168  * dacf_minor_number()
1169  * 	given a dacf_infohdl_t, obtain the device minor number of the instance
1170  * 	being configured.
1171  */
1172 minor_t
dacf_minor_number(dacf_infohdl_t info_hdl)1173 dacf_minor_number(dacf_infohdl_t info_hdl)
1174 {
1175 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1176 
1177 	return (getminor(dmdp->ddm_dev));
1178 }
1179 
1180 /*
1181  * dacf_get_dev()
1182  *	given a dacf_infohdl_t, obtain the dev_t of the instance being
1183  *	configured.
1184  */
1185 dev_t
dacf_get_dev(dacf_infohdl_t info_hdl)1186 dacf_get_dev(dacf_infohdl_t info_hdl)
1187 {
1188 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1189 
1190 	return (dmdp->ddm_dev);
1191 }
1192 
1193 /*
1194  * dacf_driver_name()
1195  * 	given a dacf_infohdl_t, obtain the device driver name of the device
1196  * 	instance being configured.
1197  */
1198 const char *
dacf_driver_name(dacf_infohdl_t info_hdl)1199 dacf_driver_name(dacf_infohdl_t info_hdl)
1200 {
1201 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1202 
1203 	return (ddi_driver_name(dmdp->dip));
1204 }
1205 
1206 /*
1207  * dacf_devinfo_node()
1208  * 	given a dacf_infohdl_t, obtain the dev_info_t of the device instance
1209  * 	being configured.
1210  */
1211 dev_info_t *
dacf_devinfo_node(dacf_infohdl_t info_hdl)1212 dacf_devinfo_node(dacf_infohdl_t info_hdl)
1213 {
1214 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1215 
1216 	return (dmdp->dip);
1217 }
1218 
1219 /*
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.
1223  *
1224  * 	returns NULL if the argument is not found.
1225  */
1226 const char *
dacf_get_arg(dacf_arghdl_t arghdl,char * arg_name)1227 dacf_get_arg(dacf_arghdl_t arghdl, char *arg_name)
1228 {
1229 	dacf_arg_t *arg_list = (dacf_arg_t *)arghdl;
1230 	ASSERT(arg_name);
1231 
1232 	while (arg_list != NULL) {
1233 		if (strcmp(arg_list->arg_name, arg_name) == 0) {
1234 			return (arg_list->arg_val);
1235 		}
1236 		arg_list = arg_list->arg_next;
1237 	}
1238 
1239 	return (NULL);
1240 }
1241 
1242 /*
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.
1249  */
1250 void
dacf_store_info(dacf_infohdl_t info_hdl,void * data)1251 dacf_store_info(dacf_infohdl_t info_hdl, void *data)
1252 {
1253 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1254 
1255 	/*
1256 	 * If the client is 'storing NULL' we can represent that by blowing
1257 	 * the info entry out of the hash.
1258 	 */
1259 	if (data == NULL) {
1260 		(void) mod_hash_destroy(dacf_info_hash, (mod_hash_key_t)dmdp);
1261 	} else {
1262 		/*
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.
1265 		 */
1266 		(void) mod_hash_replace(dacf_info_hash, (mod_hash_key_t)dmdp,
1267 		    (mod_hash_val_t)data);
1268 	}
1269 }
1270 
1271 /*
1272  * dacf_retrieve_info()
1273  * 	retrieve instance-specific data associated with a device instance.
1274  */
1275 void *
dacf_retrieve_info(dacf_infohdl_t info_hdl)1276 dacf_retrieve_info(dacf_infohdl_t info_hdl)
1277 {
1278 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1279 	void *data;
1280 
1281 	if (mod_hash_find(dacf_info_hash, (mod_hash_key_t)dmdp,
1282 	    (mod_hash_val_t *)&data) != 0) {
1283 		return (NULL);
1284 	}
1285 
1286 	return (data);
1287 }
1288 
1289 /*
1290  * dacf_makevp()
1291  * 	make a vnode for the specified dacf_infohdl_t.
1292  */
1293 struct vnode *
dacf_makevp(dacf_infohdl_t info_hdl)1294 dacf_makevp(dacf_infohdl_t info_hdl)
1295 {
1296 	struct ddi_minor_data *dmdp = (struct ddi_minor_data *)info_hdl;
1297 	struct vnode	*vp;
1298 
1299 	vp = makespecvp(dmdp->ddm_dev, VCHR);
1300 	spec_assoc_vp_with_devi(vp, dmdp->dip);
1301 	return (vp);
1302 }
1303