xref: /illumos-gate/usr/src/uts/common/os/driver_lyr.c (revision 3123e98a)
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 (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * Layered driver support.
27  */
28 
29 #include <sys/atomic.h>
30 #include <sys/types.h>
31 #include <sys/t_lock.h>
32 #include <sys/param.h>
33 #include <sys/conf.h>
34 #include <sys/systm.h>
35 #include <sys/sysmacros.h>
36 #include <sys/buf.h>
37 #include <sys/cred.h>
38 #include <sys/uio.h>
39 #include <sys/vnode.h>
40 #include <sys/fs/snode.h>
41 #include <sys/open.h>
42 #include <sys/kmem.h>
43 #include <sys/file.h>
44 #include <sys/bootconf.h>
45 #include <sys/pathname.h>
46 #include <sys/bitmap.h>
47 #include <sys/stat.h>
48 #include <sys/dditypes.h>
49 #include <sys/ddi_impldefs.h>
50 #include <sys/ddi.h>
51 #include <sys/sunddi.h>
52 #include <sys/sunndi.h>
53 #include <sys/esunddi.h>
54 #include <sys/autoconf.h>
55 #include <sys/sunldi.h>
56 #include <sys/sunldi_impl.h>
57 #include <sys/errno.h>
58 #include <sys/debug.h>
59 #include <sys/modctl.h>
60 #include <sys/var.h>
61 #include <vm/seg_vn.h>
62 
63 #include <sys/stropts.h>
64 #include <sys/strsubr.h>
65 #include <sys/socket.h>
66 #include <sys/socketvar.h>
67 #include <sys/kstr.h>
68 
69 /*
70  * Device contract related
71  */
72 #include <sys/contract_impl.h>
73 #include <sys/contract/device_impl.h>
74 
75 /*
76  * Define macros to manipulate snode, vnode, and open device flags
77  */
78 #define	VTYP_VALID(i)	(((i) == VCHR) || ((i) == VBLK))
79 #define	VTYP_TO_OTYP(i)	(((i) == VCHR) ? OTYP_CHR : OTYP_BLK)
80 #define	VTYP_TO_STYP(i)	(((i) == VCHR) ? S_IFCHR : S_IFBLK)
81 
82 #define	OTYP_VALID(i)	(((i) == OTYP_CHR) || ((i) == OTYP_BLK))
83 #define	OTYP_TO_VTYP(i)	(((i) == OTYP_CHR) ? VCHR : VBLK)
84 #define	OTYP_TO_STYP(i)	(((i) == OTYP_CHR) ? S_IFCHR : S_IFBLK)
85 
86 #define	STYP_VALID(i)	(((i) == S_IFCHR) || ((i) == S_IFBLK))
87 #define	STYP_TO_VTYP(i)	(((i) == S_IFCHR) ? VCHR : VBLK)
88 
89 /*
90  * Define macros for accessing layered driver hash structures
91  */
92 #define	LH_HASH(vp)		(handle_hash_func(vp) % LH_HASH_SZ)
93 #define	LI_HASH(mid, dip, dev)	(ident_hash_func(mid, dip, dev) % LI_HASH_SZ)
94 
95 /*
96  * Define layered handle flags used in the lh_type field
97  */
98 #define	LH_STREAM	(0x1)	/* handle to a streams device */
99 #define	LH_CBDEV	(0x2)	/* handle to a char/block device */
100 
101 /*
102  * Define macro for devid property lookups
103  */
104 #define	DEVID_PROP_FLAGS	(DDI_PROP_DONTPASS | \
105 				DDI_PROP_TYPE_STRING|DDI_PROP_CANSLEEP)
106 
107 /*
108  * Dummy string for NDI events
109  */
110 #define	NDI_EVENT_SERVICE	"NDI_EVENT_SERVICE"
111 
112 static void ldi_ev_lock(void);
113 static void ldi_ev_unlock(void);
114 
115 #ifdef	LDI_OBSOLETE_EVENT
116 int ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id);
117 #endif
118 
119 
120 /*
121  * globals
122  */
123 static kmutex_t			ldi_ident_hash_lock[LI_HASH_SZ];
124 static struct ldi_ident		*ldi_ident_hash[LI_HASH_SZ];
125 
126 static kmutex_t			ldi_handle_hash_lock[LH_HASH_SZ];
127 static struct ldi_handle	*ldi_handle_hash[LH_HASH_SZ];
128 static size_t			ldi_handle_hash_count;
129 
130 static struct ldi_ev_callback_list ldi_ev_callback_list;
131 
132 static uint32_t ldi_ev_id_pool = 0;
133 
134 struct ldi_ev_cookie {
135 	char *ck_evname;
136 	uint_t ck_sync;
137 	uint_t ck_ctype;
138 };
139 
140 static struct ldi_ev_cookie ldi_ev_cookies[] = {
141 	{ LDI_EV_OFFLINE, 1, CT_DEV_EV_OFFLINE},
142 	{ LDI_EV_DEGRADE, 0, CT_DEV_EV_DEGRADED},
143 	{ LDI_EV_DEVICE_REMOVE, 0, 0},
144 	{ NULL}			/* must terminate list */
145 };
146 
147 void
148 ldi_init(void)
149 {
150 	int i;
151 
152 	ldi_handle_hash_count = 0;
153 	for (i = 0; i < LH_HASH_SZ; i++) {
154 		mutex_init(&ldi_handle_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
155 		ldi_handle_hash[i] = NULL;
156 	}
157 	for (i = 0; i < LI_HASH_SZ; i++) {
158 		mutex_init(&ldi_ident_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
159 		ldi_ident_hash[i] = NULL;
160 	}
161 
162 	/*
163 	 * Initialize the LDI event subsystem
164 	 */
165 	mutex_init(&ldi_ev_callback_list.le_lock, NULL, MUTEX_DEFAULT, NULL);
166 	cv_init(&ldi_ev_callback_list.le_cv, NULL, CV_DEFAULT, NULL);
167 	ldi_ev_callback_list.le_busy = 0;
168 	ldi_ev_callback_list.le_thread = NULL;
169 	list_create(&ldi_ev_callback_list.le_head,
170 	    sizeof (ldi_ev_callback_impl_t),
171 	    offsetof(ldi_ev_callback_impl_t, lec_list));
172 }
173 
174 /*
175  * LDI ident manipulation functions
176  */
177 static uint_t
178 ident_hash_func(modid_t modid, dev_info_t *dip, dev_t dev)
179 {
180 	if (dip != NULL) {
181 		uintptr_t k = (uintptr_t)dip;
182 		k >>= (int)highbit(sizeof (struct dev_info));
183 		return ((uint_t)k);
184 	} else if (dev != DDI_DEV_T_NONE) {
185 		return (modid + getminor(dev) + getmajor(dev));
186 	} else {
187 		return (modid);
188 	}
189 }
190 
191 static struct ldi_ident **
192 ident_find_ref_nolock(modid_t modid, dev_info_t *dip, dev_t dev, major_t major)
193 {
194 	struct ldi_ident	**lipp = NULL;
195 	uint_t			index = LI_HASH(modid, dip, dev);
196 
197 	ASSERT(MUTEX_HELD(&ldi_ident_hash_lock[index]));
198 
199 	for (lipp = &(ldi_ident_hash[index]);
200 	    (*lipp != NULL);
201 	    lipp = &((*lipp)->li_next)) {
202 		if (((*lipp)->li_modid == modid) &&
203 		    ((*lipp)->li_major == major) &&
204 		    ((*lipp)->li_dip == dip) &&
205 		    ((*lipp)->li_dev == dev))
206 			break;
207 	}
208 
209 	ASSERT(lipp != NULL);
210 	return (lipp);
211 }
212 
213 static struct ldi_ident *
214 ident_alloc(char *mod_name, dev_info_t *dip, dev_t dev, major_t major)
215 {
216 	struct ldi_ident	*lip, **lipp, *retlip;
217 	modid_t			modid;
218 	uint_t			index;
219 
220 	ASSERT(mod_name != NULL);
221 
222 	/* get the module id */
223 	modid = mod_name_to_modid(mod_name);
224 	ASSERT(modid != -1);
225 
226 	/* allocate a new ident in case we need it */
227 	lip = kmem_zalloc(sizeof (*lip), KM_SLEEP);
228 
229 	/* search the hash for a matching ident */
230 	index = LI_HASH(modid, dip, dev);
231 	mutex_enter(&ldi_ident_hash_lock[index]);
232 	lipp = ident_find_ref_nolock(modid, dip, dev, major);
233 
234 	if (*lipp != NULL) {
235 		/* we found an ident in the hash */
236 		ASSERT(strcmp((*lipp)->li_modname, mod_name) == 0);
237 		(*lipp)->li_ref++;
238 		retlip = *lipp;
239 		mutex_exit(&ldi_ident_hash_lock[index]);
240 		kmem_free(lip, sizeof (struct ldi_ident));
241 		return (retlip);
242 	}
243 
244 	/* initialize the new ident */
245 	lip->li_next = NULL;
246 	lip->li_ref = 1;
247 	lip->li_modid = modid;
248 	lip->li_major = major;
249 	lip->li_dip = dip;
250 	lip->li_dev = dev;
251 	(void) strncpy(lip->li_modname, mod_name, sizeof (lip->li_modname) - 1);
252 
253 	/* add it to the ident hash */
254 	lip->li_next = ldi_ident_hash[index];
255 	ldi_ident_hash[index] = lip;
256 
257 	mutex_exit(&ldi_ident_hash_lock[index]);
258 	return (lip);
259 }
260 
261 static void
262 ident_hold(struct ldi_ident *lip)
263 {
264 	uint_t			index;
265 
266 	ASSERT(lip != NULL);
267 	index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
268 	mutex_enter(&ldi_ident_hash_lock[index]);
269 	ASSERT(lip->li_ref > 0);
270 	lip->li_ref++;
271 	mutex_exit(&ldi_ident_hash_lock[index]);
272 }
273 
274 static void
275 ident_release(struct ldi_ident *lip)
276 {
277 	struct ldi_ident	**lipp;
278 	uint_t			index;
279 
280 	ASSERT(lip != NULL);
281 	index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
282 	mutex_enter(&ldi_ident_hash_lock[index]);
283 
284 	ASSERT(lip->li_ref > 0);
285 	if (--lip->li_ref > 0) {
286 		/* there are more references to this ident */
287 		mutex_exit(&ldi_ident_hash_lock[index]);
288 		return;
289 	}
290 
291 	/* this was the last reference/open for this ident.  free it. */
292 	lipp = ident_find_ref_nolock(
293 	    lip->li_modid, lip->li_dip, lip->li_dev, lip->li_major);
294 
295 	ASSERT((lipp != NULL) && (*lipp != NULL));
296 	*lipp = lip->li_next;
297 	mutex_exit(&ldi_ident_hash_lock[index]);
298 	kmem_free(lip, sizeof (struct ldi_ident));
299 }
300 
301 /*
302  * LDI handle manipulation functions
303  */
304 static uint_t
305 handle_hash_func(void *vp)
306 {
307 	uintptr_t k = (uintptr_t)vp;
308 	k >>= (int)highbit(sizeof (vnode_t));
309 	return ((uint_t)k);
310 }
311 
312 static struct ldi_handle **
313 handle_find_ref_nolock(vnode_t *vp, struct ldi_ident *ident)
314 {
315 	struct ldi_handle	**lhpp = NULL;
316 	uint_t			index = LH_HASH(vp);
317 
318 	ASSERT(MUTEX_HELD(&ldi_handle_hash_lock[index]));
319 
320 	for (lhpp = &(ldi_handle_hash[index]);
321 	    (*lhpp != NULL);
322 	    lhpp = &((*lhpp)->lh_next)) {
323 		if (((*lhpp)->lh_ident == ident) &&
324 		    ((*lhpp)->lh_vp == vp))
325 			break;
326 	}
327 
328 	ASSERT(lhpp != NULL);
329 	return (lhpp);
330 }
331 
332 static struct ldi_handle *
333 handle_find(vnode_t *vp, struct ldi_ident *ident)
334 {
335 	struct ldi_handle	**lhpp, *retlhp;
336 	int			index = LH_HASH(vp);
337 
338 	mutex_enter(&ldi_handle_hash_lock[index]);
339 	lhpp = handle_find_ref_nolock(vp, ident);
340 	retlhp = *lhpp;
341 	mutex_exit(&ldi_handle_hash_lock[index]);
342 	return (retlhp);
343 }
344 
345 static struct ldi_handle *
346 handle_alloc(vnode_t *vp, struct ldi_ident *ident)
347 {
348 	struct ldi_handle	*lhp, **lhpp, *retlhp;
349 	uint_t			index;
350 
351 	ASSERT((vp != NULL) && (ident != NULL));
352 
353 	/* allocate a new handle in case we need it */
354 	lhp = kmem_zalloc(sizeof (*lhp), KM_SLEEP);
355 
356 	/* search the hash for a matching handle */
357 	index = LH_HASH(vp);
358 	mutex_enter(&ldi_handle_hash_lock[index]);
359 	lhpp = handle_find_ref_nolock(vp, ident);
360 
361 	if (*lhpp != NULL) {
362 		/* we found a handle in the hash */
363 		(*lhpp)->lh_ref++;
364 		retlhp = *lhpp;
365 		mutex_exit(&ldi_handle_hash_lock[index]);
366 
367 		LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: dup "
368 		    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
369 		    (void *)retlhp, (void *)ident, (void *)vp,
370 		    mod_major_to_name(getmajor(vp->v_rdev)),
371 		    getminor(vp->v_rdev)));
372 
373 		kmem_free(lhp, sizeof (struct ldi_handle));
374 		return (retlhp);
375 	}
376 
377 	/* initialize the new handle */
378 	lhp->lh_ref = 1;
379 	lhp->lh_vp = vp;
380 	lhp->lh_ident = ident;
381 #ifdef	LDI_OBSOLETE_EVENT
382 	mutex_init(lhp->lh_lock, NULL, MUTEX_DEFAULT, NULL);
383 #endif
384 
385 	/* set the device type for this handle */
386 	lhp->lh_type = 0;
387 	if (vp->v_stream) {
388 		ASSERT(vp->v_type == VCHR);
389 		lhp->lh_type |= LH_STREAM;
390 	} else {
391 		lhp->lh_type |= LH_CBDEV;
392 	}
393 
394 	/* get holds on other objects */
395 	ident_hold(ident);
396 	ASSERT(vp->v_count >= 1);
397 	VN_HOLD(vp);
398 
399 	/* add it to the handle hash */
400 	lhp->lh_next = ldi_handle_hash[index];
401 	ldi_handle_hash[index] = lhp;
402 	atomic_add_long(&ldi_handle_hash_count, 1);
403 
404 	LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: new "
405 	    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
406 	    (void *)lhp, (void *)ident, (void *)vp,
407 	    mod_major_to_name(getmajor(vp->v_rdev)),
408 	    getminor(vp->v_rdev)));
409 
410 	mutex_exit(&ldi_handle_hash_lock[index]);
411 	return (lhp);
412 }
413 
414 static void
415 handle_release(struct ldi_handle *lhp)
416 {
417 	struct ldi_handle	**lhpp;
418 	uint_t			index;
419 
420 	ASSERT(lhp != NULL);
421 
422 	index = LH_HASH(lhp->lh_vp);
423 	mutex_enter(&ldi_handle_hash_lock[index]);
424 
425 	LDI_ALLOCFREE((CE_WARN, "ldi handle release: "
426 	    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
427 	    (void *)lhp, (void *)lhp->lh_ident, (void *)lhp->lh_vp,
428 	    mod_major_to_name(getmajor(lhp->lh_vp->v_rdev)),
429 	    getminor(lhp->lh_vp->v_rdev)));
430 
431 	ASSERT(lhp->lh_ref > 0);
432 	if (--lhp->lh_ref > 0) {
433 		/* there are more references to this handle */
434 		mutex_exit(&ldi_handle_hash_lock[index]);
435 		return;
436 	}
437 
438 	/* this was the last reference/open for this handle.  free it. */
439 	lhpp = handle_find_ref_nolock(lhp->lh_vp, lhp->lh_ident);
440 	ASSERT((lhpp != NULL) && (*lhpp != NULL));
441 	*lhpp = lhp->lh_next;
442 	atomic_add_long(&ldi_handle_hash_count, -1);
443 	mutex_exit(&ldi_handle_hash_lock[index]);
444 
445 	VN_RELE(lhp->lh_vp);
446 	ident_release(lhp->lh_ident);
447 #ifdef	LDI_OBSOLETE_EVENT
448 	mutex_destroy(lhp->lh_lock);
449 #endif
450 	kmem_free(lhp, sizeof (struct ldi_handle));
451 }
452 
453 #ifdef	LDI_OBSOLETE_EVENT
454 /*
455  * LDI event manipulation functions
456  */
457 static void
458 handle_event_add(ldi_event_t *lep)
459 {
460 	struct ldi_handle *lhp = lep->le_lhp;
461 
462 	ASSERT(lhp != NULL);
463 
464 	mutex_enter(lhp->lh_lock);
465 	if (lhp->lh_events == NULL) {
466 		lhp->lh_events = lep;
467 		mutex_exit(lhp->lh_lock);
468 		return;
469 	}
470 
471 	lep->le_next = lhp->lh_events;
472 	lhp->lh_events->le_prev = lep;
473 	lhp->lh_events = lep;
474 	mutex_exit(lhp->lh_lock);
475 }
476 
477 static void
478 handle_event_remove(ldi_event_t *lep)
479 {
480 	struct ldi_handle *lhp = lep->le_lhp;
481 
482 	ASSERT(lhp != NULL);
483 
484 	mutex_enter(lhp->lh_lock);
485 	if (lep->le_prev)
486 		lep->le_prev->le_next = lep->le_next;
487 	if (lep->le_next)
488 		lep->le_next->le_prev = lep->le_prev;
489 	if (lhp->lh_events == lep)
490 		lhp->lh_events = lep->le_next;
491 	mutex_exit(lhp->lh_lock);
492 
493 }
494 
495 static void
496 i_ldi_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie,
497     void *arg, void *bus_impldata)
498 {
499 	ldi_event_t *lep = (ldi_event_t *)arg;
500 
501 	ASSERT(lep != NULL);
502 
503 	LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, "
504 	    "event_cookie=0x%p, ldi_eventp=0x%p", "i_ldi_callback",
505 	    (void *)dip, (void *)event_cookie, (void *)lep));
506 
507 	lep->le_handler(lep->le_lhp, event_cookie, lep->le_arg, bus_impldata);
508 }
509 #endif
510 
511 /*
512  * LDI open helper functions
513  */
514 
515 /* get a vnode to a device by dev_t and otyp */
516 static int
517 ldi_vp_from_dev(dev_t dev, int otyp, vnode_t **vpp)
518 {
519 	dev_info_t		*dip;
520 	vnode_t			*vp;
521 
522 	/* sanity check required input parameters */
523 	if ((dev == DDI_DEV_T_NONE) || (!OTYP_VALID(otyp)) || (vpp == NULL))
524 		return (EINVAL);
525 
526 	if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
527 		return (ENODEV);
528 
529 	vp = makespecvp(dev, OTYP_TO_VTYP(otyp));
530 	spec_assoc_vp_with_devi(vp, dip);
531 	ddi_release_devi(dip);  /* from e_ddi_hold_devi_by_dev */
532 
533 	*vpp = vp;
534 	return (0);
535 }
536 
537 /* get a vnode to a device by pathname */
538 int
539 ldi_vp_from_name(char *path, vnode_t **vpp)
540 {
541 	vnode_t			*vp = NULL;
542 	int			ret;
543 
544 	/* sanity check required input parameters */
545 	if ((path == NULL) || (vpp == NULL))
546 		return (EINVAL);
547 
548 	if (modrootloaded) {
549 		cred_t *saved_cred = curthread->t_cred;
550 
551 		/* we don't want lookupname to fail because of credentials */
552 		curthread->t_cred = kcred;
553 
554 		/*
555 		 * all lookups should be done in the global zone.  but
556 		 * lookupnameat() won't actually do this if an absolute
557 		 * path is passed in.  since the ldi interfaces require an
558 		 * absolute path we pass lookupnameat() a pointer to
559 		 * the character after the leading '/' and tell it to
560 		 * start searching at the current system root directory.
561 		 */
562 		ASSERT(*path == '/');
563 		ret = lookupnameat(path + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
564 		    &vp, rootdir);
565 
566 		/* restore this threads credentials */
567 		curthread->t_cred = saved_cred;
568 
569 		if (ret == 0) {
570 			if (!vn_matchops(vp, spec_getvnodeops()) ||
571 			    !VTYP_VALID(vp->v_type)) {
572 				VN_RELE(vp);
573 				return (ENXIO);
574 			}
575 		}
576 	}
577 
578 	if (vp == NULL) {
579 		dev_info_t	*dip;
580 		dev_t		dev;
581 		int		spec_type;
582 
583 		/*
584 		 * Root is not mounted, the minor node is not specified,
585 		 * or an OBP path has been specified.
586 		 */
587 
588 		/*
589 		 * Determine if path can be pruned to produce an
590 		 * OBP or devfs path for resolve_pathname.
591 		 */
592 		if (strncmp(path, "/devices/", 9) == 0)
593 			path += strlen("/devices");
594 
595 		/*
596 		 * if no minor node was specified the DEFAULT minor node
597 		 * will be returned.  if there is no DEFAULT minor node
598 		 * one will be fabricated of type S_IFCHR with the minor
599 		 * number equal to the instance number.
600 		 */
601 		ret = resolve_pathname(path, &dip, &dev, &spec_type);
602 		if (ret != 0)
603 			return (ENODEV);
604 
605 		ASSERT(STYP_VALID(spec_type));
606 		vp = makespecvp(dev, STYP_TO_VTYP(spec_type));
607 		spec_assoc_vp_with_devi(vp, dip);
608 		ddi_release_devi(dip);
609 	}
610 
611 	*vpp = vp;
612 	return (0);
613 }
614 
615 static int
616 ldi_devid_match(ddi_devid_t devid, dev_info_t *dip, dev_t dev)
617 {
618 	char		*devidstr;
619 	ddi_prop_t	*propp;
620 
621 	/* convert devid as a string property */
622 	if ((devidstr = ddi_devid_str_encode(devid, NULL)) == NULL)
623 		return (0);
624 
625 	/*
626 	 * Search for the devid.  For speed and ease in locking this
627 	 * code directly uses the property implementation.  See
628 	 * ddi_common_devid_to_devlist() for a comment as to why.
629 	 */
630 	mutex_enter(&(DEVI(dip)->devi_lock));
631 
632 	/* check if there is a DDI_DEV_T_NONE devid property */
633 	propp = i_ddi_prop_search(DDI_DEV_T_NONE,
634 	    DEVID_PROP_NAME, DEVID_PROP_FLAGS, &DEVI(dip)->devi_hw_prop_ptr);
635 	if (propp != NULL) {
636 		if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
637 			/* a DDI_DEV_T_NONE devid exists and matchs */
638 			mutex_exit(&(DEVI(dip)->devi_lock));
639 			ddi_devid_str_free(devidstr);
640 			return (1);
641 		} else {
642 			/* a DDI_DEV_T_NONE devid exists and doesn't match */
643 			mutex_exit(&(DEVI(dip)->devi_lock));
644 			ddi_devid_str_free(devidstr);
645 			return (0);
646 		}
647 	}
648 
649 	/* check if there is a devt specific devid property */
650 	propp = i_ddi_prop_search(dev,
651 	    DEVID_PROP_NAME, DEVID_PROP_FLAGS, &(DEVI(dip)->devi_hw_prop_ptr));
652 	if (propp != NULL) {
653 		if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
654 			/* a devt specific devid exists and matchs */
655 			mutex_exit(&(DEVI(dip)->devi_lock));
656 			ddi_devid_str_free(devidstr);
657 			return (1);
658 		} else {
659 			/* a devt specific devid exists and doesn't match */
660 			mutex_exit(&(DEVI(dip)->devi_lock));
661 			ddi_devid_str_free(devidstr);
662 			return (0);
663 		}
664 	}
665 
666 	/* we didn't find any devids associated with the device */
667 	mutex_exit(&(DEVI(dip)->devi_lock));
668 	ddi_devid_str_free(devidstr);
669 	return (0);
670 }
671 
672 /* get a handle to a device by devid and minor name */
673 int
674 ldi_vp_from_devid(ddi_devid_t devid, char *minor_name, vnode_t **vpp)
675 {
676 	dev_info_t		*dip;
677 	vnode_t			*vp;
678 	int			ret, i, ndevs, styp;
679 	dev_t			dev, *devs;
680 
681 	/* sanity check required input parameters */
682 	if ((devid == NULL) || (minor_name == NULL) || (vpp == NULL))
683 		return (EINVAL);
684 
685 	ret = ddi_lyr_devid_to_devlist(devid, minor_name, &ndevs, &devs);
686 	if ((ret != DDI_SUCCESS) || (ndevs <= 0))
687 		return (ENODEV);
688 
689 	for (i = 0; i < ndevs; i++) {
690 		dev = devs[i];
691 
692 		if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
693 			continue;
694 
695 		/*
696 		 * now we have to verify that the devid of the disk
697 		 * still matches what was requested.
698 		 *
699 		 * we have to do this because the devid could have
700 		 * changed between the call to ddi_lyr_devid_to_devlist()
701 		 * and e_ddi_hold_devi_by_dev().  this is because when
702 		 * ddi_lyr_devid_to_devlist() returns a list of devts
703 		 * there is no kind of hold on those devts so a device
704 		 * could have been replaced out from under us in the
705 		 * interim.
706 		 */
707 		if ((i_ddi_minorname_to_devtspectype(dip, minor_name,
708 		    NULL, &styp) == DDI_SUCCESS) &&
709 		    ldi_devid_match(devid, dip, dev))
710 			break;
711 
712 		ddi_release_devi(dip);	/* from e_ddi_hold_devi_by_dev() */
713 	}
714 
715 	ddi_lyr_free_devlist(devs, ndevs);
716 
717 	if (i == ndevs)
718 		return (ENODEV);
719 
720 	ASSERT(STYP_VALID(styp));
721 	vp = makespecvp(dev, STYP_TO_VTYP(styp));
722 	spec_assoc_vp_with_devi(vp, dip);
723 	ddi_release_devi(dip);		/* from e_ddi_hold_devi_by_dev */
724 
725 	*vpp = vp;
726 	return (0);
727 }
728 
729 /* given a vnode, open a device */
730 static int
731 ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
732     ldi_handle_t *lhp, struct ldi_ident *li)
733 {
734 	struct ldi_handle	*nlhp;
735 	vnode_t			*vp;
736 	int			err;
737 
738 	ASSERT((vpp != NULL) && (*vpp != NULL));
739 	ASSERT((lhp != NULL) && (li != NULL));
740 
741 	vp = *vpp;
742 	/* if the vnode passed in is not a device, then bail */
743 	if (!vn_matchops(vp, spec_getvnodeops()) || !VTYP_VALID(vp->v_type))
744 		return (ENXIO);
745 
746 	/*
747 	 * the caller may have specified a node that
748 	 * doesn't have cb_ops defined.  the ldi doesn't yet
749 	 * support opening devices without a valid cb_ops.
750 	 */
751 	if (devopsp[getmajor(vp->v_rdev)]->devo_cb_ops == NULL)
752 		return (ENXIO);
753 
754 	/* open the device */
755 	if ((err = VOP_OPEN(&vp, flag | FKLYR, cr, NULL)) != 0)
756 		return (err);
757 
758 	/* possible clone open, make sure that we still have a spec node */
759 	ASSERT(vn_matchops(vp, spec_getvnodeops()));
760 
761 	nlhp = handle_alloc(vp, li);
762 
763 	if (vp != *vpp) {
764 		/*
765 		 * allocating the layered handle took a new hold on the vnode
766 		 * so we can release the hold that was returned by the clone
767 		 * open
768 		 */
769 		LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
770 		    "ldi clone open", (void *)nlhp));
771 	} else {
772 		LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
773 		    "ldi open", (void *)nlhp));
774 	}
775 
776 	*vpp = vp;
777 	*lhp = (ldi_handle_t)nlhp;
778 	return (0);
779 }
780 
781 /* Call a drivers prop_op(9E) interface */
782 static int
783 i_ldi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
784     int flags, char *name, caddr_t valuep, int *lengthp)
785 {
786 	struct dev_ops	*ops = NULL;
787 	int		res;
788 
789 	ASSERT((dip != NULL) && (name != NULL));
790 	ASSERT((prop_op == PROP_LEN) || (valuep != NULL));
791 	ASSERT(lengthp != NULL);
792 
793 	/*
794 	 * we can only be invoked after a driver has been opened and
795 	 * someone has a layered handle to it, so there had better be
796 	 * a valid ops vector.
797 	 */
798 	ops = DEVI(dip)->devi_ops;
799 	ASSERT(ops && ops->devo_cb_ops);
800 
801 	/*
802 	 * Some nexus drivers incorrectly set cb_prop_op to nodev,
803 	 * nulldev or even NULL.
804 	 */
805 	if ((ops->devo_cb_ops->cb_prop_op == nodev) ||
806 	    (ops->devo_cb_ops->cb_prop_op == nulldev) ||
807 	    (ops->devo_cb_ops->cb_prop_op == NULL)) {
808 		return (DDI_PROP_NOT_FOUND);
809 	}
810 
811 	/* check if this is actually DDI_DEV_T_ANY query */
812 	if (flags & LDI_DEV_T_ANY) {
813 		flags &= ~LDI_DEV_T_ANY;
814 		dev = DDI_DEV_T_ANY;
815 	}
816 
817 	res = cdev_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp);
818 	return (res);
819 }
820 
821 static void
822 i_ldi_prop_op_free(struct prop_driver_data *pdd)
823 {
824 	kmem_free(pdd, pdd->pdd_size);
825 }
826 
827 static caddr_t
828 i_ldi_prop_op_alloc(int prop_len)
829 {
830 	struct prop_driver_data	*pdd;
831 	int			pdd_size;
832 
833 	pdd_size = sizeof (struct prop_driver_data) + prop_len;
834 	pdd = kmem_alloc(pdd_size, KM_SLEEP);
835 	pdd->pdd_size = pdd_size;
836 	pdd->pdd_prop_free = i_ldi_prop_op_free;
837 	return ((caddr_t)&pdd[1]);
838 }
839 
840 /*
841  * i_ldi_prop_op_typed() is a wrapper for i_ldi_prop_op that is used
842  * by the typed ldi property lookup interfaces.
843  */
844 static int
845 i_ldi_prop_op_typed(dev_t dev, dev_info_t *dip, int flags, char *name,
846     caddr_t *datap, int *lengthp, int elem_size)
847 {
848 	caddr_t	prop_val;
849 	int	prop_len, res;
850 
851 	ASSERT((dip != NULL) && (name != NULL));
852 	ASSERT((datap != NULL) && (lengthp != NULL));
853 
854 	/*
855 	 * first call the drivers prop_op() interface to allow it
856 	 * it to override default property values.
857 	 */
858 	res = i_ldi_prop_op(dev, dip, PROP_LEN,
859 	    flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
860 	if (res != DDI_PROP_SUCCESS)
861 		return (DDI_PROP_NOT_FOUND);
862 
863 	/* sanity check the property length */
864 	if (prop_len == 0) {
865 		/*
866 		 * the ddi typed interfaces don't allow a drivers to
867 		 * create properties with a length of 0.  so we should
868 		 * prevent drivers from returning 0 length dynamic
869 		 * properties for typed property lookups.
870 		 */
871 		return (DDI_PROP_NOT_FOUND);
872 	}
873 
874 	/* sanity check the property length against the element size */
875 	if (elem_size && ((prop_len % elem_size) != 0))
876 		return (DDI_PROP_NOT_FOUND);
877 
878 	/*
879 	 * got it.  now allocate a prop_driver_data struct so that the
880 	 * user can free the property via ddi_prop_free().
881 	 */
882 	prop_val = i_ldi_prop_op_alloc(prop_len);
883 
884 	/* lookup the property again, this time get the value */
885 	res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
886 	    flags | DDI_PROP_DYNAMIC, name, prop_val, &prop_len);
887 	if (res != DDI_PROP_SUCCESS) {
888 		ddi_prop_free(prop_val);
889 		return (DDI_PROP_NOT_FOUND);
890 	}
891 
892 	/* sanity check the property length */
893 	if (prop_len == 0) {
894 		ddi_prop_free(prop_val);
895 		return (DDI_PROP_NOT_FOUND);
896 	}
897 
898 	/* sanity check the property length against the element size */
899 	if (elem_size && ((prop_len % elem_size) != 0)) {
900 		ddi_prop_free(prop_val);
901 		return (DDI_PROP_NOT_FOUND);
902 	}
903 
904 	/*
905 	 * return the prop_driver_data struct and, optionally, the length
906 	 * of the data.
907 	 */
908 	*datap = prop_val;
909 	*lengthp = prop_len;
910 
911 	return (DDI_PROP_SUCCESS);
912 }
913 
914 /*
915  * i_check_string looks at a string property and makes sure its
916  * a valid null terminated string
917  */
918 static int
919 i_check_string(char *str, int prop_len)
920 {
921 	int i;
922 
923 	ASSERT(str != NULL);
924 
925 	for (i = 0; i < prop_len; i++) {
926 		if (str[i] == '\0')
927 			return (0);
928 	}
929 	return (1);
930 }
931 
932 /*
933  * i_pack_string_array takes a a string array property that is represented
934  * as a concatenation of strings (with the NULL character included for
935  * each string) and converts it into a format that can be returned by
936  * ldi_prop_lookup_string_array.
937  */
938 static int
939 i_pack_string_array(char *str_concat, int prop_len,
940     char ***str_arrayp, int *nelemp)
941 {
942 	int i, nelem, pack_size;
943 	char **str_array, *strptr;
944 
945 	/*
946 	 * first we need to sanity check the input string array.
947 	 * in essence this can be done my making sure that the last
948 	 * character of the array passed in is null.  (meaning the last
949 	 * string in the array is NULL terminated.
950 	 */
951 	if (str_concat[prop_len - 1] != '\0')
952 		return (1);
953 
954 	/* now let's count the number of strings in the array */
955 	for (nelem = i = 0; i < prop_len; i++)
956 		if (str_concat[i] == '\0')
957 			nelem++;
958 	ASSERT(nelem >= 1);
959 
960 	/* now let's allocate memory for the new packed property */
961 	pack_size = (sizeof (char *) * (nelem + 1)) + prop_len;
962 	str_array = (char **)i_ldi_prop_op_alloc(pack_size);
963 
964 	/* let's copy the actual string data into the new property */
965 	strptr = (char *)&(str_array[nelem + 1]);
966 	bcopy(str_concat, strptr, prop_len);
967 
968 	/* now initialize the string array pointers */
969 	for (i = 0; i < nelem; i++) {
970 		str_array[i] = strptr;
971 		strptr += strlen(strptr) + 1;
972 	}
973 	str_array[nelem] = NULL;
974 
975 	/* set the return values */
976 	*str_arrayp = str_array;
977 	*nelemp = nelem;
978 
979 	return (0);
980 }
981 
982 
983 /*
984  * LDI Project private device usage interfaces
985  */
986 
987 /*
988  * Get a count of how many devices are currentl open by different consumers
989  */
990 int
991 ldi_usage_count()
992 {
993 	return (ldi_handle_hash_count);
994 }
995 
996 static void
997 ldi_usage_walker_tgt_helper(ldi_usage_t *ldi_usage, vnode_t *vp)
998 {
999 	dev_info_t	*dip;
1000 	dev_t		dev;
1001 
1002 	ASSERT(STYP_VALID(VTYP_TO_STYP(vp->v_type)));
1003 
1004 	/* get the target devt */
1005 	dev = vp->v_rdev;
1006 
1007 	/* try to get the target dip */
1008 	dip = VTOCS(vp)->s_dip;
1009 	if (dip != NULL) {
1010 		e_ddi_hold_devi(dip);
1011 	} else if (dev != DDI_DEV_T_NONE) {
1012 		dip = e_ddi_hold_devi_by_dev(dev, 0);
1013 	}
1014 
1015 	/* set the target information */
1016 	ldi_usage->tgt_name = mod_major_to_name(getmajor(dev));
1017 	ldi_usage->tgt_modid = mod_name_to_modid(ldi_usage->tgt_name);
1018 	ldi_usage->tgt_devt = dev;
1019 	ldi_usage->tgt_spec_type = VTYP_TO_STYP(vp->v_type);
1020 	ldi_usage->tgt_dip = dip;
1021 }
1022 
1023 
1024 static int
1025 ldi_usage_walker_helper(struct ldi_ident *lip, vnode_t *vp,
1026     void *arg, int (*callback)(const ldi_usage_t *, void *))
1027 {
1028 	ldi_usage_t	ldi_usage;
1029 	struct devnames	*dnp;
1030 	dev_info_t	*dip;
1031 	major_t		major;
1032 	dev_t		dev;
1033 	int		ret = LDI_USAGE_CONTINUE;
1034 
1035 	/* set the target device information */
1036 	ldi_usage_walker_tgt_helper(&ldi_usage, vp);
1037 
1038 	/* get the source devt */
1039 	dev = lip->li_dev;
1040 
1041 	/* try to get the source dip */
1042 	dip = lip->li_dip;
1043 	if (dip != NULL) {
1044 		e_ddi_hold_devi(dip);
1045 	} else if (dev != DDI_DEV_T_NONE) {
1046 		dip = e_ddi_hold_devi_by_dev(dev, 0);
1047 	}
1048 
1049 	/* set the valid source information */
1050 	ldi_usage.src_modid = lip->li_modid;
1051 	ldi_usage.src_name = lip->li_modname;
1052 	ldi_usage.src_devt = dev;
1053 	ldi_usage.src_dip = dip;
1054 
1055 	/*
1056 	 * if the source ident represents either:
1057 	 *
1058 	 * - a kernel module (and not a device or device driver)
1059 	 * - a device node
1060 	 *
1061 	 * then we currently have all the info we need to report the
1062 	 * usage information so invoke the callback function.
1063 	 */
1064 	if (((lip->li_major == -1) && (dev == DDI_DEV_T_NONE)) ||
1065 	    (dip != NULL)) {
1066 		ret = callback(&ldi_usage, arg);
1067 		if (dip != NULL)
1068 			ddi_release_devi(dip);
1069 		if (ldi_usage.tgt_dip != NULL)
1070 			ddi_release_devi(ldi_usage.tgt_dip);
1071 		return (ret);
1072 	}
1073 
1074 	/*
1075 	 * now this is kinda gross.
1076 	 *
1077 	 * what we do here is attempt to associate every device instance
1078 	 * of the source driver on the system with the open target driver.
1079 	 * we do this because we don't know which instance of the device
1080 	 * could potentially access the lower device so we assume that all
1081 	 * the instances could access it.
1082 	 *
1083 	 * there are two ways we could have gotten here:
1084 	 *
1085 	 * 1) this layered ident represents one created using only a
1086 	 *    major number or a driver module name.  this means that when
1087 	 *    it was created we could not associate it with a particular
1088 	 *    dev_t or device instance.
1089 	 *
1090 	 *    when could this possibly happen you ask?
1091 	 *
1092 	 *    a perfect example of this is streams persistent links.
1093 	 *    when a persistant streams link is formed we can't associate
1094 	 *    the lower device stream with any particular upper device
1095 	 *    stream or instance.  this is because any particular upper
1096 	 *    device stream could be closed, then another could be
1097 	 *    opened with a different dev_t and device instance, and it
1098 	 *    would still have access to the lower linked stream.
1099 	 *
1100 	 *    since any instance of the upper streams driver could
1101 	 *    potentially access the lower stream whenever it wants,
1102 	 *    we represent that here by associating the opened lower
1103 	 *    device with every existing device instance of the upper
1104 	 *    streams driver.
1105 	 *
1106 	 * 2) This case should really never happen but we'll include it
1107 	 *    for completeness.
1108 	 *
1109 	 *    it's possible that we could have gotten here because we
1110 	 *    have a dev_t for the upper device but we couldn't find a
1111 	 *    dip associated with that dev_t.
1112 	 *
1113 	 *    the only types of devices that have dev_t without an
1114 	 *    associated dip are unbound DLPIv2 network devices.  These
1115 	 *    types of devices exist to be able to attach a stream to any
1116 	 *    instance of a hardware network device.  since these types of
1117 	 *    devices are usually hardware devices they should never
1118 	 *    really have other devices open.
1119 	 */
1120 	if (dev != DDI_DEV_T_NONE)
1121 		major = getmajor(dev);
1122 	else
1123 		major = lip->li_major;
1124 
1125 	ASSERT((major >= 0) && (major < devcnt));
1126 
1127 	dnp = &devnamesp[major];
1128 	LOCK_DEV_OPS(&dnp->dn_lock);
1129 	dip = dnp->dn_head;
1130 	while ((dip) && (ret == LDI_USAGE_CONTINUE)) {
1131 		e_ddi_hold_devi(dip);
1132 		UNLOCK_DEV_OPS(&dnp->dn_lock);
1133 
1134 		/* set the source dip */
1135 		ldi_usage.src_dip = dip;
1136 
1137 		/* invoke the callback function */
1138 		ret = callback(&ldi_usage, arg);
1139 
1140 		LOCK_DEV_OPS(&dnp->dn_lock);
1141 		ddi_release_devi(dip);
1142 		dip = ddi_get_next(dip);
1143 	}
1144 	UNLOCK_DEV_OPS(&dnp->dn_lock);
1145 
1146 	/* if there was a target dip, release it */
1147 	if (ldi_usage.tgt_dip != NULL)
1148 		ddi_release_devi(ldi_usage.tgt_dip);
1149 
1150 	return (ret);
1151 }
1152 
1153 /*
1154  * ldi_usage_walker() - this walker reports LDI kernel device usage
1155  * information via the callback() callback function.  the LDI keeps track
1156  * of what devices are being accessed in its own internal data structures.
1157  * this function walks those data structures to determine device usage.
1158  */
1159 void
1160 ldi_usage_walker(void *arg, int (*callback)(const ldi_usage_t *, void *))
1161 {
1162 	struct ldi_handle	*lhp;
1163 	struct ldi_ident	*lip;
1164 	vnode_t			*vp;
1165 	int			i;
1166 	int			ret = LDI_USAGE_CONTINUE;
1167 
1168 	for (i = 0; i < LH_HASH_SZ; i++) {
1169 		mutex_enter(&ldi_handle_hash_lock[i]);
1170 
1171 		lhp = ldi_handle_hash[i];
1172 		while ((lhp != NULL) && (ret == LDI_USAGE_CONTINUE)) {
1173 			lip = lhp->lh_ident;
1174 			vp = lhp->lh_vp;
1175 
1176 			/* invoke the devinfo callback function */
1177 			ret = ldi_usage_walker_helper(lip, vp, arg, callback);
1178 
1179 			lhp = lhp->lh_next;
1180 		}
1181 		mutex_exit(&ldi_handle_hash_lock[i]);
1182 
1183 		if (ret != LDI_USAGE_CONTINUE)
1184 			break;
1185 	}
1186 }
1187 
1188 /*
1189  * LDI Project private interfaces (streams linking interfaces)
1190  *
1191  * Streams supports a type of built in device layering via linking.
1192  * Certain types of streams drivers can be streams multiplexors.
1193  * A streams multiplexor supports the I_LINK/I_PLINK operation.
1194  * These operations allows other streams devices to be linked under the
1195  * multiplexor.  By definition all streams multiplexors are devices
1196  * so this linking is a type of device layering where the multiplexor
1197  * device is layered on top of the device linked below it.
1198  */
1199 
1200 /*
1201  * ldi_mlink_lh() is invoked when streams are linked using LDI handles.
1202  * It is not used for normal I_LINKs and I_PLINKs using file descriptors.
1203  *
1204  * The streams framework keeps track of links via the file_t of the lower
1205  * stream.  The LDI keeps track of devices using a vnode.  In the case
1206  * of a streams link created via an LDI handle, fnk_lh() allocates
1207  * a file_t that the streams framework can use to track the linkage.
1208  */
1209 int
1210 ldi_mlink_lh(vnode_t *vp, int cmd, intptr_t arg, cred_t *crp, int *rvalp)
1211 {
1212 	struct ldi_handle	*lhp = (struct ldi_handle *)arg;
1213 	vnode_t			*vpdown;
1214 	file_t			*fpdown;
1215 	int			err;
1216 
1217 	if (lhp == NULL)
1218 		return (EINVAL);
1219 
1220 	vpdown = lhp->lh_vp;
1221 	ASSERT(vn_matchops(vpdown, spec_getvnodeops()));
1222 	ASSERT(cmd == _I_PLINK_LH);
1223 
1224 	/*
1225 	 * create a new lower vnode and a file_t that points to it,
1226 	 * streams linking requires a file_t.  falloc() returns with
1227 	 * fpdown locked.
1228 	 */
1229 	VN_HOLD(vpdown);
1230 	(void) falloc(vpdown, FREAD|FWRITE, &fpdown, NULL);
1231 	mutex_exit(&fpdown->f_tlock);
1232 
1233 	/* try to establish the link */
1234 	err = mlink_file(vp, I_PLINK, fpdown, crp, rvalp, 1);
1235 
1236 	if (err != 0) {
1237 		/* the link failed, free the file_t and release the vnode */
1238 		mutex_enter(&fpdown->f_tlock);
1239 		unfalloc(fpdown);
1240 		VN_RELE(vpdown);
1241 	}
1242 
1243 	return (err);
1244 }
1245 
1246 /*
1247  * ldi_mlink_fp() is invoked for all successful streams linkages created
1248  * via I_LINK and I_PLINK.  ldi_mlink_fp() records the linkage information
1249  * in its internal state so that the devinfo snapshot code has some
1250  * observability into streams device linkage information.
1251  */
1252 void
1253 ldi_mlink_fp(struct stdata *stp, file_t *fpdown, int lhlink, int type)
1254 {
1255 	vnode_t			*vp = fpdown->f_vnode;
1256 	struct snode		*sp, *csp;
1257 	ldi_ident_t		li;
1258 	major_t			major;
1259 	int			ret;
1260 
1261 	/* if the lower stream is not a device then return */
1262 	if (!vn_matchops(vp, spec_getvnodeops()))
1263 		return;
1264 
1265 	ASSERT(!servicing_interrupt());
1266 
1267 	LDI_STREAMS_LNK((CE_NOTE, "%s: linking streams "
1268 	    "stp=0x%p, fpdown=0x%p", "ldi_mlink_fp",
1269 	    (void *)stp, (void *)fpdown));
1270 
1271 	sp = VTOS(vp);
1272 	csp = VTOS(sp->s_commonvp);
1273 
1274 	/* check if this was a plink via a layered handle */
1275 	if (lhlink) {
1276 		/*
1277 		 * increment the common snode s_count.
1278 		 *
1279 		 * this is done because after the link operation there
1280 		 * are two ways that s_count can be decremented.
1281 		 *
1282 		 * when the layered handle used to create the link is
1283 		 * closed, spec_close() is called and it will decrement
1284 		 * s_count in the common snode.  if we don't increment
1285 		 * s_count here then this could cause spec_close() to
1286 		 * actually close the device while it's still linked
1287 		 * under a multiplexer.
1288 		 *
1289 		 * also, when the lower stream is unlinked, closef() is
1290 		 * called for the file_t associated with this snode.
1291 		 * closef() will call spec_close(), which will decrement
1292 		 * s_count.  if we dont't increment s_count here then this
1293 		 * could cause spec_close() to actually close the device
1294 		 * while there may still be valid layered handles
1295 		 * pointing to it.
1296 		 */
1297 		mutex_enter(&csp->s_lock);
1298 		ASSERT(csp->s_count >= 1);
1299 		csp->s_count++;
1300 		mutex_exit(&csp->s_lock);
1301 
1302 		/*
1303 		 * decrement the f_count.
1304 		 * this is done because the layered driver framework does
1305 		 * not actually cache a copy of the file_t allocated to
1306 		 * do the link.  this is done here instead of in ldi_mlink_lh()
1307 		 * because there is a window in ldi_mlink_lh() between where
1308 		 * milnk_file() returns and we would decrement the f_count
1309 		 * when the stream could be unlinked.
1310 		 */
1311 		mutex_enter(&fpdown->f_tlock);
1312 		fpdown->f_count--;
1313 		mutex_exit(&fpdown->f_tlock);
1314 	}
1315 
1316 	/*
1317 	 * NOTE: here we rely on the streams subsystem not allowing
1318 	 * a stream to be multiplexed more than once.  if this
1319 	 * changes, we break.
1320 	 *
1321 	 * mark the snode/stream as multiplexed
1322 	 */
1323 	mutex_enter(&sp->s_lock);
1324 	ASSERT(!(sp->s_flag & SMUXED));
1325 	sp->s_flag |= SMUXED;
1326 	mutex_exit(&sp->s_lock);
1327 
1328 	/* get a layered ident for the upper stream */
1329 	if (type == LINKNORMAL) {
1330 		/*
1331 		 * if the link is not persistant then we can associate
1332 		 * the upper stream with a dev_t.  this is because the
1333 		 * upper stream is associated with a vnode, which is
1334 		 * associated with a dev_t and this binding can't change
1335 		 * during the life of the stream.  since the link isn't
1336 		 * persistant once the stream is destroyed the link is
1337 		 * destroyed.  so the dev_t will be valid for the life
1338 		 * of the link.
1339 		 */
1340 		ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
1341 	} else {
1342 		/*
1343 		 * if the link is persistant we can only associate the
1344 		 * link with a driver (and not a dev_t.)  this is
1345 		 * because subsequent opens of the upper device may result
1346 		 * in a different stream (and dev_t) having access to
1347 		 * the lower stream.
1348 		 *
1349 		 * for example, if the upper stream is closed after the
1350 		 * persistant link operation is compleated, a subsequent
1351 		 * open of the upper device will create a new stream which
1352 		 * may have a different dev_t and an unlink operation
1353 		 * can be performed using this new upper stream.
1354 		 */
1355 		ASSERT(type == LINKPERSIST);
1356 		major = getmajor(stp->sd_vnode->v_rdev);
1357 		ret = ldi_ident_from_major(major, &li);
1358 	}
1359 
1360 	ASSERT(ret == 0);
1361 	(void) handle_alloc(vp, (struct ldi_ident *)li);
1362 	ldi_ident_release(li);
1363 }
1364 
1365 void
1366 ldi_munlink_fp(struct stdata *stp, file_t *fpdown, int type)
1367 {
1368 	struct ldi_handle	*lhp;
1369 	vnode_t			*vp = (vnode_t *)fpdown->f_vnode;
1370 	struct snode		*sp;
1371 	ldi_ident_t		li;
1372 	major_t			major;
1373 	int			ret;
1374 
1375 	/* if the lower stream is not a device then return */
1376 	if (!vn_matchops(vp, spec_getvnodeops()))
1377 		return;
1378 
1379 	ASSERT(!servicing_interrupt());
1380 	ASSERT((type == LINKNORMAL) || (type == LINKPERSIST));
1381 
1382 	LDI_STREAMS_LNK((CE_NOTE, "%s: unlinking streams "
1383 	    "stp=0x%p, fpdown=0x%p", "ldi_munlink_fp",
1384 	    (void *)stp, (void *)fpdown));
1385 
1386 	/*
1387 	 * NOTE: here we rely on the streams subsystem not allowing
1388 	 * a stream to be multiplexed more than once.  if this
1389 	 * changes, we break.
1390 	 *
1391 	 * mark the snode/stream as not multiplexed
1392 	 */
1393 	sp = VTOS(vp);
1394 	mutex_enter(&sp->s_lock);
1395 	ASSERT(sp->s_flag & SMUXED);
1396 	sp->s_flag &= ~SMUXED;
1397 	mutex_exit(&sp->s_lock);
1398 
1399 	/*
1400 	 * clear the owner for this snode
1401 	 * see the comment in ldi_mlink_fp() for information about how
1402 	 * the ident is allocated
1403 	 */
1404 	if (type == LINKNORMAL) {
1405 		ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
1406 	} else {
1407 		ASSERT(type == LINKPERSIST);
1408 		major = getmajor(stp->sd_vnode->v_rdev);
1409 		ret = ldi_ident_from_major(major, &li);
1410 	}
1411 
1412 	ASSERT(ret == 0);
1413 	lhp = handle_find(vp, (struct ldi_ident *)li);
1414 	handle_release(lhp);
1415 	ldi_ident_release(li);
1416 }
1417 
1418 /*
1419  * LDI Consolidation private interfaces
1420  */
1421 int
1422 ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip)
1423 {
1424 	struct modctl		*modp;
1425 	major_t			major;
1426 	char			*name;
1427 
1428 	if ((modlp == NULL) || (lip == NULL))
1429 		return (EINVAL);
1430 
1431 	ASSERT(!servicing_interrupt());
1432 
1433 	modp = mod_getctl(modlp);
1434 	if (modp == NULL)
1435 		return (EINVAL);
1436 	name = modp->mod_modname;
1437 	if (name == NULL)
1438 		return (EINVAL);
1439 	major = mod_name_to_major(name);
1440 
1441 	*lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
1442 
1443 	LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1444 	    "ldi_ident_from_mod", (void *)*lip, name));
1445 
1446 	return (0);
1447 }
1448 
1449 ldi_ident_t
1450 ldi_ident_from_anon()
1451 {
1452 	ldi_ident_t	lip;
1453 
1454 	ASSERT(!servicing_interrupt());
1455 
1456 	lip = (ldi_ident_t)ident_alloc("genunix", NULL, DDI_DEV_T_NONE, -1);
1457 
1458 	LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1459 	    "ldi_ident_from_anon", (void *)lip, "genunix"));
1460 
1461 	return (lip);
1462 }
1463 
1464 
1465 /*
1466  * LDI Public interfaces
1467  */
1468 int
1469 ldi_ident_from_stream(struct queue *sq, ldi_ident_t *lip)
1470 {
1471 	struct stdata		*stp;
1472 	dev_t			dev;
1473 	char			*name;
1474 
1475 	if ((sq == NULL) || (lip == NULL))
1476 		return (EINVAL);
1477 
1478 	ASSERT(!servicing_interrupt());
1479 
1480 	stp = sq->q_stream;
1481 	if (!vn_matchops(stp->sd_vnode, spec_getvnodeops()))
1482 		return (EINVAL);
1483 
1484 	dev = stp->sd_vnode->v_rdev;
1485 	name = mod_major_to_name(getmajor(dev));
1486 	if (name == NULL)
1487 		return (EINVAL);
1488 	*lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
1489 
1490 	LDI_ALLOCFREE((CE_WARN,
1491 	    "%s: li=0x%p, mod=%s, minor=0x%x, stp=0x%p",
1492 	    "ldi_ident_from_stream", (void *)*lip, name, getminor(dev),
1493 	    (void *)stp));
1494 
1495 	return (0);
1496 }
1497 
1498 int
1499 ldi_ident_from_dev(dev_t dev, ldi_ident_t *lip)
1500 {
1501 	char			*name;
1502 
1503 	if (lip == NULL)
1504 		return (EINVAL);
1505 
1506 	ASSERT(!servicing_interrupt());
1507 
1508 	name = mod_major_to_name(getmajor(dev));
1509 	if (name == NULL)
1510 		return (EINVAL);
1511 	*lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
1512 
1513 	LDI_ALLOCFREE((CE_WARN,
1514 	    "%s: li=0x%p, mod=%s, minor=0x%x",
1515 	    "ldi_ident_from_dev", (void *)*lip, name, getminor(dev)));
1516 
1517 	return (0);
1518 }
1519 
1520 int
1521 ldi_ident_from_dip(dev_info_t *dip, ldi_ident_t *lip)
1522 {
1523 	struct dev_info		*devi = (struct dev_info *)dip;
1524 	char			*name;
1525 
1526 	if ((dip == NULL) || (lip == NULL))
1527 		return (EINVAL);
1528 
1529 	ASSERT(!servicing_interrupt());
1530 
1531 	name = mod_major_to_name(devi->devi_major);
1532 	if (name == NULL)
1533 		return (EINVAL);
1534 	*lip = (ldi_ident_t)ident_alloc(name, dip, DDI_DEV_T_NONE, -1);
1535 
1536 	LDI_ALLOCFREE((CE_WARN,
1537 	    "%s: li=0x%p, mod=%s, dip=0x%p",
1538 	    "ldi_ident_from_dip", (void *)*lip, name, (void *)devi));
1539 
1540 	return (0);
1541 }
1542 
1543 int
1544 ldi_ident_from_major(major_t major, ldi_ident_t *lip)
1545 {
1546 	char			*name;
1547 
1548 	if (lip == NULL)
1549 		return (EINVAL);
1550 
1551 	ASSERT(!servicing_interrupt());
1552 
1553 	name = mod_major_to_name(major);
1554 	if (name == NULL)
1555 		return (EINVAL);
1556 	*lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
1557 
1558 	LDI_ALLOCFREE((CE_WARN,
1559 	    "%s: li=0x%p, mod=%s",
1560 	    "ldi_ident_from_major", (void *)*lip, name));
1561 
1562 	return (0);
1563 }
1564 
1565 void
1566 ldi_ident_release(ldi_ident_t li)
1567 {
1568 	struct ldi_ident	*ident = (struct ldi_ident *)li;
1569 	char			*name;
1570 
1571 	if (li == NULL)
1572 		return;
1573 
1574 	ASSERT(!servicing_interrupt());
1575 
1576 	name = ident->li_modname;
1577 
1578 	LDI_ALLOCFREE((CE_WARN,
1579 	    "%s: li=0x%p, mod=%s",
1580 	    "ldi_ident_release", (void *)li, name));
1581 
1582 	ident_release((struct ldi_ident *)li);
1583 }
1584 
1585 /* get a handle to a device by dev_t and otyp */
1586 int
1587 ldi_open_by_dev(dev_t *devp, int otyp, int flag, cred_t *cr,
1588     ldi_handle_t *lhp, ldi_ident_t li)
1589 {
1590 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1591 	int			ret;
1592 	vnode_t			*vp;
1593 
1594 	/* sanity check required input parameters */
1595 	if ((devp == NULL) || (!OTYP_VALID(otyp)) || (cr == NULL) ||
1596 	    (lhp == NULL) || (lip == NULL))
1597 		return (EINVAL);
1598 
1599 	ASSERT(!servicing_interrupt());
1600 
1601 	if ((ret = ldi_vp_from_dev(*devp, otyp, &vp)) != 0)
1602 		return (ret);
1603 
1604 	if ((ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip)) == 0) {
1605 		*devp = vp->v_rdev;
1606 	}
1607 	VN_RELE(vp);
1608 
1609 	return (ret);
1610 }
1611 
1612 /* get a handle to a device by pathname */
1613 int
1614 ldi_open_by_name(char *pathname, int flag, cred_t *cr,
1615     ldi_handle_t *lhp, ldi_ident_t li)
1616 {
1617 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1618 	int			ret;
1619 	vnode_t			*vp;
1620 
1621 	/* sanity check required input parameters */
1622 	if ((pathname == NULL) || (*pathname != '/') ||
1623 	    (cr == NULL) || (lhp == NULL) || (lip == NULL))
1624 		return (EINVAL);
1625 
1626 	ASSERT(!servicing_interrupt());
1627 
1628 	if ((ret = ldi_vp_from_name(pathname, &vp)) != 0)
1629 		return (ret);
1630 
1631 	ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
1632 	VN_RELE(vp);
1633 
1634 	return (ret);
1635 }
1636 
1637 /* get a handle to a device by devid and minor_name */
1638 int
1639 ldi_open_by_devid(ddi_devid_t devid, char *minor_name,
1640     int flag, cred_t *cr, ldi_handle_t *lhp, ldi_ident_t li)
1641 {
1642 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1643 	int			ret;
1644 	vnode_t			*vp;
1645 
1646 	/* sanity check required input parameters */
1647 	if ((minor_name == NULL) || (cr == NULL) ||
1648 	    (lhp == NULL) || (lip == NULL))
1649 		return (EINVAL);
1650 
1651 	ASSERT(!servicing_interrupt());
1652 
1653 	if ((ret = ldi_vp_from_devid(devid, minor_name, &vp)) != 0)
1654 		return (ret);
1655 
1656 	ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
1657 	VN_RELE(vp);
1658 
1659 	return (ret);
1660 }
1661 
1662 int
1663 ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
1664 {
1665 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1666 	struct ldi_event	*lep;
1667 	int			err = 0;
1668 	int			notify = 0;
1669 	list_t			*listp;
1670 	ldi_ev_callback_impl_t	*lecp;
1671 
1672 	if (lh == NULL)
1673 		return (EINVAL);
1674 
1675 	ASSERT(!servicing_interrupt());
1676 
1677 #ifdef	LDI_OBSOLETE_EVENT
1678 
1679 	/*
1680 	 * Any event handlers should have been unregistered by the
1681 	 * time ldi_close() is called.  If they haven't then it's a
1682 	 * bug.
1683 	 *
1684 	 * In a debug kernel we'll panic to make the problem obvious.
1685 	 */
1686 	ASSERT(handlep->lh_events == NULL);
1687 
1688 	/*
1689 	 * On a production kernel we'll "do the right thing" (unregister
1690 	 * the event handlers) and then complain about having to do the
1691 	 * work ourselves.
1692 	 */
1693 	while ((lep = handlep->lh_events) != NULL) {
1694 		err = 1;
1695 		(void) ldi_remove_event_handler(lh, (ldi_callback_id_t)lep);
1696 	}
1697 	if (err) {
1698 		struct ldi_ident *lip = handlep->lh_ident;
1699 		ASSERT(lip != NULL);
1700 		cmn_err(CE_NOTE, "ldi err: %s "
1701 		    "failed to unregister layered event handlers before "
1702 		    "closing devices", lip->li_modname);
1703 	}
1704 #endif
1705 
1706 	/* do a layered close on the device */
1707 	err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr, NULL);
1708 
1709 	LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", "ldi close", (void *)lh));
1710 
1711 	/*
1712 	 * Search the event callback list for callbacks with this
1713 	 * handle. There are 2 cases
1714 	 * 1. Called in the context of a notify. The handle consumer
1715 	 *    is releasing its hold on the device to allow a reconfiguration
1716 	 *    of the device. Simply NULL out the handle and the notify callback.
1717 	 *    The finalize callback is still available so that the consumer
1718 	 *    knows of the final disposition of the device.
1719 	 * 2. Not called in the context of notify. NULL out the handle as well
1720 	 *    as the notify and finalize callbacks. Since the consumer has
1721 	 *    closed the handle, we assume it is not interested in the
1722 	 *    notify and finalize callbacks.
1723 	 */
1724 	ldi_ev_lock();
1725 
1726 	if (handlep->lh_flags & LH_FLAGS_NOTIFY)
1727 		notify = 1;
1728 	listp = &ldi_ev_callback_list.le_head;
1729 	for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
1730 		if (lecp->lec_lhp != handlep)
1731 			continue;
1732 		lecp->lec_lhp = NULL;
1733 		lecp->lec_notify = NULL;
1734 		LDI_EVDBG((CE_NOTE, "ldi_close: NULLed lh and notify"));
1735 		if (!notify) {
1736 			LDI_EVDBG((CE_NOTE, "ldi_close: NULLed finalize"));
1737 			lecp->lec_finalize = NULL;
1738 		}
1739 	}
1740 
1741 	if (notify)
1742 		handlep->lh_flags &= ~LH_FLAGS_NOTIFY;
1743 	ldi_ev_unlock();
1744 
1745 	/*
1746 	 * Free the handle even if the device close failed.  why?
1747 	 *
1748 	 * If the device close failed we can't really make assumptions
1749 	 * about the devices state so we shouldn't allow access to the
1750 	 * device via this handle any more.  If the device consumer wants
1751 	 * to access the device again they should open it again.
1752 	 *
1753 	 * This is the same way file/device close failures are handled
1754 	 * in other places like spec_close() and closeandsetf().
1755 	 */
1756 	handle_release(handlep);
1757 	return (err);
1758 }
1759 
1760 int
1761 ldi_read(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
1762 {
1763 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1764 	vnode_t			*vp;
1765 	dev_t			dev;
1766 	int			ret;
1767 
1768 	if (lh == NULL)
1769 		return (EINVAL);
1770 
1771 	vp = handlep->lh_vp;
1772 	dev = vp->v_rdev;
1773 	if (handlep->lh_type & LH_CBDEV) {
1774 		ret = cdev_read(dev, uiop, credp);
1775 	} else if (handlep->lh_type & LH_STREAM) {
1776 		ret = strread(vp, uiop, credp);
1777 	} else {
1778 		return (ENOTSUP);
1779 	}
1780 	return (ret);
1781 }
1782 
1783 int
1784 ldi_write(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
1785 {
1786 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1787 	vnode_t			*vp;
1788 	dev_t			dev;
1789 	int			ret;
1790 
1791 	if (lh == NULL)
1792 		return (EINVAL);
1793 
1794 	vp = handlep->lh_vp;
1795 	dev = vp->v_rdev;
1796 	if (handlep->lh_type & LH_CBDEV) {
1797 		ret = cdev_write(dev, uiop, credp);
1798 	} else if (handlep->lh_type & LH_STREAM) {
1799 		ret = strwrite(vp, uiop, credp);
1800 	} else {
1801 		return (ENOTSUP);
1802 	}
1803 	return (ret);
1804 }
1805 
1806 int
1807 ldi_get_size(ldi_handle_t lh, uint64_t *sizep)
1808 {
1809 	int			otyp;
1810 	uint_t			value;
1811 	int64_t			drv_prop64;
1812 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1813 	uint_t			blksize;
1814 	int			blkshift;
1815 
1816 
1817 	if ((lh == NULL) || (sizep == NULL))
1818 		return (DDI_FAILURE);
1819 
1820 	if (handlep->lh_type & LH_STREAM)
1821 		return (DDI_FAILURE);
1822 
1823 	/*
1824 	 * Determine device type (char or block).
1825 	 * Character devices support Size/size
1826 	 * property value. Block devices may support
1827 	 * Nblocks/nblocks or Size/size property value.
1828 	 */
1829 	if ((ldi_get_otyp(lh, &otyp)) != 0)
1830 		return (DDI_FAILURE);
1831 
1832 	if (otyp == OTYP_BLK) {
1833 		if (ldi_prop_exists(lh,
1834 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Nblocks")) {
1835 
1836 			drv_prop64 = ldi_prop_get_int64(lh,
1837 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1838 			    "Nblocks", 0);
1839 			blksize = ldi_prop_get_int(lh,
1840 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1841 			    "blksize", DEV_BSIZE);
1842 			if (blksize == DEV_BSIZE)
1843 				blksize = ldi_prop_get_int(lh, LDI_DEV_T_ANY |
1844 				    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1845 				    "device-blksize", DEV_BSIZE);
1846 
1847 			/* blksize must be a power of two */
1848 			ASSERT(BIT_ONLYONESET(blksize));
1849 			blkshift = highbit(blksize) - 1;
1850 
1851 			/*
1852 			 * We don't support Nblocks values that don't have
1853 			 * an accurate uint64_t byte count representation.
1854 			 */
1855 			if ((uint64_t)drv_prop64 >= (UINT64_MAX >> blkshift))
1856 				return (DDI_FAILURE);
1857 
1858 			*sizep = (uint64_t)
1859 			    (((u_offset_t)drv_prop64) << blkshift);
1860 			return (DDI_SUCCESS);
1861 		}
1862 
1863 		if (ldi_prop_exists(lh,
1864 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "nblocks")) {
1865 
1866 			value = ldi_prop_get_int(lh,
1867 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1868 			    "nblocks", 0);
1869 			blksize = ldi_prop_get_int(lh,
1870 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1871 			    "blksize", DEV_BSIZE);
1872 			if (blksize == DEV_BSIZE)
1873 				blksize = ldi_prop_get_int(lh, LDI_DEV_T_ANY |
1874 				    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1875 				    "device-blksize", DEV_BSIZE);
1876 
1877 			/* blksize must be a power of two */
1878 			ASSERT(BIT_ONLYONESET(blksize));
1879 			blkshift = highbit(blksize) - 1;
1880 
1881 			/*
1882 			 * We don't support nblocks values that don't have an
1883 			 * accurate uint64_t byte count representation.
1884 			 */
1885 			if ((uint64_t)value >= (UINT64_MAX >> blkshift))
1886 				return (DDI_FAILURE);
1887 
1888 			*sizep = (uint64_t)
1889 			    (((u_offset_t)value) << blkshift);
1890 			return (DDI_SUCCESS);
1891 		}
1892 	}
1893 
1894 	if (ldi_prop_exists(lh,
1895 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size")) {
1896 
1897 		drv_prop64 = ldi_prop_get_int64(lh,
1898 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size", 0);
1899 		*sizep = (uint64_t)drv_prop64;
1900 		return (DDI_SUCCESS);
1901 	}
1902 
1903 	if (ldi_prop_exists(lh,
1904 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size")) {
1905 
1906 		value = ldi_prop_get_int(lh,
1907 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size", 0);
1908 		*sizep = (uint64_t)value;
1909 		return (DDI_SUCCESS);
1910 	}
1911 
1912 	/* unable to determine device size */
1913 	return (DDI_FAILURE);
1914 }
1915 
1916 int
1917 ldi_ioctl(ldi_handle_t lh, int cmd, intptr_t arg, int mode,
1918 	cred_t *cr, int *rvalp)
1919 {
1920 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1921 	vnode_t			*vp;
1922 	dev_t			dev;
1923 	int			ret, copymode, unused;
1924 
1925 	if (lh == NULL)
1926 		return (EINVAL);
1927 
1928 	/*
1929 	 * if the data pointed to by arg is located in the kernel then
1930 	 * make sure the FNATIVE flag is set.
1931 	 */
1932 	if (mode & FKIOCTL)
1933 		mode = (mode & ~FMODELS) | FNATIVE | FKIOCTL;
1934 
1935 	/*
1936 	 * Some drivers assume that rvalp will always be non-NULL, so in
1937 	 * an attempt to avoid panics if the caller passed in a NULL
1938 	 * value, update rvalp to point to a temporary variable.
1939 	 */
1940 	if (rvalp == NULL)
1941 		rvalp = &unused;
1942 	vp = handlep->lh_vp;
1943 	dev = vp->v_rdev;
1944 	if (handlep->lh_type & LH_CBDEV) {
1945 		ret = cdev_ioctl(dev, cmd, arg, mode, cr, rvalp);
1946 	} else if (handlep->lh_type & LH_STREAM) {
1947 		copymode = (mode & FKIOCTL) ? K_TO_K : U_TO_K;
1948 
1949 		/*
1950 		 * if we get an I_PLINK from within the kernel the
1951 		 * arg is a layered handle pointer instead of
1952 		 * a file descriptor, so we translate this ioctl
1953 		 * into a private one that can handle this.
1954 		 */
1955 		if ((mode & FKIOCTL) && (cmd == I_PLINK))
1956 			cmd = _I_PLINK_LH;
1957 
1958 		ret = strioctl(vp, cmd, arg, mode, copymode, cr, rvalp);
1959 	} else {
1960 		return (ENOTSUP);
1961 	}
1962 
1963 	return (ret);
1964 }
1965 
1966 int
1967 ldi_poll(ldi_handle_t lh, short events, int anyyet, short *reventsp,
1968     struct pollhead **phpp)
1969 {
1970 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1971 	vnode_t			*vp;
1972 	dev_t			dev;
1973 	int			ret;
1974 
1975 	if (lh == NULL)
1976 		return (EINVAL);
1977 
1978 	vp = handlep->lh_vp;
1979 	dev = vp->v_rdev;
1980 	if (handlep->lh_type & LH_CBDEV) {
1981 		ret = cdev_poll(dev, events, anyyet, reventsp, phpp);
1982 	} else if (handlep->lh_type & LH_STREAM) {
1983 		ret = strpoll(vp->v_stream, events, anyyet, reventsp, phpp);
1984 	} else {
1985 		return (ENOTSUP);
1986 	}
1987 
1988 	return (ret);
1989 }
1990 
1991 int
1992 ldi_prop_op(ldi_handle_t lh, ddi_prop_op_t prop_op,
1993 	int flags, char *name, caddr_t valuep, int *length)
1994 {
1995 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1996 	dev_t			dev;
1997 	dev_info_t		*dip;
1998 	int			ret;
1999 	struct snode		*csp;
2000 
2001 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2002 		return (DDI_PROP_INVAL_ARG);
2003 
2004 	if ((prop_op != PROP_LEN) && (valuep == NULL))
2005 		return (DDI_PROP_INVAL_ARG);
2006 
2007 	if (length == NULL)
2008 		return (DDI_PROP_INVAL_ARG);
2009 
2010 	/*
2011 	 * try to find the associated dip,
2012 	 * this places a hold on the driver
2013 	 */
2014 	dev = handlep->lh_vp->v_rdev;
2015 
2016 	csp = VTOCS(handlep->lh_vp);
2017 	mutex_enter(&csp->s_lock);
2018 	if ((dip = csp->s_dip) != NULL)
2019 		e_ddi_hold_devi(dip);
2020 	mutex_exit(&csp->s_lock);
2021 	if (dip == NULL)
2022 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2023 
2024 	if (dip == NULL)
2025 		return (DDI_PROP_NOT_FOUND);
2026 
2027 	ret = i_ldi_prop_op(dev, dip, prop_op, flags, name, valuep, length);
2028 	ddi_release_devi(dip);
2029 
2030 	return (ret);
2031 }
2032 
2033 int
2034 ldi_strategy(ldi_handle_t lh, struct buf *bp)
2035 {
2036 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2037 	dev_t			dev;
2038 
2039 	if ((lh == NULL) || (bp == NULL))
2040 		return (EINVAL);
2041 
2042 	/* this entry point is only supported for cb devices */
2043 	dev = handlep->lh_vp->v_rdev;
2044 	if (!(handlep->lh_type & LH_CBDEV))
2045 		return (ENOTSUP);
2046 
2047 	bp->b_edev = dev;
2048 	bp->b_dev = cmpdev(dev);
2049 	return (bdev_strategy(bp));
2050 }
2051 
2052 int
2053 ldi_dump(ldi_handle_t lh, caddr_t addr, daddr_t blkno, int nblk)
2054 {
2055 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2056 	dev_t			dev;
2057 
2058 	if (lh == NULL)
2059 		return (EINVAL);
2060 
2061 	/* this entry point is only supported for cb devices */
2062 	dev = handlep->lh_vp->v_rdev;
2063 	if (!(handlep->lh_type & LH_CBDEV))
2064 		return (ENOTSUP);
2065 
2066 	return (bdev_dump(dev, addr, blkno, nblk));
2067 }
2068 
2069 int
2070 ldi_devmap(ldi_handle_t lh, devmap_cookie_t dhp, offset_t off,
2071     size_t len, size_t *maplen, uint_t model)
2072 {
2073 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2074 	dev_t			dev;
2075 
2076 	if (lh == NULL)
2077 		return (EINVAL);
2078 
2079 	/* this entry point is only supported for cb devices */
2080 	dev = handlep->lh_vp->v_rdev;
2081 	if (!(handlep->lh_type & LH_CBDEV))
2082 		return (ENOTSUP);
2083 
2084 	return (cdev_devmap(dev, dhp, off, len, maplen, model));
2085 }
2086 
2087 int
2088 ldi_aread(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
2089 {
2090 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2091 	dev_t			dev;
2092 	struct cb_ops		*cb;
2093 
2094 	if (lh == NULL)
2095 		return (EINVAL);
2096 
2097 	/* this entry point is only supported for cb devices */
2098 	if (!(handlep->lh_type & LH_CBDEV))
2099 		return (ENOTSUP);
2100 
2101 	/*
2102 	 * Kaio is only supported on block devices.
2103 	 */
2104 	dev = handlep->lh_vp->v_rdev;
2105 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
2106 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
2107 		return (ENOTSUP);
2108 
2109 	if (cb->cb_aread == NULL)
2110 		return (ENOTSUP);
2111 
2112 	return (cb->cb_aread(dev, aio_reqp, cr));
2113 }
2114 
2115 int
2116 ldi_awrite(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
2117 {
2118 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2119 	struct cb_ops		*cb;
2120 	dev_t			dev;
2121 
2122 	if (lh == NULL)
2123 		return (EINVAL);
2124 
2125 	/* this entry point is only supported for cb devices */
2126 	if (!(handlep->lh_type & LH_CBDEV))
2127 		return (ENOTSUP);
2128 
2129 	/*
2130 	 * Kaio is only supported on block devices.
2131 	 */
2132 	dev = handlep->lh_vp->v_rdev;
2133 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
2134 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
2135 		return (ENOTSUP);
2136 
2137 	if (cb->cb_awrite == NULL)
2138 		return (ENOTSUP);
2139 
2140 	return (cb->cb_awrite(dev, aio_reqp, cr));
2141 }
2142 
2143 int
2144 ldi_putmsg(ldi_handle_t lh, mblk_t *smp)
2145 {
2146 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2147 	int			ret;
2148 
2149 	if ((lh == NULL) || (smp == NULL))
2150 		return (EINVAL);
2151 
2152 	if (!(handlep->lh_type & LH_STREAM)) {
2153 		freemsg(smp);
2154 		return (ENOTSUP);
2155 	}
2156 
2157 	/*
2158 	 * If we don't have db_credp, set it. Note that we can not be called
2159 	 * from interrupt context.
2160 	 */
2161 	if (msg_getcred(smp, NULL) == NULL)
2162 		mblk_setcred(smp, CRED(), curproc->p_pid);
2163 
2164 	/* Send message while honoring flow control */
2165 	ret = kstrputmsg(handlep->lh_vp, smp, NULL, 0, 0,
2166 	    MSG_BAND | MSG_HOLDSIG | MSG_IGNERROR, 0);
2167 
2168 	return (ret);
2169 }
2170 
2171 int
2172 ldi_getmsg(ldi_handle_t lh, mblk_t **rmp, timestruc_t *timeo)
2173 {
2174 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2175 	clock_t			timout; /* milliseconds */
2176 	uchar_t			pri;
2177 	rval_t			rval;
2178 	int			ret, pflag;
2179 
2180 
2181 	if (lh == NULL)
2182 		return (EINVAL);
2183 
2184 	if (!(handlep->lh_type & LH_STREAM))
2185 		return (ENOTSUP);
2186 
2187 	/* Convert from nanoseconds to milliseconds */
2188 	if (timeo != NULL) {
2189 		timout = timeo->tv_sec * 1000 + timeo->tv_nsec / 1000000;
2190 		if (timout > INT_MAX)
2191 			return (EINVAL);
2192 	} else
2193 		timout = -1;
2194 
2195 	/* Wait for timeout millseconds for a message */
2196 	pflag = MSG_ANY;
2197 	pri = 0;
2198 	*rmp = NULL;
2199 	ret = kstrgetmsg(handlep->lh_vp,
2200 	    rmp, NULL, &pri, &pflag, timout, &rval);
2201 	return (ret);
2202 }
2203 
2204 int
2205 ldi_get_dev(ldi_handle_t lh, dev_t *devp)
2206 {
2207 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2208 
2209 	if ((lh == NULL) || (devp == NULL))
2210 		return (EINVAL);
2211 
2212 	*devp = handlep->lh_vp->v_rdev;
2213 	return (0);
2214 }
2215 
2216 int
2217 ldi_get_otyp(ldi_handle_t lh, int *otyp)
2218 {
2219 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2220 
2221 	if ((lh == NULL) || (otyp == NULL))
2222 		return (EINVAL);
2223 
2224 	*otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
2225 	return (0);
2226 }
2227 
2228 int
2229 ldi_get_devid(ldi_handle_t lh, ddi_devid_t *devid)
2230 {
2231 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2232 	int			ret;
2233 	dev_t			dev;
2234 
2235 	if ((lh == NULL) || (devid == NULL))
2236 		return (EINVAL);
2237 
2238 	dev = handlep->lh_vp->v_rdev;
2239 
2240 	ret = ddi_lyr_get_devid(dev, devid);
2241 	if (ret != DDI_SUCCESS)
2242 		return (ENOTSUP);
2243 
2244 	return (0);
2245 }
2246 
2247 int
2248 ldi_get_minor_name(ldi_handle_t lh, char **minor_name)
2249 {
2250 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2251 	int			ret, otyp;
2252 	dev_t			dev;
2253 
2254 	if ((lh == NULL) || (minor_name == NULL))
2255 		return (EINVAL);
2256 
2257 	dev = handlep->lh_vp->v_rdev;
2258 	otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
2259 
2260 	ret = ddi_lyr_get_minor_name(dev, OTYP_TO_STYP(otyp), minor_name);
2261 	if (ret != DDI_SUCCESS)
2262 		return (ENOTSUP);
2263 
2264 	return (0);
2265 }
2266 
2267 int
2268 ldi_prop_lookup_int_array(ldi_handle_t lh,
2269     uint_t flags, char *name, int **data, uint_t *nelements)
2270 {
2271 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2272 	dev_info_t		*dip;
2273 	dev_t			dev;
2274 	int			res;
2275 	struct snode		*csp;
2276 
2277 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2278 		return (DDI_PROP_INVAL_ARG);
2279 
2280 	dev = handlep->lh_vp->v_rdev;
2281 
2282 	csp = VTOCS(handlep->lh_vp);
2283 	mutex_enter(&csp->s_lock);
2284 	if ((dip = csp->s_dip) != NULL)
2285 		e_ddi_hold_devi(dip);
2286 	mutex_exit(&csp->s_lock);
2287 	if (dip == NULL)
2288 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2289 
2290 	if (dip == NULL) {
2291 		flags |= DDI_UNBND_DLPI2;
2292 	} else if (flags & LDI_DEV_T_ANY) {
2293 		flags &= ~LDI_DEV_T_ANY;
2294 		dev = DDI_DEV_T_ANY;
2295 	}
2296 
2297 	if (dip != NULL) {
2298 		int *prop_val, prop_len;
2299 
2300 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2301 		    (caddr_t *)&prop_val, &prop_len, sizeof (int));
2302 
2303 		/* if we got it then return it */
2304 		if (res == DDI_PROP_SUCCESS) {
2305 			*nelements = prop_len / sizeof (int);
2306 			*data = prop_val;
2307 
2308 			ddi_release_devi(dip);
2309 			return (res);
2310 		}
2311 	}
2312 
2313 	/* call the normal property interfaces */
2314 	res = ddi_prop_lookup_int_array(dev, dip, flags,
2315 	    name, data, nelements);
2316 
2317 	if (dip != NULL)
2318 		ddi_release_devi(dip);
2319 
2320 	return (res);
2321 }
2322 
2323 int
2324 ldi_prop_lookup_int64_array(ldi_handle_t lh,
2325     uint_t flags, char *name, int64_t **data, uint_t *nelements)
2326 {
2327 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2328 	dev_info_t		*dip;
2329 	dev_t			dev;
2330 	int			res;
2331 	struct snode		*csp;
2332 
2333 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2334 		return (DDI_PROP_INVAL_ARG);
2335 
2336 	dev = handlep->lh_vp->v_rdev;
2337 
2338 	csp = VTOCS(handlep->lh_vp);
2339 	mutex_enter(&csp->s_lock);
2340 	if ((dip = csp->s_dip) != NULL)
2341 		e_ddi_hold_devi(dip);
2342 	mutex_exit(&csp->s_lock);
2343 	if (dip == NULL)
2344 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2345 
2346 	if (dip == NULL) {
2347 		flags |= DDI_UNBND_DLPI2;
2348 	} else if (flags & LDI_DEV_T_ANY) {
2349 		flags &= ~LDI_DEV_T_ANY;
2350 		dev = DDI_DEV_T_ANY;
2351 	}
2352 
2353 	if (dip != NULL) {
2354 		int64_t	*prop_val;
2355 		int	prop_len;
2356 
2357 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2358 		    (caddr_t *)&prop_val, &prop_len, sizeof (int64_t));
2359 
2360 		/* if we got it then return it */
2361 		if (res == DDI_PROP_SUCCESS) {
2362 			*nelements = prop_len / sizeof (int64_t);
2363 			*data = prop_val;
2364 
2365 			ddi_release_devi(dip);
2366 			return (res);
2367 		}
2368 	}
2369 
2370 	/* call the normal property interfaces */
2371 	res = ddi_prop_lookup_int64_array(dev, dip, flags,
2372 	    name, data, nelements);
2373 
2374 	if (dip != NULL)
2375 		ddi_release_devi(dip);
2376 
2377 	return (res);
2378 }
2379 
2380 int
2381 ldi_prop_lookup_string_array(ldi_handle_t lh,
2382     uint_t flags, char *name, char ***data, uint_t *nelements)
2383 {
2384 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2385 	dev_info_t		*dip;
2386 	dev_t			dev;
2387 	int			res;
2388 	struct snode		*csp;
2389 
2390 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2391 		return (DDI_PROP_INVAL_ARG);
2392 
2393 	dev = handlep->lh_vp->v_rdev;
2394 
2395 	csp = VTOCS(handlep->lh_vp);
2396 	mutex_enter(&csp->s_lock);
2397 	if ((dip = csp->s_dip) != NULL)
2398 		e_ddi_hold_devi(dip);
2399 	mutex_exit(&csp->s_lock);
2400 	if (dip == NULL)
2401 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2402 
2403 	if (dip == NULL) {
2404 		flags |= DDI_UNBND_DLPI2;
2405 	} else if (flags & LDI_DEV_T_ANY) {
2406 		flags &= ~LDI_DEV_T_ANY;
2407 		dev = DDI_DEV_T_ANY;
2408 	}
2409 
2410 	if (dip != NULL) {
2411 		char	*prop_val;
2412 		int	prop_len;
2413 
2414 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2415 		    (caddr_t *)&prop_val, &prop_len, 0);
2416 
2417 		/* if we got it then return it */
2418 		if (res == DDI_PROP_SUCCESS) {
2419 			char	**str_array;
2420 			int	nelem;
2421 
2422 			/*
2423 			 * pack the returned string array into the format
2424 			 * our callers expect
2425 			 */
2426 			if (i_pack_string_array(prop_val, prop_len,
2427 			    &str_array, &nelem) == 0) {
2428 
2429 				*data = str_array;
2430 				*nelements = nelem;
2431 
2432 				ddi_prop_free(prop_val);
2433 				ddi_release_devi(dip);
2434 				return (res);
2435 			}
2436 
2437 			/*
2438 			 * the format of the returned property must have
2439 			 * been bad so throw it out
2440 			 */
2441 			ddi_prop_free(prop_val);
2442 		}
2443 	}
2444 
2445 	/* call the normal property interfaces */
2446 	res = ddi_prop_lookup_string_array(dev, dip, flags,
2447 	    name, data, nelements);
2448 
2449 	if (dip != NULL)
2450 		ddi_release_devi(dip);
2451 
2452 	return (res);
2453 }
2454 
2455 int
2456 ldi_prop_lookup_string(ldi_handle_t lh,
2457     uint_t flags, char *name, char **data)
2458 {
2459 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2460 	dev_info_t		*dip;
2461 	dev_t			dev;
2462 	int			res;
2463 	struct snode		*csp;
2464 
2465 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2466 		return (DDI_PROP_INVAL_ARG);
2467 
2468 	dev = handlep->lh_vp->v_rdev;
2469 
2470 	csp = VTOCS(handlep->lh_vp);
2471 	mutex_enter(&csp->s_lock);
2472 	if ((dip = csp->s_dip) != NULL)
2473 		e_ddi_hold_devi(dip);
2474 	mutex_exit(&csp->s_lock);
2475 	if (dip == NULL)
2476 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2477 
2478 	if (dip == NULL) {
2479 		flags |= DDI_UNBND_DLPI2;
2480 	} else if (flags & LDI_DEV_T_ANY) {
2481 		flags &= ~LDI_DEV_T_ANY;
2482 		dev = DDI_DEV_T_ANY;
2483 	}
2484 
2485 	if (dip != NULL) {
2486 		char	*prop_val;
2487 		int	prop_len;
2488 
2489 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2490 		    (caddr_t *)&prop_val, &prop_len, 0);
2491 
2492 		/* if we got it then return it */
2493 		if (res == DDI_PROP_SUCCESS) {
2494 			/*
2495 			 * sanity check the vaule returned.
2496 			 */
2497 			if (i_check_string(prop_val, prop_len)) {
2498 				ddi_prop_free(prop_val);
2499 			} else {
2500 				*data = prop_val;
2501 				ddi_release_devi(dip);
2502 				return (res);
2503 			}
2504 		}
2505 	}
2506 
2507 	/* call the normal property interfaces */
2508 	res = ddi_prop_lookup_string(dev, dip, flags, name, data);
2509 
2510 	if (dip != NULL)
2511 		ddi_release_devi(dip);
2512 
2513 #ifdef DEBUG
2514 	if (res == DDI_PROP_SUCCESS) {
2515 		/*
2516 		 * keep ourselves honest
2517 		 * make sure the framework returns strings in the
2518 		 * same format as we're demanding from drivers.
2519 		 */
2520 		struct prop_driver_data	*pdd;
2521 		int			pdd_prop_size;
2522 
2523 		pdd = ((struct prop_driver_data *)(*data)) - 1;
2524 		pdd_prop_size = pdd->pdd_size -
2525 		    sizeof (struct prop_driver_data);
2526 		ASSERT(i_check_string(*data, pdd_prop_size) == 0);
2527 	}
2528 #endif /* DEBUG */
2529 
2530 	return (res);
2531 }
2532 
2533 int
2534 ldi_prop_lookup_byte_array(ldi_handle_t lh,
2535     uint_t flags, char *name, uchar_t **data, uint_t *nelements)
2536 {
2537 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2538 	dev_info_t		*dip;
2539 	dev_t			dev;
2540 	int			res;
2541 	struct snode		*csp;
2542 
2543 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2544 		return (DDI_PROP_INVAL_ARG);
2545 
2546 	dev = handlep->lh_vp->v_rdev;
2547 
2548 	csp = VTOCS(handlep->lh_vp);
2549 	mutex_enter(&csp->s_lock);
2550 	if ((dip = csp->s_dip) != NULL)
2551 		e_ddi_hold_devi(dip);
2552 	mutex_exit(&csp->s_lock);
2553 	if (dip == NULL)
2554 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2555 
2556 	if (dip == NULL) {
2557 		flags |= DDI_UNBND_DLPI2;
2558 	} else if (flags & LDI_DEV_T_ANY) {
2559 		flags &= ~LDI_DEV_T_ANY;
2560 		dev = DDI_DEV_T_ANY;
2561 	}
2562 
2563 	if (dip != NULL) {
2564 		uchar_t	*prop_val;
2565 		int	prop_len;
2566 
2567 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
2568 		    (caddr_t *)&prop_val, &prop_len, sizeof (uchar_t));
2569 
2570 		/* if we got it then return it */
2571 		if (res == DDI_PROP_SUCCESS) {
2572 			*nelements = prop_len / sizeof (uchar_t);
2573 			*data = prop_val;
2574 
2575 			ddi_release_devi(dip);
2576 			return (res);
2577 		}
2578 	}
2579 
2580 	/* call the normal property interfaces */
2581 	res = ddi_prop_lookup_byte_array(dev, dip, flags,
2582 	    name, data, nelements);
2583 
2584 	if (dip != NULL)
2585 		ddi_release_devi(dip);
2586 
2587 	return (res);
2588 }
2589 
2590 int
2591 ldi_prop_get_int(ldi_handle_t lh,
2592     uint_t flags, char *name, int defvalue)
2593 {
2594 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2595 	dev_info_t		*dip;
2596 	dev_t			dev;
2597 	int			res;
2598 	struct snode		*csp;
2599 
2600 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2601 		return (defvalue);
2602 
2603 	dev = handlep->lh_vp->v_rdev;
2604 
2605 	csp = VTOCS(handlep->lh_vp);
2606 	mutex_enter(&csp->s_lock);
2607 	if ((dip = csp->s_dip) != NULL)
2608 		e_ddi_hold_devi(dip);
2609 	mutex_exit(&csp->s_lock);
2610 	if (dip == NULL)
2611 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2612 
2613 	if (dip == NULL) {
2614 		flags |= DDI_UNBND_DLPI2;
2615 	} else if (flags & LDI_DEV_T_ANY) {
2616 		flags &= ~LDI_DEV_T_ANY;
2617 		dev = DDI_DEV_T_ANY;
2618 	}
2619 
2620 	if (dip != NULL) {
2621 		int	prop_val;
2622 		int	prop_len;
2623 
2624 		/*
2625 		 * first call the drivers prop_op interface to allow it
2626 		 * it to override default property values.
2627 		 */
2628 		prop_len = sizeof (int);
2629 		res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2630 		    flags | DDI_PROP_DYNAMIC, name,
2631 		    (caddr_t)&prop_val, &prop_len);
2632 
2633 		/* if we got it then return it */
2634 		if ((res == DDI_PROP_SUCCESS) &&
2635 		    (prop_len == sizeof (int))) {
2636 			res = prop_val;
2637 			ddi_release_devi(dip);
2638 			return (res);
2639 		}
2640 	}
2641 
2642 	/* call the normal property interfaces */
2643 	res = ddi_prop_get_int(dev, dip, flags, name, defvalue);
2644 
2645 	if (dip != NULL)
2646 		ddi_release_devi(dip);
2647 
2648 	return (res);
2649 }
2650 
2651 int64_t
2652 ldi_prop_get_int64(ldi_handle_t lh,
2653     uint_t flags, char *name, int64_t defvalue)
2654 {
2655 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2656 	dev_info_t		*dip;
2657 	dev_t			dev;
2658 	int64_t			res;
2659 	struct snode		*csp;
2660 
2661 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2662 		return (defvalue);
2663 
2664 	dev = handlep->lh_vp->v_rdev;
2665 
2666 	csp = VTOCS(handlep->lh_vp);
2667 	mutex_enter(&csp->s_lock);
2668 	if ((dip = csp->s_dip) != NULL)
2669 		e_ddi_hold_devi(dip);
2670 	mutex_exit(&csp->s_lock);
2671 	if (dip == NULL)
2672 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2673 
2674 	if (dip == NULL) {
2675 		flags |= DDI_UNBND_DLPI2;
2676 	} else if (flags & LDI_DEV_T_ANY) {
2677 		flags &= ~LDI_DEV_T_ANY;
2678 		dev = DDI_DEV_T_ANY;
2679 	}
2680 
2681 	if (dip != NULL) {
2682 		int64_t	prop_val;
2683 		int	prop_len;
2684 
2685 		/*
2686 		 * first call the drivers prop_op interface to allow it
2687 		 * it to override default property values.
2688 		 */
2689 		prop_len = sizeof (int64_t);
2690 		res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2691 		    flags | DDI_PROP_DYNAMIC, name,
2692 		    (caddr_t)&prop_val, &prop_len);
2693 
2694 		/* if we got it then return it */
2695 		if ((res == DDI_PROP_SUCCESS) &&
2696 		    (prop_len == sizeof (int64_t))) {
2697 			res = prop_val;
2698 			ddi_release_devi(dip);
2699 			return (res);
2700 		}
2701 	}
2702 
2703 	/* call the normal property interfaces */
2704 	res = ddi_prop_get_int64(dev, dip, flags, name, defvalue);
2705 
2706 	if (dip != NULL)
2707 		ddi_release_devi(dip);
2708 
2709 	return (res);
2710 }
2711 
2712 int
2713 ldi_prop_exists(ldi_handle_t lh, uint_t flags, char *name)
2714 {
2715 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2716 	dev_info_t		*dip;
2717 	dev_t			dev;
2718 	int			res, prop_len;
2719 	struct snode		*csp;
2720 
2721 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
2722 		return (0);
2723 
2724 	dev = handlep->lh_vp->v_rdev;
2725 
2726 	csp = VTOCS(handlep->lh_vp);
2727 	mutex_enter(&csp->s_lock);
2728 	if ((dip = csp->s_dip) != NULL)
2729 		e_ddi_hold_devi(dip);
2730 	mutex_exit(&csp->s_lock);
2731 	if (dip == NULL)
2732 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2733 
2734 	/* if NULL dip, prop does NOT exist */
2735 	if (dip == NULL)
2736 		return (0);
2737 
2738 	if (flags & LDI_DEV_T_ANY) {
2739 		flags &= ~LDI_DEV_T_ANY;
2740 		dev = DDI_DEV_T_ANY;
2741 	}
2742 
2743 	/*
2744 	 * first call the drivers prop_op interface to allow it
2745 	 * it to override default property values.
2746 	 */
2747 	res = i_ldi_prop_op(dev, dip, PROP_LEN,
2748 	    flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
2749 
2750 	if (res == DDI_PROP_SUCCESS) {
2751 		ddi_release_devi(dip);
2752 		return (1);
2753 	}
2754 
2755 	/* call the normal property interfaces */
2756 	res = ddi_prop_exists(dev, dip, flags, name);
2757 
2758 	ddi_release_devi(dip);
2759 	return (res);
2760 }
2761 
2762 #ifdef	LDI_OBSOLETE_EVENT
2763 
2764 int
2765 ldi_get_eventcookie(ldi_handle_t lh, char *name, ddi_eventcookie_t *ecp)
2766 {
2767 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2768 	dev_info_t		*dip;
2769 	dev_t			dev;
2770 	int			res;
2771 	struct snode		*csp;
2772 
2773 	if ((lh == NULL) || (name == NULL) ||
2774 	    (strlen(name) == 0) || (ecp == NULL)) {
2775 		return (DDI_FAILURE);
2776 	}
2777 
2778 	ASSERT(!servicing_interrupt());
2779 
2780 	dev = handlep->lh_vp->v_rdev;
2781 
2782 	csp = VTOCS(handlep->lh_vp);
2783 	mutex_enter(&csp->s_lock);
2784 	if ((dip = csp->s_dip) != NULL)
2785 		e_ddi_hold_devi(dip);
2786 	mutex_exit(&csp->s_lock);
2787 	if (dip == NULL)
2788 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2789 
2790 	if (dip == NULL)
2791 		return (DDI_FAILURE);
2792 
2793 	LDI_EVENTCB((CE_NOTE, "%s: event_name=%s, "
2794 	    "dip=0x%p, event_cookiep=0x%p", "ldi_get_eventcookie",
2795 	    name, (void *)dip, (void *)ecp));
2796 
2797 	res = ddi_get_eventcookie(dip, name, ecp);
2798 
2799 	ddi_release_devi(dip);
2800 	return (res);
2801 }
2802 
2803 int
2804 ldi_add_event_handler(ldi_handle_t lh, ddi_eventcookie_t ec,
2805     void (*handler)(ldi_handle_t, ddi_eventcookie_t, void *, void *),
2806     void *arg, ldi_callback_id_t *id)
2807 {
2808 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2809 	struct ldi_event	*lep;
2810 	dev_info_t		*dip;
2811 	dev_t			dev;
2812 	int			res;
2813 	struct snode		*csp;
2814 
2815 	if ((lh == NULL) || (ec == NULL) || (handler == NULL) || (id == NULL))
2816 		return (DDI_FAILURE);
2817 
2818 	ASSERT(!servicing_interrupt());
2819 
2820 	dev = handlep->lh_vp->v_rdev;
2821 
2822 	csp = VTOCS(handlep->lh_vp);
2823 	mutex_enter(&csp->s_lock);
2824 	if ((dip = csp->s_dip) != NULL)
2825 		e_ddi_hold_devi(dip);
2826 	mutex_exit(&csp->s_lock);
2827 	if (dip == NULL)
2828 		dip = e_ddi_hold_devi_by_dev(dev, 0);
2829 
2830 	if (dip == NULL)
2831 		return (DDI_FAILURE);
2832 
2833 	lep = kmem_zalloc(sizeof (struct ldi_event), KM_SLEEP);
2834 	lep->le_lhp = handlep;
2835 	lep->le_arg = arg;
2836 	lep->le_handler = handler;
2837 
2838 	if ((res = ddi_add_event_handler(dip, ec, i_ldi_callback,
2839 	    (void *)lep, &lep->le_id)) != DDI_SUCCESS) {
2840 		LDI_EVENTCB((CE_WARN, "%s: unable to add"
2841 		    "event callback", "ldi_add_event_handler"));
2842 		ddi_release_devi(dip);
2843 		kmem_free(lep, sizeof (struct ldi_event));
2844 		return (res);
2845 	}
2846 
2847 	*id = (ldi_callback_id_t)lep;
2848 
2849 	LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, event=0x%p, "
2850 	    "ldi_eventp=0x%p, cb_id=0x%p", "ldi_add_event_handler",
2851 	    (void *)dip, (void *)ec, (void *)lep, (void *)id));
2852 
2853 	handle_event_add(lep);
2854 	ddi_release_devi(dip);
2855 	return (res);
2856 }
2857 
2858 int
2859 ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id)
2860 {
2861 	ldi_event_t		*lep = (ldi_event_t *)id;
2862 	int			res;
2863 
2864 	if ((lh == NULL) || (id == NULL))
2865 		return (DDI_FAILURE);
2866 
2867 	ASSERT(!servicing_interrupt());
2868 
2869 	if ((res = ddi_remove_event_handler(lep->le_id))
2870 	    != DDI_SUCCESS) {
2871 		LDI_EVENTCB((CE_WARN, "%s: unable to remove "
2872 		    "event callback", "ldi_remove_event_handler"));
2873 		return (res);
2874 	}
2875 
2876 	handle_event_remove(lep);
2877 	kmem_free(lep, sizeof (struct ldi_event));
2878 	return (res);
2879 }
2880 
2881 #endif
2882 
2883 /*
2884  * Here are some definitions of terms used in the following LDI events
2885  * code:
2886  *
2887  * "LDI events" AKA "native events": These are events defined by the
2888  * "new" LDI event framework. These events are serviced by the LDI event
2889  * framework itself and thus are native to it.
2890  *
2891  * "LDI contract events": These are contract events that correspond to the
2892  *  LDI events. This mapping of LDI events to contract events is defined by
2893  * the ldi_ev_cookies[] array above.
2894  *
2895  * NDI events: These are events which are serviced by the NDI event subsystem.
2896  * LDI subsystem just provides a thin wrapper around the NDI event interfaces
2897  * These events are therefore *not* native events.
2898  */
2899 
2900 static int
2901 ldi_native_event(const char *evname)
2902 {
2903 	int i;
2904 
2905 	LDI_EVTRC((CE_NOTE, "ldi_native_event: entered: ev=%s", evname));
2906 
2907 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2908 		if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
2909 			return (1);
2910 	}
2911 
2912 	return (0);
2913 }
2914 
2915 static uint_t
2916 ldi_ev_sync_event(const char *evname)
2917 {
2918 	int i;
2919 
2920 	ASSERT(ldi_native_event(evname));
2921 
2922 	LDI_EVTRC((CE_NOTE, "ldi_ev_sync_event: entered: %s", evname));
2923 
2924 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2925 		if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
2926 			return (ldi_ev_cookies[i].ck_sync);
2927 	}
2928 
2929 	/*
2930 	 * This should never happen until non-contract based
2931 	 * LDI events are introduced. If that happens, we will
2932 	 * use a "special" token to indicate that there are no
2933 	 * contracts corresponding to this LDI event.
2934 	 */
2935 	cmn_err(CE_PANIC, "Unknown LDI event: %s", evname);
2936 
2937 	return (0);
2938 }
2939 
2940 static uint_t
2941 ldi_contract_event(const char *evname)
2942 {
2943 	int i;
2944 
2945 	ASSERT(ldi_native_event(evname));
2946 
2947 	LDI_EVTRC((CE_NOTE, "ldi_contract_event: entered: %s", evname));
2948 
2949 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2950 		if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
2951 			return (ldi_ev_cookies[i].ck_ctype);
2952 	}
2953 
2954 	/*
2955 	 * This should never happen until non-contract based
2956 	 * LDI events are introduced. If that happens, we will
2957 	 * use a "special" token to indicate that there are no
2958 	 * contracts corresponding to this LDI event.
2959 	 */
2960 	cmn_err(CE_PANIC, "Unknown LDI event: %s", evname);
2961 
2962 	return (0);
2963 }
2964 
2965 char *
2966 ldi_ev_get_type(ldi_ev_cookie_t cookie)
2967 {
2968 	int i;
2969 	struct ldi_ev_cookie *cookie_impl = (struct ldi_ev_cookie *)cookie;
2970 
2971 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2972 		if (&ldi_ev_cookies[i] == cookie_impl) {
2973 			LDI_EVTRC((CE_NOTE, "ldi_ev_get_type: LDI: %s",
2974 			    ldi_ev_cookies[i].ck_evname));
2975 			return (ldi_ev_cookies[i].ck_evname);
2976 		}
2977 	}
2978 
2979 	/*
2980 	 * Not an LDI native event. Must be NDI event service.
2981 	 * Just return a generic string
2982 	 */
2983 	LDI_EVTRC((CE_NOTE, "ldi_ev_get_type: is NDI"));
2984 	return (NDI_EVENT_SERVICE);
2985 }
2986 
2987 static int
2988 ldi_native_cookie(ldi_ev_cookie_t cookie)
2989 {
2990 	int i;
2991 	struct ldi_ev_cookie *cookie_impl = (struct ldi_ev_cookie *)cookie;
2992 
2993 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
2994 		if (&ldi_ev_cookies[i] == cookie_impl) {
2995 			LDI_EVTRC((CE_NOTE, "ldi_native_cookie: native LDI"));
2996 			return (1);
2997 		}
2998 	}
2999 
3000 	LDI_EVTRC((CE_NOTE, "ldi_native_cookie: is NDI"));
3001 	return (0);
3002 }
3003 
3004 static ldi_ev_cookie_t
3005 ldi_get_native_cookie(const char *evname)
3006 {
3007 	int i;
3008 
3009 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
3010 		if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0) {
3011 			LDI_EVTRC((CE_NOTE, "ldi_get_native_cookie: found"));
3012 			return ((ldi_ev_cookie_t)&ldi_ev_cookies[i]);
3013 		}
3014 	}
3015 
3016 	LDI_EVTRC((CE_NOTE, "ldi_get_native_cookie: NOT found"));
3017 	return (NULL);
3018 }
3019 
3020 /*
3021  * ldi_ev_lock() needs to be recursive, since layered drivers may call
3022  * other LDI interfaces (such as ldi_close() from within the context of
3023  * a notify callback. Since the notify callback is called with the
3024  * ldi_ev_lock() held and ldi_close() also grabs ldi_ev_lock, the lock needs
3025  * to be recursive.
3026  */
3027 static void
3028 ldi_ev_lock(void)
3029 {
3030 	LDI_EVTRC((CE_NOTE, "ldi_ev_lock: entered"));
3031 
3032 	mutex_enter(&ldi_ev_callback_list.le_lock);
3033 	if (ldi_ev_callback_list.le_thread == curthread) {
3034 		ASSERT(ldi_ev_callback_list.le_busy >= 1);
3035 		ldi_ev_callback_list.le_busy++;
3036 	} else {
3037 		while (ldi_ev_callback_list.le_busy)
3038 			cv_wait(&ldi_ev_callback_list.le_cv,
3039 			    &ldi_ev_callback_list.le_lock);
3040 		ASSERT(ldi_ev_callback_list.le_thread == NULL);
3041 		ldi_ev_callback_list.le_busy = 1;
3042 		ldi_ev_callback_list.le_thread = curthread;
3043 	}
3044 	mutex_exit(&ldi_ev_callback_list.le_lock);
3045 
3046 	LDI_EVTRC((CE_NOTE, "ldi_ev_lock: exit"));
3047 }
3048 
3049 static void
3050 ldi_ev_unlock(void)
3051 {
3052 	LDI_EVTRC((CE_NOTE, "ldi_ev_unlock: entered"));
3053 	mutex_enter(&ldi_ev_callback_list.le_lock);
3054 	ASSERT(ldi_ev_callback_list.le_thread == curthread);
3055 	ASSERT(ldi_ev_callback_list.le_busy >= 1);
3056 
3057 	ldi_ev_callback_list.le_busy--;
3058 	if (ldi_ev_callback_list.le_busy == 0) {
3059 		ldi_ev_callback_list.le_thread = NULL;
3060 		cv_signal(&ldi_ev_callback_list.le_cv);
3061 	}
3062 	mutex_exit(&ldi_ev_callback_list.le_lock);
3063 	LDI_EVTRC((CE_NOTE, "ldi_ev_unlock: exit"));
3064 }
3065 
3066 int
3067 ldi_ev_get_cookie(ldi_handle_t lh, char *evname, ldi_ev_cookie_t *cookiep)
3068 {
3069 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
3070 	dev_info_t		*dip;
3071 	dev_t			dev;
3072 	int			res;
3073 	struct snode		*csp;
3074 	ddi_eventcookie_t	ddi_cookie;
3075 	ldi_ev_cookie_t		tcookie;
3076 
3077 	LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: entered: evname=%s",
3078 	    evname ? evname : "<NULL>"));
3079 
3080 	if (lh == NULL || evname == NULL ||
3081 	    strlen(evname) == 0 || cookiep == NULL) {
3082 		LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: invalid args"));
3083 		return (LDI_EV_FAILURE);
3084 	}
3085 
3086 	*cookiep = NULL;
3087 
3088 	/*
3089 	 * First check if it is a LDI native event
3090 	 */
3091 	tcookie = ldi_get_native_cookie(evname);
3092 	if (tcookie) {
3093 		LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: got native cookie"));
3094 		*cookiep = tcookie;
3095 		return (LDI_EV_SUCCESS);
3096 	}
3097 
3098 	/*
3099 	 * Not a LDI native event. Try NDI event services
3100 	 */
3101 
3102 	dev = handlep->lh_vp->v_rdev;
3103 
3104 	csp = VTOCS(handlep->lh_vp);
3105 	mutex_enter(&csp->s_lock);
3106 	if ((dip = csp->s_dip) != NULL)
3107 		e_ddi_hold_devi(dip);
3108 	mutex_exit(&csp->s_lock);
3109 	if (dip == NULL)
3110 		dip = e_ddi_hold_devi_by_dev(dev, 0);
3111 
3112 	if (dip == NULL) {
3113 		cmn_err(CE_WARN, "ldi_ev_get_cookie: No devinfo node for LDI "
3114 		    "handle: %p", (void *)handlep);
3115 		return (LDI_EV_FAILURE);
3116 	}
3117 
3118 	LDI_EVDBG((CE_NOTE, "Calling ddi_get_eventcookie: dip=%p, ev=%s",
3119 	    (void *)dip, evname));
3120 
3121 	res = ddi_get_eventcookie(dip, evname, &ddi_cookie);
3122 
3123 	ddi_release_devi(dip);
3124 
3125 	if (res == DDI_SUCCESS) {
3126 		LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: NDI cookie found"));
3127 		*cookiep = (ldi_ev_cookie_t)ddi_cookie;
3128 		return (LDI_EV_SUCCESS);
3129 	} else {
3130 		LDI_EVDBG((CE_WARN, "ldi_ev_get_cookie: NDI cookie: failed"));
3131 		return (LDI_EV_FAILURE);
3132 	}
3133 }
3134 
3135 /*ARGSUSED*/
3136 static void
3137 i_ldi_ev_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie,
3138     void *arg, void *ev_data)
3139 {
3140 	ldi_ev_callback_impl_t *lecp = (ldi_ev_callback_impl_t *)arg;
3141 
3142 	ASSERT(lecp != NULL);
3143 	ASSERT(!ldi_native_cookie(lecp->lec_cookie));
3144 	ASSERT(lecp->lec_lhp);
3145 	ASSERT(lecp->lec_notify == NULL);
3146 	ASSERT(lecp->lec_finalize);
3147 
3148 	LDI_EVDBG((CE_NOTE, "i_ldi_ev_callback: ldh=%p, cookie=%p, arg=%p, "
3149 	    "ev_data=%p", (void *)lecp->lec_lhp, (void *)event_cookie,
3150 	    (void *)lecp->lec_arg, (void *)ev_data));
3151 
3152 	lecp->lec_finalize(lecp->lec_lhp, (ldi_ev_cookie_t)event_cookie,
3153 	    lecp->lec_arg, ev_data);
3154 }
3155 
3156 int
3157 ldi_ev_register_callbacks(ldi_handle_t lh, ldi_ev_cookie_t cookie,
3158     ldi_ev_callback_t *callb, void *arg, ldi_callback_id_t *id)
3159 {
3160 	struct ldi_handle	*lhp = (struct ldi_handle *)lh;
3161 	ldi_ev_callback_impl_t	*lecp;
3162 	dev_t			dev;
3163 	struct snode		*csp;
3164 	dev_info_t		*dip;
3165 	int			ddi_event;
3166 
3167 	ASSERT(!servicing_interrupt());
3168 
3169 	if (lh == NULL || cookie == NULL || callb == NULL || id == NULL) {
3170 		LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: Invalid args"));
3171 		return (LDI_EV_FAILURE);
3172 	}
3173 
3174 	if (callb->cb_vers != LDI_EV_CB_VERS) {
3175 		LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: Invalid vers"));
3176 		return (LDI_EV_FAILURE);
3177 	}
3178 
3179 	if (callb->cb_notify == NULL && callb->cb_finalize == NULL) {
3180 		LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: NULL callb"));
3181 		return (LDI_EV_FAILURE);
3182 	}
3183 
3184 	*id = 0;
3185 
3186 	dev = lhp->lh_vp->v_rdev;
3187 	csp = VTOCS(lhp->lh_vp);
3188 	mutex_enter(&csp->s_lock);
3189 	if ((dip = csp->s_dip) != NULL)
3190 		e_ddi_hold_devi(dip);
3191 	mutex_exit(&csp->s_lock);
3192 	if (dip == NULL)
3193 		dip = e_ddi_hold_devi_by_dev(dev, 0);
3194 
3195 	if (dip == NULL) {
3196 		cmn_err(CE_WARN, "ldi_ev_register: No devinfo node for "
3197 		    "LDI handle: %p", (void *)lhp);
3198 		return (LDI_EV_FAILURE);
3199 	}
3200 
3201 	lecp = kmem_zalloc(sizeof (ldi_ev_callback_impl_t), KM_SLEEP);
3202 
3203 	ddi_event = 0;
3204 	if (!ldi_native_cookie(cookie)) {
3205 		if (callb->cb_notify || callb->cb_finalize == NULL) {
3206 			/*
3207 			 * NDI event services only accept finalize
3208 			 */
3209 			cmn_err(CE_WARN, "%s: module: %s: NDI event cookie. "
3210 			    "Only finalize"
3211 			    " callback supported with this cookie",
3212 			    "ldi_ev_register_callbacks",
3213 			    lhp->lh_ident->li_modname);
3214 			kmem_free(lecp, sizeof (ldi_ev_callback_impl_t));
3215 			ddi_release_devi(dip);
3216 			return (LDI_EV_FAILURE);
3217 		}
3218 
3219 		if (ddi_add_event_handler(dip, (ddi_eventcookie_t)cookie,
3220 		    i_ldi_ev_callback, (void *)lecp,
3221 		    (ddi_callback_id_t *)&lecp->lec_id)
3222 		    != DDI_SUCCESS) {
3223 			kmem_free(lecp, sizeof (ldi_ev_callback_impl_t));
3224 			ddi_release_devi(dip);
3225 			LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks(): "
3226 			    "ddi_add_event_handler failed"));
3227 			return (LDI_EV_FAILURE);
3228 		}
3229 		ddi_event = 1;
3230 		LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks(): "
3231 		    "ddi_add_event_handler success"));
3232 	}
3233 
3234 
3235 
3236 	ldi_ev_lock();
3237 
3238 	/*
3239 	 * Add the notify/finalize callback to the LDI's list of callbacks.
3240 	 */
3241 	lecp->lec_lhp = lhp;
3242 	lecp->lec_dev = lhp->lh_vp->v_rdev;
3243 	lecp->lec_spec = VTYP_TO_STYP(lhp->lh_vp->v_type);
3244 	lecp->lec_notify = callb->cb_notify;
3245 	lecp->lec_finalize = callb->cb_finalize;
3246 	lecp->lec_arg = arg;
3247 	lecp->lec_cookie = cookie;
3248 	if (!ddi_event)
3249 		lecp->lec_id = (void *)(uintptr_t)(++ldi_ev_id_pool);
3250 	else
3251 		ASSERT(lecp->lec_id);
3252 	lecp->lec_dip = dip;
3253 	list_insert_tail(&ldi_ev_callback_list.le_head, lecp);
3254 
3255 	*id = (ldi_callback_id_t)lecp->lec_id;
3256 
3257 	ldi_ev_unlock();
3258 
3259 	ddi_release_devi(dip);
3260 
3261 	LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: registered "
3262 	    "notify/finalize"));
3263 
3264 	return (LDI_EV_SUCCESS);
3265 }
3266 
3267 static int
3268 ldi_ev_device_match(ldi_ev_callback_impl_t *lecp, dev_info_t *dip,
3269     dev_t dev, int spec_type)
3270 {
3271 	ASSERT(lecp);
3272 	ASSERT(dip);
3273 	ASSERT(dev != DDI_DEV_T_NONE);
3274 	ASSERT(dev != NODEV);
3275 	ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
3276 	    (spec_type == S_IFCHR || spec_type == S_IFBLK));
3277 	ASSERT(lecp->lec_dip);
3278 	ASSERT(lecp->lec_spec == S_IFCHR || lecp->lec_spec == S_IFBLK);
3279 	ASSERT(lecp->lec_dev != DDI_DEV_T_ANY);
3280 	ASSERT(lecp->lec_dev != DDI_DEV_T_NONE);
3281 	ASSERT(lecp->lec_dev != NODEV);
3282 
3283 	if (dip != lecp->lec_dip)
3284 		return (0);
3285 
3286 	if (dev != DDI_DEV_T_ANY) {
3287 		if (dev != lecp->lec_dev || spec_type != lecp->lec_spec)
3288 			return (0);
3289 	}
3290 
3291 	LDI_EVTRC((CE_NOTE, "ldi_ev_device_match: MATCH dip=%p", (void *)dip));
3292 
3293 	return (1);
3294 }
3295 
3296 /*
3297  * LDI framework function to post a "notify" event to all layered drivers
3298  * that have registered for that event
3299  *
3300  * Returns:
3301  *		LDI_EV_SUCCESS - registered callbacks allow event
3302  *		LDI_EV_FAILURE - registered callbacks block event
3303  *		LDI_EV_NONE    - No matching LDI callbacks
3304  *
3305  * This function is *not* to be called by layered drivers. It is for I/O
3306  * framework code in Solaris, such as the I/O retire code and DR code
3307  * to call while servicing a device event such as offline or degraded.
3308  */
3309 int
3310 ldi_invoke_notify(dev_info_t *dip, dev_t dev, int spec_type, char *event,
3311     void *ev_data)
3312 {
3313 	ldi_ev_callback_impl_t *lecp;
3314 	list_t	*listp;
3315 	int	ret;
3316 	char	*lec_event;
3317 
3318 	ASSERT(dip);
3319 	ASSERT(dev != DDI_DEV_T_NONE);
3320 	ASSERT(dev != NODEV);
3321 	ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
3322 	    (spec_type == S_IFCHR || spec_type == S_IFBLK));
3323 	ASSERT(event);
3324 	ASSERT(ldi_native_event(event));
3325 	ASSERT(ldi_ev_sync_event(event));
3326 
3327 	LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): entered: dip=%p, ev=%s",
3328 	    (void *)dip, event));
3329 
3330 	ret = LDI_EV_NONE;
3331 	ldi_ev_lock();
3332 	listp = &ldi_ev_callback_list.le_head;
3333 	for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
3334 
3335 		/* Check if matching device */
3336 		if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3337 			continue;
3338 
3339 		if (lecp->lec_lhp == NULL) {
3340 			/*
3341 			 * Consumer has unregistered the handle and so
3342 			 * is no longer interested in notify events.
3343 			 */
3344 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): No LDI "
3345 			    "handle, skipping"));
3346 			continue;
3347 		}
3348 
3349 		if (lecp->lec_notify == NULL) {
3350 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): No notify "
3351 			    "callback. skipping"));
3352 			continue;	/* not interested in notify */
3353 		}
3354 
3355 		/*
3356 		 * Check if matching event
3357 		 */
3358 		lec_event = ldi_ev_get_type(lecp->lec_cookie);
3359 		if (strcmp(event, lec_event) != 0) {
3360 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): Not matching"
3361 			    " event {%s,%s}. skipping", event, lec_event));
3362 			continue;
3363 		}
3364 
3365 		lecp->lec_lhp->lh_flags |= LH_FLAGS_NOTIFY;
3366 		if (lecp->lec_notify(lecp->lec_lhp, lecp->lec_cookie,
3367 		    lecp->lec_arg, ev_data) != LDI_EV_SUCCESS) {
3368 			ret = LDI_EV_FAILURE;
3369 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): notify"
3370 			    " FAILURE"));
3371 			break;
3372 		}
3373 
3374 		/* We have a matching callback that allows the event to occur */
3375 		ret = LDI_EV_SUCCESS;
3376 
3377 		LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): 1 consumer success"));
3378 	}
3379 
3380 	if (ret != LDI_EV_FAILURE)
3381 		goto out;
3382 
3383 	LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): undoing notify"));
3384 
3385 	/*
3386 	 * Undo notifies already sent
3387 	 */
3388 	lecp = list_prev(listp, lecp);
3389 	for (; lecp; lecp = list_prev(listp, lecp)) {
3390 
3391 		/*
3392 		 * Check if matching device
3393 		 */
3394 		if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3395 			continue;
3396 
3397 
3398 		if (lecp->lec_finalize == NULL) {
3399 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no finalize, "
3400 			    "skipping"));
3401 			continue;	/* not interested in finalize */
3402 		}
3403 
3404 		/*
3405 		 * it is possible that in response to a notify event a
3406 		 * layered driver closed its LDI handle so it is ok
3407 		 * to have a NULL LDI handle for finalize. The layered
3408 		 * driver is expected to maintain state in its "arg"
3409 		 * parameter to keep track of the closed device.
3410 		 */
3411 
3412 		/* Check if matching event */
3413 		lec_event = ldi_ev_get_type(lecp->lec_cookie);
3414 		if (strcmp(event, lec_event) != 0) {
3415 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): not matching "
3416 			    "event: %s,%s, skipping", event, lec_event));
3417 			continue;
3418 		}
3419 
3420 		LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): calling finalize"));
3421 
3422 		lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
3423 		    LDI_EV_FAILURE, lecp->lec_arg, ev_data);
3424 
3425 		/*
3426 		 * If LDI native event and LDI handle closed in context
3427 		 * of notify, NULL out the finalize callback as we have
3428 		 * already called the 1 finalize above allowed in this situation
3429 		 */
3430 		if (lecp->lec_lhp == NULL &&
3431 		    ldi_native_cookie(lecp->lec_cookie)) {
3432 			LDI_EVDBG((CE_NOTE,
3433 			    "ldi_invoke_notify(): NULL-ing finalize after "
3434 			    "calling 1 finalize following ldi_close"));
3435 			lecp->lec_finalize = NULL;
3436 		}
3437 	}
3438 
3439 out:
3440 	ldi_ev_unlock();
3441 
3442 	if (ret == LDI_EV_NONE) {
3443 		LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no matching "
3444 		    "LDI callbacks"));
3445 	}
3446 
3447 	return (ret);
3448 }
3449 
3450 /*
3451  * Framework function to be called from a layered driver to propagate
3452  * LDI "notify" events to exported minors.
3453  *
3454  * This function is a public interface exported by the LDI framework
3455  * for use by layered drivers to propagate device events up the software
3456  * stack.
3457  */
3458 int
3459 ldi_ev_notify(dev_info_t *dip, minor_t minor, int spec_type,
3460     ldi_ev_cookie_t cookie, void *ev_data)
3461 {
3462 	char		*evname = ldi_ev_get_type(cookie);
3463 	uint_t		ct_evtype;
3464 	dev_t		dev;
3465 	major_t		major;
3466 	int		retc;
3467 	int		retl;
3468 
3469 	ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
3470 	ASSERT(dip);
3471 	ASSERT(ldi_native_cookie(cookie));
3472 
3473 	LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): entered: event=%s, dip=%p",
3474 	    evname, (void *)dip));
3475 
3476 	if (!ldi_ev_sync_event(evname)) {
3477 		cmn_err(CE_PANIC, "ldi_ev_notify(): %s not a "
3478 		    "negotiatable event", evname);
3479 		return (LDI_EV_SUCCESS);
3480 	}
3481 
3482 	major = ddi_driver_major(dip);
3483 	if (major == DDI_MAJOR_T_NONE) {
3484 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
3485 		(void) ddi_pathname(dip, path);
3486 		cmn_err(CE_WARN, "ldi_ev_notify: cannot derive major number "
3487 		    "for device %s", path);
3488 		kmem_free(path, MAXPATHLEN);
3489 		return (LDI_EV_FAILURE);
3490 	}
3491 	dev = makedevice(major, minor);
3492 
3493 	/*
3494 	 * Generate negotiation contract events on contracts (if any) associated
3495 	 * with this minor.
3496 	 */
3497 	LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): calling contract nego."));
3498 	ct_evtype = ldi_contract_event(evname);
3499 	retc = contract_device_negotiate(dip, dev, spec_type, ct_evtype);
3500 	if (retc == CT_NACK) {
3501 		LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): contract neg. NACK"));
3502 		return (LDI_EV_FAILURE);
3503 	}
3504 
3505 	LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): LDI invoke notify"));
3506 	retl = ldi_invoke_notify(dip, dev, spec_type, evname, ev_data);
3507 	if (retl == LDI_EV_FAILURE) {
3508 		LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): ldi_invoke_notify "
3509 		    "returned FAILURE. Calling contract negend"));
3510 		contract_device_negend(dip, dev, spec_type, CT_EV_FAILURE);
3511 		return (LDI_EV_FAILURE);
3512 	}
3513 
3514 	/*
3515 	 * The very fact that we are here indicates that there is a
3516 	 * LDI callback (and hence a constraint) for the retire of the
3517 	 * HW device. So we just return success even if there are no
3518 	 * contracts or LDI callbacks against the minors layered on top
3519 	 * of the HW minors
3520 	 */
3521 	LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): returning SUCCESS"));
3522 	return (LDI_EV_SUCCESS);
3523 }
3524 
3525 /*
3526  * LDI framework function to invoke "finalize" callbacks for all layered
3527  * drivers that have registered callbacks for that event.
3528  *
3529  * This function is *not* to be called by layered drivers. It is for I/O
3530  * framework code in Solaris, such as the I/O retire code and DR code
3531  * to call while servicing a device event such as offline or degraded.
3532  */
3533 void
3534 ldi_invoke_finalize(dev_info_t *dip, dev_t dev, int spec_type, char *event,
3535     int ldi_result, void *ev_data)
3536 {
3537 	ldi_ev_callback_impl_t *lecp;
3538 	list_t	*listp;
3539 	char	*lec_event;
3540 	int	found = 0;
3541 
3542 	ASSERT(dip);
3543 	ASSERT(dev != DDI_DEV_T_NONE);
3544 	ASSERT(dev != NODEV);
3545 	ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
3546 	    (spec_type == S_IFCHR || spec_type == S_IFBLK));
3547 	ASSERT(event);
3548 	ASSERT(ldi_native_event(event));
3549 	ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
3550 
3551 	LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): entered: dip=%p, result=%d"
3552 	    " event=%s", (void *)dip, ldi_result, event));
3553 
3554 	ldi_ev_lock();
3555 	listp = &ldi_ev_callback_list.le_head;
3556 	for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
3557 
3558 		if (lecp->lec_finalize == NULL) {
3559 			LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): No "
3560 			    "finalize. Skipping"));
3561 			continue;	/* Not interested in finalize */
3562 		}
3563 
3564 		/*
3565 		 * Check if matching device
3566 		 */
3567 		if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
3568 			continue;
3569 
3570 		/*
3571 		 * It is valid for the LDI handle to be NULL during finalize.
3572 		 * The layered driver may have done an LDI close in the notify
3573 		 * callback.
3574 		 */
3575 
3576 		/*
3577 		 * Check if matching event
3578 		 */
3579 		lec_event = ldi_ev_get_type(lecp->lec_cookie);
3580 		if (strcmp(event, lec_event) != 0) {
3581 			LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): Not "
3582 			    "matching event {%s,%s}. Skipping",
3583 			    event, lec_event));
3584 			continue;
3585 		}
3586 
3587 		LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): calling finalize"));
3588 
3589 		found = 1;
3590 
3591 		lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
3592 		    ldi_result, lecp->lec_arg, ev_data);
3593 
3594 		/*
3595 		 * If LDI native event and LDI handle closed in context
3596 		 * of notify, NULL out the finalize callback as we have
3597 		 * already called the 1 finalize above allowed in this situation
3598 		 */
3599 		if (lecp->lec_lhp == NULL &&
3600 		    ldi_native_cookie(lecp->lec_cookie)) {
3601 			LDI_EVDBG((CE_NOTE,
3602 			    "ldi_invoke_finalize(): NULLing finalize after "
3603 			    "calling 1 finalize following ldi_close"));
3604 			lecp->lec_finalize = NULL;
3605 		}
3606 	}
3607 	ldi_ev_unlock();
3608 
3609 	if (found)
3610 		return;
3611 
3612 	LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): no matching callbacks"));
3613 }
3614 
3615 /*
3616  * Framework function to be called from a layered driver to propagate
3617  * LDI "finalize" events to exported minors.
3618  *
3619  * This function is a public interface exported by the LDI framework
3620  * for use by layered drivers to propagate device events up the software
3621  * stack.
3622  */
3623 void
3624 ldi_ev_finalize(dev_info_t *dip, minor_t minor, int spec_type, int ldi_result,
3625     ldi_ev_cookie_t cookie, void *ev_data)
3626 {
3627 	dev_t dev;
3628 	major_t major;
3629 	char *evname;
3630 	int ct_result = (ldi_result == LDI_EV_SUCCESS) ?
3631 	    CT_EV_SUCCESS : CT_EV_FAILURE;
3632 	uint_t ct_evtype;
3633 
3634 	ASSERT(dip);
3635 	ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
3636 	ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
3637 	ASSERT(ldi_native_cookie(cookie));
3638 
3639 	LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: entered: dip=%p", (void *)dip));
3640 
3641 	major = ddi_driver_major(dip);
3642 	if (major == DDI_MAJOR_T_NONE) {
3643 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
3644 		(void) ddi_pathname(dip, path);
3645 		cmn_err(CE_WARN, "ldi_ev_finalize: cannot derive major number "
3646 		    "for device %s", path);
3647 		kmem_free(path, MAXPATHLEN);
3648 		return;
3649 	}
3650 	dev = makedevice(major, minor);
3651 
3652 	evname = ldi_ev_get_type(cookie);
3653 
3654 	LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: calling contracts"));
3655 	ct_evtype = ldi_contract_event(evname);
3656 	contract_device_finalize(dip, dev, spec_type, ct_evtype, ct_result);
3657 
3658 	LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: calling ldi_invoke_finalize"));
3659 	ldi_invoke_finalize(dip, dev, spec_type, evname, ldi_result, ev_data);
3660 }
3661 
3662 int
3663 ldi_ev_remove_callbacks(ldi_callback_id_t id)
3664 {
3665 	ldi_ev_callback_impl_t	*lecp;
3666 	ldi_ev_callback_impl_t	*next;
3667 	ldi_ev_callback_impl_t	*found;
3668 	list_t			*listp;
3669 
3670 	ASSERT(!servicing_interrupt());
3671 
3672 	if (id == 0) {
3673 		cmn_err(CE_WARN, "ldi_ev_remove_callbacks: Invalid ID 0");
3674 		return (LDI_EV_FAILURE);
3675 	}
3676 
3677 	LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: entered: id=%p",
3678 	    (void *)id));
3679 
3680 	ldi_ev_lock();
3681 
3682 	listp = &ldi_ev_callback_list.le_head;
3683 	next = found = NULL;
3684 	for (lecp = list_head(listp); lecp; lecp = next) {
3685 		next = list_next(listp, lecp);
3686 		if (lecp->lec_id == id) {
3687 			ASSERT(found == NULL);
3688 			list_remove(listp, lecp);
3689 			found = lecp;
3690 		}
3691 	}
3692 	ldi_ev_unlock();
3693 
3694 	if (found == NULL) {
3695 		cmn_err(CE_WARN, "No LDI event handler for id (%p)",
3696 		    (void *)id);
3697 		return (LDI_EV_SUCCESS);
3698 	}
3699 
3700 	if (!ldi_native_cookie(found->lec_cookie)) {
3701 		ASSERT(found->lec_notify == NULL);
3702 		if (ddi_remove_event_handler((ddi_callback_id_t)id)
3703 		    != DDI_SUCCESS) {
3704 			cmn_err(CE_WARN, "failed to remove NDI event handler "
3705 			    "for id (%p)", (void *)id);
3706 			ldi_ev_lock();
3707 			list_insert_tail(listp, found);
3708 			ldi_ev_unlock();
3709 			return (LDI_EV_FAILURE);
3710 		}
3711 		LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: NDI event "
3712 		    "service removal succeeded"));
3713 	} else {
3714 		LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: removed "
3715 		    "LDI native callbacks"));
3716 	}
3717 	kmem_free(found, sizeof (ldi_ev_callback_impl_t));
3718 
3719 	return (LDI_EV_SUCCESS);
3720 }
3721