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