xref: /illumos-gate/usr/src/uts/common/os/driver_lyr.c (revision 3db86aab)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Layered driver support.
31  */
32 
33 #include <sys/atomic.h>
34 #include <sys/types.h>
35 #include <sys/t_lock.h>
36 #include <sys/param.h>
37 #include <sys/conf.h>
38 #include <sys/systm.h>
39 #include <sys/sysmacros.h>
40 #include <sys/buf.h>
41 #include <sys/cred.h>
42 #include <sys/uio.h>
43 #include <sys/vnode.h>
44 #include <sys/fs/snode.h>
45 #include <sys/open.h>
46 #include <sys/kmem.h>
47 #include <sys/file.h>
48 #include <sys/bootconf.h>
49 #include <sys/pathname.h>
50 #include <sys/bitmap.h>
51 #include <sys/stat.h>
52 #include <sys/dditypes.h>
53 #include <sys/ddi_impldefs.h>
54 #include <sys/ddi.h>
55 #include <sys/sunddi.h>
56 #include <sys/sunndi.h>
57 #include <sys/esunddi.h>
58 #include <sys/autoconf.h>
59 #include <sys/sunldi.h>
60 #include <sys/sunldi_impl.h>
61 #include <sys/errno.h>
62 #include <sys/debug.h>
63 #include <sys/modctl.h>
64 #include <sys/var.h>
65 #include <vm/seg_vn.h>
66 
67 #include <sys/stropts.h>
68 #include <sys/strsubr.h>
69 #include <sys/socket.h>
70 #include <sys/socketvar.h>
71 #include <sys/kstr.h>
72 
73 
74 /*
75  * Define macros to manipulate snode, vnode, and open device flags
76  */
77 #define	VTYP_VALID(i)	(((i) == VCHR) || ((i) == VBLK))
78 #define	VTYP_TO_OTYP(i)	(((i) == VCHR) ? OTYP_CHR : OTYP_BLK)
79 #define	VTYP_TO_STYP(i)	(((i) == VCHR) ? S_IFCHR : S_IFBLK)
80 
81 #define	OTYP_VALID(i)	(((i) == OTYP_CHR) || ((i) == OTYP_BLK))
82 #define	OTYP_TO_VTYP(i)	(((i) == OTYP_CHR) ? VCHR : VBLK)
83 #define	OTYP_TO_STYP(i)	(((i) == OTYP_CHR) ? S_IFCHR : S_IFBLK)
84 
85 #define	STYP_VALID(i)	(((i) == S_IFCHR) || ((i) == S_IFBLK))
86 #define	STYP_TO_VTYP(i)	(((i) == S_IFCHR) ? VCHR : VBLK)
87 
88 /*
89  * Define macros for accessing layered driver hash structures
90  */
91 #define	LH_HASH(vp)		(handle_hash_func(vp) % LH_HASH_SZ)
92 #define	LI_HASH(mid, dip, dev)	(ident_hash_func(mid, dip, dev) % LI_HASH_SZ)
93 
94 /*
95  * Define layered handle flags used in the lh_type field
96  */
97 #define	LH_STREAM	(0x1)	/* handle to a streams device */
98 #define	LH_CBDEV	(0x2)	/* handle to a char/block device */
99 
100 /*
101  * Define marco for devid property lookups
102  */
103 #define	DEVID_PROP_FLAGS	(DDI_PROP_DONTPASS | \
104 				DDI_PROP_TYPE_STRING|DDI_PROP_CANSLEEP)
105 
106 
107 /*
108  * globals
109  */
110 static kmutex_t			ldi_ident_hash_lock[LI_HASH_SZ];
111 static struct ldi_ident		*ldi_ident_hash[LI_HASH_SZ];
112 
113 static kmutex_t			ldi_handle_hash_lock[LH_HASH_SZ];
114 static struct ldi_handle	*ldi_handle_hash[LH_HASH_SZ];
115 static size_t			ldi_handle_hash_count;
116 
117 void
118 ldi_init(void)
119 {
120 	int i;
121 
122 	ldi_handle_hash_count = 0;
123 	for (i = 0; i < LH_HASH_SZ; i++) {
124 		mutex_init(&ldi_handle_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
125 		ldi_handle_hash[i] = NULL;
126 	}
127 	for (i = 0; i < LI_HASH_SZ; i++) {
128 		mutex_init(&ldi_ident_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
129 		ldi_ident_hash[i] = NULL;
130 	}
131 }
132 
133 /*
134  * LDI ident manipulation functions
135  */
136 static uint_t
137 ident_hash_func(modid_t modid, dev_info_t *dip, dev_t dev)
138 {
139 	if (dip != NULL) {
140 		uintptr_t k = (uintptr_t)dip;
141 		k >>= (int)highbit(sizeof (struct dev_info));
142 		return ((uint_t)k);
143 	} else if (dev != DDI_DEV_T_NONE) {
144 		return (modid + getminor(dev) + getmajor(dev));
145 	} else {
146 		return (modid);
147 	}
148 }
149 
150 static struct ldi_ident **
151 ident_find_ref_nolock(modid_t modid, dev_info_t *dip, dev_t dev, major_t major)
152 {
153 	struct ldi_ident	**lipp = NULL;
154 	uint_t			index = LI_HASH(modid, dip, dev);
155 
156 	ASSERT(MUTEX_HELD(&ldi_ident_hash_lock[index]));
157 
158 	for (lipp = &(ldi_ident_hash[index]);
159 	    (*lipp != NULL);
160 	    lipp = &((*lipp)->li_next)) {
161 		if (((*lipp)->li_modid == modid) &&
162 		    ((*lipp)->li_major == major) &&
163 		    ((*lipp)->li_dip == dip) &&
164 		    ((*lipp)->li_dev == dev))
165 			break;
166 	}
167 
168 	ASSERT(lipp != NULL);
169 	return (lipp);
170 }
171 
172 static struct ldi_ident *
173 ident_alloc(char *mod_name, dev_info_t *dip, dev_t dev, major_t major)
174 {
175 	struct ldi_ident	*lip, **lipp;
176 	modid_t			modid;
177 	uint_t			index;
178 
179 	ASSERT(mod_name != NULL);
180 
181 	/* get the module id */
182 	modid = mod_name_to_modid(mod_name);
183 	ASSERT(modid != -1);
184 
185 	/* allocate a new ident in case we need it */
186 	lip = kmem_zalloc(sizeof (*lip), KM_SLEEP);
187 
188 	/* search the hash for a matching ident */
189 	index = LI_HASH(modid, dip, dev);
190 	mutex_enter(&ldi_ident_hash_lock[index]);
191 	lipp = ident_find_ref_nolock(modid, dip, dev, major);
192 
193 	if (*lipp != NULL) {
194 		/* we found an indent in the hash */
195 		ASSERT(strcmp((*lipp)->li_modname, mod_name) == 0);
196 		(*lipp)->li_ref++;
197 		mutex_exit(&ldi_ident_hash_lock[index]);
198 		kmem_free(lip, sizeof (struct ldi_ident));
199 		return (*lipp);
200 	}
201 
202 	/* initialize the new ident */
203 	lip->li_next = NULL;
204 	lip->li_ref = 1;
205 	lip->li_modid = modid;
206 	lip->li_major = major;
207 	lip->li_dip = dip;
208 	lip->li_dev = dev;
209 	(void) strncpy(lip->li_modname, mod_name, sizeof (lip->li_modname) - 1);
210 
211 	/* add it to the ident hash */
212 	lip->li_next = ldi_ident_hash[index];
213 	ldi_ident_hash[index] = lip;
214 
215 	mutex_exit(&ldi_ident_hash_lock[index]);
216 	return (lip);
217 }
218 
219 static void
220 ident_hold(struct ldi_ident *lip)
221 {
222 	uint_t			index;
223 
224 	ASSERT(lip != NULL);
225 	index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
226 	mutex_enter(&ldi_ident_hash_lock[index]);
227 	ASSERT(lip->li_ref > 0);
228 	lip->li_ref++;
229 	mutex_exit(&ldi_ident_hash_lock[index]);
230 }
231 
232 static void
233 ident_release(struct ldi_ident *lip)
234 {
235 	struct ldi_ident	**lipp;
236 	uint_t			index;
237 
238 	ASSERT(lip != NULL);
239 	index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
240 	mutex_enter(&ldi_ident_hash_lock[index]);
241 
242 	ASSERT(lip->li_ref > 0);
243 	if (--lip->li_ref > 0) {
244 		/* there are more references to this ident */
245 		mutex_exit(&ldi_ident_hash_lock[index]);
246 		return;
247 	}
248 
249 	/* this was the last reference/open for this ident.  free it. */
250 	lipp = ident_find_ref_nolock(
251 	    lip->li_modid, lip->li_dip, lip->li_dev, lip->li_major);
252 
253 	ASSERT((lipp != NULL) && (*lipp != NULL));
254 	*lipp = lip->li_next;
255 	mutex_exit(&ldi_ident_hash_lock[index]);
256 	kmem_free(lip, sizeof (struct ldi_ident));
257 }
258 
259 /*
260  * LDI handle manipulation functions
261  */
262 static uint_t
263 handle_hash_func(void *vp)
264 {
265 	uintptr_t k = (uintptr_t)vp;
266 	k >>= (int)highbit(sizeof (vnode_t));
267 	return ((uint_t)k);
268 }
269 
270 static struct ldi_handle **
271 handle_find_ref_nolock(vnode_t *vp, struct ldi_ident *ident)
272 {
273 	struct ldi_handle	**lhpp = NULL;
274 	uint_t			index = LH_HASH(vp);
275 
276 	ASSERT(MUTEX_HELD(&ldi_handle_hash_lock[index]));
277 
278 	for (lhpp = &(ldi_handle_hash[index]);
279 	    (*lhpp != NULL);
280 	    lhpp = &((*lhpp)->lh_next)) {
281 		if (((*lhpp)->lh_ident == ident) &&
282 		    ((*lhpp)->lh_vp == vp))
283 			break;
284 	}
285 
286 	ASSERT(lhpp != NULL);
287 	return (lhpp);
288 }
289 
290 static struct ldi_handle *
291 handle_find(vnode_t *vp, struct ldi_ident *ident)
292 {
293 	struct ldi_handle	**lhpp;
294 	int			index = LH_HASH(vp);
295 
296 	mutex_enter(&ldi_handle_hash_lock[index]);
297 	lhpp = handle_find_ref_nolock(vp, ident);
298 	mutex_exit(&ldi_handle_hash_lock[index]);
299 	ASSERT(lhpp != NULL);
300 	return (*lhpp);
301 }
302 
303 static struct ldi_handle *
304 handle_alloc(vnode_t *vp, struct ldi_ident *ident)
305 {
306 	struct ldi_handle	*lhp, **lhpp;
307 	uint_t			index;
308 
309 	ASSERT((vp != NULL) && (ident != NULL));
310 
311 	/* allocate a new handle in case we need it */
312 	lhp = kmem_zalloc(sizeof (*lhp), KM_SLEEP);
313 
314 	/* search the hash for a matching handle */
315 	index = LH_HASH(vp);
316 	mutex_enter(&ldi_handle_hash_lock[index]);
317 	lhpp = handle_find_ref_nolock(vp, ident);
318 
319 	if (*lhpp != NULL) {
320 		/* we found a handle in the hash */
321 		(*lhpp)->lh_ref++;
322 		mutex_exit(&ldi_handle_hash_lock[index]);
323 
324 		LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: dup "
325 			"lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
326 			(void *)*lhpp, (void *)ident, (void *)vp,
327 			mod_major_to_name(getmajor(vp->v_rdev)),
328 			getminor(vp->v_rdev)));
329 
330 		kmem_free(lhp, sizeof (struct ldi_handle));
331 		return (*lhpp);
332 	}
333 
334 	/* initialize the new handle */
335 	lhp->lh_ref = 1;
336 	lhp->lh_vp = vp;
337 	lhp->lh_ident = ident;
338 	mutex_init(lhp->lh_lock, NULL, MUTEX_DEFAULT, NULL);
339 
340 	/* set the device type for this handle */
341 	lhp->lh_type = 0;
342 	if (STREAMSTAB(getmajor(vp->v_rdev))) {
343 		ASSERT(vp->v_type == VCHR);
344 		lhp->lh_type |= LH_STREAM;
345 	} else {
346 		lhp->lh_type |= LH_CBDEV;
347 	}
348 
349 	/* get holds on other objects */
350 	ident_hold(ident);
351 	ASSERT(vp->v_count >= 1);
352 	VN_HOLD(vp);
353 
354 	/* add it to the handle hash */
355 	lhp->lh_next = ldi_handle_hash[index];
356 	ldi_handle_hash[index] = lhp;
357 	atomic_add_long(&ldi_handle_hash_count, 1);
358 
359 	LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: new "
360 		"lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
361 		(void *)lhp, (void *)ident, (void *)vp,
362 		mod_major_to_name(getmajor(vp->v_rdev)),
363 		getminor(vp->v_rdev)));
364 
365 	mutex_exit(&ldi_handle_hash_lock[index]);
366 	return (lhp);
367 }
368 
369 static void
370 handle_release(struct ldi_handle *lhp)
371 {
372 	struct ldi_handle	**lhpp;
373 	uint_t			index;
374 
375 	ASSERT(lhp != NULL);
376 
377 	index = LH_HASH(lhp->lh_vp);
378 	mutex_enter(&ldi_handle_hash_lock[index]);
379 
380 	LDI_ALLOCFREE((CE_WARN, "ldi handle release: "
381 		"lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
382 		(void *)lhp, (void *)lhp->lh_ident, (void *)lhp->lh_vp,
383 		mod_major_to_name(getmajor(lhp->lh_vp->v_rdev)),
384 		getminor(lhp->lh_vp->v_rdev)));
385 
386 	ASSERT(lhp->lh_ref > 0);
387 	if (--lhp->lh_ref > 0) {
388 		/* there are more references to this handle */
389 		mutex_exit(&ldi_handle_hash_lock[index]);
390 		return;
391 	}
392 
393 	/* this was the last reference/open for this handle.  free it. */
394 	lhpp = handle_find_ref_nolock(lhp->lh_vp, lhp->lh_ident);
395 	ASSERT((lhpp != NULL) && (*lhpp != NULL));
396 	*lhpp = lhp->lh_next;
397 	atomic_add_long(&ldi_handle_hash_count, -1);
398 	mutex_exit(&ldi_handle_hash_lock[index]);
399 
400 	VN_RELE(lhp->lh_vp);
401 	ident_release(lhp->lh_ident);
402 	mutex_destroy(lhp->lh_lock);
403 	kmem_free(lhp, sizeof (struct ldi_handle));
404 }
405 
406 /*
407  * LDI event manipulation functions
408  */
409 static void
410 handle_event_add(ldi_event_t *lep)
411 {
412 	struct ldi_handle *lhp = lep->le_lhp;
413 
414 	ASSERT(lhp != NULL);
415 
416 	mutex_enter(lhp->lh_lock);
417 	if (lhp->lh_events == NULL) {
418 		lhp->lh_events = lep;
419 		mutex_exit(lhp->lh_lock);
420 		return;
421 	}
422 
423 	lep->le_next = lhp->lh_events;
424 	lhp->lh_events->le_prev = lep;
425 	lhp->lh_events = lep;
426 	mutex_exit(lhp->lh_lock);
427 }
428 
429 static void
430 handle_event_remove(ldi_event_t *lep)
431 {
432 	struct ldi_handle *lhp = lep->le_lhp;
433 
434 	ASSERT(lhp != NULL);
435 
436 	mutex_enter(lhp->lh_lock);
437 	if (lep->le_prev)
438 		lep->le_prev->le_next = lep->le_next;
439 	if (lep->le_next)
440 		lep->le_next->le_prev = lep->le_prev;
441 	if (lhp->lh_events == lep)
442 		lhp->lh_events = lep->le_next;
443 	mutex_exit(lhp->lh_lock);
444 
445 }
446 
447 static void
448 i_ldi_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie,
449     void *arg, void *bus_impldata)
450 {
451 	ldi_event_t *lep = (ldi_event_t *)arg;
452 
453 	ASSERT(lep != NULL);
454 
455 	LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, "
456 	    "event_cookie=0x%p, ldi_eventp=0x%p", "i_ldi_callback",
457 	    (void *)dip, (void *)event_cookie, (void *)lep));
458 
459 	lep->le_handler(lep->le_lhp, event_cookie, lep->le_arg, bus_impldata);
460 }
461 
462 /*
463  * LDI open helper functions
464  */
465 
466 /* get a vnode to a device by dev_t and otyp */
467 static int
468 ldi_vp_from_dev(dev_t dev, int otyp, vnode_t **vpp)
469 {
470 	dev_info_t		*dip;
471 	vnode_t			*vp;
472 
473 	/* sanity check required input parameters */
474 	if ((dev == DDI_DEV_T_NONE) || (!OTYP_VALID(otyp)) || (vpp == NULL))
475 		return (EINVAL);
476 
477 	if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
478 		return (ENODEV);
479 
480 	if (STREAMSTAB(getmajor(dev)) && (otyp != OTYP_CHR)) {
481 		ddi_release_devi(dip);  /* from e_ddi_hold_devi_by_dev */
482 		return (ENXIO);
483 	}
484 
485 	vp = makespecvp(dev, OTYP_TO_VTYP(otyp));
486 	spec_assoc_vp_with_devi(vp, dip);
487 	ddi_release_devi(dip);  /* from e_ddi_hold_devi_by_dev */
488 
489 	*vpp = vp;
490 	return (0);
491 }
492 
493 /* get a vnode to a device by pathname */
494 static int
495 ldi_vp_from_name(char *path, vnode_t **vpp)
496 {
497 	vnode_t			*vp = NULL;
498 	int			ret;
499 
500 	/* sanity check required input parameters */
501 	if ((path == NULL) || (vpp == NULL))
502 		return (EINVAL);
503 
504 	if (modrootloaded) {
505 		cred_t *saved_cred = curthread->t_cred;
506 
507 		/* we don't want lookupname to fail because of credentials */
508 		curthread->t_cred = kcred;
509 
510 		/*
511 		 * all lookups should be done in the global zone.  but
512 		 * lookupnameat() won't actually do this if an absolute
513 		 * path is passed in.  since the ldi interfaces require an
514 		 * absolute path we pass lookupnameat() a pointer to
515 		 * the character after the leading '/' and tell it to
516 		 * start searching at the current system root directory.
517 		 */
518 		ASSERT(*path == '/');
519 		ret = lookupnameat(path + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
520 		    &vp, rootdir);
521 
522 		/* restore this threads credentials */
523 		curthread->t_cred = saved_cred;
524 
525 		if (ret == 0) {
526 			if (!vn_matchops(vp, spec_getvnodeops()) ||
527 			    !VTYP_VALID(vp->v_type)) {
528 				VN_RELE(vp);
529 				return (ENXIO);
530 			}
531 		}
532 	}
533 
534 	if (vp == NULL) {
535 		dev_info_t	*dip;
536 		dev_t		dev;
537 		int		spec_type;
538 
539 		/*
540 		 * Root is not mounted, the minor node is not specified,
541 		 * or an OBP path has been specified.
542 		 */
543 
544 		/*
545 		 * Determine if path can be pruned to produce an
546 		 * OBP or devfs path for resolve_pathname.
547 		 */
548 		if (strncmp(path, "/devices/", 9) == 0)
549 			path += strlen("/devices");
550 
551 		/*
552 		 * if no minor node was specified the DEFAULT minor node
553 		 * will be returned.  if there is no DEFAULT minor node
554 		 * one will be fabricated of type S_IFCHR with the minor
555 		 * number equal to the instance number.
556 		 */
557 		ret = resolve_pathname(path, &dip, &dev, &spec_type);
558 		if (ret != 0)
559 			return (ENODEV);
560 
561 		ASSERT(STYP_VALID(spec_type));
562 		vp = makespecvp(dev, STYP_TO_VTYP(spec_type));
563 		spec_assoc_vp_with_devi(vp, dip);
564 		ddi_release_devi(dip);
565 	}
566 
567 	*vpp = vp;
568 	return (0);
569 }
570 
571 static int
572 ldi_devid_match(ddi_devid_t devid, dev_info_t *dip, dev_t dev)
573 {
574 	char		*devidstr;
575 	ddi_prop_t	*propp;
576 
577 	/* convert devid as a string property */
578 	if ((devidstr = ddi_devid_str_encode(devid, NULL)) == NULL)
579 		return (0);
580 
581 	/*
582 	 * Search for the devid.  For speed and ease in locking this
583 	 * code directly uses the property implementation.  See
584 	 * ddi_common_devid_to_devlist() for a comment as to why.
585 	 */
586 	mutex_enter(&(DEVI(dip)->devi_lock));
587 
588 	/* check if there is a DDI_DEV_T_NONE devid property */
589 	propp = i_ddi_prop_search(DDI_DEV_T_NONE,
590 	    DEVID_PROP_NAME, DEVID_PROP_FLAGS, &DEVI(dip)->devi_hw_prop_ptr);
591 	if (propp != NULL) {
592 		if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
593 			/* a DDI_DEV_T_NONE devid exists and matchs */
594 			mutex_exit(&(DEVI(dip)->devi_lock));
595 			ddi_devid_str_free(devidstr);
596 			return (1);
597 		} else {
598 			/* a DDI_DEV_T_NONE devid exists and doesn't match */
599 			mutex_exit(&(DEVI(dip)->devi_lock));
600 			ddi_devid_str_free(devidstr);
601 			return (0);
602 		}
603 	}
604 
605 	/* check if there is a devt specific devid property */
606 	propp = i_ddi_prop_search(dev,
607 	    DEVID_PROP_NAME, DEVID_PROP_FLAGS, &(DEVI(dip)->devi_hw_prop_ptr));
608 	if (propp != NULL) {
609 		if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
610 			/* a devt specific devid exists and matchs */
611 			mutex_exit(&(DEVI(dip)->devi_lock));
612 			ddi_devid_str_free(devidstr);
613 			return (1);
614 		} else {
615 			/* a devt specific devid exists and doesn't match */
616 			mutex_exit(&(DEVI(dip)->devi_lock));
617 			ddi_devid_str_free(devidstr);
618 			return (0);
619 		}
620 	}
621 
622 	/* we didn't find any devids associated with the device */
623 	mutex_exit(&(DEVI(dip)->devi_lock));
624 	ddi_devid_str_free(devidstr);
625 	return (0);
626 }
627 
628 /* get a handle to a device by devid and minor name */
629 static int
630 ldi_vp_from_devid(ddi_devid_t devid, char *minor_name, vnode_t **vpp)
631 {
632 	dev_info_t		*dip;
633 	vnode_t			*vp;
634 	int			ret, i, ndevs, styp;
635 	dev_t			dev, *devs;
636 
637 	/* sanity check required input parameters */
638 	if ((devid == NULL) || (minor_name == NULL) || (vpp == NULL))
639 		return (EINVAL);
640 
641 	ret = ddi_lyr_devid_to_devlist(devid, minor_name, &ndevs, &devs);
642 	if ((ret != DDI_SUCCESS) || (ndevs <= 0))
643 		return (ENODEV);
644 
645 	for (i = 0; i < ndevs; i++) {
646 		dev = devs[i];
647 
648 		if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
649 			continue;
650 
651 		/*
652 		 * now we have to verify that the devid of the disk
653 		 * still matches what was requested.
654 		 *
655 		 * we have to do this because the devid could have
656 		 * changed between the call to ddi_lyr_devid_to_devlist()
657 		 * and e_ddi_hold_devi_by_dev().  this is because when
658 		 * ddi_lyr_devid_to_devlist() returns a list of devts
659 		 * there is no kind of hold on those devts so a device
660 		 * could have been replaced out from under us in the
661 		 * interim.
662 		 */
663 		if ((i_ddi_minorname_to_devtspectype(dip, minor_name,
664 		    NULL, &styp) == DDI_SUCCESS) &&
665 		    ldi_devid_match(devid, dip, dev))
666 			break;
667 
668 		ddi_release_devi(dip);	/* from e_ddi_hold_devi_by_dev() */
669 	}
670 
671 	ddi_lyr_free_devlist(devs, ndevs);
672 
673 	if (i == ndevs)
674 		return (ENODEV);
675 
676 	ASSERT(STYP_VALID(styp));
677 	vp = makespecvp(dev, STYP_TO_VTYP(styp));
678 	spec_assoc_vp_with_devi(vp, dip);
679 	ddi_release_devi(dip);		/* from e_ddi_hold_devi_by_dev */
680 
681 	*vpp = vp;
682 	return (0);
683 }
684 
685 /* given a vnode, open a device */
686 static int
687 ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
688     ldi_handle_t *lhp, struct ldi_ident *li)
689 {
690 	struct ldi_handle	*nlhp;
691 	vnode_t			*vp;
692 	int			err;
693 
694 	ASSERT((vpp != NULL) && (*vpp != NULL));
695 	ASSERT((lhp != NULL) && (li != NULL));
696 
697 	vp = *vpp;
698 	/* if the vnode passed in is not a device, then bail */
699 	if (!vn_matchops(vp, spec_getvnodeops()) || !VTYP_VALID(vp->v_type))
700 		return (ENXIO);
701 
702 	/*
703 	 * the caller may have specified a node that
704 	 * doesn't have cb_ops defined.  the ldi doesn't yet
705 	 * support opening devices without a valid cb_ops.
706 	 */
707 	if (devopsp[getmajor(vp->v_rdev)]->devo_cb_ops == NULL)
708 		return (ENXIO);
709 
710 	/* open the device */
711 	if ((err = VOP_OPEN(&vp, flag | FKLYR, cr)) != 0)
712 		return (err);
713 
714 	/* possible clone open, make sure that we still have a spec node */
715 	ASSERT(vn_matchops(vp, spec_getvnodeops()));
716 
717 	nlhp = handle_alloc(vp, li);
718 
719 	if (vp != *vpp) {
720 		/*
721 		 * allocating the layered handle took a new hold on the vnode
722 		 * so we can release the hold that was returned by the clone
723 		 * open
724 		 */
725 		LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
726 			"ldi clone open", (void *)nlhp));
727 	} else {
728 		LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
729 			"ldi open", (void *)nlhp));
730 	}
731 
732 	/* Flush back any dirty pages associated with the device. */
733 	if (nlhp->lh_type & LH_CBDEV) {
734 		vnode_t	*cvp = common_specvp(nlhp->lh_vp);
735 		dev_t	dev = cvp->v_rdev;
736 
737 		(void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred);
738 		bflush(dev);
739 	}
740 
741 	*vpp = vp;
742 	*lhp = (ldi_handle_t)nlhp;
743 	return (0);
744 }
745 
746 /* Call a drivers prop_op(9E) interface */
747 static int
748 i_ldi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
749     int flags, char *name, caddr_t valuep, int *lengthp)
750 {
751 	struct dev_ops	*ops = NULL;
752 	int		res;
753 
754 	ASSERT((dip != NULL) && (name != NULL));
755 	ASSERT((prop_op == PROP_LEN) || (valuep != NULL));
756 	ASSERT(lengthp != NULL);
757 
758 	/*
759 	 * we can only be invoked after a driver has been opened and
760 	 * someone has a layered handle to it, so there had better be
761 	 * a valid ops vector.
762 	 */
763 	ops = DEVI(dip)->devi_ops;
764 	ASSERT(ops && ops->devo_cb_ops);
765 
766 	/*
767 	 * Some nexus drivers incorrectly set cb_prop_op to nodev,
768 	 * nulldev or even NULL.
769 	 */
770 	if ((ops->devo_cb_ops->cb_prop_op == nodev) ||
771 	    (ops->devo_cb_ops->cb_prop_op == nulldev) ||
772 	    (ops->devo_cb_ops->cb_prop_op == NULL)) {
773 		return (DDI_PROP_NOT_FOUND);
774 	}
775 
776 	/* check if this is actually DDI_DEV_T_ANY query */
777 	if (flags & LDI_DEV_T_ANY) {
778 		flags &= ~LDI_DEV_T_ANY;
779 		dev = DDI_DEV_T_ANY;
780 	}
781 
782 	res = cdev_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp);
783 	return (res);
784 }
785 
786 static void
787 i_ldi_prop_op_free(struct prop_driver_data *pdd)
788 {
789 	kmem_free(pdd, pdd->pdd_size);
790 }
791 
792 static caddr_t
793 i_ldi_prop_op_alloc(int prop_len)
794 {
795 	struct prop_driver_data	*pdd;
796 	int			pdd_size;
797 
798 	pdd_size = sizeof (struct prop_driver_data) + prop_len;
799 	pdd = kmem_alloc(pdd_size, KM_SLEEP);
800 	pdd->pdd_size = pdd_size;
801 	pdd->pdd_prop_free = i_ldi_prop_op_free;
802 	return ((caddr_t)&pdd[1]);
803 }
804 
805 /*
806  * i_ldi_prop_op_typed() is a wrapper for i_ldi_prop_op that is used
807  * by the typed ldi property lookup interfaces.
808  */
809 static int
810 i_ldi_prop_op_typed(dev_t dev, dev_info_t *dip, int flags, char *name,
811     caddr_t *datap, int *lengthp, int elem_size)
812 {
813 	caddr_t	prop_val;
814 	int	prop_len, res;
815 
816 	ASSERT((dip != NULL) && (name != NULL));
817 	ASSERT((datap != NULL) && (lengthp != NULL));
818 
819 	/*
820 	 * first call the drivers prop_op() interface to allow it
821 	 * it to override default property values.
822 	 */
823 	res = i_ldi_prop_op(dev, dip, PROP_LEN,
824 	    flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
825 	if (res != DDI_PROP_SUCCESS)
826 		return (DDI_PROP_NOT_FOUND);
827 
828 	/* sanity check the property length */
829 	if (prop_len == 0) {
830 		/*
831 		 * the ddi typed interfaces don't allow a drivers to
832 		 * create properties with a length of 0.  so we should
833 		 * prevent drivers from returning 0 length dynamic
834 		 * properties for typed property lookups.
835 		 */
836 		return (DDI_PROP_NOT_FOUND);
837 	}
838 
839 	/* sanity check the property length against the element size */
840 	if (elem_size && ((prop_len % elem_size) != 0))
841 		return (DDI_PROP_NOT_FOUND);
842 
843 	/*
844 	 * got it.  now allocate a prop_driver_data struct so that the
845 	 * user can free the property via ddi_prop_free().
846 	 */
847 	prop_val = i_ldi_prop_op_alloc(prop_len);
848 
849 	/* lookup the property again, this time get the value */
850 	res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
851 	    flags | DDI_PROP_DYNAMIC, name, prop_val, &prop_len);
852 	if (res != DDI_PROP_SUCCESS) {
853 		ddi_prop_free(prop_val);
854 		return (DDI_PROP_NOT_FOUND);
855 	}
856 
857 	/* sanity check the property length */
858 	if (prop_len == 0) {
859 		ddi_prop_free(prop_val);
860 		return (DDI_PROP_NOT_FOUND);
861 	}
862 
863 	/* sanity check the property length against the element size */
864 	if (elem_size && ((prop_len % elem_size) != 0)) {
865 		ddi_prop_free(prop_val);
866 		return (DDI_PROP_NOT_FOUND);
867 	}
868 
869 	/*
870 	 * return the prop_driver_data struct and, optionally, the length
871 	 * of the data.
872 	 */
873 	*datap = prop_val;
874 	*lengthp = prop_len;
875 
876 	return (DDI_PROP_SUCCESS);
877 }
878 
879 /*
880  * i_check_string looks at a string property and makes sure its
881  * a valid null terminated string
882  */
883 static int
884 i_check_string(char *str, int prop_len)
885 {
886 	int i;
887 
888 	ASSERT(str != NULL);
889 
890 	for (i = 0; i < prop_len; i++) {
891 		if (str[i] == '\0')
892 			return (0);
893 	}
894 	return (1);
895 }
896 
897 /*
898  * i_pack_string_array takes a a string array property that is represented
899  * as a concatination of strings (with the NULL character included for
900  * each string) and converts it into a format that can be returned by
901  * ldi_prop_lookup_string_array.
902  */
903 static int
904 i_pack_string_array(char *str_concat, int prop_len,
905     char ***str_arrayp, int *nelemp)
906 {
907 	int i, nelem, pack_size;
908 	char **str_array, *strptr;
909 
910 	/*
911 	 * first we need to sanity check the input string array.
912 	 * in essence this can be done my making sure that the last
913 	 * character of the array passed in is null.  (meaning the last
914 	 * string in the array is NULL terminated.
915 	 */
916 	if (str_concat[prop_len - 1] != '\0')
917 		return (1);
918 
919 	/* now let's count the number of strings in the array */
920 	for (nelem = i = 0; i < prop_len; i++)
921 		if (str_concat[i] == '\0')
922 			nelem++;
923 	ASSERT(nelem >= 1);
924 
925 	/* now let's allocate memory for the new packed property */
926 	pack_size = (sizeof (char *) * (nelem + 1)) + prop_len;
927 	str_array = (char **)i_ldi_prop_op_alloc(pack_size);
928 
929 	/* let's copy the actual string data into the new property */
930 	strptr = (char *)&(str_array[nelem + 1]);
931 	bcopy(str_concat, strptr, prop_len);
932 
933 	/* now initialize the string array pointers */
934 	for (i = 0; i < nelem; i++) {
935 		str_array[i] = strptr;
936 		strptr += strlen(strptr) + 1;
937 	}
938 	str_array[nelem] = NULL;
939 
940 	/* set the return values */
941 	*str_arrayp = str_array;
942 	*nelemp = nelem;
943 
944 	return (0);
945 }
946 
947 
948 /*
949  * LDI Project private device usage interfaces
950  */
951 
952 /*
953  * Get a count of how many devices are currentl open by different consumers
954  */
955 int
956 ldi_usage_count()
957 {
958 	return (ldi_handle_hash_count);
959 }
960 
961 static void
962 ldi_usage_walker_tgt_helper(ldi_usage_t *ldi_usage, vnode_t *vp)
963 {
964 	dev_info_t	*dip;
965 	dev_t		dev;
966 
967 	ASSERT(STYP_VALID(VTYP_TO_STYP(vp->v_type)));
968 
969 	/* get the target devt */
970 	dev = vp->v_rdev;
971 
972 	/* try to get the target dip */
973 	dip = VTOCS(vp)->s_dip;
974 	if (dip != NULL) {
975 		e_ddi_hold_devi(dip);
976 	} else if (dev != DDI_DEV_T_NONE) {
977 		dip = e_ddi_hold_devi_by_dev(dev, 0);
978 	}
979 
980 	/* set the target information */
981 	ldi_usage->tgt_name = mod_major_to_name(getmajor(dev));
982 	ldi_usage->tgt_modid = mod_name_to_modid(ldi_usage->tgt_name);
983 	ldi_usage->tgt_devt = dev;
984 	ldi_usage->tgt_spec_type = VTYP_TO_STYP(vp->v_type);
985 	ldi_usage->tgt_dip = dip;
986 }
987 
988 
989 static int
990 ldi_usage_walker_helper(struct ldi_ident *lip, vnode_t *vp,
991     void *arg, int (*callback)(const ldi_usage_t *, void *))
992 {
993 	ldi_usage_t	ldi_usage;
994 	struct devnames	*dnp;
995 	dev_info_t	*dip;
996 	major_t		major;
997 	dev_t		dev;
998 	int		ret = LDI_USAGE_CONTINUE;
999 
1000 	/* set the target device information */
1001 	ldi_usage_walker_tgt_helper(&ldi_usage, vp);
1002 
1003 	/* get the source devt */
1004 	dev = lip->li_dev;
1005 
1006 	/* try to get the source dip */
1007 	dip = lip->li_dip;
1008 	if (dip != NULL) {
1009 		e_ddi_hold_devi(dip);
1010 	} else if (dev != DDI_DEV_T_NONE) {
1011 		dip = e_ddi_hold_devi_by_dev(dev, 0);
1012 	}
1013 
1014 	/* set the valid source information */
1015 	ldi_usage.src_modid = lip->li_modid;
1016 	ldi_usage.src_name = lip->li_modname;
1017 	ldi_usage.src_devt = dev;
1018 	ldi_usage.src_dip = dip;
1019 
1020 	/*
1021 	 * if the source ident represents either:
1022 	 *
1023 	 * - a kernel module (and not a device or device driver)
1024 	 * - a device node
1025 	 *
1026 	 * then we currently have all the info we need to report the
1027 	 * usage information so invoke the callback function.
1028 	 */
1029 	if (((lip->li_major == -1) && (dev == DDI_DEV_T_NONE)) ||
1030 	    (dip != NULL)) {
1031 		ret = callback(&ldi_usage, arg);
1032 		if (dip != NULL)
1033 			ddi_release_devi(dip);
1034 		if (ldi_usage.tgt_dip != NULL)
1035 			ddi_release_devi(ldi_usage.tgt_dip);
1036 		return (ret);
1037 	}
1038 
1039 	/*
1040 	 * now this is kinda gross.
1041 	 *
1042 	 * what we do here is attempt to associate every device instance
1043 	 * of the source driver on the system with the open target driver.
1044 	 * we do this because we don't know which instance of the device
1045 	 * could potentially access the lower device so we assume that all
1046 	 * the instances could access it.
1047 	 *
1048 	 * there are two ways we could have gotten here:
1049 	 *
1050 	 * 1) this layered ident represents one created using only a
1051 	 *    major number or a driver module name.  this means that when
1052 	 *    it was created we could not associate it with a particular
1053 	 *    dev_t or device instance.
1054 	 *
1055 	 *    when could this possibly happen you ask?
1056 	 *
1057 	 *    a perfect example of this is streams persistent links.
1058 	 *    when a persistant streams link is formed we can't associate
1059 	 *    the lower device stream with any particular upper device
1060 	 *    stream or instance.  this is because any particular upper
1061 	 *    device stream could be closed, then another could be
1062 	 *    opened with a different dev_t and device instance, and it
1063 	 *    would still have access to the lower linked stream.
1064 	 *
1065 	 *    since any instance of the upper streams driver could
1066 	 *    potentially access the lower stream whenever it wants,
1067 	 *    we represent that here by associating the opened lower
1068 	 *    device with every existing device instance of the upper
1069 	 *    streams driver.
1070 	 *
1071 	 * 2) This case should really never happen but we'll include it
1072 	 *    for completeness.
1073 	 *
1074 	 *    it's possible that we could have gotten here because we
1075 	 *    have a dev_t for the upper device but we couldn't find a
1076 	 *    dip associated with that dev_t.
1077 	 *
1078 	 *    the only types of devices that have dev_t without an
1079 	 *    associated dip are unbound DLPIv2 network devices.  These
1080 	 *    types of devices exist to be able to attach a stream to any
1081 	 *    instance of a hardware network device.  since these types of
1082 	 *    devices are usually hardware devices they should never
1083 	 *    really have other devices open.
1084 	 */
1085 	if (dev != DDI_DEV_T_NONE)
1086 		major = getmajor(dev);
1087 	else
1088 		major = lip->li_major;
1089 
1090 	ASSERT((major >= 0) && (major < devcnt));
1091 
1092 	dnp = &devnamesp[major];
1093 	LOCK_DEV_OPS(&dnp->dn_lock);
1094 	dip = dnp->dn_head;
1095 	while ((dip) && (ret == LDI_USAGE_CONTINUE)) {
1096 		e_ddi_hold_devi(dip);
1097 		UNLOCK_DEV_OPS(&dnp->dn_lock);
1098 
1099 		/* set the source dip */
1100 		ldi_usage.src_dip = dip;
1101 
1102 		/* invoke the callback function */
1103 		ret = callback(&ldi_usage, arg);
1104 
1105 		LOCK_DEV_OPS(&dnp->dn_lock);
1106 		ddi_release_devi(dip);
1107 		dip = ddi_get_next(dip);
1108 	}
1109 	UNLOCK_DEV_OPS(&dnp->dn_lock);
1110 
1111 	/* if there was a target dip, release it */
1112 	if (ldi_usage.tgt_dip != NULL)
1113 		ddi_release_devi(ldi_usage.tgt_dip);
1114 
1115 	return (ret);
1116 }
1117 
1118 /*
1119  * ldi_usage_walker() - this walker reports LDI kernel device usage
1120  * information via the callback() callback function.  the LDI keeps track
1121  * of what devices are being accessed in its own internal data structures.
1122  * this function walks those data structures to determine device usage.
1123  */
1124 void
1125 ldi_usage_walker(void *arg, int (*callback)(const ldi_usage_t *, void *))
1126 {
1127 	struct ldi_handle	*lhp;
1128 	struct ldi_ident	*lip;
1129 	vnode_t			*vp;
1130 	int			i;
1131 	int			ret = LDI_USAGE_CONTINUE;
1132 
1133 	for (i = 0; i < LH_HASH_SZ; i++) {
1134 		mutex_enter(&ldi_handle_hash_lock[i]);
1135 
1136 		lhp = ldi_handle_hash[i];
1137 		while ((lhp != NULL) && (ret == LDI_USAGE_CONTINUE)) {
1138 			lip = lhp->lh_ident;
1139 			vp = lhp->lh_vp;
1140 
1141 			/* invoke the devinfo callback function */
1142 			ret = ldi_usage_walker_helper(lip, vp, arg, callback);
1143 
1144 			lhp = lhp->lh_next;
1145 		}
1146 		mutex_exit(&ldi_handle_hash_lock[i]);
1147 
1148 		if (ret != LDI_USAGE_CONTINUE)
1149 			break;
1150 	}
1151 }
1152 
1153 /*
1154  * LDI Project private interfaces (streams linking interfaces)
1155  *
1156  * Streams supports a type of built in device layering via linking.
1157  * Certain types of streams drivers can be streams multiplexors.
1158  * A streams multiplexor supports the I_LINK/I_PLINK operation.
1159  * These operations allows other streams devices to be linked under the
1160  * multiplexor.  By definition all streams multiplexors are devices
1161  * so this linking is a type of device layering where the multiplexor
1162  * device is layered on top of the device linked below it.
1163  */
1164 
1165 /*
1166  * ldi_mlink_lh() is invoked when streams are linked using LDI handles.
1167  * It is not used for normal I_LINKs and I_PLINKs using file descriptors.
1168  *
1169  * The streams framework keeps track of links via the file_t of the lower
1170  * stream.  The LDI keeps track of devices using a vnode.  In the case
1171  * of a streams link created via an LDI handle, fnk_lh() allocates
1172  * a file_t that the streams framework can use to track the linkage.
1173  */
1174 int
1175 ldi_mlink_lh(vnode_t *vp, int cmd, intptr_t arg, cred_t *crp, int *rvalp)
1176 {
1177 	struct ldi_handle	*lhp = (struct ldi_handle *)arg;
1178 	vnode_t			*vpdown;
1179 	file_t			*fpdown;
1180 	int			err;
1181 
1182 	if (lhp == NULL)
1183 		return (EINVAL);
1184 
1185 	vpdown = lhp->lh_vp;
1186 	ASSERT(vn_matchops(vpdown, spec_getvnodeops()));
1187 	ASSERT(cmd == _I_PLINK_LH);
1188 
1189 	/*
1190 	 * create a new lower vnode and a file_t that points to it,
1191 	 * streams linking requires a file_t.  falloc() returns with
1192 	 * fpdown locked.
1193 	 */
1194 	VN_HOLD(vpdown);
1195 	(void) falloc(vpdown, FREAD|FWRITE, &fpdown, NULL);
1196 	mutex_exit(&fpdown->f_tlock);
1197 
1198 	/* try to establish the link */
1199 	err = mlink_file(vp, I_PLINK, fpdown, crp, rvalp, 1);
1200 
1201 	if (err != 0) {
1202 		/* the link failed, free the file_t and release the vnode */
1203 		mutex_enter(&fpdown->f_tlock);
1204 		unfalloc(fpdown);
1205 		VN_RELE(vpdown);
1206 	}
1207 
1208 	return (err);
1209 }
1210 
1211 /*
1212  * ldi_mlink_fp() is invoked for all successfull streams linkages created
1213  * via I_LINK and I_PLINK.  ldi_mlink_fp() records the linkage information
1214  * in its internal state so that the devinfo snapshot code has some
1215  * observability into streams device linkage information.
1216  */
1217 void
1218 ldi_mlink_fp(struct stdata *stp, file_t *fpdown, int lhlink, int type)
1219 {
1220 	vnode_t			*vp = fpdown->f_vnode;
1221 	struct snode		*sp, *csp;
1222 	ldi_ident_t		li;
1223 	major_t			major;
1224 	int			ret;
1225 
1226 	/* if the lower stream is not a device then return */
1227 	if (!vn_matchops(vp, spec_getvnodeops()))
1228 		return;
1229 
1230 	ASSERT(!servicing_interrupt());
1231 
1232 	LDI_STREAMS_LNK((CE_NOTE, "%s: linking streams "
1233 		"stp=0x%p, fpdown=0x%p", "ldi_mlink_fp",
1234 		(void *)stp, (void *)fpdown));
1235 
1236 	sp = VTOS(vp);
1237 	csp = VTOS(sp->s_commonvp);
1238 
1239 	/* check if this was a plink via a layered handle */
1240 	if (lhlink) {
1241 		/*
1242 		 * increment the common snode s_count.
1243 		 *
1244 		 * this is done because after the link operation there
1245 		 * are two ways that s_count can be decremented.
1246 		 *
1247 		 * when the layered handle used to create the link is
1248 		 * closed, spec_close() is called and it will decrement
1249 		 * s_count in the common snode.  if we don't increment
1250 		 * s_count here then this could cause spec_close() to
1251 		 * actually close the device while it's still linked
1252 		 * under a multiplexer.
1253 		 *
1254 		 * also, when the lower stream is unlinked, closef() is
1255 		 * called for the file_t associated with this snode.
1256 		 * closef() will call spec_close(), which will decrement
1257 		 * s_count.  if we dont't increment s_count here then this
1258 		 * could cause spec_close() to actually close the device
1259 		 * while there may still be valid layered handles
1260 		 * pointing to it.
1261 		 */
1262 		mutex_enter(&csp->s_lock);
1263 		ASSERT(csp->s_count >= 1);
1264 		csp->s_count++;
1265 		mutex_exit(&csp->s_lock);
1266 
1267 		/*
1268 		 * decrement the f_count.
1269 		 * this is done because the layered driver framework does
1270 		 * not actually cache a copy of the file_t allocated to
1271 		 * do the link.  this is done here instead of in ldi_mlink_lh()
1272 		 * because there is a window in ldi_mlink_lh() between where
1273 		 * milnk_file() returns and we would decrement the f_count
1274 		 * when the stream could be unlinked.
1275 		 */
1276 		mutex_enter(&fpdown->f_tlock);
1277 		fpdown->f_count--;
1278 		mutex_exit(&fpdown->f_tlock);
1279 	}
1280 
1281 	/*
1282 	 * NOTE: here we rely on the streams subsystem not allowing
1283 	 * a stream to be multiplexed more than once.  if this
1284 	 * changes, we break.
1285 	 *
1286 	 * mark the snode/stream as multiplexed
1287 	 */
1288 	mutex_enter(&sp->s_lock);
1289 	ASSERT(!(sp->s_flag & SMUXED));
1290 	sp->s_flag |= SMUXED;
1291 	mutex_exit(&sp->s_lock);
1292 
1293 	/* get a layered ident for the upper stream */
1294 	if (type == LINKNORMAL) {
1295 		/*
1296 		 * if the link is not persistant then we can associate
1297 		 * the upper stream with a dev_t.  this is because the
1298 		 * upper stream is associated with a vnode, which is
1299 		 * associated with a dev_t and this binding can't change
1300 		 * during the life of the stream.  since the link isn't
1301 		 * persistant once the stream is destroyed the link is
1302 		 * destroyed.  so the dev_t will be valid for the life
1303 		 * of the link.
1304 		 */
1305 		ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
1306 	} else {
1307 		/*
1308 		 * if the link is persistant we can only associate the
1309 		 * link with a driver (and not a dev_t.)  this is
1310 		 * because subsequent opens of the upper device may result
1311 		 * in a different stream (and dev_t) having access to
1312 		 * the lower stream.
1313 		 *
1314 		 * for example, if the upper stream is closed after the
1315 		 * persistant link operation is compleated, a subsequent
1316 		 * open of the upper device will create a new stream which
1317 		 * may have a different dev_t and an unlink operation
1318 		 * can be performed using this new upper stream.
1319 		 */
1320 		ASSERT(type == LINKPERSIST);
1321 		major = getmajor(stp->sd_vnode->v_rdev);
1322 		ret = ldi_ident_from_major(major, &li);
1323 	}
1324 
1325 	ASSERT(ret == 0);
1326 	(void) handle_alloc(vp, (struct ldi_ident *)li);
1327 	ldi_ident_release(li);
1328 }
1329 
1330 void
1331 ldi_munlink_fp(struct stdata *stp, file_t *fpdown, int type)
1332 {
1333 	struct ldi_handle	*lhp;
1334 	vnode_t			*vp = (vnode_t *)fpdown->f_vnode;
1335 	struct snode		*sp;
1336 	ldi_ident_t		li;
1337 	major_t			major;
1338 	int			ret;
1339 
1340 	/* if the lower stream is not a device then return */
1341 	if (!vn_matchops(vp, spec_getvnodeops()))
1342 		return;
1343 
1344 	ASSERT(!servicing_interrupt());
1345 	ASSERT((type == LINKNORMAL) || (type == LINKPERSIST));
1346 
1347 	LDI_STREAMS_LNK((CE_NOTE, "%s: unlinking streams "
1348 		"stp=0x%p, fpdown=0x%p", "ldi_munlink_fp",
1349 		(void *)stp, (void *)fpdown));
1350 
1351 	/*
1352 	 * NOTE: here we rely on the streams subsystem not allowing
1353 	 * a stream to be multiplexed more than once.  if this
1354 	 * changes, we break.
1355 	 *
1356 	 * mark the snode/stream as not multiplexed
1357 	 */
1358 	sp = VTOS(vp);
1359 	mutex_enter(&sp->s_lock);
1360 	ASSERT(sp->s_flag & SMUXED);
1361 	sp->s_flag &= ~SMUXED;
1362 	mutex_exit(&sp->s_lock);
1363 
1364 	/*
1365 	 * clear the owner for this snode
1366 	 * see the comment in ldi_mlink_fp() for information about how
1367 	 * the ident is allocated
1368 	 */
1369 	if (type == LINKNORMAL) {
1370 		ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
1371 	} else {
1372 		ASSERT(type == LINKPERSIST);
1373 		major = getmajor(stp->sd_vnode->v_rdev);
1374 		ret = ldi_ident_from_major(major, &li);
1375 	}
1376 
1377 	ASSERT(ret == 0);
1378 	lhp = handle_find(vp, (struct ldi_ident *)li);
1379 	handle_release(lhp);
1380 	ldi_ident_release(li);
1381 }
1382 
1383 /*
1384  * LDI Consolidation private interfaces
1385  */
1386 int
1387 ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip)
1388 {
1389 	struct modctl		*modp;
1390 	major_t			major;
1391 	char			*name;
1392 
1393 	if ((modlp == NULL) || (lip == NULL))
1394 		return (EINVAL);
1395 
1396 	ASSERT(!servicing_interrupt());
1397 
1398 	modp = mod_getctl(modlp);
1399 	if (modp == NULL)
1400 		return (EINVAL);
1401 	name = modp->mod_modname;
1402 	if (name == NULL)
1403 		return (EINVAL);
1404 	major = mod_name_to_major(name);
1405 
1406 	*lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
1407 
1408 	LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1409 		"ldi_ident_from_mod", (void *)*lip, name));
1410 
1411 	return (0);
1412 }
1413 
1414 ldi_ident_t
1415 ldi_ident_from_anon()
1416 {
1417 	ldi_ident_t	lip;
1418 
1419 	ASSERT(!servicing_interrupt());
1420 
1421 	lip = (ldi_ident_t)ident_alloc("genunix", NULL, DDI_DEV_T_NONE, -1);
1422 
1423 	LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1424 		"ldi_ident_from_anon", (void *)lip, "genunix"));
1425 
1426 	return (lip);
1427 }
1428 
1429 
1430 /*
1431  * LDI Public interfaces
1432  */
1433 int
1434 ldi_ident_from_stream(struct queue *sq, ldi_ident_t *lip)
1435 {
1436 	struct stdata		*stp;
1437 	dev_t			dev;
1438 	char			*name;
1439 
1440 	if ((sq == NULL) || (lip == NULL))
1441 		return (EINVAL);
1442 
1443 	ASSERT(!servicing_interrupt());
1444 
1445 	stp = sq->q_stream;
1446 	if (!vn_matchops(stp->sd_vnode, spec_getvnodeops()))
1447 		return (EINVAL);
1448 
1449 	dev = stp->sd_vnode->v_rdev;
1450 	name = mod_major_to_name(getmajor(dev));
1451 	if (name == NULL)
1452 		return (EINVAL);
1453 	*lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
1454 
1455 	LDI_ALLOCFREE((CE_WARN,
1456 		"%s: li=0x%p, mod=%s, minor=0x%x, stp=0x%p",
1457 		"ldi_ident_from_stream", (void *)*lip, name, getminor(dev),
1458 		(void *)stp));
1459 
1460 	return (0);
1461 }
1462 
1463 int
1464 ldi_ident_from_dev(dev_t dev, ldi_ident_t *lip)
1465 {
1466 	char			*name;
1467 
1468 	if (lip == NULL)
1469 		return (EINVAL);
1470 
1471 	ASSERT(!servicing_interrupt());
1472 
1473 	name = mod_major_to_name(getmajor(dev));
1474 	if (name == NULL)
1475 		return (EINVAL);
1476 	*lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
1477 
1478 	LDI_ALLOCFREE((CE_WARN,
1479 		"%s: li=0x%p, mod=%s, minor=0x%x",
1480 		"ldi_ident_from_dev", (void *)*lip, name, getminor(dev)));
1481 
1482 	return (0);
1483 }
1484 
1485 int
1486 ldi_ident_from_dip(dev_info_t *dip, ldi_ident_t *lip)
1487 {
1488 	struct dev_info		*devi = (struct dev_info *)dip;
1489 	char			*name;
1490 
1491 	if ((dip == NULL) || (lip == NULL))
1492 		return (EINVAL);
1493 
1494 	ASSERT(!servicing_interrupt());
1495 
1496 	name = mod_major_to_name(devi->devi_major);
1497 	if (name == NULL)
1498 		return (EINVAL);
1499 	*lip = (ldi_ident_t)ident_alloc(name, dip, DDI_DEV_T_NONE, -1);
1500 
1501 	LDI_ALLOCFREE((CE_WARN,
1502 		"%s: li=0x%p, mod=%s, dip=0x%p",
1503 		"ldi_ident_from_dip", (void *)*lip, name, (void *)devi));
1504 
1505 	return (0);
1506 }
1507 
1508 int
1509 ldi_ident_from_major(major_t major, ldi_ident_t *lip)
1510 {
1511 	char			*name;
1512 
1513 	if (lip == NULL)
1514 		return (EINVAL);
1515 
1516 	ASSERT(!servicing_interrupt());
1517 
1518 	name = mod_major_to_name(major);
1519 	if (name == NULL)
1520 		return (EINVAL);
1521 	*lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
1522 
1523 	LDI_ALLOCFREE((CE_WARN,
1524 		"%s: li=0x%p, mod=%s",
1525 		"ldi_ident_from_major", (void *)*lip, name));
1526 
1527 	return (0);
1528 }
1529 
1530 void
1531 ldi_ident_release(ldi_ident_t li)
1532 {
1533 	struct ldi_ident	*ident = (struct ldi_ident *)li;
1534 	char			*name;
1535 
1536 	if (li == NULL)
1537 		return;
1538 
1539 	ASSERT(!servicing_interrupt());
1540 
1541 	name = ident->li_modname;
1542 
1543 	LDI_ALLOCFREE((CE_WARN,
1544 		"%s: li=0x%p, mod=%s",
1545 		"ldi_ident_release", (void *)li, name));
1546 
1547 	ident_release((struct ldi_ident *)li);
1548 }
1549 
1550 /* get a handle to a device by dev_t and otyp */
1551 int
1552 ldi_open_by_dev(dev_t *devp, int otyp, int flag, cred_t *cr,
1553     ldi_handle_t *lhp, ldi_ident_t li)
1554 {
1555 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1556 	int 			ret;
1557 	vnode_t			*vp;
1558 
1559 	/* sanity check required input parameters */
1560 	if ((devp == NULL) || (!OTYP_VALID(otyp)) || (cr == NULL) ||
1561 	    (lhp == NULL) || (lip == NULL))
1562 		return (EINVAL);
1563 
1564 	ASSERT(!servicing_interrupt());
1565 
1566 	if ((ret = ldi_vp_from_dev(*devp, otyp, &vp)) != 0)
1567 		return (ret);
1568 
1569 	if ((ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip)) == 0) {
1570 		*devp = vp->v_rdev;
1571 	}
1572 	VN_RELE(vp);
1573 
1574 	return (ret);
1575 }
1576 
1577 /* get a handle to a device by pathname */
1578 int
1579 ldi_open_by_name(char *pathname, int flag, cred_t *cr,
1580     ldi_handle_t *lhp, ldi_ident_t li)
1581 {
1582 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1583 	int 			ret;
1584 	vnode_t			*vp;
1585 
1586 	/* sanity check required input parameters */
1587 	if ((pathname == NULL) || (*pathname != '/') ||
1588 	    (cr == NULL) || (lhp == NULL) || (lip == NULL))
1589 		return (EINVAL);
1590 
1591 	ASSERT(!servicing_interrupt());
1592 
1593 	if ((ret = ldi_vp_from_name(pathname, &vp)) != 0)
1594 		return (ret);
1595 
1596 	ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
1597 	VN_RELE(vp);
1598 
1599 	return (ret);
1600 }
1601 
1602 /* get a handle to a device by devid and minor_name */
1603 int
1604 ldi_open_by_devid(ddi_devid_t devid, char *minor_name,
1605     int flag, cred_t *cr, ldi_handle_t *lhp, ldi_ident_t li)
1606 {
1607 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1608 	int			ret;
1609 	vnode_t			*vp;
1610 
1611 	/* sanity check required input parameters */
1612 	if ((minor_name == NULL) || (cr == NULL) ||
1613 	    (lhp == NULL) || (lip == NULL))
1614 		return (EINVAL);
1615 
1616 	ASSERT(!servicing_interrupt());
1617 
1618 	if ((ret = ldi_vp_from_devid(devid, minor_name, &vp)) != 0)
1619 		return (ret);
1620 
1621 	ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
1622 	VN_RELE(vp);
1623 
1624 	return (ret);
1625 }
1626 
1627 int
1628 ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
1629 {
1630 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1631 	struct ldi_event	*lep;
1632 	int 			err = 0;
1633 
1634 	if (lh == NULL)
1635 		return (EINVAL);
1636 
1637 	ASSERT(!servicing_interrupt());
1638 
1639 	/* Flush back any dirty pages associated with the device. */
1640 	if (handlep->lh_type & LH_CBDEV) {
1641 		vnode_t	*cvp = common_specvp(handlep->lh_vp);
1642 		dev_t	dev = cvp->v_rdev;
1643 
1644 		(void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred);
1645 		bflush(dev);
1646 	}
1647 
1648 	/*
1649 	 * Any event handlers should have been unregistered by the
1650 	 * time ldi_close() is called.  If they haven't then it's a
1651 	 * bug.
1652 	 *
1653 	 * In a debug kernel we'll panic to make the problem obvious.
1654 	 */
1655 	ASSERT(handlep->lh_events == NULL);
1656 
1657 	/*
1658 	 * On a production kernel we'll "do the right thing" (unregister
1659 	 * the event handlers) and then complain about having to do the
1660 	 * work ourselves.
1661 	 */
1662 	while ((lep = handlep->lh_events) != NULL) {
1663 		err = 1;
1664 		(void) ldi_remove_event_handler(lh, (ldi_callback_id_t)lep);
1665 	}
1666 	if (err) {
1667 		struct ldi_ident *lip = handlep->lh_ident;
1668 		ASSERT(lip != NULL);
1669 		cmn_err(CE_NOTE, "ldi err: %s "
1670 		    "failed to unregister layered event handlers before "
1671 		    "closing devices", lip->li_modname);
1672 	}
1673 
1674 	/* do a layered close on the device */
1675 	err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr);
1676 
1677 	LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", "ldi close", (void *)lh));
1678 
1679 	/*
1680 	 * Free the handle even if the device close failed.  why?
1681 	 *
1682 	 * If the device close failed we can't really make assumptions
1683 	 * about the devices state so we shouldn't allow access to the
1684 	 * device via this handle any more.  If the device consumer wants
1685 	 * to access the device again they should open it again.
1686 	 *
1687 	 * This is the same way file/device close failures are handled
1688 	 * in other places like spec_close() and closeandsetf().
1689 	 */
1690 	handle_release(handlep);
1691 	return (err);
1692 }
1693 
1694 int
1695 ldi_read(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
1696 {
1697 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1698 	vnode_t			*vp;
1699 	dev_t			dev;
1700 	int			ret;
1701 
1702 	if (lh == NULL)
1703 		return (EINVAL);
1704 
1705 	vp = handlep->lh_vp;
1706 	dev = vp->v_rdev;
1707 	if (handlep->lh_type & LH_CBDEV) {
1708 		ret = cdev_read(dev, uiop, credp);
1709 	} else if (handlep->lh_type & LH_STREAM) {
1710 		ret = strread(vp, uiop, credp);
1711 	} else {
1712 		return (ENOTSUP);
1713 	}
1714 	return (ret);
1715 }
1716 
1717 int
1718 ldi_write(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
1719 {
1720 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1721 	vnode_t			*vp;
1722 	dev_t			dev;
1723 	int			ret;
1724 
1725 	if (lh == NULL)
1726 		return (EINVAL);
1727 
1728 	vp = handlep->lh_vp;
1729 	dev = vp->v_rdev;
1730 	if (handlep->lh_type & LH_CBDEV) {
1731 		ret = cdev_write(dev, uiop, credp);
1732 	} else if (handlep->lh_type & LH_STREAM) {
1733 		ret = strwrite(vp, uiop, credp);
1734 	} else {
1735 		return (ENOTSUP);
1736 	}
1737 	return (ret);
1738 }
1739 
1740 int
1741 ldi_get_size(ldi_handle_t lh, uint64_t *sizep)
1742 {
1743 	int 			otyp;
1744 	uint_t			value;
1745 	int64_t			drv_prop64;
1746 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1747 
1748 
1749 	if ((lh == NULL) || (sizep == NULL))
1750 		return (DDI_FAILURE);
1751 
1752 	if (handlep->lh_type & LH_STREAM)
1753 		return (DDI_FAILURE);
1754 
1755 	/*
1756 	 * Determine device type (char or block).
1757 	 * Character devices support Size/size
1758 	 * property value. Block devices may support
1759 	 * Nblocks/nblocks or Size/size property value.
1760 	 */
1761 	if ((ldi_get_otyp(lh, &otyp)) != 0)
1762 		return (DDI_FAILURE);
1763 
1764 	if (otyp == OTYP_BLK) {
1765 		if (ldi_prop_exists(lh,
1766 			DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Nblocks")) {
1767 
1768 			drv_prop64 = ldi_prop_get_int64(lh,
1769 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1770 			    "Nblocks", 0);
1771 			*sizep = (uint64_t)ldbtob((uint64_t)drv_prop64);
1772 			return (DDI_SUCCESS);
1773 		}
1774 
1775 		if (ldi_prop_exists(lh,
1776 			DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "nblocks")) {
1777 
1778 			value = ldi_prop_get_int(lh,
1779 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1780 			    "nblocks", 0);
1781 			*sizep = (uint64_t)ldbtob(value);
1782 			return (DDI_SUCCESS);
1783 		}
1784 	}
1785 
1786 	if (ldi_prop_exists(lh,
1787 		DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size")) {
1788 
1789 		drv_prop64 = ldi_prop_get_int64(lh,
1790 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size", 0);
1791 		*sizep = (uint64_t)drv_prop64;
1792 		return (DDI_SUCCESS);
1793 	}
1794 
1795 	if (ldi_prop_exists(lh,
1796 		DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size")) {
1797 
1798 		value = ldi_prop_get_int(lh,
1799 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size", 0);
1800 		*sizep = (uint64_t)value;
1801 		return (DDI_SUCCESS);
1802 	}
1803 
1804 	/* unable to determine device size */
1805 	return (DDI_FAILURE);
1806 }
1807 
1808 int
1809 ldi_ioctl(ldi_handle_t lh, int cmd, intptr_t arg, int mode,
1810 	cred_t *cr, int *rvalp)
1811 {
1812 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1813 	vnode_t			*vp;
1814 	dev_t			dev;
1815 	int			ret, copymode;
1816 
1817 	if (lh == NULL)
1818 		return (EINVAL);
1819 
1820 	/*
1821 	 * if the data pointed to by arg is located in the kernel then
1822 	 * make sure the FNATIVE flag is set.
1823 	 */
1824 	if (mode & FKIOCTL)
1825 		mode = (mode & ~FMODELS) | FNATIVE | FKIOCTL;
1826 
1827 	vp = handlep->lh_vp;
1828 	dev = vp->v_rdev;
1829 	if (handlep->lh_type & LH_CBDEV) {
1830 		ret = cdev_ioctl(dev, cmd, arg, mode, cr, rvalp);
1831 	} else if (handlep->lh_type & LH_STREAM) {
1832 		copymode = (mode & FKIOCTL) ? K_TO_K : U_TO_K;
1833 
1834 		/*
1835 		 * if we get an I_PLINK from within the kernel the
1836 		 * arg is a layered handle pointer instead of
1837 		 * a file descriptor, so we translate this ioctl
1838 		 * into a private one that can handle this.
1839 		 */
1840 		if ((mode & FKIOCTL) && (cmd == I_PLINK))
1841 			cmd = _I_PLINK_LH;
1842 
1843 		ret = strioctl(vp, cmd, arg, mode, copymode, cr, rvalp);
1844 	} else {
1845 		return (ENOTSUP);
1846 	}
1847 
1848 	return (ret);
1849 }
1850 
1851 int
1852 ldi_poll(ldi_handle_t lh, short events, int anyyet, short *reventsp,
1853     struct pollhead **phpp)
1854 {
1855 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1856 	vnode_t			*vp;
1857 	dev_t			dev;
1858 	int			ret;
1859 
1860 	if (lh == NULL)
1861 		return (EINVAL);
1862 
1863 	vp = handlep->lh_vp;
1864 	dev = vp->v_rdev;
1865 	if (handlep->lh_type & LH_CBDEV) {
1866 		ret = cdev_poll(dev, events, anyyet, reventsp, phpp);
1867 	} else if (handlep->lh_type & LH_STREAM) {
1868 		ret = strpoll(vp->v_stream, events, anyyet, reventsp, phpp);
1869 	} else {
1870 		return (ENOTSUP);
1871 	}
1872 
1873 	return (ret);
1874 }
1875 
1876 int
1877 ldi_prop_op(ldi_handle_t lh, ddi_prop_op_t prop_op,
1878 	int flags, char *name, caddr_t valuep, int *length)
1879 {
1880 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1881 	dev_t			dev;
1882 	dev_info_t		*dip;
1883 	int			ret;
1884 	struct snode		*csp;
1885 
1886 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
1887 		return (DDI_PROP_INVAL_ARG);
1888 
1889 	if ((prop_op != PROP_LEN) && (valuep == NULL))
1890 		return (DDI_PROP_INVAL_ARG);
1891 
1892 	if (length == NULL)
1893 		return (DDI_PROP_INVAL_ARG);
1894 
1895 	/*
1896 	 * try to find the associated dip,
1897 	 * this places a hold on the driver
1898 	 */
1899 	dev = handlep->lh_vp->v_rdev;
1900 
1901 	csp = VTOCS(handlep->lh_vp);
1902 	mutex_enter(&csp->s_lock);
1903 	if ((dip = csp->s_dip) != NULL)
1904 		e_ddi_hold_devi(dip);
1905 	mutex_exit(&csp->s_lock);
1906 	if (dip == NULL)
1907 		dip = e_ddi_hold_devi_by_dev(dev, 0);
1908 
1909 	if (dip == NULL)
1910 		return (DDI_PROP_NOT_FOUND);
1911 
1912 	ret = i_ldi_prop_op(dev, dip, prop_op, flags, name, valuep, length);
1913 	ddi_release_devi(dip);
1914 
1915 	return (ret);
1916 }
1917 
1918 int
1919 ldi_strategy(ldi_handle_t lh, struct buf *bp)
1920 {
1921 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1922 	dev_t			dev;
1923 
1924 	if ((lh == NULL) || (bp == NULL))
1925 		return (EINVAL);
1926 
1927 	/* this entry point is only supported for cb devices */
1928 	dev = handlep->lh_vp->v_rdev;
1929 	if (!(handlep->lh_type & LH_CBDEV))
1930 		return (ENOTSUP);
1931 
1932 	bp->b_edev = dev;
1933 	bp->b_dev = cmpdev(dev);
1934 	return (bdev_strategy(bp));
1935 }
1936 
1937 int
1938 ldi_dump(ldi_handle_t lh, caddr_t addr, daddr_t blkno, int nblk)
1939 {
1940 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1941 	dev_t			dev;
1942 
1943 	if (lh == NULL)
1944 		return (EINVAL);
1945 
1946 	/* this entry point is only supported for cb devices */
1947 	dev = handlep->lh_vp->v_rdev;
1948 	if (!(handlep->lh_type & LH_CBDEV))
1949 		return (ENOTSUP);
1950 
1951 	return (bdev_dump(dev, addr, blkno, nblk));
1952 }
1953 
1954 int
1955 ldi_devmap(ldi_handle_t lh, devmap_cookie_t dhp, offset_t off,
1956     size_t len, size_t *maplen, uint_t model)
1957 {
1958 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1959 	dev_t			dev;
1960 
1961 	if (lh == NULL)
1962 		return (EINVAL);
1963 
1964 	/* this entry point is only supported for cb devices */
1965 	dev = handlep->lh_vp->v_rdev;
1966 	if (!(handlep->lh_type & LH_CBDEV))
1967 		return (ENOTSUP);
1968 
1969 	return (cdev_devmap(dev, dhp, off, len, maplen, model));
1970 }
1971 
1972 int
1973 ldi_aread(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
1974 {
1975 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1976 	dev_t			dev;
1977 	struct cb_ops		*cb;
1978 
1979 	if (lh == NULL)
1980 		return (EINVAL);
1981 
1982 	/* this entry point is only supported for cb devices */
1983 	if (!(handlep->lh_type & LH_CBDEV))
1984 		return (ENOTSUP);
1985 
1986 	/*
1987 	 * Kaio is only supported on block devices.
1988 	 */
1989 	dev = handlep->lh_vp->v_rdev;
1990 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
1991 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
1992 		return (ENOTSUP);
1993 
1994 	if (cb->cb_aread == NULL)
1995 		return (ENOTSUP);
1996 
1997 	return (cb->cb_aread(dev, aio_reqp, cr));
1998 }
1999 
2000 int
2001 ldi_awrite(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
2002 {
2003 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2004 	struct cb_ops		*cb;
2005 	dev_t			dev;
2006 
2007 	if (lh == NULL)
2008 		return (EINVAL);
2009 
2010 	/* this entry point is only supported for cb devices */
2011 	if (!(handlep->lh_type & LH_CBDEV))
2012 		return (ENOTSUP);
2013 
2014 	/*
2015 	 * Kaio is only supported on block devices.
2016 	 */
2017 	dev = handlep->lh_vp->v_rdev;
2018 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
2019 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
2020 		return (ENOTSUP);
2021 
2022 	if (cb->cb_awrite == NULL)
2023 		return (ENOTSUP);
2024 
2025 	return (cb->cb_awrite(dev, aio_reqp, cr));
2026 }
2027 
2028 int
2029 ldi_putmsg(ldi_handle_t lh, mblk_t *smp)
2030 {
2031 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2032 	int			ret;
2033 
2034 	if ((lh == NULL) || (smp == NULL))
2035 		return (EINVAL);
2036 
2037 	if (!(handlep->lh_type & LH_STREAM)) {
2038 		freemsg(smp);
2039 		return (ENOTSUP);
2040 	}
2041 
2042 	/* Send message while honoring flow control */
2043 	ret = kstrputmsg(handlep->lh_vp, smp, NULL, 0, 0,
2044 				MSG_BAND | MSG_HOLDSIG | MSG_IGNERROR, 0);
2045 
2046 	return (ret);
2047 }
2048 
2049 int
2050 ldi_getmsg(ldi_handle_t lh, mblk_t **rmp, timestruc_t *timeo)
2051 {
2052 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2053 	clock_t			timout; /* milliseconds */
2054 	uchar_t			pri;
2055 	rval_t			rval;
2056 	int			ret, pflag;
2057 
2058 
2059 	if (lh == NULL)
2060 		return (EINVAL);
2061 
2062 	if (!(handlep->lh_type & LH_STREAM))
2063 		return (ENOTSUP);
2064 
2065 	/* Convert from nanoseconds to milliseconds */
2066 	if (timeo != NULL) {
2067 		timout = timeo->tv_sec * 1000 + timeo->tv_nsec / 1000000;
2068 		if (timout > INT_MAX)
2069 			return (EINVAL);
2070 	} else
2071 		timout = -1;
2072 
2073 	/* Wait for timeout millseconds for a message */
2074 	pflag = MSG_ANY;
2075 	pri = 0;
2076 	*rmp = NULL;
2077 	ret = kstrgetmsg(handlep->lh_vp,
2078 				rmp, NULL, &pri, &pflag, timout, &rval);
2079 	return (ret);
2080 }
2081 
2082 int
2083 ldi_get_dev(ldi_handle_t lh, dev_t *devp)
2084 {
2085 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2086 
2087 	if ((lh == NULL) || (devp == NULL))
2088 		return (EINVAL);
2089 
2090 	*devp = handlep->lh_vp->v_rdev;
2091 	return (0);
2092 }
2093 
2094 int
2095 ldi_get_otyp(ldi_handle_t lh, int *otyp)
2096 {
2097 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2098 
2099 	if ((lh == NULL) || (otyp == NULL))
2100 		return (EINVAL);
2101 
2102 	*otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
2103 	return (0);
2104 }
2105 
2106 int
2107 ldi_get_devid(ldi_handle_t lh, ddi_devid_t *devid)
2108 {
2109 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2110 	int			ret;
2111 	dev_t			dev;
2112 
2113 	if ((lh == NULL) || (devid == NULL))
2114 		return (EINVAL);
2115 
2116 	dev = handlep->lh_vp->v_rdev;
2117 
2118 	ret = ddi_lyr_get_devid(dev, devid);
2119 	if (ret != DDI_SUCCESS)
2120 		return (ENOTSUP);
2121 
2122 	return (0);
2123 }
2124 
2125 int
2126 ldi_get_minor_name(ldi_handle_t lh, char **minor_name)
2127 {
2128 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2129 	int			ret, otyp;
2130 	dev_t			dev;
2131 
2132 	if ((lh == NULL) || (minor_name == NULL))
2133 		return (EINVAL);
2134 
2135 	dev = handlep->lh_vp->v_rdev;
2136 	otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
2137 
2138 	ret = ddi_lyr_get_minor_name(dev, OTYP_TO_STYP(otyp), minor_name);
2139 	if (ret != DDI_SUCCESS)
2140 		return (ENOTSUP);
2141 
2142 	return (0);
2143 }
2144 
2145 int
2146 ldi_prop_lookup_int_array(ldi_handle_t lh,
2147     uint_t flags, char *name, int **data, uint_t *nelements)
2148 {
2149 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2150 	dev_info_t		*dip;
2151 	dev_t			dev;
2152 	int			res;
2153 	struct snode		*csp;
2154 
2155 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2156 		return (DDI_PROP_INVAL_ARG);
2157 
2158 	dev = handlep->lh_vp->v_rdev;
2159 
2160 	csp = VTOCS(handlep->lh_vp);
2161 	mutex_enter(&csp->s_lock);
2162 	if ((dip = csp->s_dip) != NULL)
2163 		e_ddi_hold_devi(dip);
2164 	mutex_exit(&csp->s_lock);
2165 	if (dip == NULL)
2166 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2167 
2168 	if (dip == NULL) {
2169 		flags |= DDI_UNBND_DLPI2;
2170 	} else if (flags & LDI_DEV_T_ANY) {
2171 		flags &= ~LDI_DEV_T_ANY;
2172 		dev = DDI_DEV_T_ANY;
2173 	}
2174 
2175 	if (dip != NULL) {
2176 		int *prop_val, prop_len;
2177 
2178 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2179 		    (caddr_t *)&prop_val, &prop_len, sizeof (int));
2180 
2181 		/* if we got it then return it */
2182 		if (res == DDI_PROP_SUCCESS) {
2183 			*nelements = prop_len / sizeof (int);
2184 			*data = prop_val;
2185 
2186 			ddi_release_devi(dip);
2187 			return (res);
2188 		}
2189 	}
2190 
2191 	/* call the normal property interfaces */
2192 	res = ddi_prop_lookup_int_array(dev, dip, flags,
2193 	    name, data, nelements);
2194 
2195 	if (dip != NULL)
2196 		ddi_release_devi(dip);
2197 
2198 	return (res);
2199 }
2200 
2201 int
2202 ldi_prop_lookup_int64_array(ldi_handle_t lh,
2203     uint_t flags, char *name, int64_t **data, uint_t *nelements)
2204 {
2205 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2206 	dev_info_t		*dip;
2207 	dev_t			dev;
2208 	int			res;
2209 	struct snode		*csp;
2210 
2211 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2212 		return (DDI_PROP_INVAL_ARG);
2213 
2214 	dev = handlep->lh_vp->v_rdev;
2215 
2216 	csp = VTOCS(handlep->lh_vp);
2217 	mutex_enter(&csp->s_lock);
2218 	if ((dip = csp->s_dip) != NULL)
2219 		e_ddi_hold_devi(dip);
2220 	mutex_exit(&csp->s_lock);
2221 	if (dip == NULL)
2222 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2223 
2224 	if (dip == NULL) {
2225 		flags |= DDI_UNBND_DLPI2;
2226 	} else if (flags & LDI_DEV_T_ANY) {
2227 		flags &= ~LDI_DEV_T_ANY;
2228 		dev = DDI_DEV_T_ANY;
2229 	}
2230 
2231 	if (dip != NULL) {
2232 		int64_t	*prop_val;
2233 		int	prop_len;
2234 
2235 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2236 		    (caddr_t *)&prop_val, &prop_len, sizeof (int64_t));
2237 
2238 		/* if we got it then return it */
2239 		if (res == DDI_PROP_SUCCESS) {
2240 			*nelements = prop_len / sizeof (int64_t);
2241 			*data = prop_val;
2242 
2243 			ddi_release_devi(dip);
2244 			return (res);
2245 		}
2246 	}
2247 
2248 	/* call the normal property interfaces */
2249 	res = ddi_prop_lookup_int64_array(dev, dip, flags,
2250 	    name, data, nelements);
2251 
2252 	if (dip != NULL)
2253 		ddi_release_devi(dip);
2254 
2255 	return (res);
2256 }
2257 
2258 int
2259 ldi_prop_lookup_string_array(ldi_handle_t lh,
2260     uint_t flags, char *name, char ***data, uint_t *nelements)
2261 {
2262 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2263 	dev_info_t		*dip;
2264 	dev_t			dev;
2265 	int			res;
2266 	struct snode		*csp;
2267 
2268 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2269 		return (DDI_PROP_INVAL_ARG);
2270 
2271 	dev = handlep->lh_vp->v_rdev;
2272 
2273 	csp = VTOCS(handlep->lh_vp);
2274 	mutex_enter(&csp->s_lock);
2275 	if ((dip = csp->s_dip) != NULL)
2276 		e_ddi_hold_devi(dip);
2277 	mutex_exit(&csp->s_lock);
2278 	if (dip == NULL)
2279 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2280 
2281 	if (dip == NULL) {
2282 		flags |= DDI_UNBND_DLPI2;
2283 	} else if (flags & LDI_DEV_T_ANY) {
2284 		flags &= ~LDI_DEV_T_ANY;
2285 		dev = DDI_DEV_T_ANY;
2286 	}
2287 
2288 	if (dip != NULL) {
2289 		char	*prop_val;
2290 		int	prop_len;
2291 
2292 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2293 		    (caddr_t *)&prop_val, &prop_len, 0);
2294 
2295 		/* if we got it then return it */
2296 		if (res == DDI_PROP_SUCCESS) {
2297 			char	**str_array;
2298 			int	nelem;
2299 
2300 			/*
2301 			 * pack the returned string array into the format
2302 			 * our callers expect
2303 			 */
2304 			if (i_pack_string_array(prop_val, prop_len,
2305 				&str_array, &nelem) == 0) {
2306 
2307 				*data = str_array;
2308 				*nelements = nelem;
2309 
2310 				ddi_prop_free(prop_val);
2311 				ddi_release_devi(dip);
2312 				return (res);
2313 			}
2314 
2315 			/*
2316 			 * the format of the returned property must have
2317 			 * been bad so throw it out
2318 			 */
2319 			ddi_prop_free(prop_val);
2320 		}
2321 	}
2322 
2323 	/* call the normal property interfaces */
2324 	res = ddi_prop_lookup_string_array(dev, dip, flags,
2325 	    name, data, nelements);
2326 
2327 	if (dip != NULL)
2328 		ddi_release_devi(dip);
2329 
2330 	return (res);
2331 }
2332 
2333 int
2334 ldi_prop_lookup_string(ldi_handle_t lh,
2335     uint_t flags, char *name, char **data)
2336 {
2337 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2338 	dev_info_t		*dip;
2339 	dev_t			dev;
2340 	int			res;
2341 	struct snode		*csp;
2342 
2343 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2344 		return (DDI_PROP_INVAL_ARG);
2345 
2346 	dev = handlep->lh_vp->v_rdev;
2347 
2348 	csp = VTOCS(handlep->lh_vp);
2349 	mutex_enter(&csp->s_lock);
2350 	if ((dip = csp->s_dip) != NULL)
2351 		e_ddi_hold_devi(dip);
2352 	mutex_exit(&csp->s_lock);
2353 	if (dip == NULL)
2354 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2355 
2356 	if (dip == NULL) {
2357 		flags |= DDI_UNBND_DLPI2;
2358 	} else if (flags & LDI_DEV_T_ANY) {
2359 		flags &= ~LDI_DEV_T_ANY;
2360 		dev = DDI_DEV_T_ANY;
2361 	}
2362 
2363 	if (dip != NULL) {
2364 		char	*prop_val;
2365 		int	prop_len;
2366 
2367 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2368 		    (caddr_t *)&prop_val, &prop_len, 0);
2369 
2370 		/* if we got it then return it */
2371 		if (res == DDI_PROP_SUCCESS) {
2372 			/*
2373 			 * sanity check the vaule returned.
2374 			 */
2375 			if (i_check_string(prop_val, prop_len)) {
2376 				ddi_prop_free(prop_val);
2377 			} else {
2378 				*data = prop_val;
2379 				ddi_release_devi(dip);
2380 				return (res);
2381 			}
2382 		}
2383 	}
2384 
2385 	/* call the normal property interfaces */
2386 	res = ddi_prop_lookup_string(dev, dip, flags, name, data);
2387 
2388 	if (dip != NULL)
2389 		ddi_release_devi(dip);
2390 
2391 #ifdef DEBUG
2392 	if (res == DDI_PROP_SUCCESS) {
2393 		/*
2394 		 * keep ourselves honest
2395 		 * make sure the framework returns strings in the
2396 		 * same format as we're demanding from drivers.
2397 		 */
2398 		struct prop_driver_data	*pdd;
2399 		int			pdd_prop_size;
2400 
2401 		pdd = ((struct prop_driver_data *)(*data)) - 1;
2402 		pdd_prop_size = pdd->pdd_size -
2403 		    sizeof (struct prop_driver_data);
2404 		ASSERT(i_check_string(*data, pdd_prop_size) == 0);
2405 	}
2406 #endif /* DEBUG */
2407 
2408 	return (res);
2409 }
2410 
2411 int
2412 ldi_prop_lookup_byte_array(ldi_handle_t lh,
2413     uint_t flags, char *name, uchar_t **data, uint_t *nelements)
2414 {
2415 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2416 	dev_info_t		*dip;
2417 	dev_t			dev;
2418 	int			res;
2419 	struct snode		*csp;
2420 
2421 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2422 		return (DDI_PROP_INVAL_ARG);
2423 
2424 	dev = handlep->lh_vp->v_rdev;
2425 
2426 	csp = VTOCS(handlep->lh_vp);
2427 	mutex_enter(&csp->s_lock);
2428 	if ((dip = csp->s_dip) != NULL)
2429 		e_ddi_hold_devi(dip);
2430 	mutex_exit(&csp->s_lock);
2431 	if (dip == NULL)
2432 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2433 
2434 	if (dip == NULL) {
2435 		flags |= DDI_UNBND_DLPI2;
2436 	} else if (flags & LDI_DEV_T_ANY) {
2437 		flags &= ~LDI_DEV_T_ANY;
2438 		dev = DDI_DEV_T_ANY;
2439 	}
2440 
2441 	if (dip != NULL) {
2442 		uchar_t	*prop_val;
2443 		int	prop_len;
2444 
2445 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2446 		    (caddr_t *)&prop_val, &prop_len, sizeof (uchar_t));
2447 
2448 		/* if we got it then return it */
2449 		if (res == DDI_PROP_SUCCESS) {
2450 			*nelements = prop_len / sizeof (uchar_t);
2451 			*data = prop_val;
2452 
2453 			ddi_release_devi(dip);
2454 			return (res);
2455 		}
2456 	}
2457 
2458 	/* call the normal property interfaces */
2459 	res = ddi_prop_lookup_byte_array(dev, dip, flags,
2460 	    name, data, nelements);
2461 
2462 	if (dip != NULL)
2463 		ddi_release_devi(dip);
2464 
2465 	return (res);
2466 }
2467 
2468 int
2469 ldi_prop_get_int(ldi_handle_t lh,
2470     uint_t flags, char *name, int defvalue)
2471 {
2472 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2473 	dev_info_t		*dip;
2474 	dev_t			dev;
2475 	int			res;
2476 	struct snode		*csp;
2477 
2478 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2479 		return (defvalue);
2480 
2481 	dev = handlep->lh_vp->v_rdev;
2482 
2483 	csp = VTOCS(handlep->lh_vp);
2484 	mutex_enter(&csp->s_lock);
2485 	if ((dip = csp->s_dip) != NULL)
2486 		e_ddi_hold_devi(dip);
2487 	mutex_exit(&csp->s_lock);
2488 	if (dip == NULL)
2489 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2490 
2491 	if (dip == NULL) {
2492 		flags |= DDI_UNBND_DLPI2;
2493 	} else if (flags & LDI_DEV_T_ANY) {
2494 		flags &= ~LDI_DEV_T_ANY;
2495 		dev = DDI_DEV_T_ANY;
2496 	}
2497 
2498 	if (dip != NULL) {
2499 		int	prop_val;
2500 		int	prop_len;
2501 
2502 		/*
2503 		 * first call the drivers prop_op interface to allow it
2504 		 * it to override default property values.
2505 		 */
2506 		prop_len = sizeof (int);
2507 		res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2508 		    flags | DDI_PROP_DYNAMIC, name,
2509 		    (caddr_t)&prop_val, &prop_len);
2510 
2511 		/* if we got it then return it */
2512 		if ((res == DDI_PROP_SUCCESS) &&
2513 		    (prop_len == sizeof (int))) {
2514 			res = prop_val;
2515 			ddi_release_devi(dip);
2516 			return (res);
2517 		}
2518 	}
2519 
2520 	/* call the normal property interfaces */
2521 	res = ddi_prop_get_int(dev, dip, flags, name, defvalue);
2522 
2523 	if (dip != NULL)
2524 		ddi_release_devi(dip);
2525 
2526 	return (res);
2527 }
2528 
2529 int64_t
2530 ldi_prop_get_int64(ldi_handle_t lh,
2531     uint_t flags, char *name, int64_t defvalue)
2532 {
2533 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2534 	dev_info_t		*dip;
2535 	dev_t			dev;
2536 	int64_t			res;
2537 	struct snode		*csp;
2538 
2539 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2540 		return (defvalue);
2541 
2542 	dev = handlep->lh_vp->v_rdev;
2543 
2544 	csp = VTOCS(handlep->lh_vp);
2545 	mutex_enter(&csp->s_lock);
2546 	if ((dip = csp->s_dip) != NULL)
2547 		e_ddi_hold_devi(dip);
2548 	mutex_exit(&csp->s_lock);
2549 	if (dip == NULL)
2550 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2551 
2552 	if (dip == NULL) {
2553 		flags |= DDI_UNBND_DLPI2;
2554 	} else if (flags & LDI_DEV_T_ANY) {
2555 		flags &= ~LDI_DEV_T_ANY;
2556 		dev = DDI_DEV_T_ANY;
2557 	}
2558 
2559 	if (dip != NULL) {
2560 		int64_t	prop_val;
2561 		int	prop_len;
2562 
2563 		/*
2564 		 * first call the drivers prop_op interface to allow it
2565 		 * it to override default property values.
2566 		 */
2567 		prop_len = sizeof (int64_t);
2568 		res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2569 		    flags | DDI_PROP_DYNAMIC, name,
2570 		    (caddr_t)&prop_val, &prop_len);
2571 
2572 		/* if we got it then return it */
2573 		if ((res == DDI_PROP_SUCCESS) &&
2574 		    (prop_len == sizeof (int64_t))) {
2575 			res = prop_val;
2576 			ddi_release_devi(dip);
2577 			return (res);
2578 		}
2579 	}
2580 
2581 	/* call the normal property interfaces */
2582 	res = ddi_prop_get_int64(dev, dip, flags, name, defvalue);
2583 
2584 	if (dip != NULL)
2585 		ddi_release_devi(dip);
2586 
2587 	return (res);
2588 }
2589 
2590 int
2591 ldi_prop_exists(ldi_handle_t lh, uint_t flags, char *name)
2592 {
2593 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2594 	dev_info_t 		*dip;
2595 	dev_t 			dev;
2596 	int			res, prop_len;
2597 	struct snode		*csp;
2598 
2599 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2600 		return (0);
2601 
2602 	dev = handlep->lh_vp->v_rdev;
2603 
2604 	csp = VTOCS(handlep->lh_vp);
2605 	mutex_enter(&csp->s_lock);
2606 	if ((dip = csp->s_dip) != NULL)
2607 		e_ddi_hold_devi(dip);
2608 	mutex_exit(&csp->s_lock);
2609 	if (dip == NULL)
2610 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2611 
2612 	/* if NULL dip, prop does NOT exist */
2613 	if (dip == NULL)
2614 		return (0);
2615 
2616 	if (flags & LDI_DEV_T_ANY) {
2617 		flags &= ~LDI_DEV_T_ANY;
2618 		dev = DDI_DEV_T_ANY;
2619 	}
2620 
2621 	/*
2622 	 * first call the drivers prop_op interface to allow it
2623 	 * it to override default property values.
2624 	 */
2625 	res = i_ldi_prop_op(dev, dip, PROP_LEN,
2626 	    flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
2627 
2628 	if (res == DDI_PROP_SUCCESS) {
2629 		ddi_release_devi(dip);
2630 		return (1);
2631 	}
2632 
2633 	/* call the normal property interfaces */
2634 	res = ddi_prop_exists(dev, dip, flags, name);
2635 
2636 	ddi_release_devi(dip);
2637 	return (res);
2638 }
2639 
2640 int
2641 ldi_get_eventcookie(ldi_handle_t lh, char *name, ddi_eventcookie_t *ecp)
2642 {
2643 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2644 	dev_info_t		*dip;
2645 	dev_t			dev;
2646 	int			res;
2647 	struct snode		*csp;
2648 
2649 	if ((lh == NULL) || (name == NULL) ||
2650 	    (strlen(name) == 0) || (ecp == NULL)) {
2651 		return (DDI_FAILURE);
2652 	}
2653 
2654 	ASSERT(!servicing_interrupt());
2655 
2656 	dev = handlep->lh_vp->v_rdev;
2657 
2658 	csp = VTOCS(handlep->lh_vp);
2659 	mutex_enter(&csp->s_lock);
2660 	if ((dip = csp->s_dip) != NULL)
2661 		e_ddi_hold_devi(dip);
2662 	mutex_exit(&csp->s_lock);
2663 	if (dip == NULL)
2664 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2665 
2666 	if (dip == NULL)
2667 		return (DDI_FAILURE);
2668 
2669 	LDI_EVENTCB((CE_NOTE, "%s: event_name=%s, "
2670 	    "dip=0x%p, event_cookiep=0x%p", "ldi_get_eventcookie",
2671 	    name, (void *)dip, (void *)ecp));
2672 
2673 	res = ddi_get_eventcookie(dip, name, ecp);
2674 
2675 	ddi_release_devi(dip);
2676 	return (res);
2677 }
2678 
2679 int
2680 ldi_add_event_handler(ldi_handle_t lh, ddi_eventcookie_t ec,
2681     void (*handler)(ldi_handle_t, ddi_eventcookie_t, void *, void *),
2682     void *arg, ldi_callback_id_t *id)
2683 {
2684 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2685 	struct ldi_event	*lep;
2686 	dev_info_t		*dip;
2687 	dev_t			dev;
2688 	int			res;
2689 	struct snode		*csp;
2690 
2691 	if ((lh == NULL) || (ec == NULL) || (handler == NULL) || (id == NULL))
2692 		return (DDI_FAILURE);
2693 
2694 	ASSERT(!servicing_interrupt());
2695 
2696 	dev = handlep->lh_vp->v_rdev;
2697 
2698 	csp = VTOCS(handlep->lh_vp);
2699 	mutex_enter(&csp->s_lock);
2700 	if ((dip = csp->s_dip) != NULL)
2701 		e_ddi_hold_devi(dip);
2702 	mutex_exit(&csp->s_lock);
2703 	if (dip == NULL)
2704 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2705 
2706 	if (dip == NULL)
2707 		return (DDI_FAILURE);
2708 
2709 	lep = kmem_zalloc(sizeof (struct ldi_event), KM_SLEEP);
2710 	lep->le_lhp = handlep;
2711 	lep->le_arg = arg;
2712 	lep->le_handler = handler;
2713 
2714 	if ((res = ddi_add_event_handler(dip, ec, i_ldi_callback,
2715 	    (void *)lep, &lep->le_id)) != DDI_SUCCESS) {
2716 		LDI_EVENTCB((CE_WARN, "%s: unable to add"
2717 		    "event callback", "ldi_add_event_handler"));
2718 		ddi_release_devi(dip);
2719 		kmem_free(lep, sizeof (struct ldi_event));
2720 		return (res);
2721 	}
2722 
2723 	*id = (ldi_callback_id_t)lep;
2724 
2725 	LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, event=0x%p, "
2726 	    "ldi_eventp=0x%p, cb_id=0x%p", "ldi_add_event_handler",
2727 	    (void *)dip, (void *)ec, (void *)lep, (void *)id));
2728 
2729 	handle_event_add(lep);
2730 	ddi_release_devi(dip);
2731 	return (res);
2732 }
2733 
2734 int
2735 ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id)
2736 {
2737 	ldi_event_t		*lep = (ldi_event_t *)id;
2738 	int			res;
2739 
2740 	if ((lh == NULL) || (id == NULL))
2741 		return (DDI_FAILURE);
2742 
2743 	ASSERT(!servicing_interrupt());
2744 
2745 	if ((res = ddi_remove_event_handler(lep->le_id))
2746 	    != DDI_SUCCESS) {
2747 		LDI_EVENTCB((CE_WARN, "%s: unable to remove "
2748 		    "event callback", "ldi_remove_event_handler"));
2749 		return (res);
2750 	}
2751 
2752 	handle_event_remove(lep);
2753 	kmem_free(lep, sizeof (struct ldi_event));
2754 	return (res);
2755 }
2756