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