xref: /illumos-gate/usr/src/uts/common/os/driver_lyr.c (revision 184cd04c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*184cd04cScth  * Common Development and Distribution License (the "License").
6*184cd04cScth  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*184cd04cScth  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Layered driver support.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
337c478bd9Sstevel@tonic-gate #include <sys/types.h>
347c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
357c478bd9Sstevel@tonic-gate #include <sys/param.h>
367c478bd9Sstevel@tonic-gate #include <sys/conf.h>
377c478bd9Sstevel@tonic-gate #include <sys/systm.h>
387c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
397c478bd9Sstevel@tonic-gate #include <sys/buf.h>
407c478bd9Sstevel@tonic-gate #include <sys/cred.h>
417c478bd9Sstevel@tonic-gate #include <sys/uio.h>
427c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
437c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h>
447c478bd9Sstevel@tonic-gate #include <sys/open.h>
457c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
467c478bd9Sstevel@tonic-gate #include <sys/file.h>
477c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
487c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
497c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
507c478bd9Sstevel@tonic-gate #include <sys/stat.h>
517c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
527c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
537c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
547c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
557c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
567c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
577c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
587c478bd9Sstevel@tonic-gate #include <sys/sunldi.h>
597c478bd9Sstevel@tonic-gate #include <sys/sunldi_impl.h>
607c478bd9Sstevel@tonic-gate #include <sys/errno.h>
617c478bd9Sstevel@tonic-gate #include <sys/debug.h>
627c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
637c478bd9Sstevel@tonic-gate #include <sys/var.h>
647c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
677c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
687c478bd9Sstevel@tonic-gate #include <sys/socket.h>
697c478bd9Sstevel@tonic-gate #include <sys/socketvar.h>
707c478bd9Sstevel@tonic-gate #include <sys/kstr.h>
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Define macros to manipulate snode, vnode, and open device flags
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate #define	VTYP_VALID(i)	(((i) == VCHR) || ((i) == VBLK))
777c478bd9Sstevel@tonic-gate #define	VTYP_TO_OTYP(i)	(((i) == VCHR) ? OTYP_CHR : OTYP_BLK)
787c478bd9Sstevel@tonic-gate #define	VTYP_TO_STYP(i)	(((i) == VCHR) ? S_IFCHR : S_IFBLK)
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate #define	OTYP_VALID(i)	(((i) == OTYP_CHR) || ((i) == OTYP_BLK))
817c478bd9Sstevel@tonic-gate #define	OTYP_TO_VTYP(i)	(((i) == OTYP_CHR) ? VCHR : VBLK)
827c478bd9Sstevel@tonic-gate #define	OTYP_TO_STYP(i)	(((i) == OTYP_CHR) ? S_IFCHR : S_IFBLK)
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate #define	STYP_VALID(i)	(((i) == S_IFCHR) || ((i) == S_IFBLK))
857c478bd9Sstevel@tonic-gate #define	STYP_TO_VTYP(i)	(((i) == S_IFCHR) ? VCHR : VBLK)
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * Define macros for accessing layered driver hash structures
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate #define	LH_HASH(vp)		(handle_hash_func(vp) % LH_HASH_SZ)
917c478bd9Sstevel@tonic-gate #define	LI_HASH(mid, dip, dev)	(ident_hash_func(mid, dip, dev) % LI_HASH_SZ)
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /*
947c478bd9Sstevel@tonic-gate  * Define layered handle flags used in the lh_type field
957c478bd9Sstevel@tonic-gate  */
967c478bd9Sstevel@tonic-gate #define	LH_STREAM	(0x1)	/* handle to a streams device */
977c478bd9Sstevel@tonic-gate #define	LH_CBDEV	(0x2)	/* handle to a char/block device */
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * Define marco for devid property lookups
1017c478bd9Sstevel@tonic-gate  */
1027c478bd9Sstevel@tonic-gate #define	DEVID_PROP_FLAGS	(DDI_PROP_DONTPASS | \
1037c478bd9Sstevel@tonic-gate 				DDI_PROP_TYPE_STRING|DDI_PROP_CANSLEEP)
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
1077c478bd9Sstevel@tonic-gate  * globals
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate static kmutex_t			ldi_ident_hash_lock[LI_HASH_SZ];
1107c478bd9Sstevel@tonic-gate static struct ldi_ident		*ldi_ident_hash[LI_HASH_SZ];
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate static kmutex_t			ldi_handle_hash_lock[LH_HASH_SZ];
1137c478bd9Sstevel@tonic-gate static struct ldi_handle	*ldi_handle_hash[LH_HASH_SZ];
1147c478bd9Sstevel@tonic-gate static size_t			ldi_handle_hash_count;
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate void
1177c478bd9Sstevel@tonic-gate ldi_init(void)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	int i;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 	ldi_handle_hash_count = 0;
1227c478bd9Sstevel@tonic-gate 	for (i = 0; i < LH_HASH_SZ; i++) {
1237c478bd9Sstevel@tonic-gate 		mutex_init(&ldi_handle_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
1247c478bd9Sstevel@tonic-gate 		ldi_handle_hash[i] = NULL;
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 	for (i = 0; i < LI_HASH_SZ; i++) {
1277c478bd9Sstevel@tonic-gate 		mutex_init(&ldi_ident_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
1287c478bd9Sstevel@tonic-gate 		ldi_ident_hash[i] = NULL;
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  * LDI ident manipulation functions
1347c478bd9Sstevel@tonic-gate  */
1357c478bd9Sstevel@tonic-gate static uint_t
1367c478bd9Sstevel@tonic-gate ident_hash_func(modid_t modid, dev_info_t *dip, dev_t dev)
1377c478bd9Sstevel@tonic-gate {
1387c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
1397c478bd9Sstevel@tonic-gate 		uintptr_t k = (uintptr_t)dip;
1407c478bd9Sstevel@tonic-gate 		k >>= (int)highbit(sizeof (struct dev_info));
1417c478bd9Sstevel@tonic-gate 		return ((uint_t)k);
1427c478bd9Sstevel@tonic-gate 	} else if (dev != DDI_DEV_T_NONE) {
1437c478bd9Sstevel@tonic-gate 		return (modid + getminor(dev) + getmajor(dev));
1447c478bd9Sstevel@tonic-gate 	} else {
1457c478bd9Sstevel@tonic-gate 		return (modid);
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static struct ldi_ident **
1507c478bd9Sstevel@tonic-gate ident_find_ref_nolock(modid_t modid, dev_info_t *dip, dev_t dev, major_t major)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	struct ldi_ident	**lipp = NULL;
1537c478bd9Sstevel@tonic-gate 	uint_t			index = LI_HASH(modid, dip, dev);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ldi_ident_hash_lock[index]));
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	for (lipp = &(ldi_ident_hash[index]);
1587c478bd9Sstevel@tonic-gate 	    (*lipp != NULL);
1597c478bd9Sstevel@tonic-gate 	    lipp = &((*lipp)->li_next)) {
1607c478bd9Sstevel@tonic-gate 		if (((*lipp)->li_modid == modid) &&
1617c478bd9Sstevel@tonic-gate 		    ((*lipp)->li_major == major) &&
1627c478bd9Sstevel@tonic-gate 		    ((*lipp)->li_dip == dip) &&
1637c478bd9Sstevel@tonic-gate 		    ((*lipp)->li_dev == dev))
1647c478bd9Sstevel@tonic-gate 			break;
1657c478bd9Sstevel@tonic-gate 	}
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	ASSERT(lipp != NULL);
1687c478bd9Sstevel@tonic-gate 	return (lipp);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate static struct ldi_ident *
1727c478bd9Sstevel@tonic-gate ident_alloc(char *mod_name, dev_info_t *dip, dev_t dev, major_t major)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip, **lipp;
1757c478bd9Sstevel@tonic-gate 	modid_t			modid;
1767c478bd9Sstevel@tonic-gate 	uint_t			index;
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	ASSERT(mod_name != NULL);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/* get the module id */
1817c478bd9Sstevel@tonic-gate 	modid = mod_name_to_modid(mod_name);
1827c478bd9Sstevel@tonic-gate 	ASSERT(modid != -1);
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	/* allocate a new ident in case we need it */
1857c478bd9Sstevel@tonic-gate 	lip = kmem_zalloc(sizeof (*lip), KM_SLEEP);
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	/* search the hash for a matching ident */
1887c478bd9Sstevel@tonic-gate 	index = LI_HASH(modid, dip, dev);
1897c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_ident_hash_lock[index]);
1907c478bd9Sstevel@tonic-gate 	lipp = ident_find_ref_nolock(modid, dip, dev, major);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	if (*lipp != NULL) {
1937c478bd9Sstevel@tonic-gate 		/* we found an indent in the hash */
1947c478bd9Sstevel@tonic-gate 		ASSERT(strcmp((*lipp)->li_modname, mod_name) == 0);
1957c478bd9Sstevel@tonic-gate 		(*lipp)->li_ref++;
1967c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_ident_hash_lock[index]);
1977c478bd9Sstevel@tonic-gate 		kmem_free(lip, sizeof (struct ldi_ident));
1987c478bd9Sstevel@tonic-gate 		return (*lipp);
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	/* initialize the new ident */
2027c478bd9Sstevel@tonic-gate 	lip->li_next = NULL;
2037c478bd9Sstevel@tonic-gate 	lip->li_ref = 1;
2047c478bd9Sstevel@tonic-gate 	lip->li_modid = modid;
2057c478bd9Sstevel@tonic-gate 	lip->li_major = major;
2067c478bd9Sstevel@tonic-gate 	lip->li_dip = dip;
2077c478bd9Sstevel@tonic-gate 	lip->li_dev = dev;
2087c478bd9Sstevel@tonic-gate 	(void) strncpy(lip->li_modname, mod_name, sizeof (lip->li_modname) - 1);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	/* add it to the ident hash */
2117c478bd9Sstevel@tonic-gate 	lip->li_next = ldi_ident_hash[index];
2127c478bd9Sstevel@tonic-gate 	ldi_ident_hash[index] = lip;
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_ident_hash_lock[index]);
2157c478bd9Sstevel@tonic-gate 	return (lip);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate static void
2197c478bd9Sstevel@tonic-gate ident_hold(struct ldi_ident *lip)
2207c478bd9Sstevel@tonic-gate {
2217c478bd9Sstevel@tonic-gate 	uint_t			index;
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	ASSERT(lip != NULL);
2247c478bd9Sstevel@tonic-gate 	index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
2257c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_ident_hash_lock[index]);
2267c478bd9Sstevel@tonic-gate 	ASSERT(lip->li_ref > 0);
2277c478bd9Sstevel@tonic-gate 	lip->li_ref++;
2287c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_ident_hash_lock[index]);
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate static void
2327c478bd9Sstevel@tonic-gate ident_release(struct ldi_ident *lip)
2337c478bd9Sstevel@tonic-gate {
2347c478bd9Sstevel@tonic-gate 	struct ldi_ident	**lipp;
2357c478bd9Sstevel@tonic-gate 	uint_t			index;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	ASSERT(lip != NULL);
2387c478bd9Sstevel@tonic-gate 	index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
2397c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_ident_hash_lock[index]);
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	ASSERT(lip->li_ref > 0);
2427c478bd9Sstevel@tonic-gate 	if (--lip->li_ref > 0) {
2437c478bd9Sstevel@tonic-gate 		/* there are more references to this ident */
2447c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_ident_hash_lock[index]);
2457c478bd9Sstevel@tonic-gate 		return;
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/* this was the last reference/open for this ident.  free it. */
2497c478bd9Sstevel@tonic-gate 	lipp = ident_find_ref_nolock(
2507c478bd9Sstevel@tonic-gate 	    lip->li_modid, lip->li_dip, lip->li_dev, lip->li_major);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	ASSERT((lipp != NULL) && (*lipp != NULL));
2537c478bd9Sstevel@tonic-gate 	*lipp = lip->li_next;
2547c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_ident_hash_lock[index]);
2557c478bd9Sstevel@tonic-gate 	kmem_free(lip, sizeof (struct ldi_ident));
2567c478bd9Sstevel@tonic-gate }
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate /*
2597c478bd9Sstevel@tonic-gate  * LDI handle manipulation functions
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate static uint_t
2627c478bd9Sstevel@tonic-gate handle_hash_func(void *vp)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate 	uintptr_t k = (uintptr_t)vp;
2657c478bd9Sstevel@tonic-gate 	k >>= (int)highbit(sizeof (vnode_t));
2667c478bd9Sstevel@tonic-gate 	return ((uint_t)k);
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate static struct ldi_handle **
2707c478bd9Sstevel@tonic-gate handle_find_ref_nolock(vnode_t *vp, struct ldi_ident *ident)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	struct ldi_handle	**lhpp = NULL;
2737c478bd9Sstevel@tonic-gate 	uint_t			index = LH_HASH(vp);
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ldi_handle_hash_lock[index]));
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	for (lhpp = &(ldi_handle_hash[index]);
2787c478bd9Sstevel@tonic-gate 	    (*lhpp != NULL);
2797c478bd9Sstevel@tonic-gate 	    lhpp = &((*lhpp)->lh_next)) {
2807c478bd9Sstevel@tonic-gate 		if (((*lhpp)->lh_ident == ident) &&
2817c478bd9Sstevel@tonic-gate 		    ((*lhpp)->lh_vp == vp))
2827c478bd9Sstevel@tonic-gate 			break;
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 	ASSERT(lhpp != NULL);
2867c478bd9Sstevel@tonic-gate 	return (lhpp);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate static struct ldi_handle *
2907c478bd9Sstevel@tonic-gate handle_find(vnode_t *vp, struct ldi_ident *ident)
2917c478bd9Sstevel@tonic-gate {
2927c478bd9Sstevel@tonic-gate 	struct ldi_handle	**lhpp;
2937c478bd9Sstevel@tonic-gate 	int			index = LH_HASH(vp);
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_handle_hash_lock[index]);
2967c478bd9Sstevel@tonic-gate 	lhpp = handle_find_ref_nolock(vp, ident);
2977c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_handle_hash_lock[index]);
2987c478bd9Sstevel@tonic-gate 	ASSERT(lhpp != NULL);
2997c478bd9Sstevel@tonic-gate 	return (*lhpp);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate static struct ldi_handle *
3037c478bd9Sstevel@tonic-gate handle_alloc(vnode_t *vp, struct ldi_ident *ident)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	struct ldi_handle	*lhp, **lhpp;
3067c478bd9Sstevel@tonic-gate 	uint_t			index;
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	ASSERT((vp != NULL) && (ident != NULL));
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/* allocate a new handle in case we need it */
3117c478bd9Sstevel@tonic-gate 	lhp = kmem_zalloc(sizeof (*lhp), KM_SLEEP);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	/* search the hash for a matching handle */
3147c478bd9Sstevel@tonic-gate 	index = LH_HASH(vp);
3157c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_handle_hash_lock[index]);
3167c478bd9Sstevel@tonic-gate 	lhpp = handle_find_ref_nolock(vp, ident);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	if (*lhpp != NULL) {
3197c478bd9Sstevel@tonic-gate 		/* we found a handle in the hash */
3207c478bd9Sstevel@tonic-gate 		(*lhpp)->lh_ref++;
3217c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_handle_hash_lock[index]);
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 		LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: dup "
324*184cd04cScth 		    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
325*184cd04cScth 		    (void *)*lhpp, (void *)ident, (void *)vp,
326*184cd04cScth 		    mod_major_to_name(getmajor(vp->v_rdev)),
327*184cd04cScth 		    getminor(vp->v_rdev)));
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 		kmem_free(lhp, sizeof (struct ldi_handle));
3307c478bd9Sstevel@tonic-gate 		return (*lhpp);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	/* initialize the new handle */
3347c478bd9Sstevel@tonic-gate 	lhp->lh_ref = 1;
3357c478bd9Sstevel@tonic-gate 	lhp->lh_vp = vp;
3367c478bd9Sstevel@tonic-gate 	lhp->lh_ident = ident;
3377c478bd9Sstevel@tonic-gate 	mutex_init(lhp->lh_lock, NULL, MUTEX_DEFAULT, NULL);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 	/* set the device type for this handle */
3407c478bd9Sstevel@tonic-gate 	lhp->lh_type = 0;
3417c478bd9Sstevel@tonic-gate 	if (STREAMSTAB(getmajor(vp->v_rdev))) {
3427c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_type == VCHR);
3437c478bd9Sstevel@tonic-gate 		lhp->lh_type |= LH_STREAM;
3447c478bd9Sstevel@tonic-gate 	} else {
3457c478bd9Sstevel@tonic-gate 		lhp->lh_type |= LH_CBDEV;
3467c478bd9Sstevel@tonic-gate 	}
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	/* get holds on other objects */
3497c478bd9Sstevel@tonic-gate 	ident_hold(ident);
3507c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count >= 1);
3517c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/* add it to the handle hash */
3547c478bd9Sstevel@tonic-gate 	lhp->lh_next = ldi_handle_hash[index];
3557c478bd9Sstevel@tonic-gate 	ldi_handle_hash[index] = lhp;
3567c478bd9Sstevel@tonic-gate 	atomic_add_long(&ldi_handle_hash_count, 1);
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: new "
359*184cd04cScth 	    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
360*184cd04cScth 	    (void *)lhp, (void *)ident, (void *)vp,
361*184cd04cScth 	    mod_major_to_name(getmajor(vp->v_rdev)),
362*184cd04cScth 	    getminor(vp->v_rdev)));
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_handle_hash_lock[index]);
3657c478bd9Sstevel@tonic-gate 	return (lhp);
3667c478bd9Sstevel@tonic-gate }
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate static void
3697c478bd9Sstevel@tonic-gate handle_release(struct ldi_handle *lhp)
3707c478bd9Sstevel@tonic-gate {
3717c478bd9Sstevel@tonic-gate 	struct ldi_handle	**lhpp;
3727c478bd9Sstevel@tonic-gate 	uint_t			index;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	ASSERT(lhp != NULL);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	index = LH_HASH(lhp->lh_vp);
3777c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_handle_hash_lock[index]);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN, "ldi handle release: "
380*184cd04cScth 	    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
381*184cd04cScth 	    (void *)lhp, (void *)lhp->lh_ident, (void *)lhp->lh_vp,
382*184cd04cScth 	    mod_major_to_name(getmajor(lhp->lh_vp->v_rdev)),
383*184cd04cScth 	    getminor(lhp->lh_vp->v_rdev)));
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	ASSERT(lhp->lh_ref > 0);
3867c478bd9Sstevel@tonic-gate 	if (--lhp->lh_ref > 0) {
3877c478bd9Sstevel@tonic-gate 		/* there are more references to this handle */
3887c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_handle_hash_lock[index]);
3897c478bd9Sstevel@tonic-gate 		return;
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/* this was the last reference/open for this handle.  free it. */
3937c478bd9Sstevel@tonic-gate 	lhpp = handle_find_ref_nolock(lhp->lh_vp, lhp->lh_ident);
3947c478bd9Sstevel@tonic-gate 	ASSERT((lhpp != NULL) && (*lhpp != NULL));
3957c478bd9Sstevel@tonic-gate 	*lhpp = lhp->lh_next;
3967c478bd9Sstevel@tonic-gate 	atomic_add_long(&ldi_handle_hash_count, -1);
3977c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_handle_hash_lock[index]);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	VN_RELE(lhp->lh_vp);
4007c478bd9Sstevel@tonic-gate 	ident_release(lhp->lh_ident);
4017c478bd9Sstevel@tonic-gate 	mutex_destroy(lhp->lh_lock);
4027c478bd9Sstevel@tonic-gate 	kmem_free(lhp, sizeof (struct ldi_handle));
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate  * LDI event manipulation functions
4077c478bd9Sstevel@tonic-gate  */
4087c478bd9Sstevel@tonic-gate static void
4097c478bd9Sstevel@tonic-gate handle_event_add(ldi_event_t *lep)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate 	struct ldi_handle *lhp = lep->le_lhp;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	ASSERT(lhp != NULL);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	mutex_enter(lhp->lh_lock);
4167c478bd9Sstevel@tonic-gate 	if (lhp->lh_events == NULL) {
4177c478bd9Sstevel@tonic-gate 		lhp->lh_events = lep;
4187c478bd9Sstevel@tonic-gate 		mutex_exit(lhp->lh_lock);
4197c478bd9Sstevel@tonic-gate 		return;
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	lep->le_next = lhp->lh_events;
4237c478bd9Sstevel@tonic-gate 	lhp->lh_events->le_prev = lep;
4247c478bd9Sstevel@tonic-gate 	lhp->lh_events = lep;
4257c478bd9Sstevel@tonic-gate 	mutex_exit(lhp->lh_lock);
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate static void
4297c478bd9Sstevel@tonic-gate handle_event_remove(ldi_event_t *lep)
4307c478bd9Sstevel@tonic-gate {
4317c478bd9Sstevel@tonic-gate 	struct ldi_handle *lhp = lep->le_lhp;
4327c478bd9Sstevel@tonic-gate 
4337c478bd9Sstevel@tonic-gate 	ASSERT(lhp != NULL);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	mutex_enter(lhp->lh_lock);
4367c478bd9Sstevel@tonic-gate 	if (lep->le_prev)
4377c478bd9Sstevel@tonic-gate 		lep->le_prev->le_next = lep->le_next;
4387c478bd9Sstevel@tonic-gate 	if (lep->le_next)
4397c478bd9Sstevel@tonic-gate 		lep->le_next->le_prev = lep->le_prev;
4407c478bd9Sstevel@tonic-gate 	if (lhp->lh_events == lep)
4417c478bd9Sstevel@tonic-gate 		lhp->lh_events = lep->le_next;
4427c478bd9Sstevel@tonic-gate 	mutex_exit(lhp->lh_lock);
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate static void
4477c478bd9Sstevel@tonic-gate i_ldi_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie,
4487c478bd9Sstevel@tonic-gate     void *arg, void *bus_impldata)
4497c478bd9Sstevel@tonic-gate {
4507c478bd9Sstevel@tonic-gate 	ldi_event_t *lep = (ldi_event_t *)arg;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	ASSERT(lep != NULL);
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 	LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, "
4557c478bd9Sstevel@tonic-gate 	    "event_cookie=0x%p, ldi_eventp=0x%p", "i_ldi_callback",
4567c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)event_cookie, (void *)lep));
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	lep->le_handler(lep->le_lhp, event_cookie, lep->le_arg, bus_impldata);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate /*
4627c478bd9Sstevel@tonic-gate  * LDI open helper functions
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate /* get a vnode to a device by dev_t and otyp */
4667c478bd9Sstevel@tonic-gate static int
4677c478bd9Sstevel@tonic-gate ldi_vp_from_dev(dev_t dev, int otyp, vnode_t **vpp)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
4707c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
4737c478bd9Sstevel@tonic-gate 	if ((dev == DDI_DEV_T_NONE) || (!OTYP_VALID(otyp)) || (vpp == NULL))
4747c478bd9Sstevel@tonic-gate 		return (EINVAL);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4777c478bd9Sstevel@tonic-gate 		return (ENODEV);
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	if (STREAMSTAB(getmajor(dev)) && (otyp != OTYP_CHR)) {
4807c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);  /* from e_ddi_hold_devi_by_dev */
4817c478bd9Sstevel@tonic-gate 		return (ENXIO);
4827c478bd9Sstevel@tonic-gate 	}
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	vp = makespecvp(dev, OTYP_TO_VTYP(otyp));
4857c478bd9Sstevel@tonic-gate 	spec_assoc_vp_with_devi(vp, dip);
4867c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);  /* from e_ddi_hold_devi_by_dev */
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	*vpp = vp;
4897c478bd9Sstevel@tonic-gate 	return (0);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate /* get a vnode to a device by pathname */
4937c478bd9Sstevel@tonic-gate static int
4947c478bd9Sstevel@tonic-gate ldi_vp_from_name(char *path, vnode_t **vpp)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate 	vnode_t			*vp = NULL;
4977c478bd9Sstevel@tonic-gate 	int			ret;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
5007c478bd9Sstevel@tonic-gate 	if ((path == NULL) || (vpp == NULL))
5017c478bd9Sstevel@tonic-gate 		return (EINVAL);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	if (modrootloaded) {
5047c478bd9Sstevel@tonic-gate 		cred_t *saved_cred = curthread->t_cred;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 		/* we don't want lookupname to fail because of credentials */
5077c478bd9Sstevel@tonic-gate 		curthread->t_cred = kcred;
50886f07f8fSedp 
50986f07f8fSedp 		/*
51086f07f8fSedp 		 * all lookups should be done in the global zone.  but
51186f07f8fSedp 		 * lookupnameat() won't actually do this if an absolute
51286f07f8fSedp 		 * path is passed in.  since the ldi interfaces require an
51386f07f8fSedp 		 * absolute path we pass lookupnameat() a pointer to
51486f07f8fSedp 		 * the character after the leading '/' and tell it to
51586f07f8fSedp 		 * start searching at the current system root directory.
51686f07f8fSedp 		 */
51786f07f8fSedp 		ASSERT(*path == '/');
51886f07f8fSedp 		ret = lookupnameat(path + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
51986f07f8fSedp 		    &vp, rootdir);
52086f07f8fSedp 
52186f07f8fSedp 		/* restore this threads credentials */
5227c478bd9Sstevel@tonic-gate 		curthread->t_cred = saved_cred;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		if (ret == 0) {
5257c478bd9Sstevel@tonic-gate 			if (!vn_matchops(vp, spec_getvnodeops()) ||
5267c478bd9Sstevel@tonic-gate 			    !VTYP_VALID(vp->v_type)) {
5277c478bd9Sstevel@tonic-gate 				VN_RELE(vp);
5287c478bd9Sstevel@tonic-gate 				return (ENXIO);
5297c478bd9Sstevel@tonic-gate 			}
5307c478bd9Sstevel@tonic-gate 		}
5317c478bd9Sstevel@tonic-gate 	}
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
5347c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
5357c478bd9Sstevel@tonic-gate 		dev_t		dev;
5367c478bd9Sstevel@tonic-gate 		int		spec_type;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 		/*
5397c478bd9Sstevel@tonic-gate 		 * Root is not mounted, the minor node is not specified,
5407c478bd9Sstevel@tonic-gate 		 * or an OBP path has been specified.
5417c478bd9Sstevel@tonic-gate 		 */
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 		/*
5447c478bd9Sstevel@tonic-gate 		 * Determine if path can be pruned to produce an
5457c478bd9Sstevel@tonic-gate 		 * OBP or devfs path for resolve_pathname.
5467c478bd9Sstevel@tonic-gate 		 */
5477c478bd9Sstevel@tonic-gate 		if (strncmp(path, "/devices/", 9) == 0)
5487c478bd9Sstevel@tonic-gate 			path += strlen("/devices");
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 		/*
5517c478bd9Sstevel@tonic-gate 		 * if no minor node was specified the DEFAULT minor node
5527c478bd9Sstevel@tonic-gate 		 * will be returned.  if there is no DEFAULT minor node
5537c478bd9Sstevel@tonic-gate 		 * one will be fabricated of type S_IFCHR with the minor
5547c478bd9Sstevel@tonic-gate 		 * number equal to the instance number.
5557c478bd9Sstevel@tonic-gate 		 */
5567c478bd9Sstevel@tonic-gate 		ret = resolve_pathname(path, &dip, &dev, &spec_type);
5577c478bd9Sstevel@tonic-gate 		if (ret != 0)
5587c478bd9Sstevel@tonic-gate 			return (ENODEV);
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 		ASSERT(STYP_VALID(spec_type));
5617c478bd9Sstevel@tonic-gate 		vp = makespecvp(dev, STYP_TO_VTYP(spec_type));
5627c478bd9Sstevel@tonic-gate 		spec_assoc_vp_with_devi(vp, dip);
5637c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate 	*vpp = vp;
5677c478bd9Sstevel@tonic-gate 	return (0);
5687c478bd9Sstevel@tonic-gate }
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate static int
5717c478bd9Sstevel@tonic-gate ldi_devid_match(ddi_devid_t devid, dev_info_t *dip, dev_t dev)
5727c478bd9Sstevel@tonic-gate {
5737c478bd9Sstevel@tonic-gate 	char		*devidstr;
5747c478bd9Sstevel@tonic-gate 	ddi_prop_t	*propp;
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	/* convert devid as a string property */
5777c478bd9Sstevel@tonic-gate 	if ((devidstr = ddi_devid_str_encode(devid, NULL)) == NULL)
5787c478bd9Sstevel@tonic-gate 		return (0);
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	/*
5817c478bd9Sstevel@tonic-gate 	 * Search for the devid.  For speed and ease in locking this
5827c478bd9Sstevel@tonic-gate 	 * code directly uses the property implementation.  See
5837c478bd9Sstevel@tonic-gate 	 * ddi_common_devid_to_devlist() for a comment as to why.
5847c478bd9Sstevel@tonic-gate 	 */
5857c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 	/* check if there is a DDI_DEV_T_NONE devid property */
5887c478bd9Sstevel@tonic-gate 	propp = i_ddi_prop_search(DDI_DEV_T_NONE,
5897c478bd9Sstevel@tonic-gate 	    DEVID_PROP_NAME, DEVID_PROP_FLAGS, &DEVI(dip)->devi_hw_prop_ptr);
5907c478bd9Sstevel@tonic-gate 	if (propp != NULL) {
5917c478bd9Sstevel@tonic-gate 		if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
5927c478bd9Sstevel@tonic-gate 			/* a DDI_DEV_T_NONE devid exists and matchs */
5937c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
5947c478bd9Sstevel@tonic-gate 			ddi_devid_str_free(devidstr);
5957c478bd9Sstevel@tonic-gate 			return (1);
5967c478bd9Sstevel@tonic-gate 		} else {
5977c478bd9Sstevel@tonic-gate 			/* a DDI_DEV_T_NONE devid exists and doesn't match */
5987c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
5997c478bd9Sstevel@tonic-gate 			ddi_devid_str_free(devidstr);
6007c478bd9Sstevel@tonic-gate 			return (0);
6017c478bd9Sstevel@tonic-gate 		}
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	/* check if there is a devt specific devid property */
6057c478bd9Sstevel@tonic-gate 	propp = i_ddi_prop_search(dev,
6067c478bd9Sstevel@tonic-gate 	    DEVID_PROP_NAME, DEVID_PROP_FLAGS, &(DEVI(dip)->devi_hw_prop_ptr));
6077c478bd9Sstevel@tonic-gate 	if (propp != NULL) {
6087c478bd9Sstevel@tonic-gate 		if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
6097c478bd9Sstevel@tonic-gate 			/* a devt specific devid exists and matchs */
6107c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
6117c478bd9Sstevel@tonic-gate 			ddi_devid_str_free(devidstr);
6127c478bd9Sstevel@tonic-gate 			return (1);
6137c478bd9Sstevel@tonic-gate 		} else {
6147c478bd9Sstevel@tonic-gate 			/* a devt specific devid exists and doesn't match */
6157c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
6167c478bd9Sstevel@tonic-gate 			ddi_devid_str_free(devidstr);
6177c478bd9Sstevel@tonic-gate 			return (0);
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate 	/* we didn't find any devids associated with the device */
6227c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
6237c478bd9Sstevel@tonic-gate 	ddi_devid_str_free(devidstr);
6247c478bd9Sstevel@tonic-gate 	return (0);
6257c478bd9Sstevel@tonic-gate }
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate /* get a handle to a device by devid and minor name */
6287c478bd9Sstevel@tonic-gate static int
6297c478bd9Sstevel@tonic-gate ldi_vp_from_devid(ddi_devid_t devid, char *minor_name, vnode_t **vpp)
6307c478bd9Sstevel@tonic-gate {
6317c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
6327c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
6337c478bd9Sstevel@tonic-gate 	int			ret, i, ndevs, styp;
6347c478bd9Sstevel@tonic-gate 	dev_t			dev, *devs;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
6377c478bd9Sstevel@tonic-gate 	if ((devid == NULL) || (minor_name == NULL) || (vpp == NULL))
6387c478bd9Sstevel@tonic-gate 		return (EINVAL);
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	ret = ddi_lyr_devid_to_devlist(devid, minor_name, &ndevs, &devs);
6417c478bd9Sstevel@tonic-gate 	if ((ret != DDI_SUCCESS) || (ndevs <= 0))
6427c478bd9Sstevel@tonic-gate 		return (ENODEV);
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	for (i = 0; i < ndevs; i++) {
6457c478bd9Sstevel@tonic-gate 		dev = devs[i];
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
6487c478bd9Sstevel@tonic-gate 			continue;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		/*
6517c478bd9Sstevel@tonic-gate 		 * now we have to verify that the devid of the disk
6527c478bd9Sstevel@tonic-gate 		 * still matches what was requested.
6537c478bd9Sstevel@tonic-gate 		 *
6547c478bd9Sstevel@tonic-gate 		 * we have to do this because the devid could have
6557c478bd9Sstevel@tonic-gate 		 * changed between the call to ddi_lyr_devid_to_devlist()
6567c478bd9Sstevel@tonic-gate 		 * and e_ddi_hold_devi_by_dev().  this is because when
6577c478bd9Sstevel@tonic-gate 		 * ddi_lyr_devid_to_devlist() returns a list of devts
6587c478bd9Sstevel@tonic-gate 		 * there is no kind of hold on those devts so a device
6597c478bd9Sstevel@tonic-gate 		 * could have been replaced out from under us in the
6607c478bd9Sstevel@tonic-gate 		 * interim.
6617c478bd9Sstevel@tonic-gate 		 */
6627c478bd9Sstevel@tonic-gate 		if ((i_ddi_minorname_to_devtspectype(dip, minor_name,
6637c478bd9Sstevel@tonic-gate 		    NULL, &styp) == DDI_SUCCESS) &&
6647c478bd9Sstevel@tonic-gate 		    ldi_devid_match(devid, dip, dev))
6657c478bd9Sstevel@tonic-gate 			break;
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);	/* from e_ddi_hold_devi_by_dev() */
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	ddi_lyr_free_devlist(devs, ndevs);
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	if (i == ndevs)
6737c478bd9Sstevel@tonic-gate 		return (ENODEV);
6747c478bd9Sstevel@tonic-gate 
6757c478bd9Sstevel@tonic-gate 	ASSERT(STYP_VALID(styp));
6767c478bd9Sstevel@tonic-gate 	vp = makespecvp(dev, STYP_TO_VTYP(styp));
6777c478bd9Sstevel@tonic-gate 	spec_assoc_vp_with_devi(vp, dip);
6787c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);		/* from e_ddi_hold_devi_by_dev */
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	*vpp = vp;
6817c478bd9Sstevel@tonic-gate 	return (0);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate /* given a vnode, open a device */
6857c478bd9Sstevel@tonic-gate static int
6867c478bd9Sstevel@tonic-gate ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
6877c478bd9Sstevel@tonic-gate     ldi_handle_t *lhp, struct ldi_ident *li)
6887c478bd9Sstevel@tonic-gate {
6897c478bd9Sstevel@tonic-gate 	struct ldi_handle	*nlhp;
6907c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
6917c478bd9Sstevel@tonic-gate 	int			err;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	ASSERT((vpp != NULL) && (*vpp != NULL));
6947c478bd9Sstevel@tonic-gate 	ASSERT((lhp != NULL) && (li != NULL));
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	vp = *vpp;
6977c478bd9Sstevel@tonic-gate 	/* if the vnode passed in is not a device, then bail */
6987c478bd9Sstevel@tonic-gate 	if (!vn_matchops(vp, spec_getvnodeops()) || !VTYP_VALID(vp->v_type))
6997c478bd9Sstevel@tonic-gate 		return (ENXIO);
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	/*
7027c478bd9Sstevel@tonic-gate 	 * the caller may have specified a node that
7037c478bd9Sstevel@tonic-gate 	 * doesn't have cb_ops defined.  the ldi doesn't yet
7047c478bd9Sstevel@tonic-gate 	 * support opening devices without a valid cb_ops.
7057c478bd9Sstevel@tonic-gate 	 */
7067c478bd9Sstevel@tonic-gate 	if (devopsp[getmajor(vp->v_rdev)]->devo_cb_ops == NULL)
7077c478bd9Sstevel@tonic-gate 		return (ENXIO);
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	/* open the device */
7107c478bd9Sstevel@tonic-gate 	if ((err = VOP_OPEN(&vp, flag | FKLYR, cr)) != 0)
7117c478bd9Sstevel@tonic-gate 		return (err);
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	/* possible clone open, make sure that we still have a spec node */
7147c478bd9Sstevel@tonic-gate 	ASSERT(vn_matchops(vp, spec_getvnodeops()));
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 	nlhp = handle_alloc(vp, li);
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	if (vp != *vpp) {
7197c478bd9Sstevel@tonic-gate 		/*
7207c478bd9Sstevel@tonic-gate 		 * allocating the layered handle took a new hold on the vnode
7217c478bd9Sstevel@tonic-gate 		 * so we can release the hold that was returned by the clone
7227c478bd9Sstevel@tonic-gate 		 * open
7237c478bd9Sstevel@tonic-gate 		 */
7247c478bd9Sstevel@tonic-gate 		LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
725*184cd04cScth 		    "ldi clone open", (void *)nlhp));
7267c478bd9Sstevel@tonic-gate 	} else {
7277c478bd9Sstevel@tonic-gate 		LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
728*184cd04cScth 		    "ldi open", (void *)nlhp));
7297c478bd9Sstevel@tonic-gate 	}
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	/* Flush back any dirty pages associated with the device. */
7327c478bd9Sstevel@tonic-gate 	if (nlhp->lh_type & LH_CBDEV) {
7337c478bd9Sstevel@tonic-gate 		vnode_t	*cvp = common_specvp(nlhp->lh_vp);
7347c478bd9Sstevel@tonic-gate 		dev_t	dev = cvp->v_rdev;
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 		(void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred);
7377c478bd9Sstevel@tonic-gate 		bflush(dev);
7387c478bd9Sstevel@tonic-gate 	}
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 	*vpp = vp;
7417c478bd9Sstevel@tonic-gate 	*lhp = (ldi_handle_t)nlhp;
7427c478bd9Sstevel@tonic-gate 	return (0);
7437c478bd9Sstevel@tonic-gate }
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate /* Call a drivers prop_op(9E) interface */
7467c478bd9Sstevel@tonic-gate static int
7477c478bd9Sstevel@tonic-gate i_ldi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
7487c478bd9Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp)
7497c478bd9Sstevel@tonic-gate {
7507c478bd9Sstevel@tonic-gate 	struct dev_ops	*ops = NULL;
7517c478bd9Sstevel@tonic-gate 	int		res;
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	ASSERT((dip != NULL) && (name != NULL));
7547c478bd9Sstevel@tonic-gate 	ASSERT((prop_op == PROP_LEN) || (valuep != NULL));
7557c478bd9Sstevel@tonic-gate 	ASSERT(lengthp != NULL);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	/*
7587c478bd9Sstevel@tonic-gate 	 * we can only be invoked after a driver has been opened and
7597c478bd9Sstevel@tonic-gate 	 * someone has a layered handle to it, so there had better be
7607c478bd9Sstevel@tonic-gate 	 * a valid ops vector.
7617c478bd9Sstevel@tonic-gate 	 */
7627c478bd9Sstevel@tonic-gate 	ops = DEVI(dip)->devi_ops;
7637c478bd9Sstevel@tonic-gate 	ASSERT(ops && ops->devo_cb_ops);
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	/*
7667c478bd9Sstevel@tonic-gate 	 * Some nexus drivers incorrectly set cb_prop_op to nodev,
7677c478bd9Sstevel@tonic-gate 	 * nulldev or even NULL.
7687c478bd9Sstevel@tonic-gate 	 */
7697c478bd9Sstevel@tonic-gate 	if ((ops->devo_cb_ops->cb_prop_op == nodev) ||
7707c478bd9Sstevel@tonic-gate 	    (ops->devo_cb_ops->cb_prop_op == nulldev) ||
7717c478bd9Sstevel@tonic-gate 	    (ops->devo_cb_ops->cb_prop_op == NULL)) {
7727c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
7737c478bd9Sstevel@tonic-gate 	}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	/* check if this is actually DDI_DEV_T_ANY query */
7767c478bd9Sstevel@tonic-gate 	if (flags & LDI_DEV_T_ANY) {
7777c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
7787c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	res = cdev_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp);
7827c478bd9Sstevel@tonic-gate 	return (res);
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate static void
7867c478bd9Sstevel@tonic-gate i_ldi_prop_op_free(struct prop_driver_data *pdd)
7877c478bd9Sstevel@tonic-gate {
7887c478bd9Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate static caddr_t
7927c478bd9Sstevel@tonic-gate i_ldi_prop_op_alloc(int prop_len)
7937c478bd9Sstevel@tonic-gate {
7947c478bd9Sstevel@tonic-gate 	struct prop_driver_data	*pdd;
7957c478bd9Sstevel@tonic-gate 	int			pdd_size;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	pdd_size = sizeof (struct prop_driver_data) + prop_len;
7987c478bd9Sstevel@tonic-gate 	pdd = kmem_alloc(pdd_size, KM_SLEEP);
7997c478bd9Sstevel@tonic-gate 	pdd->pdd_size = pdd_size;
8007c478bd9Sstevel@tonic-gate 	pdd->pdd_prop_free = i_ldi_prop_op_free;
8017c478bd9Sstevel@tonic-gate 	return ((caddr_t)&pdd[1]);
8027c478bd9Sstevel@tonic-gate }
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate /*
8057c478bd9Sstevel@tonic-gate  * i_ldi_prop_op_typed() is a wrapper for i_ldi_prop_op that is used
8067c478bd9Sstevel@tonic-gate  * by the typed ldi property lookup interfaces.
8077c478bd9Sstevel@tonic-gate  */
8087c478bd9Sstevel@tonic-gate static int
8097c478bd9Sstevel@tonic-gate i_ldi_prop_op_typed(dev_t dev, dev_info_t *dip, int flags, char *name,
8107c478bd9Sstevel@tonic-gate     caddr_t *datap, int *lengthp, int elem_size)
8117c478bd9Sstevel@tonic-gate {
8127c478bd9Sstevel@tonic-gate 	caddr_t	prop_val;
8137c478bd9Sstevel@tonic-gate 	int	prop_len, res;
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	ASSERT((dip != NULL) && (name != NULL));
8167c478bd9Sstevel@tonic-gate 	ASSERT((datap != NULL) && (lengthp != NULL));
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	/*
8197c478bd9Sstevel@tonic-gate 	 * first call the drivers prop_op() interface to allow it
8207c478bd9Sstevel@tonic-gate 	 * it to override default property values.
8217c478bd9Sstevel@tonic-gate 	 */
8227c478bd9Sstevel@tonic-gate 	res = i_ldi_prop_op(dev, dip, PROP_LEN,
8237c478bd9Sstevel@tonic-gate 	    flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
8247c478bd9Sstevel@tonic-gate 	if (res != DDI_PROP_SUCCESS)
8257c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	/* sanity check the property length */
8287c478bd9Sstevel@tonic-gate 	if (prop_len == 0) {
8297c478bd9Sstevel@tonic-gate 		/*
8307c478bd9Sstevel@tonic-gate 		 * the ddi typed interfaces don't allow a drivers to
8317c478bd9Sstevel@tonic-gate 		 * create properties with a length of 0.  so we should
8327c478bd9Sstevel@tonic-gate 		 * prevent drivers from returning 0 length dynamic
8337c478bd9Sstevel@tonic-gate 		 * properties for typed property lookups.
8347c478bd9Sstevel@tonic-gate 		 */
8357c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	/* sanity check the property length against the element size */
8397c478bd9Sstevel@tonic-gate 	if (elem_size && ((prop_len % elem_size) != 0))
8407c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate 	/*
8437c478bd9Sstevel@tonic-gate 	 * got it.  now allocate a prop_driver_data struct so that the
8447c478bd9Sstevel@tonic-gate 	 * user can free the property via ddi_prop_free().
8457c478bd9Sstevel@tonic-gate 	 */
8467c478bd9Sstevel@tonic-gate 	prop_val = i_ldi_prop_op_alloc(prop_len);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	/* lookup the property again, this time get the value */
8497c478bd9Sstevel@tonic-gate 	res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
8507c478bd9Sstevel@tonic-gate 	    flags | DDI_PROP_DYNAMIC, name, prop_val, &prop_len);
8517c478bd9Sstevel@tonic-gate 	if (res != DDI_PROP_SUCCESS) {
8527c478bd9Sstevel@tonic-gate 		ddi_prop_free(prop_val);
8537c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8547c478bd9Sstevel@tonic-gate 	}
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	/* sanity check the property length */
8577c478bd9Sstevel@tonic-gate 	if (prop_len == 0) {
8587c478bd9Sstevel@tonic-gate 		ddi_prop_free(prop_val);
8597c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8607c478bd9Sstevel@tonic-gate 	}
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	/* sanity check the property length against the element size */
8637c478bd9Sstevel@tonic-gate 	if (elem_size && ((prop_len % elem_size) != 0)) {
8647c478bd9Sstevel@tonic-gate 		ddi_prop_free(prop_val);
8657c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8667c478bd9Sstevel@tonic-gate 	}
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	/*
8697c478bd9Sstevel@tonic-gate 	 * return the prop_driver_data struct and, optionally, the length
8707c478bd9Sstevel@tonic-gate 	 * of the data.
8717c478bd9Sstevel@tonic-gate 	 */
8727c478bd9Sstevel@tonic-gate 	*datap = prop_val;
8737c478bd9Sstevel@tonic-gate 	*lengthp = prop_len;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate /*
8797c478bd9Sstevel@tonic-gate  * i_check_string looks at a string property and makes sure its
8807c478bd9Sstevel@tonic-gate  * a valid null terminated string
8817c478bd9Sstevel@tonic-gate  */
8827c478bd9Sstevel@tonic-gate static int
8837c478bd9Sstevel@tonic-gate i_check_string(char *str, int prop_len)
8847c478bd9Sstevel@tonic-gate {
8857c478bd9Sstevel@tonic-gate 	int i;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	ASSERT(str != NULL);
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	for (i = 0; i < prop_len; i++) {
8907c478bd9Sstevel@tonic-gate 		if (str[i] == '\0')
8917c478bd9Sstevel@tonic-gate 			return (0);
8927c478bd9Sstevel@tonic-gate 	}
8937c478bd9Sstevel@tonic-gate 	return (1);
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate /*
8977c478bd9Sstevel@tonic-gate  * i_pack_string_array takes a a string array property that is represented
8987c478bd9Sstevel@tonic-gate  * as a concatination of strings (with the NULL character included for
8997c478bd9Sstevel@tonic-gate  * each string) and converts it into a format that can be returned by
9007c478bd9Sstevel@tonic-gate  * ldi_prop_lookup_string_array.
9017c478bd9Sstevel@tonic-gate  */
9027c478bd9Sstevel@tonic-gate static int
9037c478bd9Sstevel@tonic-gate i_pack_string_array(char *str_concat, int prop_len,
9047c478bd9Sstevel@tonic-gate     char ***str_arrayp, int *nelemp)
9057c478bd9Sstevel@tonic-gate {
9067c478bd9Sstevel@tonic-gate 	int i, nelem, pack_size;
9077c478bd9Sstevel@tonic-gate 	char **str_array, *strptr;
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	/*
9107c478bd9Sstevel@tonic-gate 	 * first we need to sanity check the input string array.
9117c478bd9Sstevel@tonic-gate 	 * in essence this can be done my making sure that the last
9127c478bd9Sstevel@tonic-gate 	 * character of the array passed in is null.  (meaning the last
9137c478bd9Sstevel@tonic-gate 	 * string in the array is NULL terminated.
9147c478bd9Sstevel@tonic-gate 	 */
9157c478bd9Sstevel@tonic-gate 	if (str_concat[prop_len - 1] != '\0')
9167c478bd9Sstevel@tonic-gate 		return (1);
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	/* now let's count the number of strings in the array */
9197c478bd9Sstevel@tonic-gate 	for (nelem = i = 0; i < prop_len; i++)
9207c478bd9Sstevel@tonic-gate 		if (str_concat[i] == '\0')
9217c478bd9Sstevel@tonic-gate 			nelem++;
9227c478bd9Sstevel@tonic-gate 	ASSERT(nelem >= 1);
9237c478bd9Sstevel@tonic-gate 
9247c478bd9Sstevel@tonic-gate 	/* now let's allocate memory for the new packed property */
9257c478bd9Sstevel@tonic-gate 	pack_size = (sizeof (char *) * (nelem + 1)) + prop_len;
9267c478bd9Sstevel@tonic-gate 	str_array = (char **)i_ldi_prop_op_alloc(pack_size);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	/* let's copy the actual string data into the new property */
9297c478bd9Sstevel@tonic-gate 	strptr = (char *)&(str_array[nelem + 1]);
9307c478bd9Sstevel@tonic-gate 	bcopy(str_concat, strptr, prop_len);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	/* now initialize the string array pointers */
9337c478bd9Sstevel@tonic-gate 	for (i = 0; i < nelem; i++) {
9347c478bd9Sstevel@tonic-gate 		str_array[i] = strptr;
9357c478bd9Sstevel@tonic-gate 		strptr += strlen(strptr) + 1;
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 	str_array[nelem] = NULL;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 	/* set the return values */
9407c478bd9Sstevel@tonic-gate 	*str_arrayp = str_array;
9417c478bd9Sstevel@tonic-gate 	*nelemp = nelem;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	return (0);
9447c478bd9Sstevel@tonic-gate }
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate /*
9487c478bd9Sstevel@tonic-gate  * LDI Project private device usage interfaces
9497c478bd9Sstevel@tonic-gate  */
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate /*
9527c478bd9Sstevel@tonic-gate  * Get a count of how many devices are currentl open by different consumers
9537c478bd9Sstevel@tonic-gate  */
9547c478bd9Sstevel@tonic-gate int
9557c478bd9Sstevel@tonic-gate ldi_usage_count()
9567c478bd9Sstevel@tonic-gate {
9577c478bd9Sstevel@tonic-gate 	return (ldi_handle_hash_count);
9587c478bd9Sstevel@tonic-gate }
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate static void
9617c478bd9Sstevel@tonic-gate ldi_usage_walker_tgt_helper(ldi_usage_t *ldi_usage, vnode_t *vp)
9627c478bd9Sstevel@tonic-gate {
9637c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
9647c478bd9Sstevel@tonic-gate 	dev_t		dev;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	ASSERT(STYP_VALID(VTYP_TO_STYP(vp->v_type)));
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	/* get the target devt */
9697c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	/* try to get the target dip */
9727c478bd9Sstevel@tonic-gate 	dip = VTOCS(vp)->s_dip;
9737c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
9747c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
9757c478bd9Sstevel@tonic-gate 	} else if (dev != DDI_DEV_T_NONE) {
9767c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/* set the target information */
9807c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_name = mod_major_to_name(getmajor(dev));
9817c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_modid = mod_name_to_modid(ldi_usage->tgt_name);
9827c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_devt = dev;
9837c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_spec_type = VTYP_TO_STYP(vp->v_type);
9847c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_dip = dip;
9857c478bd9Sstevel@tonic-gate }
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate static int
9897c478bd9Sstevel@tonic-gate ldi_usage_walker_helper(struct ldi_ident *lip, vnode_t *vp,
9907c478bd9Sstevel@tonic-gate     void *arg, int (*callback)(const ldi_usage_t *, void *))
9917c478bd9Sstevel@tonic-gate {
9927c478bd9Sstevel@tonic-gate 	ldi_usage_t	ldi_usage;
9937c478bd9Sstevel@tonic-gate 	struct devnames	*dnp;
9947c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
9957c478bd9Sstevel@tonic-gate 	major_t		major;
9967c478bd9Sstevel@tonic-gate 	dev_t		dev;
9977c478bd9Sstevel@tonic-gate 	int		ret = LDI_USAGE_CONTINUE;
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	/* set the target device information */
10007c478bd9Sstevel@tonic-gate 	ldi_usage_walker_tgt_helper(&ldi_usage, vp);
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	/* get the source devt */
10037c478bd9Sstevel@tonic-gate 	dev = lip->li_dev;
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	/* try to get the source dip */
10067c478bd9Sstevel@tonic-gate 	dip = lip->li_dip;
10077c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
10087c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
10097c478bd9Sstevel@tonic-gate 	} else if (dev != DDI_DEV_T_NONE) {
10107c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
10117c478bd9Sstevel@tonic-gate 	}
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	/* set the valid source information */
10147c478bd9Sstevel@tonic-gate 	ldi_usage.src_modid = lip->li_modid;
10157c478bd9Sstevel@tonic-gate 	ldi_usage.src_name = lip->li_modname;
10167c478bd9Sstevel@tonic-gate 	ldi_usage.src_devt = dev;
10177c478bd9Sstevel@tonic-gate 	ldi_usage.src_dip = dip;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	/*
10207c478bd9Sstevel@tonic-gate 	 * if the source ident represents either:
10217c478bd9Sstevel@tonic-gate 	 *
10227c478bd9Sstevel@tonic-gate 	 * - a kernel module (and not a device or device driver)
10237c478bd9Sstevel@tonic-gate 	 * - a device node
10247c478bd9Sstevel@tonic-gate 	 *
10257c478bd9Sstevel@tonic-gate 	 * then we currently have all the info we need to report the
10267c478bd9Sstevel@tonic-gate 	 * usage information so invoke the callback function.
10277c478bd9Sstevel@tonic-gate 	 */
10287c478bd9Sstevel@tonic-gate 	if (((lip->li_major == -1) && (dev == DDI_DEV_T_NONE)) ||
10297c478bd9Sstevel@tonic-gate 	    (dip != NULL)) {
10307c478bd9Sstevel@tonic-gate 		ret = callback(&ldi_usage, arg);
10317c478bd9Sstevel@tonic-gate 		if (dip != NULL)
10327c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
10337c478bd9Sstevel@tonic-gate 		if (ldi_usage.tgt_dip != NULL)
10347c478bd9Sstevel@tonic-gate 			ddi_release_devi(ldi_usage.tgt_dip);
10357c478bd9Sstevel@tonic-gate 		return (ret);
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	/*
10397c478bd9Sstevel@tonic-gate 	 * now this is kinda gross.
10407c478bd9Sstevel@tonic-gate 	 *
10417c478bd9Sstevel@tonic-gate 	 * what we do here is attempt to associate every device instance
10427c478bd9Sstevel@tonic-gate 	 * of the source driver on the system with the open target driver.
10437c478bd9Sstevel@tonic-gate 	 * we do this because we don't know which instance of the device
10447c478bd9Sstevel@tonic-gate 	 * could potentially access the lower device so we assume that all
10457c478bd9Sstevel@tonic-gate 	 * the instances could access it.
10467c478bd9Sstevel@tonic-gate 	 *
10477c478bd9Sstevel@tonic-gate 	 * there are two ways we could have gotten here:
10487c478bd9Sstevel@tonic-gate 	 *
10497c478bd9Sstevel@tonic-gate 	 * 1) this layered ident represents one created using only a
10507c478bd9Sstevel@tonic-gate 	 *    major number or a driver module name.  this means that when
10517c478bd9Sstevel@tonic-gate 	 *    it was created we could not associate it with a particular
10527c478bd9Sstevel@tonic-gate 	 *    dev_t or device instance.
10537c478bd9Sstevel@tonic-gate 	 *
10547c478bd9Sstevel@tonic-gate 	 *    when could this possibly happen you ask?
10557c478bd9Sstevel@tonic-gate 	 *
10567c478bd9Sstevel@tonic-gate 	 *    a perfect example of this is streams persistent links.
10577c478bd9Sstevel@tonic-gate 	 *    when a persistant streams link is formed we can't associate
10587c478bd9Sstevel@tonic-gate 	 *    the lower device stream with any particular upper device
10597c478bd9Sstevel@tonic-gate 	 *    stream or instance.  this is because any particular upper
10607c478bd9Sstevel@tonic-gate 	 *    device stream could be closed, then another could be
10617c478bd9Sstevel@tonic-gate 	 *    opened with a different dev_t and device instance, and it
10627c478bd9Sstevel@tonic-gate 	 *    would still have access to the lower linked stream.
10637c478bd9Sstevel@tonic-gate 	 *
10647c478bd9Sstevel@tonic-gate 	 *    since any instance of the upper streams driver could
10657c478bd9Sstevel@tonic-gate 	 *    potentially access the lower stream whenever it wants,
10667c478bd9Sstevel@tonic-gate 	 *    we represent that here by associating the opened lower
10677c478bd9Sstevel@tonic-gate 	 *    device with every existing device instance of the upper
10687c478bd9Sstevel@tonic-gate 	 *    streams driver.
10697c478bd9Sstevel@tonic-gate 	 *
10707c478bd9Sstevel@tonic-gate 	 * 2) This case should really never happen but we'll include it
10717c478bd9Sstevel@tonic-gate 	 *    for completeness.
10727c478bd9Sstevel@tonic-gate 	 *
10737c478bd9Sstevel@tonic-gate 	 *    it's possible that we could have gotten here because we
10747c478bd9Sstevel@tonic-gate 	 *    have a dev_t for the upper device but we couldn't find a
10757c478bd9Sstevel@tonic-gate 	 *    dip associated with that dev_t.
10767c478bd9Sstevel@tonic-gate 	 *
10777c478bd9Sstevel@tonic-gate 	 *    the only types of devices that have dev_t without an
10787c478bd9Sstevel@tonic-gate 	 *    associated dip are unbound DLPIv2 network devices.  These
10797c478bd9Sstevel@tonic-gate 	 *    types of devices exist to be able to attach a stream to any
10807c478bd9Sstevel@tonic-gate 	 *    instance of a hardware network device.  since these types of
10817c478bd9Sstevel@tonic-gate 	 *    devices are usually hardware devices they should never
10827c478bd9Sstevel@tonic-gate 	 *    really have other devices open.
10837c478bd9Sstevel@tonic-gate 	 */
10847c478bd9Sstevel@tonic-gate 	if (dev != DDI_DEV_T_NONE)
10857c478bd9Sstevel@tonic-gate 		major = getmajor(dev);
10867c478bd9Sstevel@tonic-gate 	else
10877c478bd9Sstevel@tonic-gate 		major = lip->li_major;
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	ASSERT((major >= 0) && (major < devcnt));
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate 	dnp = &devnamesp[major];
10927c478bd9Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
10937c478bd9Sstevel@tonic-gate 	dip = dnp->dn_head;
10947c478bd9Sstevel@tonic-gate 	while ((dip) && (ret == LDI_USAGE_CONTINUE)) {
10957c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
10967c478bd9Sstevel@tonic-gate 		UNLOCK_DEV_OPS(&dnp->dn_lock);
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 		/* set the source dip */
10997c478bd9Sstevel@tonic-gate 		ldi_usage.src_dip = dip;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 		/* invoke the callback function */
11027c478bd9Sstevel@tonic-gate 		ret = callback(&ldi_usage, arg);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 		LOCK_DEV_OPS(&dnp->dn_lock);
11057c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
11067c478bd9Sstevel@tonic-gate 		dip = ddi_get_next(dip);
11077c478bd9Sstevel@tonic-gate 	}
11087c478bd9Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate 	/* if there was a target dip, release it */
11117c478bd9Sstevel@tonic-gate 	if (ldi_usage.tgt_dip != NULL)
11127c478bd9Sstevel@tonic-gate 		ddi_release_devi(ldi_usage.tgt_dip);
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	return (ret);
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate /*
11187c478bd9Sstevel@tonic-gate  * ldi_usage_walker() - this walker reports LDI kernel device usage
11197c478bd9Sstevel@tonic-gate  * information via the callback() callback function.  the LDI keeps track
11207c478bd9Sstevel@tonic-gate  * of what devices are being accessed in its own internal data structures.
11217c478bd9Sstevel@tonic-gate  * this function walks those data structures to determine device usage.
11227c478bd9Sstevel@tonic-gate  */
11237c478bd9Sstevel@tonic-gate void
11247c478bd9Sstevel@tonic-gate ldi_usage_walker(void *arg, int (*callback)(const ldi_usage_t *, void *))
11257c478bd9Sstevel@tonic-gate {
11267c478bd9Sstevel@tonic-gate 	struct ldi_handle	*lhp;
11277c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip;
11287c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
11297c478bd9Sstevel@tonic-gate 	int			i;
11307c478bd9Sstevel@tonic-gate 	int			ret = LDI_USAGE_CONTINUE;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	for (i = 0; i < LH_HASH_SZ; i++) {
11337c478bd9Sstevel@tonic-gate 		mutex_enter(&ldi_handle_hash_lock[i]);
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 		lhp = ldi_handle_hash[i];
11367c478bd9Sstevel@tonic-gate 		while ((lhp != NULL) && (ret == LDI_USAGE_CONTINUE)) {
11377c478bd9Sstevel@tonic-gate 			lip = lhp->lh_ident;
11387c478bd9Sstevel@tonic-gate 			vp = lhp->lh_vp;
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 			/* invoke the devinfo callback function */
11417c478bd9Sstevel@tonic-gate 			ret = ldi_usage_walker_helper(lip, vp, arg, callback);
11427c478bd9Sstevel@tonic-gate 
11437c478bd9Sstevel@tonic-gate 			lhp = lhp->lh_next;
11447c478bd9Sstevel@tonic-gate 		}
11457c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_handle_hash_lock[i]);
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 		if (ret != LDI_USAGE_CONTINUE)
11487c478bd9Sstevel@tonic-gate 			break;
11497c478bd9Sstevel@tonic-gate 	}
11507c478bd9Sstevel@tonic-gate }
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate /*
11537c478bd9Sstevel@tonic-gate  * LDI Project private interfaces (streams linking interfaces)
11547c478bd9Sstevel@tonic-gate  *
11557c478bd9Sstevel@tonic-gate  * Streams supports a type of built in device layering via linking.
11567c478bd9Sstevel@tonic-gate  * Certain types of streams drivers can be streams multiplexors.
11577c478bd9Sstevel@tonic-gate  * A streams multiplexor supports the I_LINK/I_PLINK operation.
11587c478bd9Sstevel@tonic-gate  * These operations allows other streams devices to be linked under the
11597c478bd9Sstevel@tonic-gate  * multiplexor.  By definition all streams multiplexors are devices
11607c478bd9Sstevel@tonic-gate  * so this linking is a type of device layering where the multiplexor
11617c478bd9Sstevel@tonic-gate  * device is layered on top of the device linked below it.
11627c478bd9Sstevel@tonic-gate  */
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate /*
11657c478bd9Sstevel@tonic-gate  * ldi_mlink_lh() is invoked when streams are linked using LDI handles.
11667c478bd9Sstevel@tonic-gate  * It is not used for normal I_LINKs and I_PLINKs using file descriptors.
11677c478bd9Sstevel@tonic-gate  *
11687c478bd9Sstevel@tonic-gate  * The streams framework keeps track of links via the file_t of the lower
11697c478bd9Sstevel@tonic-gate  * stream.  The LDI keeps track of devices using a vnode.  In the case
11707c478bd9Sstevel@tonic-gate  * of a streams link created via an LDI handle, fnk_lh() allocates
11717c478bd9Sstevel@tonic-gate  * a file_t that the streams framework can use to track the linkage.
11727c478bd9Sstevel@tonic-gate  */
11737c478bd9Sstevel@tonic-gate int
11747c478bd9Sstevel@tonic-gate ldi_mlink_lh(vnode_t *vp, int cmd, intptr_t arg, cred_t *crp, int *rvalp)
11757c478bd9Sstevel@tonic-gate {
11767c478bd9Sstevel@tonic-gate 	struct ldi_handle	*lhp = (struct ldi_handle *)arg;
11777c478bd9Sstevel@tonic-gate 	vnode_t			*vpdown;
11787c478bd9Sstevel@tonic-gate 	file_t			*fpdown;
11797c478bd9Sstevel@tonic-gate 	int			err;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	if (lhp == NULL)
11827c478bd9Sstevel@tonic-gate 		return (EINVAL);
11837c478bd9Sstevel@tonic-gate 
11847c478bd9Sstevel@tonic-gate 	vpdown = lhp->lh_vp;
11857c478bd9Sstevel@tonic-gate 	ASSERT(vn_matchops(vpdown, spec_getvnodeops()));
11867c478bd9Sstevel@tonic-gate 	ASSERT(cmd == _I_PLINK_LH);
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	/*
11897c478bd9Sstevel@tonic-gate 	 * create a new lower vnode and a file_t that points to it,
11907c478bd9Sstevel@tonic-gate 	 * streams linking requires a file_t.  falloc() returns with
11917c478bd9Sstevel@tonic-gate 	 * fpdown locked.
11927c478bd9Sstevel@tonic-gate 	 */
11937c478bd9Sstevel@tonic-gate 	VN_HOLD(vpdown);
11947c478bd9Sstevel@tonic-gate 	(void) falloc(vpdown, FREAD|FWRITE, &fpdown, NULL);
11957c478bd9Sstevel@tonic-gate 	mutex_exit(&fpdown->f_tlock);
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	/* try to establish the link */
11987c478bd9Sstevel@tonic-gate 	err = mlink_file(vp, I_PLINK, fpdown, crp, rvalp, 1);
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 	if (err != 0) {
12017c478bd9Sstevel@tonic-gate 		/* the link failed, free the file_t and release the vnode */
12027c478bd9Sstevel@tonic-gate 		mutex_enter(&fpdown->f_tlock);
12037c478bd9Sstevel@tonic-gate 		unfalloc(fpdown);
12047c478bd9Sstevel@tonic-gate 		VN_RELE(vpdown);
12057c478bd9Sstevel@tonic-gate 	}
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	return (err);
12087c478bd9Sstevel@tonic-gate }
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate /*
12117c478bd9Sstevel@tonic-gate  * ldi_mlink_fp() is invoked for all successfull streams linkages created
12127c478bd9Sstevel@tonic-gate  * via I_LINK and I_PLINK.  ldi_mlink_fp() records the linkage information
12137c478bd9Sstevel@tonic-gate  * in its internal state so that the devinfo snapshot code has some
12147c478bd9Sstevel@tonic-gate  * observability into streams device linkage information.
12157c478bd9Sstevel@tonic-gate  */
12167c478bd9Sstevel@tonic-gate void
12177c478bd9Sstevel@tonic-gate ldi_mlink_fp(struct stdata *stp, file_t *fpdown, int lhlink, int type)
12187c478bd9Sstevel@tonic-gate {
12197c478bd9Sstevel@tonic-gate 	vnode_t			*vp = fpdown->f_vnode;
12207c478bd9Sstevel@tonic-gate 	struct snode		*sp, *csp;
12217c478bd9Sstevel@tonic-gate 	ldi_ident_t		li;
12227c478bd9Sstevel@tonic-gate 	major_t			major;
12237c478bd9Sstevel@tonic-gate 	int			ret;
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	/* if the lower stream is not a device then return */
12267c478bd9Sstevel@tonic-gate 	if (!vn_matchops(vp, spec_getvnodeops()))
12277c478bd9Sstevel@tonic-gate 		return;
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	LDI_STREAMS_LNK((CE_NOTE, "%s: linking streams "
1232*184cd04cScth 	    "stp=0x%p, fpdown=0x%p", "ldi_mlink_fp",
1233*184cd04cScth 	    (void *)stp, (void *)fpdown));
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	sp = VTOS(vp);
12367c478bd9Sstevel@tonic-gate 	csp = VTOS(sp->s_commonvp);
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	/* check if this was a plink via a layered handle */
12397c478bd9Sstevel@tonic-gate 	if (lhlink) {
12407c478bd9Sstevel@tonic-gate 		/*
12417c478bd9Sstevel@tonic-gate 		 * increment the common snode s_count.
12427c478bd9Sstevel@tonic-gate 		 *
12437c478bd9Sstevel@tonic-gate 		 * this is done because after the link operation there
12447c478bd9Sstevel@tonic-gate 		 * are two ways that s_count can be decremented.
12457c478bd9Sstevel@tonic-gate 		 *
12467c478bd9Sstevel@tonic-gate 		 * when the layered handle used to create the link is
12477c478bd9Sstevel@tonic-gate 		 * closed, spec_close() is called and it will decrement
12487c478bd9Sstevel@tonic-gate 		 * s_count in the common snode.  if we don't increment
12497c478bd9Sstevel@tonic-gate 		 * s_count here then this could cause spec_close() to
12507c478bd9Sstevel@tonic-gate 		 * actually close the device while it's still linked
12517c478bd9Sstevel@tonic-gate 		 * under a multiplexer.
12527c478bd9Sstevel@tonic-gate 		 *
12537c478bd9Sstevel@tonic-gate 		 * also, when the lower stream is unlinked, closef() is
12547c478bd9Sstevel@tonic-gate 		 * called for the file_t associated with this snode.
12557c478bd9Sstevel@tonic-gate 		 * closef() will call spec_close(), which will decrement
12567c478bd9Sstevel@tonic-gate 		 * s_count.  if we dont't increment s_count here then this
12577c478bd9Sstevel@tonic-gate 		 * could cause spec_close() to actually close the device
12587c478bd9Sstevel@tonic-gate 		 * while there may still be valid layered handles
12597c478bd9Sstevel@tonic-gate 		 * pointing to it.
12607c478bd9Sstevel@tonic-gate 		 */
12617c478bd9Sstevel@tonic-gate 		mutex_enter(&csp->s_lock);
12627c478bd9Sstevel@tonic-gate 		ASSERT(csp->s_count >= 1);
12637c478bd9Sstevel@tonic-gate 		csp->s_count++;
12647c478bd9Sstevel@tonic-gate 		mutex_exit(&csp->s_lock);
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		/*
12677c478bd9Sstevel@tonic-gate 		 * decrement the f_count.
12687c478bd9Sstevel@tonic-gate 		 * this is done because the layered driver framework does
12697c478bd9Sstevel@tonic-gate 		 * not actually cache a copy of the file_t allocated to
12707c478bd9Sstevel@tonic-gate 		 * do the link.  this is done here instead of in ldi_mlink_lh()
12717c478bd9Sstevel@tonic-gate 		 * because there is a window in ldi_mlink_lh() between where
12727c478bd9Sstevel@tonic-gate 		 * milnk_file() returns and we would decrement the f_count
12737c478bd9Sstevel@tonic-gate 		 * when the stream could be unlinked.
12747c478bd9Sstevel@tonic-gate 		 */
12757c478bd9Sstevel@tonic-gate 		mutex_enter(&fpdown->f_tlock);
12767c478bd9Sstevel@tonic-gate 		fpdown->f_count--;
12777c478bd9Sstevel@tonic-gate 		mutex_exit(&fpdown->f_tlock);
12787c478bd9Sstevel@tonic-gate 	}
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	/*
12817c478bd9Sstevel@tonic-gate 	 * NOTE: here we rely on the streams subsystem not allowing
12827c478bd9Sstevel@tonic-gate 	 * a stream to be multiplexed more than once.  if this
12837c478bd9Sstevel@tonic-gate 	 * changes, we break.
12847c478bd9Sstevel@tonic-gate 	 *
12857c478bd9Sstevel@tonic-gate 	 * mark the snode/stream as multiplexed
12867c478bd9Sstevel@tonic-gate 	 */
12877c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_lock);
12887c478bd9Sstevel@tonic-gate 	ASSERT(!(sp->s_flag & SMUXED));
12897c478bd9Sstevel@tonic-gate 	sp->s_flag |= SMUXED;
12907c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_lock);
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	/* get a layered ident for the upper stream */
12937c478bd9Sstevel@tonic-gate 	if (type == LINKNORMAL) {
12947c478bd9Sstevel@tonic-gate 		/*
12957c478bd9Sstevel@tonic-gate 		 * if the link is not persistant then we can associate
12967c478bd9Sstevel@tonic-gate 		 * the upper stream with a dev_t.  this is because the
12977c478bd9Sstevel@tonic-gate 		 * upper stream is associated with a vnode, which is
12987c478bd9Sstevel@tonic-gate 		 * associated with a dev_t and this binding can't change
12997c478bd9Sstevel@tonic-gate 		 * during the life of the stream.  since the link isn't
13007c478bd9Sstevel@tonic-gate 		 * persistant once the stream is destroyed the link is
13017c478bd9Sstevel@tonic-gate 		 * destroyed.  so the dev_t will be valid for the life
13027c478bd9Sstevel@tonic-gate 		 * of the link.
13037c478bd9Sstevel@tonic-gate 		 */
13047c478bd9Sstevel@tonic-gate 		ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
13057c478bd9Sstevel@tonic-gate 	} else {
13067c478bd9Sstevel@tonic-gate 		/*
13077c478bd9Sstevel@tonic-gate 		 * if the link is persistant we can only associate the
13087c478bd9Sstevel@tonic-gate 		 * link with a driver (and not a dev_t.)  this is
13097c478bd9Sstevel@tonic-gate 		 * because subsequent opens of the upper device may result
13107c478bd9Sstevel@tonic-gate 		 * in a different stream (and dev_t) having access to
13117c478bd9Sstevel@tonic-gate 		 * the lower stream.
13127c478bd9Sstevel@tonic-gate 		 *
13137c478bd9Sstevel@tonic-gate 		 * for example, if the upper stream is closed after the
13147c478bd9Sstevel@tonic-gate 		 * persistant link operation is compleated, a subsequent
13157c478bd9Sstevel@tonic-gate 		 * open of the upper device will create a new stream which
13167c478bd9Sstevel@tonic-gate 		 * may have a different dev_t and an unlink operation
13177c478bd9Sstevel@tonic-gate 		 * can be performed using this new upper stream.
13187c478bd9Sstevel@tonic-gate 		 */
13197c478bd9Sstevel@tonic-gate 		ASSERT(type == LINKPERSIST);
13207c478bd9Sstevel@tonic-gate 		major = getmajor(stp->sd_vnode->v_rdev);
13217c478bd9Sstevel@tonic-gate 		ret = ldi_ident_from_major(major, &li);
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	ASSERT(ret == 0);
13257c478bd9Sstevel@tonic-gate 	(void) handle_alloc(vp, (struct ldi_ident *)li);
13267c478bd9Sstevel@tonic-gate 	ldi_ident_release(li);
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate void
13307c478bd9Sstevel@tonic-gate ldi_munlink_fp(struct stdata *stp, file_t *fpdown, int type)
13317c478bd9Sstevel@tonic-gate {
13327c478bd9Sstevel@tonic-gate 	struct ldi_handle	*lhp;
13337c478bd9Sstevel@tonic-gate 	vnode_t			*vp = (vnode_t *)fpdown->f_vnode;
13347c478bd9Sstevel@tonic-gate 	struct snode		*sp;
13357c478bd9Sstevel@tonic-gate 	ldi_ident_t		li;
13367c478bd9Sstevel@tonic-gate 	major_t			major;
13377c478bd9Sstevel@tonic-gate 	int			ret;
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/* if the lower stream is not a device then return */
13407c478bd9Sstevel@tonic-gate 	if (!vn_matchops(vp, spec_getvnodeops()))
13417c478bd9Sstevel@tonic-gate 		return;
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
13447c478bd9Sstevel@tonic-gate 	ASSERT((type == LINKNORMAL) || (type == LINKPERSIST));
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 	LDI_STREAMS_LNK((CE_NOTE, "%s: unlinking streams "
1347*184cd04cScth 	    "stp=0x%p, fpdown=0x%p", "ldi_munlink_fp",
1348*184cd04cScth 	    (void *)stp, (void *)fpdown));
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	/*
13517c478bd9Sstevel@tonic-gate 	 * NOTE: here we rely on the streams subsystem not allowing
13527c478bd9Sstevel@tonic-gate 	 * a stream to be multiplexed more than once.  if this
13537c478bd9Sstevel@tonic-gate 	 * changes, we break.
13547c478bd9Sstevel@tonic-gate 	 *
13557c478bd9Sstevel@tonic-gate 	 * mark the snode/stream as not multiplexed
13567c478bd9Sstevel@tonic-gate 	 */
13577c478bd9Sstevel@tonic-gate 	sp = VTOS(vp);
13587c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_lock);
13597c478bd9Sstevel@tonic-gate 	ASSERT(sp->s_flag & SMUXED);
13607c478bd9Sstevel@tonic-gate 	sp->s_flag &= ~SMUXED;
13617c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_lock);
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	/*
13647c478bd9Sstevel@tonic-gate 	 * clear the owner for this snode
13657c478bd9Sstevel@tonic-gate 	 * see the comment in ldi_mlink_fp() for information about how
13667c478bd9Sstevel@tonic-gate 	 * the ident is allocated
13677c478bd9Sstevel@tonic-gate 	 */
13687c478bd9Sstevel@tonic-gate 	if (type == LINKNORMAL) {
13697c478bd9Sstevel@tonic-gate 		ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
13707c478bd9Sstevel@tonic-gate 	} else {
13717c478bd9Sstevel@tonic-gate 		ASSERT(type == LINKPERSIST);
13727c478bd9Sstevel@tonic-gate 		major = getmajor(stp->sd_vnode->v_rdev);
13737c478bd9Sstevel@tonic-gate 		ret = ldi_ident_from_major(major, &li);
13747c478bd9Sstevel@tonic-gate 	}
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	ASSERT(ret == 0);
13777c478bd9Sstevel@tonic-gate 	lhp = handle_find(vp, (struct ldi_ident *)li);
13787c478bd9Sstevel@tonic-gate 	handle_release(lhp);
13797c478bd9Sstevel@tonic-gate 	ldi_ident_release(li);
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate /*
13837c478bd9Sstevel@tonic-gate  * LDI Consolidation private interfaces
13847c478bd9Sstevel@tonic-gate  */
13857c478bd9Sstevel@tonic-gate int
13867c478bd9Sstevel@tonic-gate ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip)
13877c478bd9Sstevel@tonic-gate {
13887c478bd9Sstevel@tonic-gate 	struct modctl		*modp;
13897c478bd9Sstevel@tonic-gate 	major_t			major;
13907c478bd9Sstevel@tonic-gate 	char			*name;
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 	if ((modlp == NULL) || (lip == NULL))
13937c478bd9Sstevel@tonic-gate 		return (EINVAL);
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 	modp = mod_getctl(modlp);
13987c478bd9Sstevel@tonic-gate 	if (modp == NULL)
13997c478bd9Sstevel@tonic-gate 		return (EINVAL);
14007c478bd9Sstevel@tonic-gate 	name = modp->mod_modname;
14017c478bd9Sstevel@tonic-gate 	if (name == NULL)
14027c478bd9Sstevel@tonic-gate 		return (EINVAL);
14037c478bd9Sstevel@tonic-gate 	major = mod_name_to_major(name);
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
14067c478bd9Sstevel@tonic-gate 
14077c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1408*184cd04cScth 	    "ldi_ident_from_mod", (void *)*lip, name));
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	return (0);
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate ldi_ident_t
14147c478bd9Sstevel@tonic-gate ldi_ident_from_anon()
14157c478bd9Sstevel@tonic-gate {
14167c478bd9Sstevel@tonic-gate 	ldi_ident_t	lip;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	lip = (ldi_ident_t)ident_alloc("genunix", NULL, DDI_DEV_T_NONE, -1);
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1423*184cd04cScth 	    "ldi_ident_from_anon", (void *)lip, "genunix"));
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	return (lip);
14267c478bd9Sstevel@tonic-gate }
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate /*
14307c478bd9Sstevel@tonic-gate  * LDI Public interfaces
14317c478bd9Sstevel@tonic-gate  */
14327c478bd9Sstevel@tonic-gate int
14337c478bd9Sstevel@tonic-gate ldi_ident_from_stream(struct queue *sq, ldi_ident_t *lip)
14347c478bd9Sstevel@tonic-gate {
14357c478bd9Sstevel@tonic-gate 	struct stdata		*stp;
14367c478bd9Sstevel@tonic-gate 	dev_t			dev;
14377c478bd9Sstevel@tonic-gate 	char			*name;
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	if ((sq == NULL) || (lip == NULL))
14407c478bd9Sstevel@tonic-gate 		return (EINVAL);
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	stp = sq->q_stream;
14457c478bd9Sstevel@tonic-gate 	if (!vn_matchops(stp->sd_vnode, spec_getvnodeops()))
14467c478bd9Sstevel@tonic-gate 		return (EINVAL);
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	dev = stp->sd_vnode->v_rdev;
14497c478bd9Sstevel@tonic-gate 	name = mod_major_to_name(getmajor(dev));
14507c478bd9Sstevel@tonic-gate 	if (name == NULL)
14517c478bd9Sstevel@tonic-gate 		return (EINVAL);
14527c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1455*184cd04cScth 	    "%s: li=0x%p, mod=%s, minor=0x%x, stp=0x%p",
1456*184cd04cScth 	    "ldi_ident_from_stream", (void *)*lip, name, getminor(dev),
1457*184cd04cScth 	    (void *)stp));
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	return (0);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate int
14637c478bd9Sstevel@tonic-gate ldi_ident_from_dev(dev_t dev, ldi_ident_t *lip)
14647c478bd9Sstevel@tonic-gate {
14657c478bd9Sstevel@tonic-gate 	char			*name;
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	if (lip == NULL)
14687c478bd9Sstevel@tonic-gate 		return (EINVAL);
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
14717c478bd9Sstevel@tonic-gate 
14727c478bd9Sstevel@tonic-gate 	name = mod_major_to_name(getmajor(dev));
14737c478bd9Sstevel@tonic-gate 	if (name == NULL)
14747c478bd9Sstevel@tonic-gate 		return (EINVAL);
14757c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1478*184cd04cScth 	    "%s: li=0x%p, mod=%s, minor=0x%x",
1479*184cd04cScth 	    "ldi_ident_from_dev", (void *)*lip, name, getminor(dev)));
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	return (0);
14827c478bd9Sstevel@tonic-gate }
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate int
14857c478bd9Sstevel@tonic-gate ldi_ident_from_dip(dev_info_t *dip, ldi_ident_t *lip)
14867c478bd9Sstevel@tonic-gate {
14877c478bd9Sstevel@tonic-gate 	struct dev_info		*devi = (struct dev_info *)dip;
14887c478bd9Sstevel@tonic-gate 	char			*name;
14897c478bd9Sstevel@tonic-gate 
14907c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (lip == NULL))
14917c478bd9Sstevel@tonic-gate 		return (EINVAL);
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	name = mod_major_to_name(devi->devi_major);
14967c478bd9Sstevel@tonic-gate 	if (name == NULL)
14977c478bd9Sstevel@tonic-gate 		return (EINVAL);
14987c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, dip, DDI_DEV_T_NONE, -1);
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1501*184cd04cScth 	    "%s: li=0x%p, mod=%s, dip=0x%p",
1502*184cd04cScth 	    "ldi_ident_from_dip", (void *)*lip, name, (void *)devi));
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	return (0);
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate int
15087c478bd9Sstevel@tonic-gate ldi_ident_from_major(major_t major, ldi_ident_t *lip)
15097c478bd9Sstevel@tonic-gate {
15107c478bd9Sstevel@tonic-gate 	char			*name;
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate 	if (lip == NULL)
15137c478bd9Sstevel@tonic-gate 		return (EINVAL);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	name = mod_major_to_name(major);
15187c478bd9Sstevel@tonic-gate 	if (name == NULL)
15197c478bd9Sstevel@tonic-gate 		return (EINVAL);
15207c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1523*184cd04cScth 	    "%s: li=0x%p, mod=%s",
1524*184cd04cScth 	    "ldi_ident_from_major", (void *)*lip, name));
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	return (0);
15277c478bd9Sstevel@tonic-gate }
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate void
15307c478bd9Sstevel@tonic-gate ldi_ident_release(ldi_ident_t li)
15317c478bd9Sstevel@tonic-gate {
15327c478bd9Sstevel@tonic-gate 	struct ldi_ident	*ident = (struct ldi_ident *)li;
15337c478bd9Sstevel@tonic-gate 	char			*name;
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 	if (li == NULL)
15367c478bd9Sstevel@tonic-gate 		return;
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15397c478bd9Sstevel@tonic-gate 
15407c478bd9Sstevel@tonic-gate 	name = ident->li_modname;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1543*184cd04cScth 	    "%s: li=0x%p, mod=%s",
1544*184cd04cScth 	    "ldi_ident_release", (void *)li, name));
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	ident_release((struct ldi_ident *)li);
15477c478bd9Sstevel@tonic-gate }
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate /* get a handle to a device by dev_t and otyp */
15507c478bd9Sstevel@tonic-gate int
15517c478bd9Sstevel@tonic-gate ldi_open_by_dev(dev_t *devp, int otyp, int flag, cred_t *cr,
15527c478bd9Sstevel@tonic-gate     ldi_handle_t *lhp, ldi_ident_t li)
15537c478bd9Sstevel@tonic-gate {
15547c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1555*184cd04cScth 	int			ret;
15567c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
15597c478bd9Sstevel@tonic-gate 	if ((devp == NULL) || (!OTYP_VALID(otyp)) || (cr == NULL) ||
15607c478bd9Sstevel@tonic-gate 	    (lhp == NULL) || (lip == NULL))
15617c478bd9Sstevel@tonic-gate 		return (EINVAL);
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	if ((ret = ldi_vp_from_dev(*devp, otyp, &vp)) != 0)
15667c478bd9Sstevel@tonic-gate 		return (ret);
15677c478bd9Sstevel@tonic-gate 
15687c478bd9Sstevel@tonic-gate 	if ((ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip)) == 0) {
15697c478bd9Sstevel@tonic-gate 		*devp = vp->v_rdev;
15707c478bd9Sstevel@tonic-gate 	}
15717c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	return (ret);
15747c478bd9Sstevel@tonic-gate }
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate /* get a handle to a device by pathname */
15777c478bd9Sstevel@tonic-gate int
15787c478bd9Sstevel@tonic-gate ldi_open_by_name(char *pathname, int flag, cred_t *cr,
15797c478bd9Sstevel@tonic-gate     ldi_handle_t *lhp, ldi_ident_t li)
15807c478bd9Sstevel@tonic-gate {
15817c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1582*184cd04cScth 	int			ret;
15837c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
15867c478bd9Sstevel@tonic-gate 	if ((pathname == NULL) || (*pathname != '/') ||
15877c478bd9Sstevel@tonic-gate 	    (cr == NULL) || (lhp == NULL) || (lip == NULL))
15887c478bd9Sstevel@tonic-gate 		return (EINVAL);
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	if ((ret = ldi_vp_from_name(pathname, &vp)) != 0)
15937c478bd9Sstevel@tonic-gate 		return (ret);
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
15967c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate 	return (ret);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate 
16017c478bd9Sstevel@tonic-gate /* get a handle to a device by devid and minor_name */
16027c478bd9Sstevel@tonic-gate int
16037c478bd9Sstevel@tonic-gate ldi_open_by_devid(ddi_devid_t devid, char *minor_name,
16047c478bd9Sstevel@tonic-gate     int flag, cred_t *cr, ldi_handle_t *lhp, ldi_ident_t li)
16057c478bd9Sstevel@tonic-gate {
16067c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip = (struct ldi_ident *)li;
16077c478bd9Sstevel@tonic-gate 	int			ret;
16087c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
16117c478bd9Sstevel@tonic-gate 	if ((minor_name == NULL) || (cr == NULL) ||
16127c478bd9Sstevel@tonic-gate 	    (lhp == NULL) || (lip == NULL))
16137c478bd9Sstevel@tonic-gate 		return (EINVAL);
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	if ((ret = ldi_vp_from_devid(devid, minor_name, &vp)) != 0)
16187c478bd9Sstevel@tonic-gate 		return (ret);
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 	ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
16217c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	return (ret);
16247c478bd9Sstevel@tonic-gate }
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate int
16277c478bd9Sstevel@tonic-gate ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
16307c478bd9Sstevel@tonic-gate 	struct ldi_event	*lep;
1631*184cd04cScth 	int			err = 0;
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	if (lh == NULL)
16347c478bd9Sstevel@tonic-gate 		return (EINVAL);
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	/* Flush back any dirty pages associated with the device. */
16397c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
16407c478bd9Sstevel@tonic-gate 		vnode_t	*cvp = common_specvp(handlep->lh_vp);
16417c478bd9Sstevel@tonic-gate 		dev_t	dev = cvp->v_rdev;
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 		(void) VOP_PUTPAGE(cvp, 0, 0, B_INVAL, kcred);
16447c478bd9Sstevel@tonic-gate 		bflush(dev);
16457c478bd9Sstevel@tonic-gate 	}
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	/*
16487c478bd9Sstevel@tonic-gate 	 * Any event handlers should have been unregistered by the
16497c478bd9Sstevel@tonic-gate 	 * time ldi_close() is called.  If they haven't then it's a
16507c478bd9Sstevel@tonic-gate 	 * bug.
16517c478bd9Sstevel@tonic-gate 	 *
16527c478bd9Sstevel@tonic-gate 	 * In a debug kernel we'll panic to make the problem obvious.
16537c478bd9Sstevel@tonic-gate 	 */
16547c478bd9Sstevel@tonic-gate 	ASSERT(handlep->lh_events == NULL);
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	/*
16577c478bd9Sstevel@tonic-gate 	 * On a production kernel we'll "do the right thing" (unregister
16587c478bd9Sstevel@tonic-gate 	 * the event handlers) and then complain about having to do the
16597c478bd9Sstevel@tonic-gate 	 * work ourselves.
16607c478bd9Sstevel@tonic-gate 	 */
16617c478bd9Sstevel@tonic-gate 	while ((lep = handlep->lh_events) != NULL) {
16627c478bd9Sstevel@tonic-gate 		err = 1;
16637c478bd9Sstevel@tonic-gate 		(void) ldi_remove_event_handler(lh, (ldi_callback_id_t)lep);
16647c478bd9Sstevel@tonic-gate 	}
16657c478bd9Sstevel@tonic-gate 	if (err) {
16667c478bd9Sstevel@tonic-gate 		struct ldi_ident *lip = handlep->lh_ident;
16677c478bd9Sstevel@tonic-gate 		ASSERT(lip != NULL);
16687c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "ldi err: %s "
16697c478bd9Sstevel@tonic-gate 		    "failed to unregister layered event handlers before "
16707c478bd9Sstevel@tonic-gate 		    "closing devices", lip->li_modname);
16717c478bd9Sstevel@tonic-gate 	}
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 	/* do a layered close on the device */
16747c478bd9Sstevel@tonic-gate 	err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr);
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 	LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", "ldi close", (void *)lh));
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate 	/*
16797c478bd9Sstevel@tonic-gate 	 * Free the handle even if the device close failed.  why?
16807c478bd9Sstevel@tonic-gate 	 *
16817c478bd9Sstevel@tonic-gate 	 * If the device close failed we can't really make assumptions
16827c478bd9Sstevel@tonic-gate 	 * about the devices state so we shouldn't allow access to the
16837c478bd9Sstevel@tonic-gate 	 * device via this handle any more.  If the device consumer wants
16847c478bd9Sstevel@tonic-gate 	 * to access the device again they should open it again.
16857c478bd9Sstevel@tonic-gate 	 *
16867c478bd9Sstevel@tonic-gate 	 * This is the same way file/device close failures are handled
16877c478bd9Sstevel@tonic-gate 	 * in other places like spec_close() and closeandsetf().
16887c478bd9Sstevel@tonic-gate 	 */
16897c478bd9Sstevel@tonic-gate 	handle_release(handlep);
16907c478bd9Sstevel@tonic-gate 	return (err);
16917c478bd9Sstevel@tonic-gate }
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate int
16947c478bd9Sstevel@tonic-gate ldi_read(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
16957c478bd9Sstevel@tonic-gate {
16967c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
16977c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
16987c478bd9Sstevel@tonic-gate 	dev_t			dev;
16997c478bd9Sstevel@tonic-gate 	int			ret;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	if (lh == NULL)
17027c478bd9Sstevel@tonic-gate 		return (EINVAL);
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	vp = handlep->lh_vp;
17057c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
17067c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
17077c478bd9Sstevel@tonic-gate 		ret = cdev_read(dev, uiop, credp);
17087c478bd9Sstevel@tonic-gate 	} else if (handlep->lh_type & LH_STREAM) {
17097c478bd9Sstevel@tonic-gate 		ret = strread(vp, uiop, credp);
17107c478bd9Sstevel@tonic-gate 	} else {
17117c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
17127c478bd9Sstevel@tonic-gate 	}
17137c478bd9Sstevel@tonic-gate 	return (ret);
17147c478bd9Sstevel@tonic-gate }
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate int
17177c478bd9Sstevel@tonic-gate ldi_write(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
17187c478bd9Sstevel@tonic-gate {
17197c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
17207c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
17217c478bd9Sstevel@tonic-gate 	dev_t			dev;
17227c478bd9Sstevel@tonic-gate 	int			ret;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	if (lh == NULL)
17257c478bd9Sstevel@tonic-gate 		return (EINVAL);
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 	vp = handlep->lh_vp;
17287c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
17297c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
17307c478bd9Sstevel@tonic-gate 		ret = cdev_write(dev, uiop, credp);
17317c478bd9Sstevel@tonic-gate 	} else if (handlep->lh_type & LH_STREAM) {
17327c478bd9Sstevel@tonic-gate 		ret = strwrite(vp, uiop, credp);
17337c478bd9Sstevel@tonic-gate 	} else {
17347c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
17357c478bd9Sstevel@tonic-gate 	}
17367c478bd9Sstevel@tonic-gate 	return (ret);
17377c478bd9Sstevel@tonic-gate }
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate int
17407c478bd9Sstevel@tonic-gate ldi_get_size(ldi_handle_t lh, uint64_t *sizep)
17417c478bd9Sstevel@tonic-gate {
1742*184cd04cScth 	int			otyp;
17437c478bd9Sstevel@tonic-gate 	uint_t			value;
17447c478bd9Sstevel@tonic-gate 	int64_t			drv_prop64;
17457c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1746*184cd04cScth 	uint_t			blksize;
1747*184cd04cScth 	int			blkshift;
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 
17507c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (sizep == NULL))
17517c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_STREAM)
17547c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	/*
17577c478bd9Sstevel@tonic-gate 	 * Determine device type (char or block).
17587c478bd9Sstevel@tonic-gate 	 * Character devices support Size/size
17597c478bd9Sstevel@tonic-gate 	 * property value. Block devices may support
17607c478bd9Sstevel@tonic-gate 	 * Nblocks/nblocks or Size/size property value.
17617c478bd9Sstevel@tonic-gate 	 */
17627c478bd9Sstevel@tonic-gate 	if ((ldi_get_otyp(lh, &otyp)) != 0)
17637c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_BLK) {
17667c478bd9Sstevel@tonic-gate 		if (ldi_prop_exists(lh,
1767*184cd04cScth 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Nblocks")) {
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 			drv_prop64 = ldi_prop_get_int64(lh,
17707c478bd9Sstevel@tonic-gate 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
17717c478bd9Sstevel@tonic-gate 			    "Nblocks", 0);
1772*184cd04cScth 			blksize = ldi_prop_get_int(lh,
1773*184cd04cScth 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1774*184cd04cScth 			    "blksize", DEV_BSIZE);
1775*184cd04cScth 			if (blksize == DEV_BSIZE)
1776*184cd04cScth 				blksize = ldi_prop_get_int(lh, LDI_DEV_T_ANY |
1777*184cd04cScth 				    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1778*184cd04cScth 				    "device-blksize", DEV_BSIZE);
1779*184cd04cScth 
1780*184cd04cScth 			/* blksize must be a power of two */
1781*184cd04cScth 			ASSERT(BIT_ONLYONESET(blksize));
1782*184cd04cScth 			blkshift = highbit(blksize) - 1;
1783*184cd04cScth 
1784*184cd04cScth 			/*
1785*184cd04cScth 			 * We don't support Nblocks values that don't have
1786*184cd04cScth 			 * an accurate uint64_t byte count representation.
1787*184cd04cScth 			 */
1788*184cd04cScth 			if ((uint64_t)drv_prop64 >= (UINT64_MAX >> blkshift))
1789*184cd04cScth 				return (DDI_FAILURE);
1790*184cd04cScth 
1791*184cd04cScth 			*sizep = (uint64_t)
1792*184cd04cScth 			    (((u_offset_t)drv_prop64) << blkshift);
17937c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
17947c478bd9Sstevel@tonic-gate 		}
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 		if (ldi_prop_exists(lh,
1797*184cd04cScth 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "nblocks")) {
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 			value = ldi_prop_get_int(lh,
18007c478bd9Sstevel@tonic-gate 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
18017c478bd9Sstevel@tonic-gate 			    "nblocks", 0);
1802*184cd04cScth 			blksize = ldi_prop_get_int(lh,
1803*184cd04cScth 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1804*184cd04cScth 			    "blksize", DEV_BSIZE);
1805*184cd04cScth 			if (blksize == DEV_BSIZE)
1806*184cd04cScth 				blksize = ldi_prop_get_int(lh, LDI_DEV_T_ANY |
1807*184cd04cScth 				    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1808*184cd04cScth 				    "device-blksize", DEV_BSIZE);
1809*184cd04cScth 
1810*184cd04cScth 			/* blksize must be a power of two */
1811*184cd04cScth 			ASSERT(BIT_ONLYONESET(blksize));
1812*184cd04cScth 			blkshift = highbit(blksize) - 1;
1813*184cd04cScth 
1814*184cd04cScth 			/*
1815*184cd04cScth 			 * We don't support nblocks values that don't have an
1816*184cd04cScth 			 * accurate uint64_t byte count representation.
1817*184cd04cScth 			 */
1818*184cd04cScth 			if ((uint64_t)value >= (UINT64_MAX >> blkshift))
1819*184cd04cScth 				return (DDI_FAILURE);
1820*184cd04cScth 
1821*184cd04cScth 			*sizep = (uint64_t)
1822*184cd04cScth 			    (((u_offset_t)value) << blkshift);
18237c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
18247c478bd9Sstevel@tonic-gate 		}
18257c478bd9Sstevel@tonic-gate 	}
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	if (ldi_prop_exists(lh,
1828*184cd04cScth 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size")) {
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 		drv_prop64 = ldi_prop_get_int64(lh,
18317c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size", 0);
18327c478bd9Sstevel@tonic-gate 		*sizep = (uint64_t)drv_prop64;
18337c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
18347c478bd9Sstevel@tonic-gate 	}
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	if (ldi_prop_exists(lh,
1837*184cd04cScth 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size")) {
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate 		value = ldi_prop_get_int(lh,
18407c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size", 0);
18417c478bd9Sstevel@tonic-gate 		*sizep = (uint64_t)value;
18427c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
18437c478bd9Sstevel@tonic-gate 	}
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	/* unable to determine device size */
18467c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
18477c478bd9Sstevel@tonic-gate }
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate int
18507c478bd9Sstevel@tonic-gate ldi_ioctl(ldi_handle_t lh, int cmd, intptr_t arg, int mode,
18517c478bd9Sstevel@tonic-gate 	cred_t *cr, int *rvalp)
18527c478bd9Sstevel@tonic-gate {
18537c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
18547c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
18557c478bd9Sstevel@tonic-gate 	dev_t			dev;
18567c478bd9Sstevel@tonic-gate 	int			ret, copymode;
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	if (lh == NULL)
18597c478bd9Sstevel@tonic-gate 		return (EINVAL);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	/*
18627c478bd9Sstevel@tonic-gate 	 * if the data pointed to by arg is located in the kernel then
18637c478bd9Sstevel@tonic-gate 	 * make sure the FNATIVE flag is set.
18647c478bd9Sstevel@tonic-gate 	 */
18657c478bd9Sstevel@tonic-gate 	if (mode & FKIOCTL)
18667c478bd9Sstevel@tonic-gate 		mode = (mode & ~FMODELS) | FNATIVE | FKIOCTL;
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	vp = handlep->lh_vp;
18697c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
18707c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
18717c478bd9Sstevel@tonic-gate 		ret = cdev_ioctl(dev, cmd, arg, mode, cr, rvalp);
18727c478bd9Sstevel@tonic-gate 	} else if (handlep->lh_type & LH_STREAM) {
18737c478bd9Sstevel@tonic-gate 		copymode = (mode & FKIOCTL) ? K_TO_K : U_TO_K;
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 		/*
18767c478bd9Sstevel@tonic-gate 		 * if we get an I_PLINK from within the kernel the
18777c478bd9Sstevel@tonic-gate 		 * arg is a layered handle pointer instead of
18787c478bd9Sstevel@tonic-gate 		 * a file descriptor, so we translate this ioctl
18797c478bd9Sstevel@tonic-gate 		 * into a private one that can handle this.
18807c478bd9Sstevel@tonic-gate 		 */
18817c478bd9Sstevel@tonic-gate 		if ((mode & FKIOCTL) && (cmd == I_PLINK))
18827c478bd9Sstevel@tonic-gate 			cmd = _I_PLINK_LH;
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 		ret = strioctl(vp, cmd, arg, mode, copymode, cr, rvalp);
18857c478bd9Sstevel@tonic-gate 	} else {
18867c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
18877c478bd9Sstevel@tonic-gate 	}
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 	return (ret);
18907c478bd9Sstevel@tonic-gate }
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate int
18937c478bd9Sstevel@tonic-gate ldi_poll(ldi_handle_t lh, short events, int anyyet, short *reventsp,
18947c478bd9Sstevel@tonic-gate     struct pollhead **phpp)
18957c478bd9Sstevel@tonic-gate {
18967c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
18977c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
18987c478bd9Sstevel@tonic-gate 	dev_t			dev;
18997c478bd9Sstevel@tonic-gate 	int			ret;
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	if (lh == NULL)
19027c478bd9Sstevel@tonic-gate 		return (EINVAL);
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 	vp = handlep->lh_vp;
19057c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
19067c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
19077c478bd9Sstevel@tonic-gate 		ret = cdev_poll(dev, events, anyyet, reventsp, phpp);
19087c478bd9Sstevel@tonic-gate 	} else if (handlep->lh_type & LH_STREAM) {
19097c478bd9Sstevel@tonic-gate 		ret = strpoll(vp->v_stream, events, anyyet, reventsp, phpp);
19107c478bd9Sstevel@tonic-gate 	} else {
19117c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
19127c478bd9Sstevel@tonic-gate 	}
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	return (ret);
19157c478bd9Sstevel@tonic-gate }
19167c478bd9Sstevel@tonic-gate 
19177c478bd9Sstevel@tonic-gate int
19187c478bd9Sstevel@tonic-gate ldi_prop_op(ldi_handle_t lh, ddi_prop_op_t prop_op,
19197c478bd9Sstevel@tonic-gate 	int flags, char *name, caddr_t valuep, int *length)
19207c478bd9Sstevel@tonic-gate {
19217c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
19227c478bd9Sstevel@tonic-gate 	dev_t			dev;
19237c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
19247c478bd9Sstevel@tonic-gate 	int			ret;
19257c478bd9Sstevel@tonic-gate 	struct snode		*csp;
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
19287c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	if ((prop_op != PROP_LEN) && (valuep == NULL))
19317c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	if (length == NULL)
19347c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	/*
19377c478bd9Sstevel@tonic-gate 	 * try to find the associated dip,
19387c478bd9Sstevel@tonic-gate 	 * this places a hold on the driver
19397c478bd9Sstevel@tonic-gate 	 */
19407c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
19437c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
19447c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
19457c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
19467c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
19477c478bd9Sstevel@tonic-gate 	if (dip == NULL)
19487c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	if (dip == NULL)
19517c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	ret = i_ldi_prop_op(dev, dip, prop_op, flags, name, valuep, length);
19547c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
19557c478bd9Sstevel@tonic-gate 
19567c478bd9Sstevel@tonic-gate 	return (ret);
19577c478bd9Sstevel@tonic-gate }
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate int
19607c478bd9Sstevel@tonic-gate ldi_strategy(ldi_handle_t lh, struct buf *bp)
19617c478bd9Sstevel@tonic-gate {
19627c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
19637c478bd9Sstevel@tonic-gate 	dev_t			dev;
19647c478bd9Sstevel@tonic-gate 
19657c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (bp == NULL))
19667c478bd9Sstevel@tonic-gate 		return (EINVAL);
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
19697c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
19707c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
19717c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	bp->b_edev = dev;
19747c478bd9Sstevel@tonic-gate 	bp->b_dev = cmpdev(dev);
19757c478bd9Sstevel@tonic-gate 	return (bdev_strategy(bp));
19767c478bd9Sstevel@tonic-gate }
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate int
19797c478bd9Sstevel@tonic-gate ldi_dump(ldi_handle_t lh, caddr_t addr, daddr_t blkno, int nblk)
19807c478bd9Sstevel@tonic-gate {
19817c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
19827c478bd9Sstevel@tonic-gate 	dev_t			dev;
19837c478bd9Sstevel@tonic-gate 
19847c478bd9Sstevel@tonic-gate 	if (lh == NULL)
19857c478bd9Sstevel@tonic-gate 		return (EINVAL);
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
19887c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
19897c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
19907c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 	return (bdev_dump(dev, addr, blkno, nblk));
19937c478bd9Sstevel@tonic-gate }
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate int
19967c478bd9Sstevel@tonic-gate ldi_devmap(ldi_handle_t lh, devmap_cookie_t dhp, offset_t off,
19977c478bd9Sstevel@tonic-gate     size_t len, size_t *maplen, uint_t model)
19987c478bd9Sstevel@tonic-gate {
19997c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20007c478bd9Sstevel@tonic-gate 	dev_t			dev;
20017c478bd9Sstevel@tonic-gate 
20027c478bd9Sstevel@tonic-gate 	if (lh == NULL)
20037c478bd9Sstevel@tonic-gate 		return (EINVAL);
20047c478bd9Sstevel@tonic-gate 
20057c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
20067c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
20077c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
20087c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20097c478bd9Sstevel@tonic-gate 
20107c478bd9Sstevel@tonic-gate 	return (cdev_devmap(dev, dhp, off, len, maplen, model));
20117c478bd9Sstevel@tonic-gate }
20127c478bd9Sstevel@tonic-gate 
20137c478bd9Sstevel@tonic-gate int
20147c478bd9Sstevel@tonic-gate ldi_aread(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
20157c478bd9Sstevel@tonic-gate {
20167c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20177c478bd9Sstevel@tonic-gate 	dev_t			dev;
20187c478bd9Sstevel@tonic-gate 	struct cb_ops		*cb;
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	if (lh == NULL)
20217c478bd9Sstevel@tonic-gate 		return (EINVAL);
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
20247c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
20257c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate 	/*
20287c478bd9Sstevel@tonic-gate 	 * Kaio is only supported on block devices.
20297c478bd9Sstevel@tonic-gate 	 */
20307c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
20317c478bd9Sstevel@tonic-gate 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
20327c478bd9Sstevel@tonic-gate 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
20337c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	if (cb->cb_aread == NULL)
20367c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 	return (cb->cb_aread(dev, aio_reqp, cr));
20397c478bd9Sstevel@tonic-gate }
20407c478bd9Sstevel@tonic-gate 
20417c478bd9Sstevel@tonic-gate int
20427c478bd9Sstevel@tonic-gate ldi_awrite(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
20437c478bd9Sstevel@tonic-gate {
20447c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20457c478bd9Sstevel@tonic-gate 	struct cb_ops		*cb;
20467c478bd9Sstevel@tonic-gate 	dev_t			dev;
20477c478bd9Sstevel@tonic-gate 
20487c478bd9Sstevel@tonic-gate 	if (lh == NULL)
20497c478bd9Sstevel@tonic-gate 		return (EINVAL);
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
20527c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
20537c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 	/*
20567c478bd9Sstevel@tonic-gate 	 * Kaio is only supported on block devices.
20577c478bd9Sstevel@tonic-gate 	 */
20587c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
20597c478bd9Sstevel@tonic-gate 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
20607c478bd9Sstevel@tonic-gate 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
20617c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	if (cb->cb_awrite == NULL)
20647c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 	return (cb->cb_awrite(dev, aio_reqp, cr));
20677c478bd9Sstevel@tonic-gate }
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate int
20707c478bd9Sstevel@tonic-gate ldi_putmsg(ldi_handle_t lh, mblk_t *smp)
20717c478bd9Sstevel@tonic-gate {
20727c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20737c478bd9Sstevel@tonic-gate 	int			ret;
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (smp == NULL))
20767c478bd9Sstevel@tonic-gate 		return (EINVAL);
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_STREAM)) {
20797c478bd9Sstevel@tonic-gate 		freemsg(smp);
20807c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20817c478bd9Sstevel@tonic-gate 	}
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 	/* Send message while honoring flow control */
20847c478bd9Sstevel@tonic-gate 	ret = kstrputmsg(handlep->lh_vp, smp, NULL, 0, 0,
2085*184cd04cScth 	    MSG_BAND | MSG_HOLDSIG | MSG_IGNERROR, 0);
20867c478bd9Sstevel@tonic-gate 
20877c478bd9Sstevel@tonic-gate 	return (ret);
20887c478bd9Sstevel@tonic-gate }
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate int
20917c478bd9Sstevel@tonic-gate ldi_getmsg(ldi_handle_t lh, mblk_t **rmp, timestruc_t *timeo)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20947c478bd9Sstevel@tonic-gate 	clock_t			timout; /* milliseconds */
20957c478bd9Sstevel@tonic-gate 	uchar_t			pri;
20967c478bd9Sstevel@tonic-gate 	rval_t			rval;
20977c478bd9Sstevel@tonic-gate 	int			ret, pflag;
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 	if (lh == NULL)
21017c478bd9Sstevel@tonic-gate 		return (EINVAL);
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_STREAM))
21047c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 	/* Convert from nanoseconds to milliseconds */
21077c478bd9Sstevel@tonic-gate 	if (timeo != NULL) {
21087c478bd9Sstevel@tonic-gate 		timout = timeo->tv_sec * 1000 + timeo->tv_nsec / 1000000;
21097c478bd9Sstevel@tonic-gate 		if (timout > INT_MAX)
21107c478bd9Sstevel@tonic-gate 			return (EINVAL);
21117c478bd9Sstevel@tonic-gate 	} else
21127c478bd9Sstevel@tonic-gate 		timout = -1;
21137c478bd9Sstevel@tonic-gate 
21147c478bd9Sstevel@tonic-gate 	/* Wait for timeout millseconds for a message */
21157c478bd9Sstevel@tonic-gate 	pflag = MSG_ANY;
21167c478bd9Sstevel@tonic-gate 	pri = 0;
21177c478bd9Sstevel@tonic-gate 	*rmp = NULL;
21187c478bd9Sstevel@tonic-gate 	ret = kstrgetmsg(handlep->lh_vp,
2119*184cd04cScth 	    rmp, NULL, &pri, &pflag, timout, &rval);
21207c478bd9Sstevel@tonic-gate 	return (ret);
21217c478bd9Sstevel@tonic-gate }
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate int
21247c478bd9Sstevel@tonic-gate ldi_get_dev(ldi_handle_t lh, dev_t *devp)
21257c478bd9Sstevel@tonic-gate {
21267c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (devp == NULL))
21297c478bd9Sstevel@tonic-gate 		return (EINVAL);
21307c478bd9Sstevel@tonic-gate 
21317c478bd9Sstevel@tonic-gate 	*devp = handlep->lh_vp->v_rdev;
21327c478bd9Sstevel@tonic-gate 	return (0);
21337c478bd9Sstevel@tonic-gate }
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate int
21367c478bd9Sstevel@tonic-gate ldi_get_otyp(ldi_handle_t lh, int *otyp)
21377c478bd9Sstevel@tonic-gate {
21387c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (otyp == NULL))
21417c478bd9Sstevel@tonic-gate 		return (EINVAL);
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	*otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
21447c478bd9Sstevel@tonic-gate 	return (0);
21457c478bd9Sstevel@tonic-gate }
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate int
21487c478bd9Sstevel@tonic-gate ldi_get_devid(ldi_handle_t lh, ddi_devid_t *devid)
21497c478bd9Sstevel@tonic-gate {
21507c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21517c478bd9Sstevel@tonic-gate 	int			ret;
21527c478bd9Sstevel@tonic-gate 	dev_t			dev;
21537c478bd9Sstevel@tonic-gate 
21547c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (devid == NULL))
21557c478bd9Sstevel@tonic-gate 		return (EINVAL);
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	ret = ddi_lyr_get_devid(dev, devid);
21607c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
21617c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	return (0);
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate int
21677c478bd9Sstevel@tonic-gate ldi_get_minor_name(ldi_handle_t lh, char **minor_name)
21687c478bd9Sstevel@tonic-gate {
21697c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21707c478bd9Sstevel@tonic-gate 	int			ret, otyp;
21717c478bd9Sstevel@tonic-gate 	dev_t			dev;
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (minor_name == NULL))
21747c478bd9Sstevel@tonic-gate 		return (EINVAL);
21757c478bd9Sstevel@tonic-gate 
21767c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
21777c478bd9Sstevel@tonic-gate 	otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	ret = ddi_lyr_get_minor_name(dev, OTYP_TO_STYP(otyp), minor_name);
21807c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
21817c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	return (0);
21847c478bd9Sstevel@tonic-gate }
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate int
21877c478bd9Sstevel@tonic-gate ldi_prop_lookup_int_array(ldi_handle_t lh,
21887c478bd9Sstevel@tonic-gate     uint_t flags, char *name, int **data, uint_t *nelements)
21897c478bd9Sstevel@tonic-gate {
21907c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21917c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
21927c478bd9Sstevel@tonic-gate 	dev_t			dev;
21937c478bd9Sstevel@tonic-gate 	int			res;
21947c478bd9Sstevel@tonic-gate 	struct snode		*csp;
21957c478bd9Sstevel@tonic-gate 
21967c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
21977c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
22027c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
22037c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
22047c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
22057c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
22067c478bd9Sstevel@tonic-gate 	if (dip == NULL)
22077c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
22107c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
22117c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
22127c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
22137c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
22147c478bd9Sstevel@tonic-gate 	}
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
22177c478bd9Sstevel@tonic-gate 		int *prop_val, prop_len;
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
22207c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, sizeof (int));
22217c478bd9Sstevel@tonic-gate 
22227c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
22237c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
22247c478bd9Sstevel@tonic-gate 			*nelements = prop_len / sizeof (int);
22257c478bd9Sstevel@tonic-gate 			*data = prop_val;
22267c478bd9Sstevel@tonic-gate 
22277c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
22287c478bd9Sstevel@tonic-gate 			return (res);
22297c478bd9Sstevel@tonic-gate 		}
22307c478bd9Sstevel@tonic-gate 	}
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
22337c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_int_array(dev, dip, flags,
22347c478bd9Sstevel@tonic-gate 	    name, data, nelements);
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate 	if (dip != NULL)
22377c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
22387c478bd9Sstevel@tonic-gate 
22397c478bd9Sstevel@tonic-gate 	return (res);
22407c478bd9Sstevel@tonic-gate }
22417c478bd9Sstevel@tonic-gate 
22427c478bd9Sstevel@tonic-gate int
22437c478bd9Sstevel@tonic-gate ldi_prop_lookup_int64_array(ldi_handle_t lh,
22447c478bd9Sstevel@tonic-gate     uint_t flags, char *name, int64_t **data, uint_t *nelements)
22457c478bd9Sstevel@tonic-gate {
22467c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
22477c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
22487c478bd9Sstevel@tonic-gate 	dev_t			dev;
22497c478bd9Sstevel@tonic-gate 	int			res;
22507c478bd9Sstevel@tonic-gate 	struct snode		*csp;
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
22537c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
22567c478bd9Sstevel@tonic-gate 
22577c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
22587c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
22597c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
22607c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
22617c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
22627c478bd9Sstevel@tonic-gate 	if (dip == NULL)
22637c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
22667c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
22677c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
22687c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
22697c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
22707c478bd9Sstevel@tonic-gate 	}
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
22737c478bd9Sstevel@tonic-gate 		int64_t	*prop_val;
22747c478bd9Sstevel@tonic-gate 		int	prop_len;
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
22777c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, sizeof (int64_t));
22787c478bd9Sstevel@tonic-gate 
22797c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
22807c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
22817c478bd9Sstevel@tonic-gate 			*nelements = prop_len / sizeof (int64_t);
22827c478bd9Sstevel@tonic-gate 			*data = prop_val;
22837c478bd9Sstevel@tonic-gate 
22847c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
22857c478bd9Sstevel@tonic-gate 			return (res);
22867c478bd9Sstevel@tonic-gate 		}
22877c478bd9Sstevel@tonic-gate 	}
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
22907c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_int64_array(dev, dip, flags,
22917c478bd9Sstevel@tonic-gate 	    name, data, nelements);
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	if (dip != NULL)
22947c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	return (res);
22977c478bd9Sstevel@tonic-gate }
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate int
23007c478bd9Sstevel@tonic-gate ldi_prop_lookup_string_array(ldi_handle_t lh,
23017c478bd9Sstevel@tonic-gate     uint_t flags, char *name, char ***data, uint_t *nelements)
23027c478bd9Sstevel@tonic-gate {
23037c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
23047c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
23057c478bd9Sstevel@tonic-gate 	dev_t			dev;
23067c478bd9Sstevel@tonic-gate 	int			res;
23077c478bd9Sstevel@tonic-gate 	struct snode		*csp;
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
23107c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
23117c478bd9Sstevel@tonic-gate 
23127c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
23157c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
23167c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
23177c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
23187c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
23197c478bd9Sstevel@tonic-gate 	if (dip == NULL)
23207c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
23237c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
23247c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
23257c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
23267c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
23277c478bd9Sstevel@tonic-gate 	}
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
23307c478bd9Sstevel@tonic-gate 		char	*prop_val;
23317c478bd9Sstevel@tonic-gate 		int	prop_len;
23327c478bd9Sstevel@tonic-gate 
23337c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
23347c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, 0);
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
23377c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
23387c478bd9Sstevel@tonic-gate 			char	**str_array;
23397c478bd9Sstevel@tonic-gate 			int	nelem;
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 			/*
23427c478bd9Sstevel@tonic-gate 			 * pack the returned string array into the format
23437c478bd9Sstevel@tonic-gate 			 * our callers expect
23447c478bd9Sstevel@tonic-gate 			 */
23457c478bd9Sstevel@tonic-gate 			if (i_pack_string_array(prop_val, prop_len,
2346*184cd04cScth 			    &str_array, &nelem) == 0) {
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 				*data = str_array;
23497c478bd9Sstevel@tonic-gate 				*nelements = nelem;
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 				ddi_prop_free(prop_val);
23527c478bd9Sstevel@tonic-gate 				ddi_release_devi(dip);
23537c478bd9Sstevel@tonic-gate 				return (res);
23547c478bd9Sstevel@tonic-gate 			}
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 			/*
23577c478bd9Sstevel@tonic-gate 			 * the format of the returned property must have
23587c478bd9Sstevel@tonic-gate 			 * been bad so throw it out
23597c478bd9Sstevel@tonic-gate 			 */
23607c478bd9Sstevel@tonic-gate 			ddi_prop_free(prop_val);
23617c478bd9Sstevel@tonic-gate 		}
23627c478bd9Sstevel@tonic-gate 	}
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
23657c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_string_array(dev, dip, flags,
23667c478bd9Sstevel@tonic-gate 	    name, data, nelements);
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	if (dip != NULL)
23697c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	return (res);
23727c478bd9Sstevel@tonic-gate }
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate int
23757c478bd9Sstevel@tonic-gate ldi_prop_lookup_string(ldi_handle_t lh,
23767c478bd9Sstevel@tonic-gate     uint_t flags, char *name, char **data)
23777c478bd9Sstevel@tonic-gate {
23787c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
23797c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
23807c478bd9Sstevel@tonic-gate 	dev_t			dev;
23817c478bd9Sstevel@tonic-gate 	int			res;
23827c478bd9Sstevel@tonic-gate 	struct snode		*csp;
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
23857c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
23907c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
23917c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
23927c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
23937c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
23947c478bd9Sstevel@tonic-gate 	if (dip == NULL)
23957c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
23987c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
23997c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
24007c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
24017c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
24027c478bd9Sstevel@tonic-gate 	}
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
24057c478bd9Sstevel@tonic-gate 		char	*prop_val;
24067c478bd9Sstevel@tonic-gate 		int	prop_len;
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
24097c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, 0);
24107c478bd9Sstevel@tonic-gate 
24117c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
24127c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
24137c478bd9Sstevel@tonic-gate 			/*
24147c478bd9Sstevel@tonic-gate 			 * sanity check the vaule returned.
24157c478bd9Sstevel@tonic-gate 			 */
24167c478bd9Sstevel@tonic-gate 			if (i_check_string(prop_val, prop_len)) {
24177c478bd9Sstevel@tonic-gate 				ddi_prop_free(prop_val);
24187c478bd9Sstevel@tonic-gate 			} else {
24197c478bd9Sstevel@tonic-gate 				*data = prop_val;
24207c478bd9Sstevel@tonic-gate 				ddi_release_devi(dip);
24217c478bd9Sstevel@tonic-gate 				return (res);
24227c478bd9Sstevel@tonic-gate 			}
24237c478bd9Sstevel@tonic-gate 		}
24247c478bd9Sstevel@tonic-gate 	}
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
24277c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_string(dev, dip, flags, name, data);
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate 	if (dip != NULL)
24307c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate #ifdef DEBUG
24337c478bd9Sstevel@tonic-gate 	if (res == DDI_PROP_SUCCESS) {
24347c478bd9Sstevel@tonic-gate 		/*
24357c478bd9Sstevel@tonic-gate 		 * keep ourselves honest
24367c478bd9Sstevel@tonic-gate 		 * make sure the framework returns strings in the
24377c478bd9Sstevel@tonic-gate 		 * same format as we're demanding from drivers.
24387c478bd9Sstevel@tonic-gate 		 */
24397c478bd9Sstevel@tonic-gate 		struct prop_driver_data	*pdd;
24407c478bd9Sstevel@tonic-gate 		int			pdd_prop_size;
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 		pdd = ((struct prop_driver_data *)(*data)) - 1;
24437c478bd9Sstevel@tonic-gate 		pdd_prop_size = pdd->pdd_size -
24447c478bd9Sstevel@tonic-gate 		    sizeof (struct prop_driver_data);
24457c478bd9Sstevel@tonic-gate 		ASSERT(i_check_string(*data, pdd_prop_size) == 0);
24467c478bd9Sstevel@tonic-gate 	}
24477c478bd9Sstevel@tonic-gate #endif /* DEBUG */
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 	return (res);
24507c478bd9Sstevel@tonic-gate }
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate int
24537c478bd9Sstevel@tonic-gate ldi_prop_lookup_byte_array(ldi_handle_t lh,
24547c478bd9Sstevel@tonic-gate     uint_t flags, char *name, uchar_t **data, uint_t *nelements)
24557c478bd9Sstevel@tonic-gate {
24567c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
24577c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
24587c478bd9Sstevel@tonic-gate 	dev_t			dev;
24597c478bd9Sstevel@tonic-gate 	int			res;
24607c478bd9Sstevel@tonic-gate 	struct snode		*csp;
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
24637c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
24687c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
24697c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
24707c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
24717c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
24727c478bd9Sstevel@tonic-gate 	if (dip == NULL)
24737c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
24767c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
24777c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
24787c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
24797c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
24807c478bd9Sstevel@tonic-gate 	}
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
24837c478bd9Sstevel@tonic-gate 		uchar_t	*prop_val;
24847c478bd9Sstevel@tonic-gate 		int	prop_len;
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
24877c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, sizeof (uchar_t));
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
24907c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
24917c478bd9Sstevel@tonic-gate 			*nelements = prop_len / sizeof (uchar_t);
24927c478bd9Sstevel@tonic-gate 			*data = prop_val;
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
24957c478bd9Sstevel@tonic-gate 			return (res);
24967c478bd9Sstevel@tonic-gate 		}
24977c478bd9Sstevel@tonic-gate 	}
24987c478bd9Sstevel@tonic-gate 
24997c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
25007c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_byte_array(dev, dip, flags,
25017c478bd9Sstevel@tonic-gate 	    name, data, nelements);
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate 	if (dip != NULL)
25047c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate 	return (res);
25077c478bd9Sstevel@tonic-gate }
25087c478bd9Sstevel@tonic-gate 
25097c478bd9Sstevel@tonic-gate int
25107c478bd9Sstevel@tonic-gate ldi_prop_get_int(ldi_handle_t lh,
25117c478bd9Sstevel@tonic-gate     uint_t flags, char *name, int defvalue)
25127c478bd9Sstevel@tonic-gate {
25137c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
25147c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
25157c478bd9Sstevel@tonic-gate 	dev_t			dev;
25167c478bd9Sstevel@tonic-gate 	int			res;
25177c478bd9Sstevel@tonic-gate 	struct snode		*csp;
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
25207c478bd9Sstevel@tonic-gate 		return (defvalue);
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
25257c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
25267c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
25277c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
25287c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
25297c478bd9Sstevel@tonic-gate 	if (dip == NULL)
25307c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
25337c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
25347c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
25357c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
25367c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
25377c478bd9Sstevel@tonic-gate 	}
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
25407c478bd9Sstevel@tonic-gate 		int	prop_val;
25417c478bd9Sstevel@tonic-gate 		int	prop_len;
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 		/*
25447c478bd9Sstevel@tonic-gate 		 * first call the drivers prop_op interface to allow it
25457c478bd9Sstevel@tonic-gate 		 * it to override default property values.
25467c478bd9Sstevel@tonic-gate 		 */
25477c478bd9Sstevel@tonic-gate 		prop_len = sizeof (int);
25487c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
25497c478bd9Sstevel@tonic-gate 		    flags | DDI_PROP_DYNAMIC, name,
25507c478bd9Sstevel@tonic-gate 		    (caddr_t)&prop_val, &prop_len);
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
25537c478bd9Sstevel@tonic-gate 		if ((res == DDI_PROP_SUCCESS) &&
25547c478bd9Sstevel@tonic-gate 		    (prop_len == sizeof (int))) {
25557c478bd9Sstevel@tonic-gate 			res = prop_val;
25567c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
25577c478bd9Sstevel@tonic-gate 			return (res);
25587c478bd9Sstevel@tonic-gate 		}
25597c478bd9Sstevel@tonic-gate 	}
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
25627c478bd9Sstevel@tonic-gate 	res = ddi_prop_get_int(dev, dip, flags, name, defvalue);
25637c478bd9Sstevel@tonic-gate 
25647c478bd9Sstevel@tonic-gate 	if (dip != NULL)
25657c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
25667c478bd9Sstevel@tonic-gate 
25677c478bd9Sstevel@tonic-gate 	return (res);
25687c478bd9Sstevel@tonic-gate }
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate int64_t
25717c478bd9Sstevel@tonic-gate ldi_prop_get_int64(ldi_handle_t lh,
25727c478bd9Sstevel@tonic-gate     uint_t flags, char *name, int64_t defvalue)
25737c478bd9Sstevel@tonic-gate {
25747c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
25757c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
25767c478bd9Sstevel@tonic-gate 	dev_t			dev;
25777c478bd9Sstevel@tonic-gate 	int64_t			res;
25787c478bd9Sstevel@tonic-gate 	struct snode		*csp;
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
25817c478bd9Sstevel@tonic-gate 		return (defvalue);
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
25867c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
25877c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
25887c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
25897c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
25907c478bd9Sstevel@tonic-gate 	if (dip == NULL)
25917c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
25947c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
25957c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
25967c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
25977c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
25987c478bd9Sstevel@tonic-gate 	}
25997c478bd9Sstevel@tonic-gate 
26007c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
26017c478bd9Sstevel@tonic-gate 		int64_t	prop_val;
26027c478bd9Sstevel@tonic-gate 		int	prop_len;
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 		/*
26057c478bd9Sstevel@tonic-gate 		 * first call the drivers prop_op interface to allow it
26067c478bd9Sstevel@tonic-gate 		 * it to override default property values.
26077c478bd9Sstevel@tonic-gate 		 */
26087c478bd9Sstevel@tonic-gate 		prop_len = sizeof (int64_t);
26097c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
26107c478bd9Sstevel@tonic-gate 		    flags | DDI_PROP_DYNAMIC, name,
26117c478bd9Sstevel@tonic-gate 		    (caddr_t)&prop_val, &prop_len);
26127c478bd9Sstevel@tonic-gate 
26137c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
26147c478bd9Sstevel@tonic-gate 		if ((res == DDI_PROP_SUCCESS) &&
26157c478bd9Sstevel@tonic-gate 		    (prop_len == sizeof (int64_t))) {
26167c478bd9Sstevel@tonic-gate 			res = prop_val;
26177c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
26187c478bd9Sstevel@tonic-gate 			return (res);
26197c478bd9Sstevel@tonic-gate 		}
26207c478bd9Sstevel@tonic-gate 	}
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
26237c478bd9Sstevel@tonic-gate 	res = ddi_prop_get_int64(dev, dip, flags, name, defvalue);
26247c478bd9Sstevel@tonic-gate 
26257c478bd9Sstevel@tonic-gate 	if (dip != NULL)
26267c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate 	return (res);
26297c478bd9Sstevel@tonic-gate }
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate int
26327c478bd9Sstevel@tonic-gate ldi_prop_exists(ldi_handle_t lh, uint_t flags, char *name)
26337c478bd9Sstevel@tonic-gate {
26347c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2635*184cd04cScth 	dev_info_t		*dip;
2636*184cd04cScth 	dev_t			dev;
26377c478bd9Sstevel@tonic-gate 	int			res, prop_len;
26387c478bd9Sstevel@tonic-gate 	struct snode		*csp;
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
26417c478bd9Sstevel@tonic-gate 		return (0);
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
26467c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
26477c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
26487c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
26497c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
26507c478bd9Sstevel@tonic-gate 	if (dip == NULL)
26517c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate 	/* if NULL dip, prop does NOT exist */
26547c478bd9Sstevel@tonic-gate 	if (dip == NULL)
26557c478bd9Sstevel@tonic-gate 		return (0);
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate 	if (flags & LDI_DEV_T_ANY) {
26587c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
26597c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
26607c478bd9Sstevel@tonic-gate 	}
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate 	/*
26637c478bd9Sstevel@tonic-gate 	 * first call the drivers prop_op interface to allow it
26647c478bd9Sstevel@tonic-gate 	 * it to override default property values.
26657c478bd9Sstevel@tonic-gate 	 */
26667c478bd9Sstevel@tonic-gate 	res = i_ldi_prop_op(dev, dip, PROP_LEN,
26677c478bd9Sstevel@tonic-gate 	    flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
26687c478bd9Sstevel@tonic-gate 
26697c478bd9Sstevel@tonic-gate 	if (res == DDI_PROP_SUCCESS) {
26707c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
26717c478bd9Sstevel@tonic-gate 		return (1);
26727c478bd9Sstevel@tonic-gate 	}
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
26757c478bd9Sstevel@tonic-gate 	res = ddi_prop_exists(dev, dip, flags, name);
26767c478bd9Sstevel@tonic-gate 
26777c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
26787c478bd9Sstevel@tonic-gate 	return (res);
26797c478bd9Sstevel@tonic-gate }
26807c478bd9Sstevel@tonic-gate 
26817c478bd9Sstevel@tonic-gate int
26827c478bd9Sstevel@tonic-gate ldi_get_eventcookie(ldi_handle_t lh, char *name, ddi_eventcookie_t *ecp)
26837c478bd9Sstevel@tonic-gate {
26847c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
26857c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
26867c478bd9Sstevel@tonic-gate 	dev_t			dev;
26877c478bd9Sstevel@tonic-gate 	int			res;
26887c478bd9Sstevel@tonic-gate 	struct snode		*csp;
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) ||
26917c478bd9Sstevel@tonic-gate 	    (strlen(name) == 0) || (ecp == NULL)) {
26927c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
26937c478bd9Sstevel@tonic-gate 	}
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
26987c478bd9Sstevel@tonic-gate 
26997c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
27007c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
27017c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
27027c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
27037c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
27047c478bd9Sstevel@tonic-gate 	if (dip == NULL)
27057c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 	if (dip == NULL)
27087c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27097c478bd9Sstevel@tonic-gate 
27107c478bd9Sstevel@tonic-gate 	LDI_EVENTCB((CE_NOTE, "%s: event_name=%s, "
27117c478bd9Sstevel@tonic-gate 	    "dip=0x%p, event_cookiep=0x%p", "ldi_get_eventcookie",
27127c478bd9Sstevel@tonic-gate 	    name, (void *)dip, (void *)ecp));
27137c478bd9Sstevel@tonic-gate 
27147c478bd9Sstevel@tonic-gate 	res = ddi_get_eventcookie(dip, name, ecp);
27157c478bd9Sstevel@tonic-gate 
27167c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
27177c478bd9Sstevel@tonic-gate 	return (res);
27187c478bd9Sstevel@tonic-gate }
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate int
27217c478bd9Sstevel@tonic-gate ldi_add_event_handler(ldi_handle_t lh, ddi_eventcookie_t ec,
27227c478bd9Sstevel@tonic-gate     void (*handler)(ldi_handle_t, ddi_eventcookie_t, void *, void *),
27237c478bd9Sstevel@tonic-gate     void *arg, ldi_callback_id_t *id)
27247c478bd9Sstevel@tonic-gate {
27257c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
27267c478bd9Sstevel@tonic-gate 	struct ldi_event	*lep;
27277c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
27287c478bd9Sstevel@tonic-gate 	dev_t			dev;
27297c478bd9Sstevel@tonic-gate 	int			res;
27307c478bd9Sstevel@tonic-gate 	struct snode		*csp;
27317c478bd9Sstevel@tonic-gate 
27327c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (ec == NULL) || (handler == NULL) || (id == NULL))
27337c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
27387c478bd9Sstevel@tonic-gate 
27397c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
27407c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
27417c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
27427c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
27437c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
27447c478bd9Sstevel@tonic-gate 	if (dip == NULL)
27457c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
27467c478bd9Sstevel@tonic-gate 
27477c478bd9Sstevel@tonic-gate 	if (dip == NULL)
27487c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27497c478bd9Sstevel@tonic-gate 
27507c478bd9Sstevel@tonic-gate 	lep = kmem_zalloc(sizeof (struct ldi_event), KM_SLEEP);
27517c478bd9Sstevel@tonic-gate 	lep->le_lhp = handlep;
27527c478bd9Sstevel@tonic-gate 	lep->le_arg = arg;
27537c478bd9Sstevel@tonic-gate 	lep->le_handler = handler;
27547c478bd9Sstevel@tonic-gate 
27557c478bd9Sstevel@tonic-gate 	if ((res = ddi_add_event_handler(dip, ec, i_ldi_callback,
27567c478bd9Sstevel@tonic-gate 	    (void *)lep, &lep->le_id)) != DDI_SUCCESS) {
27577c478bd9Sstevel@tonic-gate 		LDI_EVENTCB((CE_WARN, "%s: unable to add"
27587c478bd9Sstevel@tonic-gate 		    "event callback", "ldi_add_event_handler"));
27597c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
27607c478bd9Sstevel@tonic-gate 		kmem_free(lep, sizeof (struct ldi_event));
27617c478bd9Sstevel@tonic-gate 		return (res);
27627c478bd9Sstevel@tonic-gate 	}
27637c478bd9Sstevel@tonic-gate 
27647c478bd9Sstevel@tonic-gate 	*id = (ldi_callback_id_t)lep;
27657c478bd9Sstevel@tonic-gate 
27667c478bd9Sstevel@tonic-gate 	LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, event=0x%p, "
27677c478bd9Sstevel@tonic-gate 	    "ldi_eventp=0x%p, cb_id=0x%p", "ldi_add_event_handler",
27687c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)ec, (void *)lep, (void *)id));
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate 	handle_event_add(lep);
27717c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
27727c478bd9Sstevel@tonic-gate 	return (res);
27737c478bd9Sstevel@tonic-gate }
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate int
27767c478bd9Sstevel@tonic-gate ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id)
27777c478bd9Sstevel@tonic-gate {
27787c478bd9Sstevel@tonic-gate 	ldi_event_t		*lep = (ldi_event_t *)id;
27797c478bd9Sstevel@tonic-gate 	int			res;
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (id == NULL))
27827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 	if ((res = ddi_remove_event_handler(lep->le_id))
27877c478bd9Sstevel@tonic-gate 	    != DDI_SUCCESS) {
27887c478bd9Sstevel@tonic-gate 		LDI_EVENTCB((CE_WARN, "%s: unable to remove "
27897c478bd9Sstevel@tonic-gate 		    "event callback", "ldi_remove_event_handler"));
27907c478bd9Sstevel@tonic-gate 		return (res);
27917c478bd9Sstevel@tonic-gate 	}
27927c478bd9Sstevel@tonic-gate 
27937c478bd9Sstevel@tonic-gate 	handle_event_remove(lep);
27947c478bd9Sstevel@tonic-gate 	kmem_free(lep, sizeof (struct ldi_event));
27957c478bd9Sstevel@tonic-gate 	return (res);
27967c478bd9Sstevel@tonic-gate }
2797