xref: /illumos-gate/usr/src/uts/common/os/driver_lyr.c (revision dcba9f3f)
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
5184cd04cScth  * Common Development and Distribution License (the "License").
6184cd04cScth  * 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*dcba9f3fSGeorge Wilson  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * Layered driver support.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
317c478bd9Sstevel@tonic-gate #include <sys/types.h>
327c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
337c478bd9Sstevel@tonic-gate #include <sys/param.h>
347c478bd9Sstevel@tonic-gate #include <sys/conf.h>
357c478bd9Sstevel@tonic-gate #include <sys/systm.h>
367c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
377c478bd9Sstevel@tonic-gate #include <sys/buf.h>
387c478bd9Sstevel@tonic-gate #include <sys/cred.h>
397c478bd9Sstevel@tonic-gate #include <sys/uio.h>
407c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
417c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h>
427c478bd9Sstevel@tonic-gate #include <sys/open.h>
437c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
447c478bd9Sstevel@tonic-gate #include <sys/file.h>
457c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
467c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
477c478bd9Sstevel@tonic-gate #include <sys/bitmap.h>
487c478bd9Sstevel@tonic-gate #include <sys/stat.h>
497c478bd9Sstevel@tonic-gate #include <sys/dditypes.h>
507c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
517c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
527c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
537c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
547c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
557c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
567c478bd9Sstevel@tonic-gate #include <sys/sunldi.h>
577c478bd9Sstevel@tonic-gate #include <sys/sunldi_impl.h>
587c478bd9Sstevel@tonic-gate #include <sys/errno.h>
597c478bd9Sstevel@tonic-gate #include <sys/debug.h>
607c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
617c478bd9Sstevel@tonic-gate #include <sys/var.h>
627c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
657c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
667c478bd9Sstevel@tonic-gate #include <sys/socket.h>
677c478bd9Sstevel@tonic-gate #include <sys/socketvar.h>
687c478bd9Sstevel@tonic-gate #include <sys/kstr.h>
697c478bd9Sstevel@tonic-gate 
7025e8c5aaSvikram /*
7125e8c5aaSvikram  * Device contract related
7225e8c5aaSvikram  */
7325e8c5aaSvikram #include <sys/contract_impl.h>
7425e8c5aaSvikram #include <sys/contract/device_impl.h>
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Define macros to manipulate snode, vnode, and open device flags
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate #define	VTYP_VALID(i)	(((i) == VCHR) || ((i) == VBLK))
807c478bd9Sstevel@tonic-gate #define	VTYP_TO_OTYP(i)	(((i) == VCHR) ? OTYP_CHR : OTYP_BLK)
817c478bd9Sstevel@tonic-gate #define	VTYP_TO_STYP(i)	(((i) == VCHR) ? S_IFCHR : S_IFBLK)
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate #define	OTYP_VALID(i)	(((i) == OTYP_CHR) || ((i) == OTYP_BLK))
847c478bd9Sstevel@tonic-gate #define	OTYP_TO_VTYP(i)	(((i) == OTYP_CHR) ? VCHR : VBLK)
857c478bd9Sstevel@tonic-gate #define	OTYP_TO_STYP(i)	(((i) == OTYP_CHR) ? S_IFCHR : S_IFBLK)
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #define	STYP_VALID(i)	(((i) == S_IFCHR) || ((i) == S_IFBLK))
887c478bd9Sstevel@tonic-gate #define	STYP_TO_VTYP(i)	(((i) == S_IFCHR) ? VCHR : VBLK)
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * Define macros for accessing layered driver hash structures
927c478bd9Sstevel@tonic-gate  */
937c478bd9Sstevel@tonic-gate #define	LH_HASH(vp)		(handle_hash_func(vp) % LH_HASH_SZ)
947c478bd9Sstevel@tonic-gate #define	LI_HASH(mid, dip, dev)	(ident_hash_func(mid, dip, dev) % LI_HASH_SZ)
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate /*
977c478bd9Sstevel@tonic-gate  * Define layered handle flags used in the lh_type field
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate #define	LH_STREAM	(0x1)	/* handle to a streams device */
1007c478bd9Sstevel@tonic-gate #define	LH_CBDEV	(0x2)	/* handle to a char/block device */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
10325e8c5aaSvikram  * Define macro for devid property lookups
1047c478bd9Sstevel@tonic-gate  */
1057c478bd9Sstevel@tonic-gate #define	DEVID_PROP_FLAGS	(DDI_PROP_DONTPASS | \
1067c478bd9Sstevel@tonic-gate 				DDI_PROP_TYPE_STRING|DDI_PROP_CANSLEEP)
1077c478bd9Sstevel@tonic-gate 
10825e8c5aaSvikram /*
10925e8c5aaSvikram  * Dummy string for NDI events
11025e8c5aaSvikram  */
11125e8c5aaSvikram #define	NDI_EVENT_SERVICE	"NDI_EVENT_SERVICE"
11225e8c5aaSvikram 
11325e8c5aaSvikram static void ldi_ev_lock(void);
11425e8c5aaSvikram static void ldi_ev_unlock(void);
11525e8c5aaSvikram 
11625e8c5aaSvikram #ifdef	LDI_OBSOLETE_EVENT
11725e8c5aaSvikram int ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id);
11825e8c5aaSvikram #endif
11925e8c5aaSvikram 
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * globals
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static kmutex_t			ldi_ident_hash_lock[LI_HASH_SZ];
1257c478bd9Sstevel@tonic-gate static struct ldi_ident		*ldi_ident_hash[LI_HASH_SZ];
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate static kmutex_t			ldi_handle_hash_lock[LH_HASH_SZ];
1287c478bd9Sstevel@tonic-gate static struct ldi_handle	*ldi_handle_hash[LH_HASH_SZ];
1297c478bd9Sstevel@tonic-gate static size_t			ldi_handle_hash_count;
1307c478bd9Sstevel@tonic-gate 
13125e8c5aaSvikram static struct ldi_ev_callback_list ldi_ev_callback_list;
13225e8c5aaSvikram 
13325e8c5aaSvikram static uint32_t ldi_ev_id_pool = 0;
13425e8c5aaSvikram 
13525e8c5aaSvikram struct ldi_ev_cookie {
13625e8c5aaSvikram 	char *ck_evname;
13725e8c5aaSvikram 	uint_t ck_sync;
13825e8c5aaSvikram 	uint_t ck_ctype;
13925e8c5aaSvikram };
14025e8c5aaSvikram 
14125e8c5aaSvikram static struct ldi_ev_cookie ldi_ev_cookies[] = {
14225e8c5aaSvikram 	{ LDI_EV_OFFLINE, 1, CT_DEV_EV_OFFLINE},
14325e8c5aaSvikram 	{ LDI_EV_DEGRADE, 0, CT_DEV_EV_DEGRADED},
14425e8c5aaSvikram 	{ NULL}			/* must terminate list */
14525e8c5aaSvikram };
14625e8c5aaSvikram 
1477c478bd9Sstevel@tonic-gate void
1487c478bd9Sstevel@tonic-gate ldi_init(void)
1497c478bd9Sstevel@tonic-gate {
1507c478bd9Sstevel@tonic-gate 	int i;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	ldi_handle_hash_count = 0;
1537c478bd9Sstevel@tonic-gate 	for (i = 0; i < LH_HASH_SZ; i++) {
1547c478bd9Sstevel@tonic-gate 		mutex_init(&ldi_handle_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
1557c478bd9Sstevel@tonic-gate 		ldi_handle_hash[i] = NULL;
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 	for (i = 0; i < LI_HASH_SZ; i++) {
1587c478bd9Sstevel@tonic-gate 		mutex_init(&ldi_ident_hash_lock[i], NULL, MUTEX_DEFAULT, NULL);
1597c478bd9Sstevel@tonic-gate 		ldi_ident_hash[i] = NULL;
1607c478bd9Sstevel@tonic-gate 	}
16125e8c5aaSvikram 
16225e8c5aaSvikram 	/*
16325e8c5aaSvikram 	 * Initialize the LDI event subsystem
16425e8c5aaSvikram 	 */
16525e8c5aaSvikram 	mutex_init(&ldi_ev_callback_list.le_lock, NULL, MUTEX_DEFAULT, NULL);
16625e8c5aaSvikram 	cv_init(&ldi_ev_callback_list.le_cv, NULL, CV_DEFAULT, NULL);
16725e8c5aaSvikram 	ldi_ev_callback_list.le_busy = 0;
16825e8c5aaSvikram 	ldi_ev_callback_list.le_thread = NULL;
16925e8c5aaSvikram 	list_create(&ldi_ev_callback_list.le_head,
17025e8c5aaSvikram 	    sizeof (ldi_ev_callback_impl_t),
17125e8c5aaSvikram 	    offsetof(ldi_ev_callback_impl_t, lec_list));
1727c478bd9Sstevel@tonic-gate }
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * LDI ident manipulation functions
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate static uint_t
1787c478bd9Sstevel@tonic-gate ident_hash_func(modid_t modid, dev_info_t *dip, dev_t dev)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
1817c478bd9Sstevel@tonic-gate 		uintptr_t k = (uintptr_t)dip;
1827c478bd9Sstevel@tonic-gate 		k >>= (int)highbit(sizeof (struct dev_info));
1837c478bd9Sstevel@tonic-gate 		return ((uint_t)k);
1847c478bd9Sstevel@tonic-gate 	} else if (dev != DDI_DEV_T_NONE) {
1857c478bd9Sstevel@tonic-gate 		return (modid + getminor(dev) + getmajor(dev));
1867c478bd9Sstevel@tonic-gate 	} else {
1877c478bd9Sstevel@tonic-gate 		return (modid);
1887c478bd9Sstevel@tonic-gate 	}
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate static struct ldi_ident **
1927c478bd9Sstevel@tonic-gate ident_find_ref_nolock(modid_t modid, dev_info_t *dip, dev_t dev, major_t major)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate 	struct ldi_ident	**lipp = NULL;
1957c478bd9Sstevel@tonic-gate 	uint_t			index = LI_HASH(modid, dip, dev);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ldi_ident_hash_lock[index]));
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	for (lipp = &(ldi_ident_hash[index]);
2007c478bd9Sstevel@tonic-gate 	    (*lipp != NULL);
2017c478bd9Sstevel@tonic-gate 	    lipp = &((*lipp)->li_next)) {
2027c478bd9Sstevel@tonic-gate 		if (((*lipp)->li_modid == modid) &&
2037c478bd9Sstevel@tonic-gate 		    ((*lipp)->li_major == major) &&
2047c478bd9Sstevel@tonic-gate 		    ((*lipp)->li_dip == dip) &&
2057c478bd9Sstevel@tonic-gate 		    ((*lipp)->li_dev == dev))
2067c478bd9Sstevel@tonic-gate 			break;
2077c478bd9Sstevel@tonic-gate 	}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	ASSERT(lipp != NULL);
2107c478bd9Sstevel@tonic-gate 	return (lipp);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate static struct ldi_ident *
2147c478bd9Sstevel@tonic-gate ident_alloc(char *mod_name, dev_info_t *dip, dev_t dev, major_t major)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip, **lipp;
2177c478bd9Sstevel@tonic-gate 	modid_t			modid;
2187c478bd9Sstevel@tonic-gate 	uint_t			index;
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	ASSERT(mod_name != NULL);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	/* get the module id */
2237c478bd9Sstevel@tonic-gate 	modid = mod_name_to_modid(mod_name);
2247c478bd9Sstevel@tonic-gate 	ASSERT(modid != -1);
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	/* allocate a new ident in case we need it */
2277c478bd9Sstevel@tonic-gate 	lip = kmem_zalloc(sizeof (*lip), KM_SLEEP);
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	/* search the hash for a matching ident */
2307c478bd9Sstevel@tonic-gate 	index = LI_HASH(modid, dip, dev);
2317c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_ident_hash_lock[index]);
2327c478bd9Sstevel@tonic-gate 	lipp = ident_find_ref_nolock(modid, dip, dev, major);
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	if (*lipp != NULL) {
235e88e0d0aSJerry Gilliam 		/* we found an ident in the hash */
2367c478bd9Sstevel@tonic-gate 		ASSERT(strcmp((*lipp)->li_modname, mod_name) == 0);
2377c478bd9Sstevel@tonic-gate 		(*lipp)->li_ref++;
2387c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_ident_hash_lock[index]);
2397c478bd9Sstevel@tonic-gate 		kmem_free(lip, sizeof (struct ldi_ident));
2407c478bd9Sstevel@tonic-gate 		return (*lipp);
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/* initialize the new ident */
2447c478bd9Sstevel@tonic-gate 	lip->li_next = NULL;
2457c478bd9Sstevel@tonic-gate 	lip->li_ref = 1;
2467c478bd9Sstevel@tonic-gate 	lip->li_modid = modid;
2477c478bd9Sstevel@tonic-gate 	lip->li_major = major;
2487c478bd9Sstevel@tonic-gate 	lip->li_dip = dip;
2497c478bd9Sstevel@tonic-gate 	lip->li_dev = dev;
2507c478bd9Sstevel@tonic-gate 	(void) strncpy(lip->li_modname, mod_name, sizeof (lip->li_modname) - 1);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	/* add it to the ident hash */
2537c478bd9Sstevel@tonic-gate 	lip->li_next = ldi_ident_hash[index];
2547c478bd9Sstevel@tonic-gate 	ldi_ident_hash[index] = lip;
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_ident_hash_lock[index]);
2577c478bd9Sstevel@tonic-gate 	return (lip);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate static void
2617c478bd9Sstevel@tonic-gate ident_hold(struct ldi_ident *lip)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	uint_t			index;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	ASSERT(lip != NULL);
2667c478bd9Sstevel@tonic-gate 	index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
2677c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_ident_hash_lock[index]);
2687c478bd9Sstevel@tonic-gate 	ASSERT(lip->li_ref > 0);
2697c478bd9Sstevel@tonic-gate 	lip->li_ref++;
2707c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_ident_hash_lock[index]);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate static void
2747c478bd9Sstevel@tonic-gate ident_release(struct ldi_ident *lip)
2757c478bd9Sstevel@tonic-gate {
2767c478bd9Sstevel@tonic-gate 	struct ldi_ident	**lipp;
2777c478bd9Sstevel@tonic-gate 	uint_t			index;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	ASSERT(lip != NULL);
2807c478bd9Sstevel@tonic-gate 	index = LI_HASH(lip->li_modid, lip->li_dip, lip->li_dev);
2817c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_ident_hash_lock[index]);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	ASSERT(lip->li_ref > 0);
2847c478bd9Sstevel@tonic-gate 	if (--lip->li_ref > 0) {
2857c478bd9Sstevel@tonic-gate 		/* there are more references to this ident */
2867c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_ident_hash_lock[index]);
2877c478bd9Sstevel@tonic-gate 		return;
2887c478bd9Sstevel@tonic-gate 	}
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate 	/* this was the last reference/open for this ident.  free it. */
2917c478bd9Sstevel@tonic-gate 	lipp = ident_find_ref_nolock(
2927c478bd9Sstevel@tonic-gate 	    lip->li_modid, lip->li_dip, lip->li_dev, lip->li_major);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	ASSERT((lipp != NULL) && (*lipp != NULL));
2957c478bd9Sstevel@tonic-gate 	*lipp = lip->li_next;
2967c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_ident_hash_lock[index]);
2977c478bd9Sstevel@tonic-gate 	kmem_free(lip, sizeof (struct ldi_ident));
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate  * LDI handle manipulation functions
3027c478bd9Sstevel@tonic-gate  */
3037c478bd9Sstevel@tonic-gate static uint_t
3047c478bd9Sstevel@tonic-gate handle_hash_func(void *vp)
3057c478bd9Sstevel@tonic-gate {
3067c478bd9Sstevel@tonic-gate 	uintptr_t k = (uintptr_t)vp;
3077c478bd9Sstevel@tonic-gate 	k >>= (int)highbit(sizeof (vnode_t));
3087c478bd9Sstevel@tonic-gate 	return ((uint_t)k);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate static struct ldi_handle **
3127c478bd9Sstevel@tonic-gate handle_find_ref_nolock(vnode_t *vp, struct ldi_ident *ident)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	struct ldi_handle	**lhpp = NULL;
3157c478bd9Sstevel@tonic-gate 	uint_t			index = LH_HASH(vp);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ldi_handle_hash_lock[index]));
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	for (lhpp = &(ldi_handle_hash[index]);
3207c478bd9Sstevel@tonic-gate 	    (*lhpp != NULL);
3217c478bd9Sstevel@tonic-gate 	    lhpp = &((*lhpp)->lh_next)) {
3227c478bd9Sstevel@tonic-gate 		if (((*lhpp)->lh_ident == ident) &&
3237c478bd9Sstevel@tonic-gate 		    ((*lhpp)->lh_vp == vp))
3247c478bd9Sstevel@tonic-gate 			break;
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate 	ASSERT(lhpp != NULL);
3287c478bd9Sstevel@tonic-gate 	return (lhpp);
3297c478bd9Sstevel@tonic-gate }
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate static struct ldi_handle *
3327c478bd9Sstevel@tonic-gate handle_find(vnode_t *vp, struct ldi_ident *ident)
3337c478bd9Sstevel@tonic-gate {
3347c478bd9Sstevel@tonic-gate 	struct ldi_handle	**lhpp;
3357c478bd9Sstevel@tonic-gate 	int			index = LH_HASH(vp);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_handle_hash_lock[index]);
3387c478bd9Sstevel@tonic-gate 	lhpp = handle_find_ref_nolock(vp, ident);
3397c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_handle_hash_lock[index]);
3407c478bd9Sstevel@tonic-gate 	ASSERT(lhpp != NULL);
3417c478bd9Sstevel@tonic-gate 	return (*lhpp);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate static struct ldi_handle *
3457c478bd9Sstevel@tonic-gate handle_alloc(vnode_t *vp, struct ldi_ident *ident)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 	struct ldi_handle	*lhp, **lhpp;
3487c478bd9Sstevel@tonic-gate 	uint_t			index;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	ASSERT((vp != NULL) && (ident != NULL));
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/* allocate a new handle in case we need it */
3537c478bd9Sstevel@tonic-gate 	lhp = kmem_zalloc(sizeof (*lhp), KM_SLEEP);
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/* search the hash for a matching handle */
3567c478bd9Sstevel@tonic-gate 	index = LH_HASH(vp);
3577c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_handle_hash_lock[index]);
3587c478bd9Sstevel@tonic-gate 	lhpp = handle_find_ref_nolock(vp, ident);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	if (*lhpp != NULL) {
3617c478bd9Sstevel@tonic-gate 		/* we found a handle in the hash */
3627c478bd9Sstevel@tonic-gate 		(*lhpp)->lh_ref++;
3637c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_handle_hash_lock[index]);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: dup "
366184cd04cScth 		    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
367184cd04cScth 		    (void *)*lhpp, (void *)ident, (void *)vp,
368184cd04cScth 		    mod_major_to_name(getmajor(vp->v_rdev)),
369184cd04cScth 		    getminor(vp->v_rdev)));
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 		kmem_free(lhp, sizeof (struct ldi_handle));
3727c478bd9Sstevel@tonic-gate 		return (*lhpp);
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	/* initialize the new handle */
3767c478bd9Sstevel@tonic-gate 	lhp->lh_ref = 1;
3777c478bd9Sstevel@tonic-gate 	lhp->lh_vp = vp;
3787c478bd9Sstevel@tonic-gate 	lhp->lh_ident = ident;
37925e8c5aaSvikram #ifdef	LDI_OBSOLETE_EVENT
3807c478bd9Sstevel@tonic-gate 	mutex_init(lhp->lh_lock, NULL, MUTEX_DEFAULT, NULL);
38125e8c5aaSvikram #endif
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	/* set the device type for this handle */
3847c478bd9Sstevel@tonic-gate 	lhp->lh_type = 0;
385349dcea3SGarrett D'Amore 	if (vp->v_stream) {
3867c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_type == VCHR);
3877c478bd9Sstevel@tonic-gate 		lhp->lh_type |= LH_STREAM;
3887c478bd9Sstevel@tonic-gate 	} else {
3897c478bd9Sstevel@tonic-gate 		lhp->lh_type |= LH_CBDEV;
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/* get holds on other objects */
3937c478bd9Sstevel@tonic-gate 	ident_hold(ident);
3947c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count >= 1);
3957c478bd9Sstevel@tonic-gate 	VN_HOLD(vp);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/* add it to the handle hash */
3987c478bd9Sstevel@tonic-gate 	lhp->lh_next = ldi_handle_hash[index];
3997c478bd9Sstevel@tonic-gate 	ldi_handle_hash[index] = lhp;
4007c478bd9Sstevel@tonic-gate 	atomic_add_long(&ldi_handle_hash_count, 1);
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: new "
403184cd04cScth 	    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
404184cd04cScth 	    (void *)lhp, (void *)ident, (void *)vp,
405184cd04cScth 	    mod_major_to_name(getmajor(vp->v_rdev)),
406184cd04cScth 	    getminor(vp->v_rdev)));
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_handle_hash_lock[index]);
4097c478bd9Sstevel@tonic-gate 	return (lhp);
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate static void
4137c478bd9Sstevel@tonic-gate handle_release(struct ldi_handle *lhp)
4147c478bd9Sstevel@tonic-gate {
4157c478bd9Sstevel@tonic-gate 	struct ldi_handle	**lhpp;
4167c478bd9Sstevel@tonic-gate 	uint_t			index;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	ASSERT(lhp != NULL);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	index = LH_HASH(lhp->lh_vp);
4217c478bd9Sstevel@tonic-gate 	mutex_enter(&ldi_handle_hash_lock[index]);
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN, "ldi handle release: "
424184cd04cScth 	    "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
425184cd04cScth 	    (void *)lhp, (void *)lhp->lh_ident, (void *)lhp->lh_vp,
426184cd04cScth 	    mod_major_to_name(getmajor(lhp->lh_vp->v_rdev)),
427184cd04cScth 	    getminor(lhp->lh_vp->v_rdev)));
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	ASSERT(lhp->lh_ref > 0);
4307c478bd9Sstevel@tonic-gate 	if (--lhp->lh_ref > 0) {
4317c478bd9Sstevel@tonic-gate 		/* there are more references to this handle */
4327c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_handle_hash_lock[index]);
4337c478bd9Sstevel@tonic-gate 		return;
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	/* this was the last reference/open for this handle.  free it. */
4377c478bd9Sstevel@tonic-gate 	lhpp = handle_find_ref_nolock(lhp->lh_vp, lhp->lh_ident);
4387c478bd9Sstevel@tonic-gate 	ASSERT((lhpp != NULL) && (*lhpp != NULL));
4397c478bd9Sstevel@tonic-gate 	*lhpp = lhp->lh_next;
4407c478bd9Sstevel@tonic-gate 	atomic_add_long(&ldi_handle_hash_count, -1);
4417c478bd9Sstevel@tonic-gate 	mutex_exit(&ldi_handle_hash_lock[index]);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	VN_RELE(lhp->lh_vp);
4447c478bd9Sstevel@tonic-gate 	ident_release(lhp->lh_ident);
44525e8c5aaSvikram #ifdef	LDI_OBSOLETE_EVENT
4467c478bd9Sstevel@tonic-gate 	mutex_destroy(lhp->lh_lock);
44725e8c5aaSvikram #endif
4487c478bd9Sstevel@tonic-gate 	kmem_free(lhp, sizeof (struct ldi_handle));
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
45125e8c5aaSvikram #ifdef	LDI_OBSOLETE_EVENT
4527c478bd9Sstevel@tonic-gate /*
4537c478bd9Sstevel@tonic-gate  * LDI event manipulation functions
4547c478bd9Sstevel@tonic-gate  */
4557c478bd9Sstevel@tonic-gate static void
4567c478bd9Sstevel@tonic-gate handle_event_add(ldi_event_t *lep)
4577c478bd9Sstevel@tonic-gate {
4587c478bd9Sstevel@tonic-gate 	struct ldi_handle *lhp = lep->le_lhp;
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	ASSERT(lhp != NULL);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	mutex_enter(lhp->lh_lock);
4637c478bd9Sstevel@tonic-gate 	if (lhp->lh_events == NULL) {
4647c478bd9Sstevel@tonic-gate 		lhp->lh_events = lep;
4657c478bd9Sstevel@tonic-gate 		mutex_exit(lhp->lh_lock);
4667c478bd9Sstevel@tonic-gate 		return;
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	lep->le_next = lhp->lh_events;
4707c478bd9Sstevel@tonic-gate 	lhp->lh_events->le_prev = lep;
4717c478bd9Sstevel@tonic-gate 	lhp->lh_events = lep;
4727c478bd9Sstevel@tonic-gate 	mutex_exit(lhp->lh_lock);
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate static void
4767c478bd9Sstevel@tonic-gate handle_event_remove(ldi_event_t *lep)
4777c478bd9Sstevel@tonic-gate {
4787c478bd9Sstevel@tonic-gate 	struct ldi_handle *lhp = lep->le_lhp;
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	ASSERT(lhp != NULL);
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	mutex_enter(lhp->lh_lock);
4837c478bd9Sstevel@tonic-gate 	if (lep->le_prev)
4847c478bd9Sstevel@tonic-gate 		lep->le_prev->le_next = lep->le_next;
4857c478bd9Sstevel@tonic-gate 	if (lep->le_next)
4867c478bd9Sstevel@tonic-gate 		lep->le_next->le_prev = lep->le_prev;
4877c478bd9Sstevel@tonic-gate 	if (lhp->lh_events == lep)
4887c478bd9Sstevel@tonic-gate 		lhp->lh_events = lep->le_next;
4897c478bd9Sstevel@tonic-gate 	mutex_exit(lhp->lh_lock);
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate static void
4947c478bd9Sstevel@tonic-gate i_ldi_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie,
4957c478bd9Sstevel@tonic-gate     void *arg, void *bus_impldata)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	ldi_event_t *lep = (ldi_event_t *)arg;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	ASSERT(lep != NULL);
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, "
5027c478bd9Sstevel@tonic-gate 	    "event_cookie=0x%p, ldi_eventp=0x%p", "i_ldi_callback",
5037c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)event_cookie, (void *)lep));
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	lep->le_handler(lep->le_lhp, event_cookie, lep->le_arg, bus_impldata);
5067c478bd9Sstevel@tonic-gate }
50725e8c5aaSvikram #endif
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate /*
5107c478bd9Sstevel@tonic-gate  * LDI open helper functions
5117c478bd9Sstevel@tonic-gate  */
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate /* get a vnode to a device by dev_t and otyp */
5147c478bd9Sstevel@tonic-gate static int
5157c478bd9Sstevel@tonic-gate ldi_vp_from_dev(dev_t dev, int otyp, vnode_t **vpp)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
5187c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
5217c478bd9Sstevel@tonic-gate 	if ((dev == DDI_DEV_T_NONE) || (!OTYP_VALID(otyp)) || (vpp == NULL))
5227c478bd9Sstevel@tonic-gate 		return (EINVAL);
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
5257c478bd9Sstevel@tonic-gate 		return (ENODEV);
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	vp = makespecvp(dev, OTYP_TO_VTYP(otyp));
5287c478bd9Sstevel@tonic-gate 	spec_assoc_vp_with_devi(vp, dip);
5297c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);  /* from e_ddi_hold_devi_by_dev */
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	*vpp = vp;
5327c478bd9Sstevel@tonic-gate 	return (0);
5337c478bd9Sstevel@tonic-gate }
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /* get a vnode to a device by pathname */
536*dcba9f3fSGeorge Wilson int
5377c478bd9Sstevel@tonic-gate ldi_vp_from_name(char *path, vnode_t **vpp)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	vnode_t			*vp = NULL;
5407c478bd9Sstevel@tonic-gate 	int			ret;
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
5437c478bd9Sstevel@tonic-gate 	if ((path == NULL) || (vpp == NULL))
5447c478bd9Sstevel@tonic-gate 		return (EINVAL);
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 	if (modrootloaded) {
5477c478bd9Sstevel@tonic-gate 		cred_t *saved_cred = curthread->t_cred;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 		/* we don't want lookupname to fail because of credentials */
5507c478bd9Sstevel@tonic-gate 		curthread->t_cred = kcred;
55186f07f8fSedp 
55286f07f8fSedp 		/*
55386f07f8fSedp 		 * all lookups should be done in the global zone.  but
55486f07f8fSedp 		 * lookupnameat() won't actually do this if an absolute
55586f07f8fSedp 		 * path is passed in.  since the ldi interfaces require an
55686f07f8fSedp 		 * absolute path we pass lookupnameat() a pointer to
55786f07f8fSedp 		 * the character after the leading '/' and tell it to
55886f07f8fSedp 		 * start searching at the current system root directory.
55986f07f8fSedp 		 */
56086f07f8fSedp 		ASSERT(*path == '/');
56186f07f8fSedp 		ret = lookupnameat(path + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
56286f07f8fSedp 		    &vp, rootdir);
56386f07f8fSedp 
56486f07f8fSedp 		/* restore this threads credentials */
5657c478bd9Sstevel@tonic-gate 		curthread->t_cred = saved_cred;
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 		if (ret == 0) {
5687c478bd9Sstevel@tonic-gate 			if (!vn_matchops(vp, spec_getvnodeops()) ||
5697c478bd9Sstevel@tonic-gate 			    !VTYP_VALID(vp->v_type)) {
5707c478bd9Sstevel@tonic-gate 				VN_RELE(vp);
5717c478bd9Sstevel@tonic-gate 				return (ENXIO);
5727c478bd9Sstevel@tonic-gate 			}
5737c478bd9Sstevel@tonic-gate 		}
5747c478bd9Sstevel@tonic-gate 	}
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	if (vp == NULL) {
5777c478bd9Sstevel@tonic-gate 		dev_info_t	*dip;
5787c478bd9Sstevel@tonic-gate 		dev_t		dev;
5797c478bd9Sstevel@tonic-gate 		int		spec_type;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 		/*
5827c478bd9Sstevel@tonic-gate 		 * Root is not mounted, the minor node is not specified,
5837c478bd9Sstevel@tonic-gate 		 * or an OBP path has been specified.
5847c478bd9Sstevel@tonic-gate 		 */
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 		/*
5877c478bd9Sstevel@tonic-gate 		 * Determine if path can be pruned to produce an
5887c478bd9Sstevel@tonic-gate 		 * OBP or devfs path for resolve_pathname.
5897c478bd9Sstevel@tonic-gate 		 */
5907c478bd9Sstevel@tonic-gate 		if (strncmp(path, "/devices/", 9) == 0)
5917c478bd9Sstevel@tonic-gate 			path += strlen("/devices");
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 		/*
5947c478bd9Sstevel@tonic-gate 		 * if no minor node was specified the DEFAULT minor node
5957c478bd9Sstevel@tonic-gate 		 * will be returned.  if there is no DEFAULT minor node
5967c478bd9Sstevel@tonic-gate 		 * one will be fabricated of type S_IFCHR with the minor
5977c478bd9Sstevel@tonic-gate 		 * number equal to the instance number.
5987c478bd9Sstevel@tonic-gate 		 */
5997c478bd9Sstevel@tonic-gate 		ret = resolve_pathname(path, &dip, &dev, &spec_type);
6007c478bd9Sstevel@tonic-gate 		if (ret != 0)
6017c478bd9Sstevel@tonic-gate 			return (ENODEV);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 		ASSERT(STYP_VALID(spec_type));
6047c478bd9Sstevel@tonic-gate 		vp = makespecvp(dev, STYP_TO_VTYP(spec_type));
6057c478bd9Sstevel@tonic-gate 		spec_assoc_vp_with_devi(vp, dip);
6067c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	*vpp = vp;
6107c478bd9Sstevel@tonic-gate 	return (0);
6117c478bd9Sstevel@tonic-gate }
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate static int
6147c478bd9Sstevel@tonic-gate ldi_devid_match(ddi_devid_t devid, dev_info_t *dip, dev_t dev)
6157c478bd9Sstevel@tonic-gate {
6167c478bd9Sstevel@tonic-gate 	char		*devidstr;
6177c478bd9Sstevel@tonic-gate 	ddi_prop_t	*propp;
6187c478bd9Sstevel@tonic-gate 
6197c478bd9Sstevel@tonic-gate 	/* convert devid as a string property */
6207c478bd9Sstevel@tonic-gate 	if ((devidstr = ddi_devid_str_encode(devid, NULL)) == NULL)
6217c478bd9Sstevel@tonic-gate 		return (0);
6227c478bd9Sstevel@tonic-gate 
6237c478bd9Sstevel@tonic-gate 	/*
6247c478bd9Sstevel@tonic-gate 	 * Search for the devid.  For speed and ease in locking this
6257c478bd9Sstevel@tonic-gate 	 * code directly uses the property implementation.  See
6267c478bd9Sstevel@tonic-gate 	 * ddi_common_devid_to_devlist() for a comment as to why.
6277c478bd9Sstevel@tonic-gate 	 */
6287c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	/* check if there is a DDI_DEV_T_NONE devid property */
6317c478bd9Sstevel@tonic-gate 	propp = i_ddi_prop_search(DDI_DEV_T_NONE,
6327c478bd9Sstevel@tonic-gate 	    DEVID_PROP_NAME, DEVID_PROP_FLAGS, &DEVI(dip)->devi_hw_prop_ptr);
6337c478bd9Sstevel@tonic-gate 	if (propp != NULL) {
6347c478bd9Sstevel@tonic-gate 		if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
6357c478bd9Sstevel@tonic-gate 			/* a DDI_DEV_T_NONE devid exists and matchs */
6367c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
6377c478bd9Sstevel@tonic-gate 			ddi_devid_str_free(devidstr);
6387c478bd9Sstevel@tonic-gate 			return (1);
6397c478bd9Sstevel@tonic-gate 		} else {
6407c478bd9Sstevel@tonic-gate 			/* a DDI_DEV_T_NONE devid exists and doesn't match */
6417c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
6427c478bd9Sstevel@tonic-gate 			ddi_devid_str_free(devidstr);
6437c478bd9Sstevel@tonic-gate 			return (0);
6447c478bd9Sstevel@tonic-gate 		}
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	/* check if there is a devt specific devid property */
6487c478bd9Sstevel@tonic-gate 	propp = i_ddi_prop_search(dev,
6497c478bd9Sstevel@tonic-gate 	    DEVID_PROP_NAME, DEVID_PROP_FLAGS, &(DEVI(dip)->devi_hw_prop_ptr));
6507c478bd9Sstevel@tonic-gate 	if (propp != NULL) {
6517c478bd9Sstevel@tonic-gate 		if (ddi_devid_str_compare(propp->prop_val, devidstr) == 0) {
6527c478bd9Sstevel@tonic-gate 			/* a devt specific devid exists and matchs */
6537c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
6547c478bd9Sstevel@tonic-gate 			ddi_devid_str_free(devidstr);
6557c478bd9Sstevel@tonic-gate 			return (1);
6567c478bd9Sstevel@tonic-gate 		} else {
6577c478bd9Sstevel@tonic-gate 			/* a devt specific devid exists and doesn't match */
6587c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
6597c478bd9Sstevel@tonic-gate 			ddi_devid_str_free(devidstr);
6607c478bd9Sstevel@tonic-gate 			return (0);
6617c478bd9Sstevel@tonic-gate 		}
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	/* we didn't find any devids associated with the device */
6657c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
6667c478bd9Sstevel@tonic-gate 	ddi_devid_str_free(devidstr);
6677c478bd9Sstevel@tonic-gate 	return (0);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /* get a handle to a device by devid and minor name */
671*dcba9f3fSGeorge Wilson int
6727c478bd9Sstevel@tonic-gate ldi_vp_from_devid(ddi_devid_t devid, char *minor_name, vnode_t **vpp)
6737c478bd9Sstevel@tonic-gate {
6747c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
6757c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
6767c478bd9Sstevel@tonic-gate 	int			ret, i, ndevs, styp;
6777c478bd9Sstevel@tonic-gate 	dev_t			dev, *devs;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
6807c478bd9Sstevel@tonic-gate 	if ((devid == NULL) || (minor_name == NULL) || (vpp == NULL))
6817c478bd9Sstevel@tonic-gate 		return (EINVAL);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	ret = ddi_lyr_devid_to_devlist(devid, minor_name, &ndevs, &devs);
6847c478bd9Sstevel@tonic-gate 	if ((ret != DDI_SUCCESS) || (ndevs <= 0))
6857c478bd9Sstevel@tonic-gate 		return (ENODEV);
6867c478bd9Sstevel@tonic-gate 
6877c478bd9Sstevel@tonic-gate 	for (i = 0; i < ndevs; i++) {
6887c478bd9Sstevel@tonic-gate 		dev = devs[i];
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 		if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
6917c478bd9Sstevel@tonic-gate 			continue;
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 		/*
6947c478bd9Sstevel@tonic-gate 		 * now we have to verify that the devid of the disk
6957c478bd9Sstevel@tonic-gate 		 * still matches what was requested.
6967c478bd9Sstevel@tonic-gate 		 *
6977c478bd9Sstevel@tonic-gate 		 * we have to do this because the devid could have
6987c478bd9Sstevel@tonic-gate 		 * changed between the call to ddi_lyr_devid_to_devlist()
6997c478bd9Sstevel@tonic-gate 		 * and e_ddi_hold_devi_by_dev().  this is because when
7007c478bd9Sstevel@tonic-gate 		 * ddi_lyr_devid_to_devlist() returns a list of devts
7017c478bd9Sstevel@tonic-gate 		 * there is no kind of hold on those devts so a device
7027c478bd9Sstevel@tonic-gate 		 * could have been replaced out from under us in the
7037c478bd9Sstevel@tonic-gate 		 * interim.
7047c478bd9Sstevel@tonic-gate 		 */
7057c478bd9Sstevel@tonic-gate 		if ((i_ddi_minorname_to_devtspectype(dip, minor_name,
7067c478bd9Sstevel@tonic-gate 		    NULL, &styp) == DDI_SUCCESS) &&
7077c478bd9Sstevel@tonic-gate 		    ldi_devid_match(devid, dip, dev))
7087c478bd9Sstevel@tonic-gate 			break;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);	/* from e_ddi_hold_devi_by_dev() */
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	ddi_lyr_free_devlist(devs, ndevs);
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	if (i == ndevs)
7167c478bd9Sstevel@tonic-gate 		return (ENODEV);
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	ASSERT(STYP_VALID(styp));
7197c478bd9Sstevel@tonic-gate 	vp = makespecvp(dev, STYP_TO_VTYP(styp));
7207c478bd9Sstevel@tonic-gate 	spec_assoc_vp_with_devi(vp, dip);
7217c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);		/* from e_ddi_hold_devi_by_dev */
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	*vpp = vp;
7247c478bd9Sstevel@tonic-gate 	return (0);
7257c478bd9Sstevel@tonic-gate }
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate /* given a vnode, open a device */
7287c478bd9Sstevel@tonic-gate static int
7297c478bd9Sstevel@tonic-gate ldi_open_by_vp(vnode_t **vpp, int flag, cred_t *cr,
7307c478bd9Sstevel@tonic-gate     ldi_handle_t *lhp, struct ldi_ident *li)
7317c478bd9Sstevel@tonic-gate {
7327c478bd9Sstevel@tonic-gate 	struct ldi_handle	*nlhp;
7337c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
7347c478bd9Sstevel@tonic-gate 	int			err;
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	ASSERT((vpp != NULL) && (*vpp != NULL));
7377c478bd9Sstevel@tonic-gate 	ASSERT((lhp != NULL) && (li != NULL));
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	vp = *vpp;
7407c478bd9Sstevel@tonic-gate 	/* if the vnode passed in is not a device, then bail */
7417c478bd9Sstevel@tonic-gate 	if (!vn_matchops(vp, spec_getvnodeops()) || !VTYP_VALID(vp->v_type))
7427c478bd9Sstevel@tonic-gate 		return (ENXIO);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	/*
7457c478bd9Sstevel@tonic-gate 	 * the caller may have specified a node that
7467c478bd9Sstevel@tonic-gate 	 * doesn't have cb_ops defined.  the ldi doesn't yet
7477c478bd9Sstevel@tonic-gate 	 * support opening devices without a valid cb_ops.
7487c478bd9Sstevel@tonic-gate 	 */
7497c478bd9Sstevel@tonic-gate 	if (devopsp[getmajor(vp->v_rdev)]->devo_cb_ops == NULL)
7507c478bd9Sstevel@tonic-gate 		return (ENXIO);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	/* open the device */
753da6c28aaSamw 	if ((err = VOP_OPEN(&vp, flag | FKLYR, cr, NULL)) != 0)
7547c478bd9Sstevel@tonic-gate 		return (err);
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	/* possible clone open, make sure that we still have a spec node */
7577c478bd9Sstevel@tonic-gate 	ASSERT(vn_matchops(vp, spec_getvnodeops()));
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	nlhp = handle_alloc(vp, li);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	if (vp != *vpp) {
7627c478bd9Sstevel@tonic-gate 		/*
7637c478bd9Sstevel@tonic-gate 		 * allocating the layered handle took a new hold on the vnode
7647c478bd9Sstevel@tonic-gate 		 * so we can release the hold that was returned by the clone
7657c478bd9Sstevel@tonic-gate 		 * open
7667c478bd9Sstevel@tonic-gate 		 */
7677c478bd9Sstevel@tonic-gate 		LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
768184cd04cScth 		    "ldi clone open", (void *)nlhp));
7697c478bd9Sstevel@tonic-gate 	} else {
7707c478bd9Sstevel@tonic-gate 		LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
771184cd04cScth 		    "ldi open", (void *)nlhp));
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	*vpp = vp;
7757c478bd9Sstevel@tonic-gate 	*lhp = (ldi_handle_t)nlhp;
7767c478bd9Sstevel@tonic-gate 	return (0);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate /* Call a drivers prop_op(9E) interface */
7807c478bd9Sstevel@tonic-gate static int
7817c478bd9Sstevel@tonic-gate i_ldi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
7827c478bd9Sstevel@tonic-gate     int flags, char *name, caddr_t valuep, int *lengthp)
7837c478bd9Sstevel@tonic-gate {
7847c478bd9Sstevel@tonic-gate 	struct dev_ops	*ops = NULL;
7857c478bd9Sstevel@tonic-gate 	int		res;
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	ASSERT((dip != NULL) && (name != NULL));
7887c478bd9Sstevel@tonic-gate 	ASSERT((prop_op == PROP_LEN) || (valuep != NULL));
7897c478bd9Sstevel@tonic-gate 	ASSERT(lengthp != NULL);
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	/*
7927c478bd9Sstevel@tonic-gate 	 * we can only be invoked after a driver has been opened and
7937c478bd9Sstevel@tonic-gate 	 * someone has a layered handle to it, so there had better be
7947c478bd9Sstevel@tonic-gate 	 * a valid ops vector.
7957c478bd9Sstevel@tonic-gate 	 */
7967c478bd9Sstevel@tonic-gate 	ops = DEVI(dip)->devi_ops;
7977c478bd9Sstevel@tonic-gate 	ASSERT(ops && ops->devo_cb_ops);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	/*
8007c478bd9Sstevel@tonic-gate 	 * Some nexus drivers incorrectly set cb_prop_op to nodev,
8017c478bd9Sstevel@tonic-gate 	 * nulldev or even NULL.
8027c478bd9Sstevel@tonic-gate 	 */
8037c478bd9Sstevel@tonic-gate 	if ((ops->devo_cb_ops->cb_prop_op == nodev) ||
8047c478bd9Sstevel@tonic-gate 	    (ops->devo_cb_ops->cb_prop_op == nulldev) ||
8057c478bd9Sstevel@tonic-gate 	    (ops->devo_cb_ops->cb_prop_op == NULL)) {
8067c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8077c478bd9Sstevel@tonic-gate 	}
8087c478bd9Sstevel@tonic-gate 
8097c478bd9Sstevel@tonic-gate 	/* check if this is actually DDI_DEV_T_ANY query */
8107c478bd9Sstevel@tonic-gate 	if (flags & LDI_DEV_T_ANY) {
8117c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
8127c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	res = cdev_prop_op(dev, dip, prop_op, flags, name, valuep, lengthp);
8167c478bd9Sstevel@tonic-gate 	return (res);
8177c478bd9Sstevel@tonic-gate }
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate static void
8207c478bd9Sstevel@tonic-gate i_ldi_prop_op_free(struct prop_driver_data *pdd)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
8237c478bd9Sstevel@tonic-gate }
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate static caddr_t
8267c478bd9Sstevel@tonic-gate i_ldi_prop_op_alloc(int prop_len)
8277c478bd9Sstevel@tonic-gate {
8287c478bd9Sstevel@tonic-gate 	struct prop_driver_data	*pdd;
8297c478bd9Sstevel@tonic-gate 	int			pdd_size;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	pdd_size = sizeof (struct prop_driver_data) + prop_len;
8327c478bd9Sstevel@tonic-gate 	pdd = kmem_alloc(pdd_size, KM_SLEEP);
8337c478bd9Sstevel@tonic-gate 	pdd->pdd_size = pdd_size;
8347c478bd9Sstevel@tonic-gate 	pdd->pdd_prop_free = i_ldi_prop_op_free;
8357c478bd9Sstevel@tonic-gate 	return ((caddr_t)&pdd[1]);
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate /*
8397c478bd9Sstevel@tonic-gate  * i_ldi_prop_op_typed() is a wrapper for i_ldi_prop_op that is used
8407c478bd9Sstevel@tonic-gate  * by the typed ldi property lookup interfaces.
8417c478bd9Sstevel@tonic-gate  */
8427c478bd9Sstevel@tonic-gate static int
8437c478bd9Sstevel@tonic-gate i_ldi_prop_op_typed(dev_t dev, dev_info_t *dip, int flags, char *name,
8447c478bd9Sstevel@tonic-gate     caddr_t *datap, int *lengthp, int elem_size)
8457c478bd9Sstevel@tonic-gate {
8467c478bd9Sstevel@tonic-gate 	caddr_t	prop_val;
8477c478bd9Sstevel@tonic-gate 	int	prop_len, res;
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	ASSERT((dip != NULL) && (name != NULL));
8507c478bd9Sstevel@tonic-gate 	ASSERT((datap != NULL) && (lengthp != NULL));
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	/*
8537c478bd9Sstevel@tonic-gate 	 * first call the drivers prop_op() interface to allow it
8547c478bd9Sstevel@tonic-gate 	 * it to override default property values.
8557c478bd9Sstevel@tonic-gate 	 */
8567c478bd9Sstevel@tonic-gate 	res = i_ldi_prop_op(dev, dip, PROP_LEN,
8577c478bd9Sstevel@tonic-gate 	    flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
8587c478bd9Sstevel@tonic-gate 	if (res != DDI_PROP_SUCCESS)
8597c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	/* sanity check the property length */
8627c478bd9Sstevel@tonic-gate 	if (prop_len == 0) {
8637c478bd9Sstevel@tonic-gate 		/*
8647c478bd9Sstevel@tonic-gate 		 * the ddi typed interfaces don't allow a drivers to
8657c478bd9Sstevel@tonic-gate 		 * create properties with a length of 0.  so we should
8667c478bd9Sstevel@tonic-gate 		 * prevent drivers from returning 0 length dynamic
8677c478bd9Sstevel@tonic-gate 		 * properties for typed property lookups.
8687c478bd9Sstevel@tonic-gate 		 */
8697c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	/* sanity check the property length against the element size */
8737c478bd9Sstevel@tonic-gate 	if (elem_size && ((prop_len % elem_size) != 0))
8747c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate 	/*
8777c478bd9Sstevel@tonic-gate 	 * got it.  now allocate a prop_driver_data struct so that the
8787c478bd9Sstevel@tonic-gate 	 * user can free the property via ddi_prop_free().
8797c478bd9Sstevel@tonic-gate 	 */
8807c478bd9Sstevel@tonic-gate 	prop_val = i_ldi_prop_op_alloc(prop_len);
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	/* lookup the property again, this time get the value */
8837c478bd9Sstevel@tonic-gate 	res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
8847c478bd9Sstevel@tonic-gate 	    flags | DDI_PROP_DYNAMIC, name, prop_val, &prop_len);
8857c478bd9Sstevel@tonic-gate 	if (res != DDI_PROP_SUCCESS) {
8867c478bd9Sstevel@tonic-gate 		ddi_prop_free(prop_val);
8877c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	/* sanity check the property length */
8917c478bd9Sstevel@tonic-gate 	if (prop_len == 0) {
8927c478bd9Sstevel@tonic-gate 		ddi_prop_free(prop_val);
8937c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	/* sanity check the property length against the element size */
8977c478bd9Sstevel@tonic-gate 	if (elem_size && ((prop_len % elem_size) != 0)) {
8987c478bd9Sstevel@tonic-gate 		ddi_prop_free(prop_val);
8997c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
9007c478bd9Sstevel@tonic-gate 	}
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	/*
9037c478bd9Sstevel@tonic-gate 	 * return the prop_driver_data struct and, optionally, the length
9047c478bd9Sstevel@tonic-gate 	 * of the data.
9057c478bd9Sstevel@tonic-gate 	 */
9067c478bd9Sstevel@tonic-gate 	*datap = prop_val;
9077c478bd9Sstevel@tonic-gate 	*lengthp = prop_len;
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate /*
9137c478bd9Sstevel@tonic-gate  * i_check_string looks at a string property and makes sure its
9147c478bd9Sstevel@tonic-gate  * a valid null terminated string
9157c478bd9Sstevel@tonic-gate  */
9167c478bd9Sstevel@tonic-gate static int
9177c478bd9Sstevel@tonic-gate i_check_string(char *str, int prop_len)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate 	int i;
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	ASSERT(str != NULL);
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	for (i = 0; i < prop_len; i++) {
9247c478bd9Sstevel@tonic-gate 		if (str[i] == '\0')
9257c478bd9Sstevel@tonic-gate 			return (0);
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 	return (1);
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate /*
9317c478bd9Sstevel@tonic-gate  * i_pack_string_array takes a a string array property that is represented
932da6c28aaSamw  * as a concatenation of strings (with the NULL character included for
9337c478bd9Sstevel@tonic-gate  * each string) and converts it into a format that can be returned by
9347c478bd9Sstevel@tonic-gate  * ldi_prop_lookup_string_array.
9357c478bd9Sstevel@tonic-gate  */
9367c478bd9Sstevel@tonic-gate static int
9377c478bd9Sstevel@tonic-gate i_pack_string_array(char *str_concat, int prop_len,
9387c478bd9Sstevel@tonic-gate     char ***str_arrayp, int *nelemp)
9397c478bd9Sstevel@tonic-gate {
9407c478bd9Sstevel@tonic-gate 	int i, nelem, pack_size;
9417c478bd9Sstevel@tonic-gate 	char **str_array, *strptr;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	/*
9447c478bd9Sstevel@tonic-gate 	 * first we need to sanity check the input string array.
9457c478bd9Sstevel@tonic-gate 	 * in essence this can be done my making sure that the last
9467c478bd9Sstevel@tonic-gate 	 * character of the array passed in is null.  (meaning the last
9477c478bd9Sstevel@tonic-gate 	 * string in the array is NULL terminated.
9487c478bd9Sstevel@tonic-gate 	 */
9497c478bd9Sstevel@tonic-gate 	if (str_concat[prop_len - 1] != '\0')
9507c478bd9Sstevel@tonic-gate 		return (1);
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	/* now let's count the number of strings in the array */
9537c478bd9Sstevel@tonic-gate 	for (nelem = i = 0; i < prop_len; i++)
9547c478bd9Sstevel@tonic-gate 		if (str_concat[i] == '\0')
9557c478bd9Sstevel@tonic-gate 			nelem++;
9567c478bd9Sstevel@tonic-gate 	ASSERT(nelem >= 1);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	/* now let's allocate memory for the new packed property */
9597c478bd9Sstevel@tonic-gate 	pack_size = (sizeof (char *) * (nelem + 1)) + prop_len;
9607c478bd9Sstevel@tonic-gate 	str_array = (char **)i_ldi_prop_op_alloc(pack_size);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	/* let's copy the actual string data into the new property */
9637c478bd9Sstevel@tonic-gate 	strptr = (char *)&(str_array[nelem + 1]);
9647c478bd9Sstevel@tonic-gate 	bcopy(str_concat, strptr, prop_len);
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	/* now initialize the string array pointers */
9677c478bd9Sstevel@tonic-gate 	for (i = 0; i < nelem; i++) {
9687c478bd9Sstevel@tonic-gate 		str_array[i] = strptr;
9697c478bd9Sstevel@tonic-gate 		strptr += strlen(strptr) + 1;
9707c478bd9Sstevel@tonic-gate 	}
9717c478bd9Sstevel@tonic-gate 	str_array[nelem] = NULL;
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	/* set the return values */
9747c478bd9Sstevel@tonic-gate 	*str_arrayp = str_array;
9757c478bd9Sstevel@tonic-gate 	*nelemp = nelem;
9767c478bd9Sstevel@tonic-gate 
9777c478bd9Sstevel@tonic-gate 	return (0);
9787c478bd9Sstevel@tonic-gate }
9797c478bd9Sstevel@tonic-gate 
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate /*
9827c478bd9Sstevel@tonic-gate  * LDI Project private device usage interfaces
9837c478bd9Sstevel@tonic-gate  */
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate /*
9867c478bd9Sstevel@tonic-gate  * Get a count of how many devices are currentl open by different consumers
9877c478bd9Sstevel@tonic-gate  */
9887c478bd9Sstevel@tonic-gate int
9897c478bd9Sstevel@tonic-gate ldi_usage_count()
9907c478bd9Sstevel@tonic-gate {
9917c478bd9Sstevel@tonic-gate 	return (ldi_handle_hash_count);
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate static void
9957c478bd9Sstevel@tonic-gate ldi_usage_walker_tgt_helper(ldi_usage_t *ldi_usage, vnode_t *vp)
9967c478bd9Sstevel@tonic-gate {
9977c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
9987c478bd9Sstevel@tonic-gate 	dev_t		dev;
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	ASSERT(STYP_VALID(VTYP_TO_STYP(vp->v_type)));
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 	/* get the target devt */
10037c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	/* try to get the target dip */
10067c478bd9Sstevel@tonic-gate 	dip = VTOCS(vp)->s_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 target information */
10147c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_name = mod_major_to_name(getmajor(dev));
10157c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_modid = mod_name_to_modid(ldi_usage->tgt_name);
10167c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_devt = dev;
10177c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_spec_type = VTYP_TO_STYP(vp->v_type);
10187c478bd9Sstevel@tonic-gate 	ldi_usage->tgt_dip = dip;
10197c478bd9Sstevel@tonic-gate }
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate static int
10237c478bd9Sstevel@tonic-gate ldi_usage_walker_helper(struct ldi_ident *lip, vnode_t *vp,
10247c478bd9Sstevel@tonic-gate     void *arg, int (*callback)(const ldi_usage_t *, void *))
10257c478bd9Sstevel@tonic-gate {
10267c478bd9Sstevel@tonic-gate 	ldi_usage_t	ldi_usage;
10277c478bd9Sstevel@tonic-gate 	struct devnames	*dnp;
10287c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
10297c478bd9Sstevel@tonic-gate 	major_t		major;
10307c478bd9Sstevel@tonic-gate 	dev_t		dev;
10317c478bd9Sstevel@tonic-gate 	int		ret = LDI_USAGE_CONTINUE;
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate 	/* set the target device information */
10347c478bd9Sstevel@tonic-gate 	ldi_usage_walker_tgt_helper(&ldi_usage, vp);
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	/* get the source devt */
10377c478bd9Sstevel@tonic-gate 	dev = lip->li_dev;
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	/* try to get the source dip */
10407c478bd9Sstevel@tonic-gate 	dip = lip->li_dip;
10417c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
10427c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
10437c478bd9Sstevel@tonic-gate 	} else if (dev != DDI_DEV_T_NONE) {
10447c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
10457c478bd9Sstevel@tonic-gate 	}
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	/* set the valid source information */
10487c478bd9Sstevel@tonic-gate 	ldi_usage.src_modid = lip->li_modid;
10497c478bd9Sstevel@tonic-gate 	ldi_usage.src_name = lip->li_modname;
10507c478bd9Sstevel@tonic-gate 	ldi_usage.src_devt = dev;
10517c478bd9Sstevel@tonic-gate 	ldi_usage.src_dip = dip;
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate 	/*
10547c478bd9Sstevel@tonic-gate 	 * if the source ident represents either:
10557c478bd9Sstevel@tonic-gate 	 *
10567c478bd9Sstevel@tonic-gate 	 * - a kernel module (and not a device or device driver)
10577c478bd9Sstevel@tonic-gate 	 * - a device node
10587c478bd9Sstevel@tonic-gate 	 *
10597c478bd9Sstevel@tonic-gate 	 * then we currently have all the info we need to report the
10607c478bd9Sstevel@tonic-gate 	 * usage information so invoke the callback function.
10617c478bd9Sstevel@tonic-gate 	 */
10627c478bd9Sstevel@tonic-gate 	if (((lip->li_major == -1) && (dev == DDI_DEV_T_NONE)) ||
10637c478bd9Sstevel@tonic-gate 	    (dip != NULL)) {
10647c478bd9Sstevel@tonic-gate 		ret = callback(&ldi_usage, arg);
10657c478bd9Sstevel@tonic-gate 		if (dip != NULL)
10667c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
10677c478bd9Sstevel@tonic-gate 		if (ldi_usage.tgt_dip != NULL)
10687c478bd9Sstevel@tonic-gate 			ddi_release_devi(ldi_usage.tgt_dip);
10697c478bd9Sstevel@tonic-gate 		return (ret);
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	/*
10737c478bd9Sstevel@tonic-gate 	 * now this is kinda gross.
10747c478bd9Sstevel@tonic-gate 	 *
10757c478bd9Sstevel@tonic-gate 	 * what we do here is attempt to associate every device instance
10767c478bd9Sstevel@tonic-gate 	 * of the source driver on the system with the open target driver.
10777c478bd9Sstevel@tonic-gate 	 * we do this because we don't know which instance of the device
10787c478bd9Sstevel@tonic-gate 	 * could potentially access the lower device so we assume that all
10797c478bd9Sstevel@tonic-gate 	 * the instances could access it.
10807c478bd9Sstevel@tonic-gate 	 *
10817c478bd9Sstevel@tonic-gate 	 * there are two ways we could have gotten here:
10827c478bd9Sstevel@tonic-gate 	 *
10837c478bd9Sstevel@tonic-gate 	 * 1) this layered ident represents one created using only a
10847c478bd9Sstevel@tonic-gate 	 *    major number or a driver module name.  this means that when
10857c478bd9Sstevel@tonic-gate 	 *    it was created we could not associate it with a particular
10867c478bd9Sstevel@tonic-gate 	 *    dev_t or device instance.
10877c478bd9Sstevel@tonic-gate 	 *
10887c478bd9Sstevel@tonic-gate 	 *    when could this possibly happen you ask?
10897c478bd9Sstevel@tonic-gate 	 *
10907c478bd9Sstevel@tonic-gate 	 *    a perfect example of this is streams persistent links.
10917c478bd9Sstevel@tonic-gate 	 *    when a persistant streams link is formed we can't associate
10927c478bd9Sstevel@tonic-gate 	 *    the lower device stream with any particular upper device
10937c478bd9Sstevel@tonic-gate 	 *    stream or instance.  this is because any particular upper
10947c478bd9Sstevel@tonic-gate 	 *    device stream could be closed, then another could be
10957c478bd9Sstevel@tonic-gate 	 *    opened with a different dev_t and device instance, and it
10967c478bd9Sstevel@tonic-gate 	 *    would still have access to the lower linked stream.
10977c478bd9Sstevel@tonic-gate 	 *
10987c478bd9Sstevel@tonic-gate 	 *    since any instance of the upper streams driver could
10997c478bd9Sstevel@tonic-gate 	 *    potentially access the lower stream whenever it wants,
11007c478bd9Sstevel@tonic-gate 	 *    we represent that here by associating the opened lower
11017c478bd9Sstevel@tonic-gate 	 *    device with every existing device instance of the upper
11027c478bd9Sstevel@tonic-gate 	 *    streams driver.
11037c478bd9Sstevel@tonic-gate 	 *
11047c478bd9Sstevel@tonic-gate 	 * 2) This case should really never happen but we'll include it
11057c478bd9Sstevel@tonic-gate 	 *    for completeness.
11067c478bd9Sstevel@tonic-gate 	 *
11077c478bd9Sstevel@tonic-gate 	 *    it's possible that we could have gotten here because we
11087c478bd9Sstevel@tonic-gate 	 *    have a dev_t for the upper device but we couldn't find a
11097c478bd9Sstevel@tonic-gate 	 *    dip associated with that dev_t.
11107c478bd9Sstevel@tonic-gate 	 *
11117c478bd9Sstevel@tonic-gate 	 *    the only types of devices that have dev_t without an
11127c478bd9Sstevel@tonic-gate 	 *    associated dip are unbound DLPIv2 network devices.  These
11137c478bd9Sstevel@tonic-gate 	 *    types of devices exist to be able to attach a stream to any
11147c478bd9Sstevel@tonic-gate 	 *    instance of a hardware network device.  since these types of
11157c478bd9Sstevel@tonic-gate 	 *    devices are usually hardware devices they should never
11167c478bd9Sstevel@tonic-gate 	 *    really have other devices open.
11177c478bd9Sstevel@tonic-gate 	 */
11187c478bd9Sstevel@tonic-gate 	if (dev != DDI_DEV_T_NONE)
11197c478bd9Sstevel@tonic-gate 		major = getmajor(dev);
11207c478bd9Sstevel@tonic-gate 	else
11217c478bd9Sstevel@tonic-gate 		major = lip->li_major;
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	ASSERT((major >= 0) && (major < devcnt));
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	dnp = &devnamesp[major];
11267c478bd9Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
11277c478bd9Sstevel@tonic-gate 	dip = dnp->dn_head;
11287c478bd9Sstevel@tonic-gate 	while ((dip) && (ret == LDI_USAGE_CONTINUE)) {
11297c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
11307c478bd9Sstevel@tonic-gate 		UNLOCK_DEV_OPS(&dnp->dn_lock);
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 		/* set the source dip */
11337c478bd9Sstevel@tonic-gate 		ldi_usage.src_dip = dip;
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 		/* invoke the callback function */
11367c478bd9Sstevel@tonic-gate 		ret = callback(&ldi_usage, arg);
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 		LOCK_DEV_OPS(&dnp->dn_lock);
11397c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
11407c478bd9Sstevel@tonic-gate 		dip = ddi_get_next(dip);
11417c478bd9Sstevel@tonic-gate 	}
11427c478bd9Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	/* if there was a target dip, release it */
11457c478bd9Sstevel@tonic-gate 	if (ldi_usage.tgt_dip != NULL)
11467c478bd9Sstevel@tonic-gate 		ddi_release_devi(ldi_usage.tgt_dip);
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	return (ret);
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate /*
11527c478bd9Sstevel@tonic-gate  * ldi_usage_walker() - this walker reports LDI kernel device usage
11537c478bd9Sstevel@tonic-gate  * information via the callback() callback function.  the LDI keeps track
11547c478bd9Sstevel@tonic-gate  * of what devices are being accessed in its own internal data structures.
11557c478bd9Sstevel@tonic-gate  * this function walks those data structures to determine device usage.
11567c478bd9Sstevel@tonic-gate  */
11577c478bd9Sstevel@tonic-gate void
11587c478bd9Sstevel@tonic-gate ldi_usage_walker(void *arg, int (*callback)(const ldi_usage_t *, void *))
11597c478bd9Sstevel@tonic-gate {
11607c478bd9Sstevel@tonic-gate 	struct ldi_handle	*lhp;
11617c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip;
11627c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
11637c478bd9Sstevel@tonic-gate 	int			i;
11647c478bd9Sstevel@tonic-gate 	int			ret = LDI_USAGE_CONTINUE;
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 	for (i = 0; i < LH_HASH_SZ; i++) {
11677c478bd9Sstevel@tonic-gate 		mutex_enter(&ldi_handle_hash_lock[i]);
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 		lhp = ldi_handle_hash[i];
11707c478bd9Sstevel@tonic-gate 		while ((lhp != NULL) && (ret == LDI_USAGE_CONTINUE)) {
11717c478bd9Sstevel@tonic-gate 			lip = lhp->lh_ident;
11727c478bd9Sstevel@tonic-gate 			vp = lhp->lh_vp;
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 			/* invoke the devinfo callback function */
11757c478bd9Sstevel@tonic-gate 			ret = ldi_usage_walker_helper(lip, vp, arg, callback);
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 			lhp = lhp->lh_next;
11787c478bd9Sstevel@tonic-gate 		}
11797c478bd9Sstevel@tonic-gate 		mutex_exit(&ldi_handle_hash_lock[i]);
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 		if (ret != LDI_USAGE_CONTINUE)
11827c478bd9Sstevel@tonic-gate 			break;
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate /*
11877c478bd9Sstevel@tonic-gate  * LDI Project private interfaces (streams linking interfaces)
11887c478bd9Sstevel@tonic-gate  *
11897c478bd9Sstevel@tonic-gate  * Streams supports a type of built in device layering via linking.
11907c478bd9Sstevel@tonic-gate  * Certain types of streams drivers can be streams multiplexors.
11917c478bd9Sstevel@tonic-gate  * A streams multiplexor supports the I_LINK/I_PLINK operation.
11927c478bd9Sstevel@tonic-gate  * These operations allows other streams devices to be linked under the
11937c478bd9Sstevel@tonic-gate  * multiplexor.  By definition all streams multiplexors are devices
11947c478bd9Sstevel@tonic-gate  * so this linking is a type of device layering where the multiplexor
11957c478bd9Sstevel@tonic-gate  * device is layered on top of the device linked below it.
11967c478bd9Sstevel@tonic-gate  */
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate /*
11997c478bd9Sstevel@tonic-gate  * ldi_mlink_lh() is invoked when streams are linked using LDI handles.
12007c478bd9Sstevel@tonic-gate  * It is not used for normal I_LINKs and I_PLINKs using file descriptors.
12017c478bd9Sstevel@tonic-gate  *
12027c478bd9Sstevel@tonic-gate  * The streams framework keeps track of links via the file_t of the lower
12037c478bd9Sstevel@tonic-gate  * stream.  The LDI keeps track of devices using a vnode.  In the case
12047c478bd9Sstevel@tonic-gate  * of a streams link created via an LDI handle, fnk_lh() allocates
12057c478bd9Sstevel@tonic-gate  * a file_t that the streams framework can use to track the linkage.
12067c478bd9Sstevel@tonic-gate  */
12077c478bd9Sstevel@tonic-gate int
12087c478bd9Sstevel@tonic-gate ldi_mlink_lh(vnode_t *vp, int cmd, intptr_t arg, cred_t *crp, int *rvalp)
12097c478bd9Sstevel@tonic-gate {
12107c478bd9Sstevel@tonic-gate 	struct ldi_handle	*lhp = (struct ldi_handle *)arg;
12117c478bd9Sstevel@tonic-gate 	vnode_t			*vpdown;
12127c478bd9Sstevel@tonic-gate 	file_t			*fpdown;
12137c478bd9Sstevel@tonic-gate 	int			err;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	if (lhp == NULL)
12167c478bd9Sstevel@tonic-gate 		return (EINVAL);
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	vpdown = lhp->lh_vp;
12197c478bd9Sstevel@tonic-gate 	ASSERT(vn_matchops(vpdown, spec_getvnodeops()));
12207c478bd9Sstevel@tonic-gate 	ASSERT(cmd == _I_PLINK_LH);
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	/*
12237c478bd9Sstevel@tonic-gate 	 * create a new lower vnode and a file_t that points to it,
12247c478bd9Sstevel@tonic-gate 	 * streams linking requires a file_t.  falloc() returns with
12257c478bd9Sstevel@tonic-gate 	 * fpdown locked.
12267c478bd9Sstevel@tonic-gate 	 */
12277c478bd9Sstevel@tonic-gate 	VN_HOLD(vpdown);
12287c478bd9Sstevel@tonic-gate 	(void) falloc(vpdown, FREAD|FWRITE, &fpdown, NULL);
12297c478bd9Sstevel@tonic-gate 	mutex_exit(&fpdown->f_tlock);
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	/* try to establish the link */
12327c478bd9Sstevel@tonic-gate 	err = mlink_file(vp, I_PLINK, fpdown, crp, rvalp, 1);
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	if (err != 0) {
12357c478bd9Sstevel@tonic-gate 		/* the link failed, free the file_t and release the vnode */
12367c478bd9Sstevel@tonic-gate 		mutex_enter(&fpdown->f_tlock);
12377c478bd9Sstevel@tonic-gate 		unfalloc(fpdown);
12387c478bd9Sstevel@tonic-gate 		VN_RELE(vpdown);
12397c478bd9Sstevel@tonic-gate 	}
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	return (err);
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate /*
1245da6c28aaSamw  * ldi_mlink_fp() is invoked for all successful streams linkages created
12467c478bd9Sstevel@tonic-gate  * via I_LINK and I_PLINK.  ldi_mlink_fp() records the linkage information
12477c478bd9Sstevel@tonic-gate  * in its internal state so that the devinfo snapshot code has some
12487c478bd9Sstevel@tonic-gate  * observability into streams device linkage information.
12497c478bd9Sstevel@tonic-gate  */
12507c478bd9Sstevel@tonic-gate void
12517c478bd9Sstevel@tonic-gate ldi_mlink_fp(struct stdata *stp, file_t *fpdown, int lhlink, int type)
12527c478bd9Sstevel@tonic-gate {
12537c478bd9Sstevel@tonic-gate 	vnode_t			*vp = fpdown->f_vnode;
12547c478bd9Sstevel@tonic-gate 	struct snode		*sp, *csp;
12557c478bd9Sstevel@tonic-gate 	ldi_ident_t		li;
12567c478bd9Sstevel@tonic-gate 	major_t			major;
12577c478bd9Sstevel@tonic-gate 	int			ret;
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 	/* if the lower stream is not a device then return */
12607c478bd9Sstevel@tonic-gate 	if (!vn_matchops(vp, spec_getvnodeops()))
12617c478bd9Sstevel@tonic-gate 		return;
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	LDI_STREAMS_LNK((CE_NOTE, "%s: linking streams "
1266184cd04cScth 	    "stp=0x%p, fpdown=0x%p", "ldi_mlink_fp",
1267184cd04cScth 	    (void *)stp, (void *)fpdown));
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	sp = VTOS(vp);
12707c478bd9Sstevel@tonic-gate 	csp = VTOS(sp->s_commonvp);
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	/* check if this was a plink via a layered handle */
12737c478bd9Sstevel@tonic-gate 	if (lhlink) {
12747c478bd9Sstevel@tonic-gate 		/*
12757c478bd9Sstevel@tonic-gate 		 * increment the common snode s_count.
12767c478bd9Sstevel@tonic-gate 		 *
12777c478bd9Sstevel@tonic-gate 		 * this is done because after the link operation there
12787c478bd9Sstevel@tonic-gate 		 * are two ways that s_count can be decremented.
12797c478bd9Sstevel@tonic-gate 		 *
12807c478bd9Sstevel@tonic-gate 		 * when the layered handle used to create the link is
12817c478bd9Sstevel@tonic-gate 		 * closed, spec_close() is called and it will decrement
12827c478bd9Sstevel@tonic-gate 		 * s_count in the common snode.  if we don't increment
12837c478bd9Sstevel@tonic-gate 		 * s_count here then this could cause spec_close() to
12847c478bd9Sstevel@tonic-gate 		 * actually close the device while it's still linked
12857c478bd9Sstevel@tonic-gate 		 * under a multiplexer.
12867c478bd9Sstevel@tonic-gate 		 *
12877c478bd9Sstevel@tonic-gate 		 * also, when the lower stream is unlinked, closef() is
12887c478bd9Sstevel@tonic-gate 		 * called for the file_t associated with this snode.
12897c478bd9Sstevel@tonic-gate 		 * closef() will call spec_close(), which will decrement
12907c478bd9Sstevel@tonic-gate 		 * s_count.  if we dont't increment s_count here then this
12917c478bd9Sstevel@tonic-gate 		 * could cause spec_close() to actually close the device
12927c478bd9Sstevel@tonic-gate 		 * while there may still be valid layered handles
12937c478bd9Sstevel@tonic-gate 		 * pointing to it.
12947c478bd9Sstevel@tonic-gate 		 */
12957c478bd9Sstevel@tonic-gate 		mutex_enter(&csp->s_lock);
12967c478bd9Sstevel@tonic-gate 		ASSERT(csp->s_count >= 1);
12977c478bd9Sstevel@tonic-gate 		csp->s_count++;
12987c478bd9Sstevel@tonic-gate 		mutex_exit(&csp->s_lock);
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate 		/*
13017c478bd9Sstevel@tonic-gate 		 * decrement the f_count.
13027c478bd9Sstevel@tonic-gate 		 * this is done because the layered driver framework does
13037c478bd9Sstevel@tonic-gate 		 * not actually cache a copy of the file_t allocated to
13047c478bd9Sstevel@tonic-gate 		 * do the link.  this is done here instead of in ldi_mlink_lh()
13057c478bd9Sstevel@tonic-gate 		 * because there is a window in ldi_mlink_lh() between where
13067c478bd9Sstevel@tonic-gate 		 * milnk_file() returns and we would decrement the f_count
13077c478bd9Sstevel@tonic-gate 		 * when the stream could be unlinked.
13087c478bd9Sstevel@tonic-gate 		 */
13097c478bd9Sstevel@tonic-gate 		mutex_enter(&fpdown->f_tlock);
13107c478bd9Sstevel@tonic-gate 		fpdown->f_count--;
13117c478bd9Sstevel@tonic-gate 		mutex_exit(&fpdown->f_tlock);
13127c478bd9Sstevel@tonic-gate 	}
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	/*
13157c478bd9Sstevel@tonic-gate 	 * NOTE: here we rely on the streams subsystem not allowing
13167c478bd9Sstevel@tonic-gate 	 * a stream to be multiplexed more than once.  if this
13177c478bd9Sstevel@tonic-gate 	 * changes, we break.
13187c478bd9Sstevel@tonic-gate 	 *
13197c478bd9Sstevel@tonic-gate 	 * mark the snode/stream as multiplexed
13207c478bd9Sstevel@tonic-gate 	 */
13217c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_lock);
13227c478bd9Sstevel@tonic-gate 	ASSERT(!(sp->s_flag & SMUXED));
13237c478bd9Sstevel@tonic-gate 	sp->s_flag |= SMUXED;
13247c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_lock);
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	/* get a layered ident for the upper stream */
13277c478bd9Sstevel@tonic-gate 	if (type == LINKNORMAL) {
13287c478bd9Sstevel@tonic-gate 		/*
13297c478bd9Sstevel@tonic-gate 		 * if the link is not persistant then we can associate
13307c478bd9Sstevel@tonic-gate 		 * the upper stream with a dev_t.  this is because the
13317c478bd9Sstevel@tonic-gate 		 * upper stream is associated with a vnode, which is
13327c478bd9Sstevel@tonic-gate 		 * associated with a dev_t and this binding can't change
13337c478bd9Sstevel@tonic-gate 		 * during the life of the stream.  since the link isn't
13347c478bd9Sstevel@tonic-gate 		 * persistant once the stream is destroyed the link is
13357c478bd9Sstevel@tonic-gate 		 * destroyed.  so the dev_t will be valid for the life
13367c478bd9Sstevel@tonic-gate 		 * of the link.
13377c478bd9Sstevel@tonic-gate 		 */
13387c478bd9Sstevel@tonic-gate 		ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
13397c478bd9Sstevel@tonic-gate 	} else {
13407c478bd9Sstevel@tonic-gate 		/*
13417c478bd9Sstevel@tonic-gate 		 * if the link is persistant we can only associate the
13427c478bd9Sstevel@tonic-gate 		 * link with a driver (and not a dev_t.)  this is
13437c478bd9Sstevel@tonic-gate 		 * because subsequent opens of the upper device may result
13447c478bd9Sstevel@tonic-gate 		 * in a different stream (and dev_t) having access to
13457c478bd9Sstevel@tonic-gate 		 * the lower stream.
13467c478bd9Sstevel@tonic-gate 		 *
13477c478bd9Sstevel@tonic-gate 		 * for example, if the upper stream is closed after the
13487c478bd9Sstevel@tonic-gate 		 * persistant link operation is compleated, a subsequent
13497c478bd9Sstevel@tonic-gate 		 * open of the upper device will create a new stream which
13507c478bd9Sstevel@tonic-gate 		 * may have a different dev_t and an unlink operation
13517c478bd9Sstevel@tonic-gate 		 * can be performed using this new upper stream.
13527c478bd9Sstevel@tonic-gate 		 */
13537c478bd9Sstevel@tonic-gate 		ASSERT(type == LINKPERSIST);
13547c478bd9Sstevel@tonic-gate 		major = getmajor(stp->sd_vnode->v_rdev);
13557c478bd9Sstevel@tonic-gate 		ret = ldi_ident_from_major(major, &li);
13567c478bd9Sstevel@tonic-gate 	}
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	ASSERT(ret == 0);
13597c478bd9Sstevel@tonic-gate 	(void) handle_alloc(vp, (struct ldi_ident *)li);
13607c478bd9Sstevel@tonic-gate 	ldi_ident_release(li);
13617c478bd9Sstevel@tonic-gate }
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate void
13647c478bd9Sstevel@tonic-gate ldi_munlink_fp(struct stdata *stp, file_t *fpdown, int type)
13657c478bd9Sstevel@tonic-gate {
13667c478bd9Sstevel@tonic-gate 	struct ldi_handle	*lhp;
13677c478bd9Sstevel@tonic-gate 	vnode_t			*vp = (vnode_t *)fpdown->f_vnode;
13687c478bd9Sstevel@tonic-gate 	struct snode		*sp;
13697c478bd9Sstevel@tonic-gate 	ldi_ident_t		li;
13707c478bd9Sstevel@tonic-gate 	major_t			major;
13717c478bd9Sstevel@tonic-gate 	int			ret;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	/* if the lower stream is not a device then return */
13747c478bd9Sstevel@tonic-gate 	if (!vn_matchops(vp, spec_getvnodeops()))
13757c478bd9Sstevel@tonic-gate 		return;
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
13787c478bd9Sstevel@tonic-gate 	ASSERT((type == LINKNORMAL) || (type == LINKPERSIST));
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	LDI_STREAMS_LNK((CE_NOTE, "%s: unlinking streams "
1381184cd04cScth 	    "stp=0x%p, fpdown=0x%p", "ldi_munlink_fp",
1382184cd04cScth 	    (void *)stp, (void *)fpdown));
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	/*
13857c478bd9Sstevel@tonic-gate 	 * NOTE: here we rely on the streams subsystem not allowing
13867c478bd9Sstevel@tonic-gate 	 * a stream to be multiplexed more than once.  if this
13877c478bd9Sstevel@tonic-gate 	 * changes, we break.
13887c478bd9Sstevel@tonic-gate 	 *
13897c478bd9Sstevel@tonic-gate 	 * mark the snode/stream as not multiplexed
13907c478bd9Sstevel@tonic-gate 	 */
13917c478bd9Sstevel@tonic-gate 	sp = VTOS(vp);
13927c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_lock);
13937c478bd9Sstevel@tonic-gate 	ASSERT(sp->s_flag & SMUXED);
13947c478bd9Sstevel@tonic-gate 	sp->s_flag &= ~SMUXED;
13957c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_lock);
13967c478bd9Sstevel@tonic-gate 
13977c478bd9Sstevel@tonic-gate 	/*
13987c478bd9Sstevel@tonic-gate 	 * clear the owner for this snode
13997c478bd9Sstevel@tonic-gate 	 * see the comment in ldi_mlink_fp() for information about how
14007c478bd9Sstevel@tonic-gate 	 * the ident is allocated
14017c478bd9Sstevel@tonic-gate 	 */
14027c478bd9Sstevel@tonic-gate 	if (type == LINKNORMAL) {
14037c478bd9Sstevel@tonic-gate 		ret = ldi_ident_from_stream(getendq(stp->sd_wrq), &li);
14047c478bd9Sstevel@tonic-gate 	} else {
14057c478bd9Sstevel@tonic-gate 		ASSERT(type == LINKPERSIST);
14067c478bd9Sstevel@tonic-gate 		major = getmajor(stp->sd_vnode->v_rdev);
14077c478bd9Sstevel@tonic-gate 		ret = ldi_ident_from_major(major, &li);
14087c478bd9Sstevel@tonic-gate 	}
14097c478bd9Sstevel@tonic-gate 
14107c478bd9Sstevel@tonic-gate 	ASSERT(ret == 0);
14117c478bd9Sstevel@tonic-gate 	lhp = handle_find(vp, (struct ldi_ident *)li);
14127c478bd9Sstevel@tonic-gate 	handle_release(lhp);
14137c478bd9Sstevel@tonic-gate 	ldi_ident_release(li);
14147c478bd9Sstevel@tonic-gate }
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate /*
14177c478bd9Sstevel@tonic-gate  * LDI Consolidation private interfaces
14187c478bd9Sstevel@tonic-gate  */
14197c478bd9Sstevel@tonic-gate int
14207c478bd9Sstevel@tonic-gate ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip)
14217c478bd9Sstevel@tonic-gate {
14227c478bd9Sstevel@tonic-gate 	struct modctl		*modp;
14237c478bd9Sstevel@tonic-gate 	major_t			major;
14247c478bd9Sstevel@tonic-gate 	char			*name;
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 	if ((modlp == NULL) || (lip == NULL))
14277c478bd9Sstevel@tonic-gate 		return (EINVAL);
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate 	modp = mod_getctl(modlp);
14327c478bd9Sstevel@tonic-gate 	if (modp == NULL)
14337c478bd9Sstevel@tonic-gate 		return (EINVAL);
14347c478bd9Sstevel@tonic-gate 	name = modp->mod_modname;
14357c478bd9Sstevel@tonic-gate 	if (name == NULL)
14367c478bd9Sstevel@tonic-gate 		return (EINVAL);
14377c478bd9Sstevel@tonic-gate 	major = mod_name_to_major(name);
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1442184cd04cScth 	    "ldi_ident_from_mod", (void *)*lip, name));
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	return (0);
14457c478bd9Sstevel@tonic-gate }
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate ldi_ident_t
14487c478bd9Sstevel@tonic-gate ldi_ident_from_anon()
14497c478bd9Sstevel@tonic-gate {
14507c478bd9Sstevel@tonic-gate 	ldi_ident_t	lip;
14517c478bd9Sstevel@tonic-gate 
14527c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	lip = (ldi_ident_t)ident_alloc("genunix", NULL, DDI_DEV_T_NONE, -1);
14557c478bd9Sstevel@tonic-gate 
14567c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN, "%s: li=0x%p, mod=%s",
1457184cd04cScth 	    "ldi_ident_from_anon", (void *)lip, "genunix"));
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 	return (lip);
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate /*
14647c478bd9Sstevel@tonic-gate  * LDI Public interfaces
14657c478bd9Sstevel@tonic-gate  */
14667c478bd9Sstevel@tonic-gate int
14677c478bd9Sstevel@tonic-gate ldi_ident_from_stream(struct queue *sq, ldi_ident_t *lip)
14687c478bd9Sstevel@tonic-gate {
14697c478bd9Sstevel@tonic-gate 	struct stdata		*stp;
14707c478bd9Sstevel@tonic-gate 	dev_t			dev;
14717c478bd9Sstevel@tonic-gate 	char			*name;
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 	if ((sq == NULL) || (lip == NULL))
14747c478bd9Sstevel@tonic-gate 		return (EINVAL);
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	stp = sq->q_stream;
14797c478bd9Sstevel@tonic-gate 	if (!vn_matchops(stp->sd_vnode, spec_getvnodeops()))
14807c478bd9Sstevel@tonic-gate 		return (EINVAL);
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	dev = stp->sd_vnode->v_rdev;
14837c478bd9Sstevel@tonic-gate 	name = mod_major_to_name(getmajor(dev));
14847c478bd9Sstevel@tonic-gate 	if (name == NULL)
14857c478bd9Sstevel@tonic-gate 		return (EINVAL);
14867c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1489184cd04cScth 	    "%s: li=0x%p, mod=%s, minor=0x%x, stp=0x%p",
1490184cd04cScth 	    "ldi_ident_from_stream", (void *)*lip, name, getminor(dev),
1491184cd04cScth 	    (void *)stp));
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	return (0);
14947c478bd9Sstevel@tonic-gate }
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate int
14977c478bd9Sstevel@tonic-gate ldi_ident_from_dev(dev_t dev, ldi_ident_t *lip)
14987c478bd9Sstevel@tonic-gate {
14997c478bd9Sstevel@tonic-gate 	char			*name;
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 	if (lip == NULL)
15027c478bd9Sstevel@tonic-gate 		return (EINVAL);
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	name = mod_major_to_name(getmajor(dev));
15077c478bd9Sstevel@tonic-gate 	if (name == NULL)
15087c478bd9Sstevel@tonic-gate 		return (EINVAL);
15097c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, NULL, dev, -1);
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1512184cd04cScth 	    "%s: li=0x%p, mod=%s, minor=0x%x",
1513184cd04cScth 	    "ldi_ident_from_dev", (void *)*lip, name, getminor(dev)));
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 	return (0);
15167c478bd9Sstevel@tonic-gate }
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate int
15197c478bd9Sstevel@tonic-gate ldi_ident_from_dip(dev_info_t *dip, ldi_ident_t *lip)
15207c478bd9Sstevel@tonic-gate {
15217c478bd9Sstevel@tonic-gate 	struct dev_info		*devi = (struct dev_info *)dip;
15227c478bd9Sstevel@tonic-gate 	char			*name;
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	if ((dip == NULL) || (lip == NULL))
15257c478bd9Sstevel@tonic-gate 		return (EINVAL);
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 	name = mod_major_to_name(devi->devi_major);
15307c478bd9Sstevel@tonic-gate 	if (name == NULL)
15317c478bd9Sstevel@tonic-gate 		return (EINVAL);
15327c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, dip, DDI_DEV_T_NONE, -1);
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1535184cd04cScth 	    "%s: li=0x%p, mod=%s, dip=0x%p",
1536184cd04cScth 	    "ldi_ident_from_dip", (void *)*lip, name, (void *)devi));
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	return (0);
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate int
15427c478bd9Sstevel@tonic-gate ldi_ident_from_major(major_t major, ldi_ident_t *lip)
15437c478bd9Sstevel@tonic-gate {
15447c478bd9Sstevel@tonic-gate 	char			*name;
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	if (lip == NULL)
15477c478bd9Sstevel@tonic-gate 		return (EINVAL);
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	name = mod_major_to_name(major);
15527c478bd9Sstevel@tonic-gate 	if (name == NULL)
15537c478bd9Sstevel@tonic-gate 		return (EINVAL);
15547c478bd9Sstevel@tonic-gate 	*lip = (ldi_ident_t)ident_alloc(name, NULL, DDI_DEV_T_NONE, major);
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1557184cd04cScth 	    "%s: li=0x%p, mod=%s",
1558184cd04cScth 	    "ldi_ident_from_major", (void *)*lip, name));
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	return (0);
15617c478bd9Sstevel@tonic-gate }
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate void
15647c478bd9Sstevel@tonic-gate ldi_ident_release(ldi_ident_t li)
15657c478bd9Sstevel@tonic-gate {
15667c478bd9Sstevel@tonic-gate 	struct ldi_ident	*ident = (struct ldi_ident *)li;
15677c478bd9Sstevel@tonic-gate 	char			*name;
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	if (li == NULL)
15707c478bd9Sstevel@tonic-gate 		return;
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	name = ident->li_modname;
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	LDI_ALLOCFREE((CE_WARN,
1577184cd04cScth 	    "%s: li=0x%p, mod=%s",
1578184cd04cScth 	    "ldi_ident_release", (void *)li, name));
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	ident_release((struct ldi_ident *)li);
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate /* get a handle to a device by dev_t and otyp */
15847c478bd9Sstevel@tonic-gate int
15857c478bd9Sstevel@tonic-gate ldi_open_by_dev(dev_t *devp, int otyp, int flag, cred_t *cr,
15867c478bd9Sstevel@tonic-gate     ldi_handle_t *lhp, ldi_ident_t li)
15877c478bd9Sstevel@tonic-gate {
15887c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1589184cd04cScth 	int			ret;
15907c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
15937c478bd9Sstevel@tonic-gate 	if ((devp == NULL) || (!OTYP_VALID(otyp)) || (cr == NULL) ||
15947c478bd9Sstevel@tonic-gate 	    (lhp == NULL) || (lip == NULL))
15957c478bd9Sstevel@tonic-gate 		return (EINVAL);
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	if ((ret = ldi_vp_from_dev(*devp, otyp, &vp)) != 0)
16007c478bd9Sstevel@tonic-gate 		return (ret);
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	if ((ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip)) == 0) {
16037c478bd9Sstevel@tonic-gate 		*devp = vp->v_rdev;
16047c478bd9Sstevel@tonic-gate 	}
16057c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 	return (ret);
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate /* get a handle to a device by pathname */
16117c478bd9Sstevel@tonic-gate int
16127c478bd9Sstevel@tonic-gate ldi_open_by_name(char *pathname, int flag, cred_t *cr,
16137c478bd9Sstevel@tonic-gate     ldi_handle_t *lhp, ldi_ident_t li)
16147c478bd9Sstevel@tonic-gate {
16157c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip = (struct ldi_ident *)li;
1616184cd04cScth 	int			ret;
16177c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
16207c478bd9Sstevel@tonic-gate 	if ((pathname == NULL) || (*pathname != '/') ||
16217c478bd9Sstevel@tonic-gate 	    (cr == NULL) || (lhp == NULL) || (lip == NULL))
16227c478bd9Sstevel@tonic-gate 		return (EINVAL);
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	if ((ret = ldi_vp_from_name(pathname, &vp)) != 0)
16277c478bd9Sstevel@tonic-gate 		return (ret);
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
16307c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 	return (ret);
16337c478bd9Sstevel@tonic-gate }
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate /* get a handle to a device by devid and minor_name */
16367c478bd9Sstevel@tonic-gate int
16377c478bd9Sstevel@tonic-gate ldi_open_by_devid(ddi_devid_t devid, char *minor_name,
16387c478bd9Sstevel@tonic-gate     int flag, cred_t *cr, ldi_handle_t *lhp, ldi_ident_t li)
16397c478bd9Sstevel@tonic-gate {
16407c478bd9Sstevel@tonic-gate 	struct ldi_ident	*lip = (struct ldi_ident *)li;
16417c478bd9Sstevel@tonic-gate 	int			ret;
16427c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	/* sanity check required input parameters */
16457c478bd9Sstevel@tonic-gate 	if ((minor_name == NULL) || (cr == NULL) ||
16467c478bd9Sstevel@tonic-gate 	    (lhp == NULL) || (lip == NULL))
16477c478bd9Sstevel@tonic-gate 		return (EINVAL);
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
16507c478bd9Sstevel@tonic-gate 
16517c478bd9Sstevel@tonic-gate 	if ((ret = ldi_vp_from_devid(devid, minor_name, &vp)) != 0)
16527c478bd9Sstevel@tonic-gate 		return (ret);
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	ret = ldi_open_by_vp(&vp, flag, cr, lhp, lip);
16557c478bd9Sstevel@tonic-gate 	VN_RELE(vp);
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 	return (ret);
16587c478bd9Sstevel@tonic-gate }
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate int
16617c478bd9Sstevel@tonic-gate ldi_close(ldi_handle_t lh, int flag, cred_t *cr)
16627c478bd9Sstevel@tonic-gate {
16637c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
16647c478bd9Sstevel@tonic-gate 	struct ldi_event	*lep;
1665184cd04cScth 	int			err = 0;
166625e8c5aaSvikram 	int			notify = 0;
166725e8c5aaSvikram 	list_t			*listp;
166825e8c5aaSvikram 	ldi_ev_callback_impl_t	*lecp;
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	if (lh == NULL)
16717c478bd9Sstevel@tonic-gate 		return (EINVAL);
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
16747c478bd9Sstevel@tonic-gate 
167525e8c5aaSvikram #ifdef	LDI_OBSOLETE_EVENT
167625e8c5aaSvikram 
16777c478bd9Sstevel@tonic-gate 	/*
16787c478bd9Sstevel@tonic-gate 	 * Any event handlers should have been unregistered by the
16797c478bd9Sstevel@tonic-gate 	 * time ldi_close() is called.  If they haven't then it's a
16807c478bd9Sstevel@tonic-gate 	 * bug.
16817c478bd9Sstevel@tonic-gate 	 *
16827c478bd9Sstevel@tonic-gate 	 * In a debug kernel we'll panic to make the problem obvious.
16837c478bd9Sstevel@tonic-gate 	 */
16847c478bd9Sstevel@tonic-gate 	ASSERT(handlep->lh_events == NULL);
16857c478bd9Sstevel@tonic-gate 
16867c478bd9Sstevel@tonic-gate 	/*
16877c478bd9Sstevel@tonic-gate 	 * On a production kernel we'll "do the right thing" (unregister
16887c478bd9Sstevel@tonic-gate 	 * the event handlers) and then complain about having to do the
16897c478bd9Sstevel@tonic-gate 	 * work ourselves.
16907c478bd9Sstevel@tonic-gate 	 */
16917c478bd9Sstevel@tonic-gate 	while ((lep = handlep->lh_events) != NULL) {
16927c478bd9Sstevel@tonic-gate 		err = 1;
16937c478bd9Sstevel@tonic-gate 		(void) ldi_remove_event_handler(lh, (ldi_callback_id_t)lep);
16947c478bd9Sstevel@tonic-gate 	}
16957c478bd9Sstevel@tonic-gate 	if (err) {
16967c478bd9Sstevel@tonic-gate 		struct ldi_ident *lip = handlep->lh_ident;
16977c478bd9Sstevel@tonic-gate 		ASSERT(lip != NULL);
16987c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "ldi err: %s "
16997c478bd9Sstevel@tonic-gate 		    "failed to unregister layered event handlers before "
17007c478bd9Sstevel@tonic-gate 		    "closing devices", lip->li_modname);
17017c478bd9Sstevel@tonic-gate 	}
170225e8c5aaSvikram #endif
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	/* do a layered close on the device */
1705da6c28aaSamw 	err = VOP_CLOSE(handlep->lh_vp, flag | FKLYR, 1, (offset_t)0, cr, NULL);
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p", "ldi close", (void *)lh));
17087c478bd9Sstevel@tonic-gate 
170925e8c5aaSvikram 	/*
171025e8c5aaSvikram 	 * Search the event callback list for callbacks with this
171125e8c5aaSvikram 	 * handle. There are 2 cases
171225e8c5aaSvikram 	 * 1. Called in the context of a notify. The handle consumer
171325e8c5aaSvikram 	 *    is releasing its hold on the device to allow a reconfiguration
171425e8c5aaSvikram 	 *    of the device. Simply NULL out the handle and the notify callback.
171525e8c5aaSvikram 	 *    The finalize callback is still available so that the consumer
171625e8c5aaSvikram 	 *    knows of the final disposition of the device.
171725e8c5aaSvikram 	 * 2. Not called in the context of notify. NULL out the handle as well
171825e8c5aaSvikram 	 *    as the notify and finalize callbacks. Since the consumer has
171925e8c5aaSvikram 	 *    closed the handle, we assume it is not interested in the
172025e8c5aaSvikram 	 *    notify and finalize callbacks.
172125e8c5aaSvikram 	 */
172225e8c5aaSvikram 	ldi_ev_lock();
172325e8c5aaSvikram 
172425e8c5aaSvikram 	if (handlep->lh_flags & LH_FLAGS_NOTIFY)
172525e8c5aaSvikram 		notify = 1;
172625e8c5aaSvikram 	listp = &ldi_ev_callback_list.le_head;
172725e8c5aaSvikram 	for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
172825e8c5aaSvikram 		if (lecp->lec_lhp != handlep)
172925e8c5aaSvikram 			continue;
173025e8c5aaSvikram 		lecp->lec_lhp = NULL;
173125e8c5aaSvikram 		lecp->lec_notify = NULL;
173225e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_close: NULLed lh and notify"));
173325e8c5aaSvikram 		if (!notify) {
173425e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_close: NULLed finalize"));
173525e8c5aaSvikram 			lecp->lec_finalize = NULL;
173625e8c5aaSvikram 		}
173725e8c5aaSvikram 	}
173825e8c5aaSvikram 
173925e8c5aaSvikram 	if (notify)
174025e8c5aaSvikram 		handlep->lh_flags &= ~LH_FLAGS_NOTIFY;
174125e8c5aaSvikram 	ldi_ev_unlock();
174225e8c5aaSvikram 
17437c478bd9Sstevel@tonic-gate 	/*
17447c478bd9Sstevel@tonic-gate 	 * Free the handle even if the device close failed.  why?
17457c478bd9Sstevel@tonic-gate 	 *
17467c478bd9Sstevel@tonic-gate 	 * If the device close failed we can't really make assumptions
17477c478bd9Sstevel@tonic-gate 	 * about the devices state so we shouldn't allow access to the
17487c478bd9Sstevel@tonic-gate 	 * device via this handle any more.  If the device consumer wants
17497c478bd9Sstevel@tonic-gate 	 * to access the device again they should open it again.
17507c478bd9Sstevel@tonic-gate 	 *
17517c478bd9Sstevel@tonic-gate 	 * This is the same way file/device close failures are handled
17527c478bd9Sstevel@tonic-gate 	 * in other places like spec_close() and closeandsetf().
17537c478bd9Sstevel@tonic-gate 	 */
17547c478bd9Sstevel@tonic-gate 	handle_release(handlep);
17557c478bd9Sstevel@tonic-gate 	return (err);
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate int
17597c478bd9Sstevel@tonic-gate ldi_read(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
17607c478bd9Sstevel@tonic-gate {
17617c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
17627c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
17637c478bd9Sstevel@tonic-gate 	dev_t			dev;
17647c478bd9Sstevel@tonic-gate 	int			ret;
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 	if (lh == NULL)
17677c478bd9Sstevel@tonic-gate 		return (EINVAL);
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	vp = handlep->lh_vp;
17707c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
17717c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
17727c478bd9Sstevel@tonic-gate 		ret = cdev_read(dev, uiop, credp);
17737c478bd9Sstevel@tonic-gate 	} else if (handlep->lh_type & LH_STREAM) {
17747c478bd9Sstevel@tonic-gate 		ret = strread(vp, uiop, credp);
17757c478bd9Sstevel@tonic-gate 	} else {
17767c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
17777c478bd9Sstevel@tonic-gate 	}
17787c478bd9Sstevel@tonic-gate 	return (ret);
17797c478bd9Sstevel@tonic-gate }
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate int
17827c478bd9Sstevel@tonic-gate ldi_write(ldi_handle_t lh, struct uio *uiop, cred_t *credp)
17837c478bd9Sstevel@tonic-gate {
17847c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
17857c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
17867c478bd9Sstevel@tonic-gate 	dev_t			dev;
17877c478bd9Sstevel@tonic-gate 	int			ret;
17887c478bd9Sstevel@tonic-gate 
17897c478bd9Sstevel@tonic-gate 	if (lh == NULL)
17907c478bd9Sstevel@tonic-gate 		return (EINVAL);
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 	vp = handlep->lh_vp;
17937c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
17947c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
17957c478bd9Sstevel@tonic-gate 		ret = cdev_write(dev, uiop, credp);
17967c478bd9Sstevel@tonic-gate 	} else if (handlep->lh_type & LH_STREAM) {
17977c478bd9Sstevel@tonic-gate 		ret = strwrite(vp, uiop, credp);
17987c478bd9Sstevel@tonic-gate 	} else {
17997c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 	return (ret);
18027c478bd9Sstevel@tonic-gate }
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate int
18057c478bd9Sstevel@tonic-gate ldi_get_size(ldi_handle_t lh, uint64_t *sizep)
18067c478bd9Sstevel@tonic-gate {
1807184cd04cScth 	int			otyp;
18087c478bd9Sstevel@tonic-gate 	uint_t			value;
18097c478bd9Sstevel@tonic-gate 	int64_t			drv_prop64;
18107c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
1811184cd04cScth 	uint_t			blksize;
1812184cd04cScth 	int			blkshift;
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (sizep == NULL))
18167c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_STREAM)
18197c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	/*
18227c478bd9Sstevel@tonic-gate 	 * Determine device type (char or block).
18237c478bd9Sstevel@tonic-gate 	 * Character devices support Size/size
18247c478bd9Sstevel@tonic-gate 	 * property value. Block devices may support
18257c478bd9Sstevel@tonic-gate 	 * Nblocks/nblocks or Size/size property value.
18267c478bd9Sstevel@tonic-gate 	 */
18277c478bd9Sstevel@tonic-gate 	if ((ldi_get_otyp(lh, &otyp)) != 0)
18287c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	if (otyp == OTYP_BLK) {
18317c478bd9Sstevel@tonic-gate 		if (ldi_prop_exists(lh,
1832184cd04cScth 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Nblocks")) {
18337c478bd9Sstevel@tonic-gate 
18347c478bd9Sstevel@tonic-gate 			drv_prop64 = ldi_prop_get_int64(lh,
18357c478bd9Sstevel@tonic-gate 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
18367c478bd9Sstevel@tonic-gate 			    "Nblocks", 0);
1837184cd04cScth 			blksize = ldi_prop_get_int(lh,
1838184cd04cScth 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1839184cd04cScth 			    "blksize", DEV_BSIZE);
1840184cd04cScth 			if (blksize == DEV_BSIZE)
1841184cd04cScth 				blksize = ldi_prop_get_int(lh, LDI_DEV_T_ANY |
1842184cd04cScth 				    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1843184cd04cScth 				    "device-blksize", DEV_BSIZE);
1844184cd04cScth 
1845184cd04cScth 			/* blksize must be a power of two */
1846184cd04cScth 			ASSERT(BIT_ONLYONESET(blksize));
1847184cd04cScth 			blkshift = highbit(blksize) - 1;
1848184cd04cScth 
1849184cd04cScth 			/*
1850184cd04cScth 			 * We don't support Nblocks values that don't have
1851184cd04cScth 			 * an accurate uint64_t byte count representation.
1852184cd04cScth 			 */
1853184cd04cScth 			if ((uint64_t)drv_prop64 >= (UINT64_MAX >> blkshift))
1854184cd04cScth 				return (DDI_FAILURE);
1855184cd04cScth 
1856184cd04cScth 			*sizep = (uint64_t)
1857184cd04cScth 			    (((u_offset_t)drv_prop64) << blkshift);
18587c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
18597c478bd9Sstevel@tonic-gate 		}
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 		if (ldi_prop_exists(lh,
1862184cd04cScth 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "nblocks")) {
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate 			value = ldi_prop_get_int(lh,
18657c478bd9Sstevel@tonic-gate 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
18667c478bd9Sstevel@tonic-gate 			    "nblocks", 0);
1867184cd04cScth 			blksize = ldi_prop_get_int(lh,
1868184cd04cScth 			    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1869184cd04cScth 			    "blksize", DEV_BSIZE);
1870184cd04cScth 			if (blksize == DEV_BSIZE)
1871184cd04cScth 				blksize = ldi_prop_get_int(lh, LDI_DEV_T_ANY |
1872184cd04cScth 				    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
1873184cd04cScth 				    "device-blksize", DEV_BSIZE);
1874184cd04cScth 
1875184cd04cScth 			/* blksize must be a power of two */
1876184cd04cScth 			ASSERT(BIT_ONLYONESET(blksize));
1877184cd04cScth 			blkshift = highbit(blksize) - 1;
1878184cd04cScth 
1879184cd04cScth 			/*
1880184cd04cScth 			 * We don't support nblocks values that don't have an
1881184cd04cScth 			 * accurate uint64_t byte count representation.
1882184cd04cScth 			 */
1883184cd04cScth 			if ((uint64_t)value >= (UINT64_MAX >> blkshift))
1884184cd04cScth 				return (DDI_FAILURE);
1885184cd04cScth 
1886184cd04cScth 			*sizep = (uint64_t)
1887184cd04cScth 			    (((u_offset_t)value) << blkshift);
18887c478bd9Sstevel@tonic-gate 			return (DDI_SUCCESS);
18897c478bd9Sstevel@tonic-gate 		}
18907c478bd9Sstevel@tonic-gate 	}
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 	if (ldi_prop_exists(lh,
1893184cd04cScth 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size")) {
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 		drv_prop64 = ldi_prop_get_int64(lh,
18967c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "Size", 0);
18977c478bd9Sstevel@tonic-gate 		*sizep = (uint64_t)drv_prop64;
18987c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
18997c478bd9Sstevel@tonic-gate 	}
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	if (ldi_prop_exists(lh,
1902184cd04cScth 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size")) {
19037c478bd9Sstevel@tonic-gate 
19047c478bd9Sstevel@tonic-gate 		value = ldi_prop_get_int(lh,
19057c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "size", 0);
19067c478bd9Sstevel@tonic-gate 		*sizep = (uint64_t)value;
19077c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
19087c478bd9Sstevel@tonic-gate 	}
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 	/* unable to determine device size */
19117c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
19127c478bd9Sstevel@tonic-gate }
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate int
19157c478bd9Sstevel@tonic-gate ldi_ioctl(ldi_handle_t lh, int cmd, intptr_t arg, int mode,
19167c478bd9Sstevel@tonic-gate 	cred_t *cr, int *rvalp)
19177c478bd9Sstevel@tonic-gate {
19187c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
19197c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
19207c478bd9Sstevel@tonic-gate 	dev_t			dev;
19217c478bd9Sstevel@tonic-gate 	int			ret, copymode;
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	if (lh == NULL)
19247c478bd9Sstevel@tonic-gate 		return (EINVAL);
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 	/*
19277c478bd9Sstevel@tonic-gate 	 * if the data pointed to by arg is located in the kernel then
19287c478bd9Sstevel@tonic-gate 	 * make sure the FNATIVE flag is set.
19297c478bd9Sstevel@tonic-gate 	 */
19307c478bd9Sstevel@tonic-gate 	if (mode & FKIOCTL)
19317c478bd9Sstevel@tonic-gate 		mode = (mode & ~FMODELS) | FNATIVE | FKIOCTL;
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	vp = handlep->lh_vp;
19347c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
19357c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
19367c478bd9Sstevel@tonic-gate 		ret = cdev_ioctl(dev, cmd, arg, mode, cr, rvalp);
19377c478bd9Sstevel@tonic-gate 	} else if (handlep->lh_type & LH_STREAM) {
19387c478bd9Sstevel@tonic-gate 		copymode = (mode & FKIOCTL) ? K_TO_K : U_TO_K;
19397c478bd9Sstevel@tonic-gate 
19407c478bd9Sstevel@tonic-gate 		/*
19417c478bd9Sstevel@tonic-gate 		 * if we get an I_PLINK from within the kernel the
19427c478bd9Sstevel@tonic-gate 		 * arg is a layered handle pointer instead of
19437c478bd9Sstevel@tonic-gate 		 * a file descriptor, so we translate this ioctl
19447c478bd9Sstevel@tonic-gate 		 * into a private one that can handle this.
19457c478bd9Sstevel@tonic-gate 		 */
19467c478bd9Sstevel@tonic-gate 		if ((mode & FKIOCTL) && (cmd == I_PLINK))
19477c478bd9Sstevel@tonic-gate 			cmd = _I_PLINK_LH;
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate 		ret = strioctl(vp, cmd, arg, mode, copymode, cr, rvalp);
19507c478bd9Sstevel@tonic-gate 	} else {
19517c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
19527c478bd9Sstevel@tonic-gate 	}
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 	return (ret);
19557c478bd9Sstevel@tonic-gate }
19567c478bd9Sstevel@tonic-gate 
19577c478bd9Sstevel@tonic-gate int
19587c478bd9Sstevel@tonic-gate ldi_poll(ldi_handle_t lh, short events, int anyyet, short *reventsp,
19597c478bd9Sstevel@tonic-gate     struct pollhead **phpp)
19607c478bd9Sstevel@tonic-gate {
19617c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
19627c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
19637c478bd9Sstevel@tonic-gate 	dev_t			dev;
19647c478bd9Sstevel@tonic-gate 	int			ret;
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 	if (lh == NULL)
19677c478bd9Sstevel@tonic-gate 		return (EINVAL);
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate 	vp = handlep->lh_vp;
19707c478bd9Sstevel@tonic-gate 	dev = vp->v_rdev;
19717c478bd9Sstevel@tonic-gate 	if (handlep->lh_type & LH_CBDEV) {
19727c478bd9Sstevel@tonic-gate 		ret = cdev_poll(dev, events, anyyet, reventsp, phpp);
19737c478bd9Sstevel@tonic-gate 	} else if (handlep->lh_type & LH_STREAM) {
19747c478bd9Sstevel@tonic-gate 		ret = strpoll(vp->v_stream, events, anyyet, reventsp, phpp);
19757c478bd9Sstevel@tonic-gate 	} else {
19767c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
19777c478bd9Sstevel@tonic-gate 	}
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	return (ret);
19807c478bd9Sstevel@tonic-gate }
19817c478bd9Sstevel@tonic-gate 
19827c478bd9Sstevel@tonic-gate int
19837c478bd9Sstevel@tonic-gate ldi_prop_op(ldi_handle_t lh, ddi_prop_op_t prop_op,
19847c478bd9Sstevel@tonic-gate 	int flags, char *name, caddr_t valuep, int *length)
19857c478bd9Sstevel@tonic-gate {
19867c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
19877c478bd9Sstevel@tonic-gate 	dev_t			dev;
19887c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
19897c478bd9Sstevel@tonic-gate 	int			ret;
19907c478bd9Sstevel@tonic-gate 	struct snode		*csp;
19917c478bd9Sstevel@tonic-gate 
19927c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
19937c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	if ((prop_op != PROP_LEN) && (valuep == NULL))
19967c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 	if (length == NULL)
19997c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate 	/*
20027c478bd9Sstevel@tonic-gate 	 * try to find the associated dip,
20037c478bd9Sstevel@tonic-gate 	 * this places a hold on the driver
20047c478bd9Sstevel@tonic-gate 	 */
20057c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
20087c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
20097c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
20107c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
20117c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
20127c478bd9Sstevel@tonic-gate 	if (dip == NULL)
20137c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 	if (dip == NULL)
20167c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 	ret = i_ldi_prop_op(dev, dip, prop_op, flags, name, valuep, length);
20197c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
20207c478bd9Sstevel@tonic-gate 
20217c478bd9Sstevel@tonic-gate 	return (ret);
20227c478bd9Sstevel@tonic-gate }
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate int
20257c478bd9Sstevel@tonic-gate ldi_strategy(ldi_handle_t lh, struct buf *bp)
20267c478bd9Sstevel@tonic-gate {
20277c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20287c478bd9Sstevel@tonic-gate 	dev_t			dev;
20297c478bd9Sstevel@tonic-gate 
20307c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (bp == NULL))
20317c478bd9Sstevel@tonic-gate 		return (EINVAL);
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
20347c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
20357c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
20367c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 	bp->b_edev = dev;
20397c478bd9Sstevel@tonic-gate 	bp->b_dev = cmpdev(dev);
20407c478bd9Sstevel@tonic-gate 	return (bdev_strategy(bp));
20417c478bd9Sstevel@tonic-gate }
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate int
20447c478bd9Sstevel@tonic-gate ldi_dump(ldi_handle_t lh, caddr_t addr, daddr_t blkno, int nblk)
20457c478bd9Sstevel@tonic-gate {
20467c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20477c478bd9Sstevel@tonic-gate 	dev_t			dev;
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 	if (lh == NULL)
20507c478bd9Sstevel@tonic-gate 		return (EINVAL);
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
20537c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
20547c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
20557c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	return (bdev_dump(dev, addr, blkno, nblk));
20587c478bd9Sstevel@tonic-gate }
20597c478bd9Sstevel@tonic-gate 
20607c478bd9Sstevel@tonic-gate int
20617c478bd9Sstevel@tonic-gate ldi_devmap(ldi_handle_t lh, devmap_cookie_t dhp, offset_t off,
20627c478bd9Sstevel@tonic-gate     size_t len, size_t *maplen, uint_t model)
20637c478bd9Sstevel@tonic-gate {
20647c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20657c478bd9Sstevel@tonic-gate 	dev_t			dev;
20667c478bd9Sstevel@tonic-gate 
20677c478bd9Sstevel@tonic-gate 	if (lh == NULL)
20687c478bd9Sstevel@tonic-gate 		return (EINVAL);
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
20717c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
20727c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
20737c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 	return (cdev_devmap(dev, dhp, off, len, maplen, model));
20767c478bd9Sstevel@tonic-gate }
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate int
20797c478bd9Sstevel@tonic-gate ldi_aread(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
20807c478bd9Sstevel@tonic-gate {
20817c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
20827c478bd9Sstevel@tonic-gate 	dev_t			dev;
20837c478bd9Sstevel@tonic-gate 	struct cb_ops		*cb;
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate 	if (lh == NULL)
20867c478bd9Sstevel@tonic-gate 		return (EINVAL);
20877c478bd9Sstevel@tonic-gate 
20887c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
20897c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
20907c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20917c478bd9Sstevel@tonic-gate 
20927c478bd9Sstevel@tonic-gate 	/*
20937c478bd9Sstevel@tonic-gate 	 * Kaio is only supported on block devices.
20947c478bd9Sstevel@tonic-gate 	 */
20957c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
20967c478bd9Sstevel@tonic-gate 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
20977c478bd9Sstevel@tonic-gate 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
20987c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 	if (cb->cb_aread == NULL)
21017c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate 	return (cb->cb_aread(dev, aio_reqp, cr));
21047c478bd9Sstevel@tonic-gate }
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate int
21077c478bd9Sstevel@tonic-gate ldi_awrite(ldi_handle_t lh, struct aio_req *aio_reqp, cred_t *cr)
21087c478bd9Sstevel@tonic-gate {
21097c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21107c478bd9Sstevel@tonic-gate 	struct cb_ops		*cb;
21117c478bd9Sstevel@tonic-gate 	dev_t			dev;
21127c478bd9Sstevel@tonic-gate 
21137c478bd9Sstevel@tonic-gate 	if (lh == NULL)
21147c478bd9Sstevel@tonic-gate 		return (EINVAL);
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	/* this entry point is only supported for cb devices */
21177c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_CBDEV))
21187c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	/*
21217c478bd9Sstevel@tonic-gate 	 * Kaio is only supported on block devices.
21227c478bd9Sstevel@tonic-gate 	 */
21237c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
21247c478bd9Sstevel@tonic-gate 	cb = devopsp[getmajor(dev)]->devo_cb_ops;
21257c478bd9Sstevel@tonic-gate 	if (cb->cb_strategy == nodev || cb->cb_strategy == NULL)
21267c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	if (cb->cb_awrite == NULL)
21297c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21307c478bd9Sstevel@tonic-gate 
21317c478bd9Sstevel@tonic-gate 	return (cb->cb_awrite(dev, aio_reqp, cr));
21327c478bd9Sstevel@tonic-gate }
21337c478bd9Sstevel@tonic-gate 
21347c478bd9Sstevel@tonic-gate int
21357c478bd9Sstevel@tonic-gate ldi_putmsg(ldi_handle_t lh, mblk_t *smp)
21367c478bd9Sstevel@tonic-gate {
21377c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21387c478bd9Sstevel@tonic-gate 	int			ret;
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (smp == NULL))
21417c478bd9Sstevel@tonic-gate 		return (EINVAL);
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_STREAM)) {
21447c478bd9Sstevel@tonic-gate 		freemsg(smp);
21457c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21467c478bd9Sstevel@tonic-gate 	}
21477c478bd9Sstevel@tonic-gate 
2148de8c4a14SErik Nordmark 	/*
2149de8c4a14SErik Nordmark 	 * If we don't have db_credp, set it. Note that we can not be called
2150de8c4a14SErik Nordmark 	 * from interrupt context.
2151de8c4a14SErik Nordmark 	 */
2152de8c4a14SErik Nordmark 	if (msg_getcred(smp, NULL) == NULL)
2153de8c4a14SErik Nordmark 		mblk_setcred(smp, CRED(), curproc->p_pid);
2154de8c4a14SErik Nordmark 
21557c478bd9Sstevel@tonic-gate 	/* Send message while honoring flow control */
21567c478bd9Sstevel@tonic-gate 	ret = kstrputmsg(handlep->lh_vp, smp, NULL, 0, 0,
2157184cd04cScth 	    MSG_BAND | MSG_HOLDSIG | MSG_IGNERROR, 0);
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	return (ret);
21607c478bd9Sstevel@tonic-gate }
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate int
21637c478bd9Sstevel@tonic-gate ldi_getmsg(ldi_handle_t lh, mblk_t **rmp, timestruc_t *timeo)
21647c478bd9Sstevel@tonic-gate {
21657c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21667c478bd9Sstevel@tonic-gate 	clock_t			timout; /* milliseconds */
21677c478bd9Sstevel@tonic-gate 	uchar_t			pri;
21687c478bd9Sstevel@tonic-gate 	rval_t			rval;
21697c478bd9Sstevel@tonic-gate 	int			ret, pflag;
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	if (lh == NULL)
21737c478bd9Sstevel@tonic-gate 		return (EINVAL);
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	if (!(handlep->lh_type & LH_STREAM))
21767c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
21777c478bd9Sstevel@tonic-gate 
21787c478bd9Sstevel@tonic-gate 	/* Convert from nanoseconds to milliseconds */
21797c478bd9Sstevel@tonic-gate 	if (timeo != NULL) {
21807c478bd9Sstevel@tonic-gate 		timout = timeo->tv_sec * 1000 + timeo->tv_nsec / 1000000;
21817c478bd9Sstevel@tonic-gate 		if (timout > INT_MAX)
21827c478bd9Sstevel@tonic-gate 			return (EINVAL);
21837c478bd9Sstevel@tonic-gate 	} else
21847c478bd9Sstevel@tonic-gate 		timout = -1;
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	/* Wait for timeout millseconds for a message */
21877c478bd9Sstevel@tonic-gate 	pflag = MSG_ANY;
21887c478bd9Sstevel@tonic-gate 	pri = 0;
21897c478bd9Sstevel@tonic-gate 	*rmp = NULL;
21907c478bd9Sstevel@tonic-gate 	ret = kstrgetmsg(handlep->lh_vp,
2191184cd04cScth 	    rmp, NULL, &pri, &pflag, timout, &rval);
21927c478bd9Sstevel@tonic-gate 	return (ret);
21937c478bd9Sstevel@tonic-gate }
21947c478bd9Sstevel@tonic-gate 
21957c478bd9Sstevel@tonic-gate int
21967c478bd9Sstevel@tonic-gate ldi_get_dev(ldi_handle_t lh, dev_t *devp)
21977c478bd9Sstevel@tonic-gate {
21987c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (devp == NULL))
22017c478bd9Sstevel@tonic-gate 		return (EINVAL);
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 	*devp = handlep->lh_vp->v_rdev;
22047c478bd9Sstevel@tonic-gate 	return (0);
22057c478bd9Sstevel@tonic-gate }
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate int
22087c478bd9Sstevel@tonic-gate ldi_get_otyp(ldi_handle_t lh, int *otyp)
22097c478bd9Sstevel@tonic-gate {
22107c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (otyp == NULL))
22137c478bd9Sstevel@tonic-gate 		return (EINVAL);
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	*otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
22167c478bd9Sstevel@tonic-gate 	return (0);
22177c478bd9Sstevel@tonic-gate }
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate int
22207c478bd9Sstevel@tonic-gate ldi_get_devid(ldi_handle_t lh, ddi_devid_t *devid)
22217c478bd9Sstevel@tonic-gate {
22227c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
22237c478bd9Sstevel@tonic-gate 	int			ret;
22247c478bd9Sstevel@tonic-gate 	dev_t			dev;
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (devid == NULL))
22277c478bd9Sstevel@tonic-gate 		return (EINVAL);
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 	ret = ddi_lyr_get_devid(dev, devid);
22327c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
22337c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
22347c478bd9Sstevel@tonic-gate 
22357c478bd9Sstevel@tonic-gate 	return (0);
22367c478bd9Sstevel@tonic-gate }
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate int
22397c478bd9Sstevel@tonic-gate ldi_get_minor_name(ldi_handle_t lh, char **minor_name)
22407c478bd9Sstevel@tonic-gate {
22417c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
22427c478bd9Sstevel@tonic-gate 	int			ret, otyp;
22437c478bd9Sstevel@tonic-gate 	dev_t			dev;
22447c478bd9Sstevel@tonic-gate 
22457c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (minor_name == NULL))
22467c478bd9Sstevel@tonic-gate 		return (EINVAL);
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
22497c478bd9Sstevel@tonic-gate 	otyp = VTYP_TO_OTYP(handlep->lh_vp->v_type);
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	ret = ddi_lyr_get_minor_name(dev, OTYP_TO_STYP(otyp), minor_name);
22527c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS)
22537c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 	return (0);
22567c478bd9Sstevel@tonic-gate }
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate int
22597c478bd9Sstevel@tonic-gate ldi_prop_lookup_int_array(ldi_handle_t lh,
22607c478bd9Sstevel@tonic-gate     uint_t flags, char *name, int **data, uint_t *nelements)
22617c478bd9Sstevel@tonic-gate {
22627c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
22637c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
22647c478bd9Sstevel@tonic-gate 	dev_t			dev;
22657c478bd9Sstevel@tonic-gate 	int			res;
22667c478bd9Sstevel@tonic-gate 	struct snode		*csp;
22677c478bd9Sstevel@tonic-gate 
22687c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
22697c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
22747c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
22757c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
22767c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
22777c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
22787c478bd9Sstevel@tonic-gate 	if (dip == NULL)
22797c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
22807c478bd9Sstevel@tonic-gate 
22817c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
22827c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
22837c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
22847c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
22857c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
22867c478bd9Sstevel@tonic-gate 	}
22877c478bd9Sstevel@tonic-gate 
22887c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
22897c478bd9Sstevel@tonic-gate 		int *prop_val, prop_len;
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
22927c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, sizeof (int));
22937c478bd9Sstevel@tonic-gate 
22947c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
22957c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
22967c478bd9Sstevel@tonic-gate 			*nelements = prop_len / sizeof (int);
22977c478bd9Sstevel@tonic-gate 			*data = prop_val;
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
23007c478bd9Sstevel@tonic-gate 			return (res);
23017c478bd9Sstevel@tonic-gate 		}
23027c478bd9Sstevel@tonic-gate 	}
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
23057c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_int_array(dev, dip, flags,
23067c478bd9Sstevel@tonic-gate 	    name, data, nelements);
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate 	if (dip != NULL)
23097c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
23107c478bd9Sstevel@tonic-gate 
23117c478bd9Sstevel@tonic-gate 	return (res);
23127c478bd9Sstevel@tonic-gate }
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate int
23157c478bd9Sstevel@tonic-gate ldi_prop_lookup_int64_array(ldi_handle_t lh,
23167c478bd9Sstevel@tonic-gate     uint_t flags, char *name, int64_t **data, uint_t *nelements)
23177c478bd9Sstevel@tonic-gate {
23187c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
23197c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
23207c478bd9Sstevel@tonic-gate 	dev_t			dev;
23217c478bd9Sstevel@tonic-gate 	int			res;
23227c478bd9Sstevel@tonic-gate 	struct snode		*csp;
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
23257c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
23267c478bd9Sstevel@tonic-gate 
23277c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
23307c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
23317c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
23327c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
23337c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
23347c478bd9Sstevel@tonic-gate 	if (dip == NULL)
23357c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
23387c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
23397c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
23407c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
23417c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
23427c478bd9Sstevel@tonic-gate 	}
23437c478bd9Sstevel@tonic-gate 
23447c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
23457c478bd9Sstevel@tonic-gate 		int64_t	*prop_val;
23467c478bd9Sstevel@tonic-gate 		int	prop_len;
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
23497c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, sizeof (int64_t));
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
23527c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
23537c478bd9Sstevel@tonic-gate 			*nelements = prop_len / sizeof (int64_t);
23547c478bd9Sstevel@tonic-gate 			*data = prop_val;
23557c478bd9Sstevel@tonic-gate 
23567c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
23577c478bd9Sstevel@tonic-gate 			return (res);
23587c478bd9Sstevel@tonic-gate 		}
23597c478bd9Sstevel@tonic-gate 	}
23607c478bd9Sstevel@tonic-gate 
23617c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
23627c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_int64_array(dev, dip, flags,
23637c478bd9Sstevel@tonic-gate 	    name, data, nelements);
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 	if (dip != NULL)
23667c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	return (res);
23697c478bd9Sstevel@tonic-gate }
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate int
23727c478bd9Sstevel@tonic-gate ldi_prop_lookup_string_array(ldi_handle_t lh,
23737c478bd9Sstevel@tonic-gate     uint_t flags, char *name, char ***data, uint_t *nelements)
23747c478bd9Sstevel@tonic-gate {
23757c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
23767c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
23777c478bd9Sstevel@tonic-gate 	dev_t			dev;
23787c478bd9Sstevel@tonic-gate 	int			res;
23797c478bd9Sstevel@tonic-gate 	struct snode		*csp;
23807c478bd9Sstevel@tonic-gate 
23817c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
23827c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
23837c478bd9Sstevel@tonic-gate 
23847c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
23877c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
23887c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
23897c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
23907c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
23917c478bd9Sstevel@tonic-gate 	if (dip == NULL)
23927c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
23937c478bd9Sstevel@tonic-gate 
23947c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
23957c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
23967c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
23977c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
23987c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
23997c478bd9Sstevel@tonic-gate 	}
24007c478bd9Sstevel@tonic-gate 
24017c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
24027c478bd9Sstevel@tonic-gate 		char	*prop_val;
24037c478bd9Sstevel@tonic-gate 		int	prop_len;
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
24067c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, 0);
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
24097c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
24107c478bd9Sstevel@tonic-gate 			char	**str_array;
24117c478bd9Sstevel@tonic-gate 			int	nelem;
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 			/*
24147c478bd9Sstevel@tonic-gate 			 * pack the returned string array into the format
24157c478bd9Sstevel@tonic-gate 			 * our callers expect
24167c478bd9Sstevel@tonic-gate 			 */
24177c478bd9Sstevel@tonic-gate 			if (i_pack_string_array(prop_val, prop_len,
2418184cd04cScth 			    &str_array, &nelem) == 0) {
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate 				*data = str_array;
24217c478bd9Sstevel@tonic-gate 				*nelements = nelem;
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate 				ddi_prop_free(prop_val);
24247c478bd9Sstevel@tonic-gate 				ddi_release_devi(dip);
24257c478bd9Sstevel@tonic-gate 				return (res);
24267c478bd9Sstevel@tonic-gate 			}
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate 			/*
24297c478bd9Sstevel@tonic-gate 			 * the format of the returned property must have
24307c478bd9Sstevel@tonic-gate 			 * been bad so throw it out
24317c478bd9Sstevel@tonic-gate 			 */
24327c478bd9Sstevel@tonic-gate 			ddi_prop_free(prop_val);
24337c478bd9Sstevel@tonic-gate 		}
24347c478bd9Sstevel@tonic-gate 	}
24357c478bd9Sstevel@tonic-gate 
24367c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
24377c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_string_array(dev, dip, flags,
24387c478bd9Sstevel@tonic-gate 	    name, data, nelements);
24397c478bd9Sstevel@tonic-gate 
24407c478bd9Sstevel@tonic-gate 	if (dip != NULL)
24417c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	return (res);
24447c478bd9Sstevel@tonic-gate }
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate int
24477c478bd9Sstevel@tonic-gate ldi_prop_lookup_string(ldi_handle_t lh,
24487c478bd9Sstevel@tonic-gate     uint_t flags, char *name, char **data)
24497c478bd9Sstevel@tonic-gate {
24507c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
24517c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
24527c478bd9Sstevel@tonic-gate 	dev_t			dev;
24537c478bd9Sstevel@tonic-gate 	int			res;
24547c478bd9Sstevel@tonic-gate 	struct snode		*csp;
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
24577c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
24627c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
24637c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
24647c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
24657c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
24667c478bd9Sstevel@tonic-gate 	if (dip == NULL)
24677c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
24707c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
24717c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
24727c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
24737c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
24747c478bd9Sstevel@tonic-gate 	}
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
24777c478bd9Sstevel@tonic-gate 		char	*prop_val;
24787c478bd9Sstevel@tonic-gate 		int	prop_len;
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
24817c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, 0);
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
24847c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
24857c478bd9Sstevel@tonic-gate 			/*
24867c478bd9Sstevel@tonic-gate 			 * sanity check the vaule returned.
24877c478bd9Sstevel@tonic-gate 			 */
24887c478bd9Sstevel@tonic-gate 			if (i_check_string(prop_val, prop_len)) {
24897c478bd9Sstevel@tonic-gate 				ddi_prop_free(prop_val);
24907c478bd9Sstevel@tonic-gate 			} else {
24917c478bd9Sstevel@tonic-gate 				*data = prop_val;
24927c478bd9Sstevel@tonic-gate 				ddi_release_devi(dip);
24937c478bd9Sstevel@tonic-gate 				return (res);
24947c478bd9Sstevel@tonic-gate 			}
24957c478bd9Sstevel@tonic-gate 		}
24967c478bd9Sstevel@tonic-gate 	}
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
24997c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_string(dev, dip, flags, name, data);
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 	if (dip != NULL)
25027c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate #ifdef DEBUG
25057c478bd9Sstevel@tonic-gate 	if (res == DDI_PROP_SUCCESS) {
25067c478bd9Sstevel@tonic-gate 		/*
25077c478bd9Sstevel@tonic-gate 		 * keep ourselves honest
25087c478bd9Sstevel@tonic-gate 		 * make sure the framework returns strings in the
25097c478bd9Sstevel@tonic-gate 		 * same format as we're demanding from drivers.
25107c478bd9Sstevel@tonic-gate 		 */
25117c478bd9Sstevel@tonic-gate 		struct prop_driver_data	*pdd;
25127c478bd9Sstevel@tonic-gate 		int			pdd_prop_size;
25137c478bd9Sstevel@tonic-gate 
25147c478bd9Sstevel@tonic-gate 		pdd = ((struct prop_driver_data *)(*data)) - 1;
25157c478bd9Sstevel@tonic-gate 		pdd_prop_size = pdd->pdd_size -
25167c478bd9Sstevel@tonic-gate 		    sizeof (struct prop_driver_data);
25177c478bd9Sstevel@tonic-gate 		ASSERT(i_check_string(*data, pdd_prop_size) == 0);
25187c478bd9Sstevel@tonic-gate 	}
25197c478bd9Sstevel@tonic-gate #endif /* DEBUG */
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate 	return (res);
25227c478bd9Sstevel@tonic-gate }
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate int
25257c478bd9Sstevel@tonic-gate ldi_prop_lookup_byte_array(ldi_handle_t lh,
25267c478bd9Sstevel@tonic-gate     uint_t flags, char *name, uchar_t **data, uint_t *nelements)
25277c478bd9Sstevel@tonic-gate {
25287c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
25297c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
25307c478bd9Sstevel@tonic-gate 	dev_t			dev;
25317c478bd9Sstevel@tonic-gate 	int			res;
25327c478bd9Sstevel@tonic-gate 	struct snode		*csp;
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
25357c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
25387c478bd9Sstevel@tonic-gate 
25397c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
25407c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
25417c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
25427c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
25437c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
25447c478bd9Sstevel@tonic-gate 	if (dip == NULL)
25457c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
25487c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
25497c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
25507c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
25517c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
25527c478bd9Sstevel@tonic-gate 	}
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
25557c478bd9Sstevel@tonic-gate 		uchar_t	*prop_val;
25567c478bd9Sstevel@tonic-gate 		int	prop_len;
25577c478bd9Sstevel@tonic-gate 
25587c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op_typed(dev, dip, flags, name,
25597c478bd9Sstevel@tonic-gate 		    (caddr_t *)&prop_val, &prop_len, sizeof (uchar_t));
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
25627c478bd9Sstevel@tonic-gate 		if (res == DDI_PROP_SUCCESS) {
25637c478bd9Sstevel@tonic-gate 			*nelements = prop_len / sizeof (uchar_t);
25647c478bd9Sstevel@tonic-gate 			*data = prop_val;
25657c478bd9Sstevel@tonic-gate 
25667c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
25677c478bd9Sstevel@tonic-gate 			return (res);
25687c478bd9Sstevel@tonic-gate 		}
25697c478bd9Sstevel@tonic-gate 	}
25707c478bd9Sstevel@tonic-gate 
25717c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
25727c478bd9Sstevel@tonic-gate 	res = ddi_prop_lookup_byte_array(dev, dip, flags,
25737c478bd9Sstevel@tonic-gate 	    name, data, nelements);
25747c478bd9Sstevel@tonic-gate 
25757c478bd9Sstevel@tonic-gate 	if (dip != NULL)
25767c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	return (res);
25797c478bd9Sstevel@tonic-gate }
25807c478bd9Sstevel@tonic-gate 
25817c478bd9Sstevel@tonic-gate int
25827c478bd9Sstevel@tonic-gate ldi_prop_get_int(ldi_handle_t lh,
25837c478bd9Sstevel@tonic-gate     uint_t flags, char *name, int defvalue)
25847c478bd9Sstevel@tonic-gate {
25857c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
25867c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
25877c478bd9Sstevel@tonic-gate 	dev_t			dev;
25887c478bd9Sstevel@tonic-gate 	int			res;
25897c478bd9Sstevel@tonic-gate 	struct snode		*csp;
25907c478bd9Sstevel@tonic-gate 
25917c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
25927c478bd9Sstevel@tonic-gate 		return (defvalue);
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
25977c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
25987c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
25997c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
26007c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
26017c478bd9Sstevel@tonic-gate 	if (dip == NULL)
26027c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
26057c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
26067c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
26077c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
26087c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
26097c478bd9Sstevel@tonic-gate 	}
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
26127c478bd9Sstevel@tonic-gate 		int	prop_val;
26137c478bd9Sstevel@tonic-gate 		int	prop_len;
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 		/*
26167c478bd9Sstevel@tonic-gate 		 * first call the drivers prop_op interface to allow it
26177c478bd9Sstevel@tonic-gate 		 * it to override default property values.
26187c478bd9Sstevel@tonic-gate 		 */
26197c478bd9Sstevel@tonic-gate 		prop_len = sizeof (int);
26207c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
26217c478bd9Sstevel@tonic-gate 		    flags | DDI_PROP_DYNAMIC, name,
26227c478bd9Sstevel@tonic-gate 		    (caddr_t)&prop_val, &prop_len);
26237c478bd9Sstevel@tonic-gate 
26247c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
26257c478bd9Sstevel@tonic-gate 		if ((res == DDI_PROP_SUCCESS) &&
26267c478bd9Sstevel@tonic-gate 		    (prop_len == sizeof (int))) {
26277c478bd9Sstevel@tonic-gate 			res = prop_val;
26287c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
26297c478bd9Sstevel@tonic-gate 			return (res);
26307c478bd9Sstevel@tonic-gate 		}
26317c478bd9Sstevel@tonic-gate 	}
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
26347c478bd9Sstevel@tonic-gate 	res = ddi_prop_get_int(dev, dip, flags, name, defvalue);
26357c478bd9Sstevel@tonic-gate 
26367c478bd9Sstevel@tonic-gate 	if (dip != NULL)
26377c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 	return (res);
26407c478bd9Sstevel@tonic-gate }
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate int64_t
26437c478bd9Sstevel@tonic-gate ldi_prop_get_int64(ldi_handle_t lh,
26447c478bd9Sstevel@tonic-gate     uint_t flags, char *name, int64_t defvalue)
26457c478bd9Sstevel@tonic-gate {
26467c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
26477c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
26487c478bd9Sstevel@tonic-gate 	dev_t			dev;
26497c478bd9Sstevel@tonic-gate 	int64_t			res;
26507c478bd9Sstevel@tonic-gate 	struct snode		*csp;
26517c478bd9Sstevel@tonic-gate 
26527c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
26537c478bd9Sstevel@tonic-gate 		return (defvalue);
26547c478bd9Sstevel@tonic-gate 
26557c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
26587c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
26597c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
26607c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
26617c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
26627c478bd9Sstevel@tonic-gate 	if (dip == NULL)
26637c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
26647c478bd9Sstevel@tonic-gate 
26657c478bd9Sstevel@tonic-gate 	if (dip == NULL) {
26667c478bd9Sstevel@tonic-gate 		flags |= DDI_UNBND_DLPI2;
26677c478bd9Sstevel@tonic-gate 	} else if (flags & LDI_DEV_T_ANY) {
26687c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
26697c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
26707c478bd9Sstevel@tonic-gate 	}
26717c478bd9Sstevel@tonic-gate 
26727c478bd9Sstevel@tonic-gate 	if (dip != NULL) {
26737c478bd9Sstevel@tonic-gate 		int64_t	prop_val;
26747c478bd9Sstevel@tonic-gate 		int	prop_len;
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 		/*
26777c478bd9Sstevel@tonic-gate 		 * first call the drivers prop_op interface to allow it
26787c478bd9Sstevel@tonic-gate 		 * it to override default property values.
26797c478bd9Sstevel@tonic-gate 		 */
26807c478bd9Sstevel@tonic-gate 		prop_len = sizeof (int64_t);
26817c478bd9Sstevel@tonic-gate 		res = i_ldi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
26827c478bd9Sstevel@tonic-gate 		    flags | DDI_PROP_DYNAMIC, name,
26837c478bd9Sstevel@tonic-gate 		    (caddr_t)&prop_val, &prop_len);
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 		/* if we got it then return it */
26867c478bd9Sstevel@tonic-gate 		if ((res == DDI_PROP_SUCCESS) &&
26877c478bd9Sstevel@tonic-gate 		    (prop_len == sizeof (int64_t))) {
26887c478bd9Sstevel@tonic-gate 			res = prop_val;
26897c478bd9Sstevel@tonic-gate 			ddi_release_devi(dip);
26907c478bd9Sstevel@tonic-gate 			return (res);
26917c478bd9Sstevel@tonic-gate 		}
26927c478bd9Sstevel@tonic-gate 	}
26937c478bd9Sstevel@tonic-gate 
26947c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
26957c478bd9Sstevel@tonic-gate 	res = ddi_prop_get_int64(dev, dip, flags, name, defvalue);
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate 	if (dip != NULL)
26987c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
26997c478bd9Sstevel@tonic-gate 
27007c478bd9Sstevel@tonic-gate 	return (res);
27017c478bd9Sstevel@tonic-gate }
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate int
27047c478bd9Sstevel@tonic-gate ldi_prop_exists(ldi_handle_t lh, uint_t flags, char *name)
27057c478bd9Sstevel@tonic-gate {
27067c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
2707184cd04cScth 	dev_info_t		*dip;
2708184cd04cScth 	dev_t			dev;
27097c478bd9Sstevel@tonic-gate 	int			res, prop_len;
27107c478bd9Sstevel@tonic-gate 	struct snode		*csp;
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) || (strlen(name) == 0))
27137c478bd9Sstevel@tonic-gate 		return (0);
27147c478bd9Sstevel@tonic-gate 
27157c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
27187c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
27197c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
27207c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
27217c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
27227c478bd9Sstevel@tonic-gate 	if (dip == NULL)
27237c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
27247c478bd9Sstevel@tonic-gate 
27257c478bd9Sstevel@tonic-gate 	/* if NULL dip, prop does NOT exist */
27267c478bd9Sstevel@tonic-gate 	if (dip == NULL)
27277c478bd9Sstevel@tonic-gate 		return (0);
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate 	if (flags & LDI_DEV_T_ANY) {
27307c478bd9Sstevel@tonic-gate 		flags &= ~LDI_DEV_T_ANY;
27317c478bd9Sstevel@tonic-gate 		dev = DDI_DEV_T_ANY;
27327c478bd9Sstevel@tonic-gate 	}
27337c478bd9Sstevel@tonic-gate 
27347c478bd9Sstevel@tonic-gate 	/*
27357c478bd9Sstevel@tonic-gate 	 * first call the drivers prop_op interface to allow it
27367c478bd9Sstevel@tonic-gate 	 * it to override default property values.
27377c478bd9Sstevel@tonic-gate 	 */
27387c478bd9Sstevel@tonic-gate 	res = i_ldi_prop_op(dev, dip, PROP_LEN,
27397c478bd9Sstevel@tonic-gate 	    flags | DDI_PROP_DYNAMIC, name, NULL, &prop_len);
27407c478bd9Sstevel@tonic-gate 
27417c478bd9Sstevel@tonic-gate 	if (res == DDI_PROP_SUCCESS) {
27427c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
27437c478bd9Sstevel@tonic-gate 		return (1);
27447c478bd9Sstevel@tonic-gate 	}
27457c478bd9Sstevel@tonic-gate 
27467c478bd9Sstevel@tonic-gate 	/* call the normal property interfaces */
27477c478bd9Sstevel@tonic-gate 	res = ddi_prop_exists(dev, dip, flags, name);
27487c478bd9Sstevel@tonic-gate 
27497c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
27507c478bd9Sstevel@tonic-gate 	return (res);
27517c478bd9Sstevel@tonic-gate }
27527c478bd9Sstevel@tonic-gate 
275325e8c5aaSvikram #ifdef	LDI_OBSOLETE_EVENT
275425e8c5aaSvikram 
27557c478bd9Sstevel@tonic-gate int
27567c478bd9Sstevel@tonic-gate ldi_get_eventcookie(ldi_handle_t lh, char *name, ddi_eventcookie_t *ecp)
27577c478bd9Sstevel@tonic-gate {
27587c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
27597c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
27607c478bd9Sstevel@tonic-gate 	dev_t			dev;
27617c478bd9Sstevel@tonic-gate 	int			res;
27627c478bd9Sstevel@tonic-gate 	struct snode		*csp;
27637c478bd9Sstevel@tonic-gate 
27647c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (name == NULL) ||
27657c478bd9Sstevel@tonic-gate 	    (strlen(name) == 0) || (ecp == NULL)) {
27667c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27677c478bd9Sstevel@tonic-gate 	}
27687c478bd9Sstevel@tonic-gate 
27697c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
27707c478bd9Sstevel@tonic-gate 
27717c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
27727c478bd9Sstevel@tonic-gate 
27737c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
27747c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
27757c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
27767c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
27777c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
27787c478bd9Sstevel@tonic-gate 	if (dip == NULL)
27797c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 	if (dip == NULL)
27827c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	LDI_EVENTCB((CE_NOTE, "%s: event_name=%s, "
27857c478bd9Sstevel@tonic-gate 	    "dip=0x%p, event_cookiep=0x%p", "ldi_get_eventcookie",
27867c478bd9Sstevel@tonic-gate 	    name, (void *)dip, (void *)ecp));
27877c478bd9Sstevel@tonic-gate 
27887c478bd9Sstevel@tonic-gate 	res = ddi_get_eventcookie(dip, name, ecp);
27897c478bd9Sstevel@tonic-gate 
27907c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
27917c478bd9Sstevel@tonic-gate 	return (res);
27927c478bd9Sstevel@tonic-gate }
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate int
27957c478bd9Sstevel@tonic-gate ldi_add_event_handler(ldi_handle_t lh, ddi_eventcookie_t ec,
27967c478bd9Sstevel@tonic-gate     void (*handler)(ldi_handle_t, ddi_eventcookie_t, void *, void *),
27977c478bd9Sstevel@tonic-gate     void *arg, ldi_callback_id_t *id)
27987c478bd9Sstevel@tonic-gate {
27997c478bd9Sstevel@tonic-gate 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
28007c478bd9Sstevel@tonic-gate 	struct ldi_event	*lep;
28017c478bd9Sstevel@tonic-gate 	dev_info_t		*dip;
28027c478bd9Sstevel@tonic-gate 	dev_t			dev;
28037c478bd9Sstevel@tonic-gate 	int			res;
28047c478bd9Sstevel@tonic-gate 	struct snode		*csp;
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (ec == NULL) || (handler == NULL) || (id == NULL))
28077c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
28087c478bd9Sstevel@tonic-gate 
28097c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
28107c478bd9Sstevel@tonic-gate 
28117c478bd9Sstevel@tonic-gate 	dev = handlep->lh_vp->v_rdev;
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate 	csp = VTOCS(handlep->lh_vp);
28147c478bd9Sstevel@tonic-gate 	mutex_enter(&csp->s_lock);
28157c478bd9Sstevel@tonic-gate 	if ((dip = csp->s_dip) != NULL)
28167c478bd9Sstevel@tonic-gate 		e_ddi_hold_devi(dip);
28177c478bd9Sstevel@tonic-gate 	mutex_exit(&csp->s_lock);
28187c478bd9Sstevel@tonic-gate 	if (dip == NULL)
28197c478bd9Sstevel@tonic-gate 		dip = e_ddi_hold_devi_by_dev(dev, 0);
28207c478bd9Sstevel@tonic-gate 
28217c478bd9Sstevel@tonic-gate 	if (dip == NULL)
28227c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
28237c478bd9Sstevel@tonic-gate 
28247c478bd9Sstevel@tonic-gate 	lep = kmem_zalloc(sizeof (struct ldi_event), KM_SLEEP);
28257c478bd9Sstevel@tonic-gate 	lep->le_lhp = handlep;
28267c478bd9Sstevel@tonic-gate 	lep->le_arg = arg;
28277c478bd9Sstevel@tonic-gate 	lep->le_handler = handler;
28287c478bd9Sstevel@tonic-gate 
28297c478bd9Sstevel@tonic-gate 	if ((res = ddi_add_event_handler(dip, ec, i_ldi_callback,
28307c478bd9Sstevel@tonic-gate 	    (void *)lep, &lep->le_id)) != DDI_SUCCESS) {
28317c478bd9Sstevel@tonic-gate 		LDI_EVENTCB((CE_WARN, "%s: unable to add"
28327c478bd9Sstevel@tonic-gate 		    "event callback", "ldi_add_event_handler"));
28337c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
28347c478bd9Sstevel@tonic-gate 		kmem_free(lep, sizeof (struct ldi_event));
28357c478bd9Sstevel@tonic-gate 		return (res);
28367c478bd9Sstevel@tonic-gate 	}
28377c478bd9Sstevel@tonic-gate 
28387c478bd9Sstevel@tonic-gate 	*id = (ldi_callback_id_t)lep;
28397c478bd9Sstevel@tonic-gate 
28407c478bd9Sstevel@tonic-gate 	LDI_EVENTCB((CE_NOTE, "%s: dip=0x%p, event=0x%p, "
28417c478bd9Sstevel@tonic-gate 	    "ldi_eventp=0x%p, cb_id=0x%p", "ldi_add_event_handler",
28427c478bd9Sstevel@tonic-gate 	    (void *)dip, (void *)ec, (void *)lep, (void *)id));
28437c478bd9Sstevel@tonic-gate 
28447c478bd9Sstevel@tonic-gate 	handle_event_add(lep);
28457c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);
28467c478bd9Sstevel@tonic-gate 	return (res);
28477c478bd9Sstevel@tonic-gate }
28487c478bd9Sstevel@tonic-gate 
28497c478bd9Sstevel@tonic-gate int
28507c478bd9Sstevel@tonic-gate ldi_remove_event_handler(ldi_handle_t lh, ldi_callback_id_t id)
28517c478bd9Sstevel@tonic-gate {
28527c478bd9Sstevel@tonic-gate 	ldi_event_t		*lep = (ldi_event_t *)id;
28537c478bd9Sstevel@tonic-gate 	int			res;
28547c478bd9Sstevel@tonic-gate 
28557c478bd9Sstevel@tonic-gate 	if ((lh == NULL) || (id == NULL))
28567c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 	ASSERT(!servicing_interrupt());
28597c478bd9Sstevel@tonic-gate 
28607c478bd9Sstevel@tonic-gate 	if ((res = ddi_remove_event_handler(lep->le_id))
28617c478bd9Sstevel@tonic-gate 	    != DDI_SUCCESS) {
28627c478bd9Sstevel@tonic-gate 		LDI_EVENTCB((CE_WARN, "%s: unable to remove "
28637c478bd9Sstevel@tonic-gate 		    "event callback", "ldi_remove_event_handler"));
28647c478bd9Sstevel@tonic-gate 		return (res);
28657c478bd9Sstevel@tonic-gate 	}
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 	handle_event_remove(lep);
28687c478bd9Sstevel@tonic-gate 	kmem_free(lep, sizeof (struct ldi_event));
28697c478bd9Sstevel@tonic-gate 	return (res);
28707c478bd9Sstevel@tonic-gate }
287125e8c5aaSvikram 
287225e8c5aaSvikram #endif
287325e8c5aaSvikram 
287425e8c5aaSvikram /*
287525e8c5aaSvikram  * Here are some definitions of terms used in the following LDI events
287625e8c5aaSvikram  * code:
287725e8c5aaSvikram  *
287825e8c5aaSvikram  * "LDI events" AKA "native events": These are events defined by the
287925e8c5aaSvikram  * "new" LDI event framework. These events are serviced by the LDI event
288025e8c5aaSvikram  * framework itself and thus are native to it.
288125e8c5aaSvikram  *
288225e8c5aaSvikram  * "LDI contract events": These are contract events that correspond to the
288325e8c5aaSvikram  *  LDI events. This mapping of LDI events to contract events is defined by
288425e8c5aaSvikram  * the ldi_ev_cookies[] array above.
288525e8c5aaSvikram  *
288625e8c5aaSvikram  * NDI events: These are events which are serviced by the NDI event subsystem.
288725e8c5aaSvikram  * LDI subsystem just provides a thin wrapper around the NDI event interfaces
2888da6c28aaSamw  * These events are therefore *not* native events.
288925e8c5aaSvikram  */
289025e8c5aaSvikram 
289125e8c5aaSvikram static int
289225e8c5aaSvikram ldi_native_event(const char *evname)
289325e8c5aaSvikram {
289425e8c5aaSvikram 	int i;
289525e8c5aaSvikram 
289625e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_native_event: entered: ev=%s", evname));
289725e8c5aaSvikram 
289825e8c5aaSvikram 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
289925e8c5aaSvikram 		if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
290025e8c5aaSvikram 			return (1);
290125e8c5aaSvikram 	}
290225e8c5aaSvikram 
290325e8c5aaSvikram 	return (0);
290425e8c5aaSvikram }
290525e8c5aaSvikram 
290625e8c5aaSvikram static uint_t
290725e8c5aaSvikram ldi_ev_sync_event(const char *evname)
290825e8c5aaSvikram {
290925e8c5aaSvikram 	int i;
291025e8c5aaSvikram 
291125e8c5aaSvikram 	ASSERT(ldi_native_event(evname));
291225e8c5aaSvikram 
291325e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_ev_sync_event: entered: %s", evname));
291425e8c5aaSvikram 
291525e8c5aaSvikram 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
291625e8c5aaSvikram 		if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
291725e8c5aaSvikram 			return (ldi_ev_cookies[i].ck_sync);
291825e8c5aaSvikram 	}
291925e8c5aaSvikram 
292025e8c5aaSvikram 	/*
292125e8c5aaSvikram 	 * This should never happen until non-contract based
292225e8c5aaSvikram 	 * LDI events are introduced. If that happens, we will
292325e8c5aaSvikram 	 * use a "special" token to indicate that there are no
292425e8c5aaSvikram 	 * contracts corresponding to this LDI event.
292525e8c5aaSvikram 	 */
292625e8c5aaSvikram 	cmn_err(CE_PANIC, "Unknown LDI event: %s", evname);
292725e8c5aaSvikram 
292825e8c5aaSvikram 	return (0);
292925e8c5aaSvikram }
293025e8c5aaSvikram 
293125e8c5aaSvikram static uint_t
293225e8c5aaSvikram ldi_contract_event(const char *evname)
293325e8c5aaSvikram {
293425e8c5aaSvikram 	int i;
293525e8c5aaSvikram 
293625e8c5aaSvikram 	ASSERT(ldi_native_event(evname));
293725e8c5aaSvikram 
293825e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_contract_event: entered: %s", evname));
293925e8c5aaSvikram 
294025e8c5aaSvikram 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
294125e8c5aaSvikram 		if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0)
294225e8c5aaSvikram 			return (ldi_ev_cookies[i].ck_ctype);
294325e8c5aaSvikram 	}
294425e8c5aaSvikram 
294525e8c5aaSvikram 	/*
294625e8c5aaSvikram 	 * This should never happen until non-contract based
294725e8c5aaSvikram 	 * LDI events are introduced. If that happens, we will
294825e8c5aaSvikram 	 * use a "special" token to indicate that there are no
294925e8c5aaSvikram 	 * contracts corresponding to this LDI event.
295025e8c5aaSvikram 	 */
295125e8c5aaSvikram 	cmn_err(CE_PANIC, "Unknown LDI event: %s", evname);
295225e8c5aaSvikram 
295325e8c5aaSvikram 	return (0);
295425e8c5aaSvikram }
295525e8c5aaSvikram 
295625e8c5aaSvikram char *
295725e8c5aaSvikram ldi_ev_get_type(ldi_ev_cookie_t cookie)
295825e8c5aaSvikram {
295925e8c5aaSvikram 	int i;
296025e8c5aaSvikram 	struct ldi_ev_cookie *cookie_impl = (struct ldi_ev_cookie *)cookie;
296125e8c5aaSvikram 
296225e8c5aaSvikram 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
296325e8c5aaSvikram 		if (&ldi_ev_cookies[i] == cookie_impl) {
296425e8c5aaSvikram 			LDI_EVTRC((CE_NOTE, "ldi_ev_get_type: LDI: %s",
296525e8c5aaSvikram 			    ldi_ev_cookies[i].ck_evname));
296625e8c5aaSvikram 			return (ldi_ev_cookies[i].ck_evname);
296725e8c5aaSvikram 		}
296825e8c5aaSvikram 	}
296925e8c5aaSvikram 
297025e8c5aaSvikram 	/*
297125e8c5aaSvikram 	 * Not an LDI native event. Must be NDI event service.
297225e8c5aaSvikram 	 * Just return a generic string
297325e8c5aaSvikram 	 */
297425e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_ev_get_type: is NDI"));
297525e8c5aaSvikram 	return (NDI_EVENT_SERVICE);
297625e8c5aaSvikram }
297725e8c5aaSvikram 
297825e8c5aaSvikram static int
297925e8c5aaSvikram ldi_native_cookie(ldi_ev_cookie_t cookie)
298025e8c5aaSvikram {
298125e8c5aaSvikram 	int i;
298225e8c5aaSvikram 	struct ldi_ev_cookie *cookie_impl = (struct ldi_ev_cookie *)cookie;
298325e8c5aaSvikram 
298425e8c5aaSvikram 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
298525e8c5aaSvikram 		if (&ldi_ev_cookies[i] == cookie_impl) {
298625e8c5aaSvikram 			LDI_EVTRC((CE_NOTE, "ldi_native_cookie: native LDI"));
298725e8c5aaSvikram 			return (1);
298825e8c5aaSvikram 		}
298925e8c5aaSvikram 	}
299025e8c5aaSvikram 
299125e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_native_cookie: is NDI"));
299225e8c5aaSvikram 	return (0);
299325e8c5aaSvikram }
299425e8c5aaSvikram 
299525e8c5aaSvikram static ldi_ev_cookie_t
299625e8c5aaSvikram ldi_get_native_cookie(const char *evname)
299725e8c5aaSvikram {
299825e8c5aaSvikram 	int i;
299925e8c5aaSvikram 
300025e8c5aaSvikram 	for (i = 0; ldi_ev_cookies[i].ck_evname != NULL; i++) {
300125e8c5aaSvikram 		if (strcmp(ldi_ev_cookies[i].ck_evname, evname) == 0) {
300225e8c5aaSvikram 			LDI_EVTRC((CE_NOTE, "ldi_get_native_cookie: found"));
300325e8c5aaSvikram 			return ((ldi_ev_cookie_t)&ldi_ev_cookies[i]);
300425e8c5aaSvikram 		}
300525e8c5aaSvikram 	}
300625e8c5aaSvikram 
300725e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_get_native_cookie: NOT found"));
300825e8c5aaSvikram 	return (NULL);
300925e8c5aaSvikram }
301025e8c5aaSvikram 
301125e8c5aaSvikram /*
301225e8c5aaSvikram  * ldi_ev_lock() needs to be recursive, since layered drivers may call
301325e8c5aaSvikram  * other LDI interfaces (such as ldi_close() from within the context of
301425e8c5aaSvikram  * a notify callback. Since the notify callback is called with the
301525e8c5aaSvikram  * ldi_ev_lock() held and ldi_close() also grabs ldi_ev_lock, the lock needs
301625e8c5aaSvikram  * to be recursive.
301725e8c5aaSvikram  */
301825e8c5aaSvikram static void
301925e8c5aaSvikram ldi_ev_lock(void)
302025e8c5aaSvikram {
302125e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_ev_lock: entered"));
302225e8c5aaSvikram 
302325e8c5aaSvikram 	mutex_enter(&ldi_ev_callback_list.le_lock);
302425e8c5aaSvikram 	if (ldi_ev_callback_list.le_thread == curthread) {
302525e8c5aaSvikram 		ASSERT(ldi_ev_callback_list.le_busy >= 1);
302625e8c5aaSvikram 		ldi_ev_callback_list.le_busy++;
302725e8c5aaSvikram 	} else {
302825e8c5aaSvikram 		while (ldi_ev_callback_list.le_busy)
302925e8c5aaSvikram 			cv_wait(&ldi_ev_callback_list.le_cv,
303025e8c5aaSvikram 			    &ldi_ev_callback_list.le_lock);
303125e8c5aaSvikram 		ASSERT(ldi_ev_callback_list.le_thread == NULL);
303225e8c5aaSvikram 		ldi_ev_callback_list.le_busy = 1;
303325e8c5aaSvikram 		ldi_ev_callback_list.le_thread = curthread;
303425e8c5aaSvikram 	}
303525e8c5aaSvikram 	mutex_exit(&ldi_ev_callback_list.le_lock);
303625e8c5aaSvikram 
303725e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_ev_lock: exit"));
303825e8c5aaSvikram }
303925e8c5aaSvikram 
304025e8c5aaSvikram static void
304125e8c5aaSvikram ldi_ev_unlock(void)
304225e8c5aaSvikram {
304325e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_ev_unlock: entered"));
304425e8c5aaSvikram 	mutex_enter(&ldi_ev_callback_list.le_lock);
304525e8c5aaSvikram 	ASSERT(ldi_ev_callback_list.le_thread == curthread);
304625e8c5aaSvikram 	ASSERT(ldi_ev_callback_list.le_busy >= 1);
304725e8c5aaSvikram 
304825e8c5aaSvikram 	ldi_ev_callback_list.le_busy--;
304925e8c5aaSvikram 	if (ldi_ev_callback_list.le_busy == 0) {
305025e8c5aaSvikram 		ldi_ev_callback_list.le_thread = NULL;
305125e8c5aaSvikram 		cv_signal(&ldi_ev_callback_list.le_cv);
305225e8c5aaSvikram 	}
305325e8c5aaSvikram 	mutex_exit(&ldi_ev_callback_list.le_lock);
305425e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_ev_unlock: exit"));
305525e8c5aaSvikram }
305625e8c5aaSvikram 
305725e8c5aaSvikram int
305825e8c5aaSvikram ldi_ev_get_cookie(ldi_handle_t lh, char *evname, ldi_ev_cookie_t *cookiep)
305925e8c5aaSvikram {
306025e8c5aaSvikram 	struct ldi_handle	*handlep = (struct ldi_handle *)lh;
306125e8c5aaSvikram 	dev_info_t		*dip;
306225e8c5aaSvikram 	dev_t			dev;
306325e8c5aaSvikram 	int			res;
306425e8c5aaSvikram 	struct snode		*csp;
306525e8c5aaSvikram 	ddi_eventcookie_t	ddi_cookie;
306625e8c5aaSvikram 	ldi_ev_cookie_t		tcookie;
306725e8c5aaSvikram 
306825e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: entered: evname=%s",
306925e8c5aaSvikram 	    evname ? evname : "<NULL>"));
307025e8c5aaSvikram 
307125e8c5aaSvikram 	if (lh == NULL || evname == NULL ||
307225e8c5aaSvikram 	    strlen(evname) == 0 || cookiep == NULL) {
307325e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: invalid args"));
307425e8c5aaSvikram 		return (LDI_EV_FAILURE);
307525e8c5aaSvikram 	}
307625e8c5aaSvikram 
307725e8c5aaSvikram 	*cookiep = NULL;
307825e8c5aaSvikram 
307925e8c5aaSvikram 	/*
308025e8c5aaSvikram 	 * First check if it is a LDI native event
308125e8c5aaSvikram 	 */
308225e8c5aaSvikram 	tcookie = ldi_get_native_cookie(evname);
308325e8c5aaSvikram 	if (tcookie) {
308425e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: got native cookie"));
308525e8c5aaSvikram 		*cookiep = tcookie;
308625e8c5aaSvikram 		return (LDI_EV_SUCCESS);
308725e8c5aaSvikram 	}
308825e8c5aaSvikram 
308925e8c5aaSvikram 	/*
309025e8c5aaSvikram 	 * Not a LDI native event. Try NDI event services
309125e8c5aaSvikram 	 */
309225e8c5aaSvikram 
309325e8c5aaSvikram 	dev = handlep->lh_vp->v_rdev;
309425e8c5aaSvikram 
309525e8c5aaSvikram 	csp = VTOCS(handlep->lh_vp);
309625e8c5aaSvikram 	mutex_enter(&csp->s_lock);
309725e8c5aaSvikram 	if ((dip = csp->s_dip) != NULL)
309825e8c5aaSvikram 		e_ddi_hold_devi(dip);
309925e8c5aaSvikram 	mutex_exit(&csp->s_lock);
310025e8c5aaSvikram 	if (dip == NULL)
310125e8c5aaSvikram 		dip = e_ddi_hold_devi_by_dev(dev, 0);
310225e8c5aaSvikram 
310325e8c5aaSvikram 	if (dip == NULL) {
310425e8c5aaSvikram 		cmn_err(CE_WARN, "ldi_ev_get_cookie: No devinfo node for LDI "
310525e8c5aaSvikram 		    "handle: %p", (void *)handlep);
310625e8c5aaSvikram 		return (LDI_EV_FAILURE);
310725e8c5aaSvikram 	}
310825e8c5aaSvikram 
310925e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "Calling ddi_get_eventcookie: dip=%p, ev=%s",
311025e8c5aaSvikram 	    (void *)dip, evname));
311125e8c5aaSvikram 
311225e8c5aaSvikram 	res = ddi_get_eventcookie(dip, evname, &ddi_cookie);
311325e8c5aaSvikram 
311425e8c5aaSvikram 	ddi_release_devi(dip);
311525e8c5aaSvikram 
311625e8c5aaSvikram 	if (res == DDI_SUCCESS) {
311725e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_get_cookie: NDI cookie found"));
311825e8c5aaSvikram 		*cookiep = (ldi_ev_cookie_t)ddi_cookie;
311925e8c5aaSvikram 		return (LDI_EV_SUCCESS);
312025e8c5aaSvikram 	} else {
312125e8c5aaSvikram 		LDI_EVDBG((CE_WARN, "ldi_ev_get_cookie: NDI cookie: failed"));
312225e8c5aaSvikram 		return (LDI_EV_FAILURE);
312325e8c5aaSvikram 	}
312425e8c5aaSvikram }
312525e8c5aaSvikram 
312625e8c5aaSvikram /*ARGSUSED*/
312725e8c5aaSvikram static void
312825e8c5aaSvikram i_ldi_ev_callback(dev_info_t *dip, ddi_eventcookie_t event_cookie,
312925e8c5aaSvikram     void *arg, void *ev_data)
313025e8c5aaSvikram {
313125e8c5aaSvikram 	ldi_ev_callback_impl_t *lecp = (ldi_ev_callback_impl_t *)arg;
313225e8c5aaSvikram 
313325e8c5aaSvikram 	ASSERT(lecp != NULL);
313425e8c5aaSvikram 	ASSERT(!ldi_native_cookie(lecp->lec_cookie));
313525e8c5aaSvikram 	ASSERT(lecp->lec_lhp);
313625e8c5aaSvikram 	ASSERT(lecp->lec_notify == NULL);
313725e8c5aaSvikram 	ASSERT(lecp->lec_finalize);
313825e8c5aaSvikram 
313925e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "i_ldi_ev_callback: ldh=%p, cookie=%p, arg=%p, "
314025e8c5aaSvikram 	    "ev_data=%p", (void *)lecp->lec_lhp, (void *)event_cookie,
314125e8c5aaSvikram 	    (void *)lecp->lec_arg, (void *)ev_data));
314225e8c5aaSvikram 
314325e8c5aaSvikram 	lecp->lec_finalize(lecp->lec_lhp, (ldi_ev_cookie_t)event_cookie,
314425e8c5aaSvikram 	    lecp->lec_arg, ev_data);
314525e8c5aaSvikram }
314625e8c5aaSvikram 
314725e8c5aaSvikram int
314825e8c5aaSvikram ldi_ev_register_callbacks(ldi_handle_t lh, ldi_ev_cookie_t cookie,
314925e8c5aaSvikram     ldi_ev_callback_t *callb, void *arg, ldi_callback_id_t *id)
315025e8c5aaSvikram {
315125e8c5aaSvikram 	struct ldi_handle	*lhp = (struct ldi_handle *)lh;
315225e8c5aaSvikram 	ldi_ev_callback_impl_t	*lecp;
315325e8c5aaSvikram 	dev_t			dev;
315425e8c5aaSvikram 	struct snode		*csp;
315525e8c5aaSvikram 	dev_info_t		*dip;
315625e8c5aaSvikram 	int			ddi_event;
315725e8c5aaSvikram 
315825e8c5aaSvikram 	ASSERT(!servicing_interrupt());
315925e8c5aaSvikram 
316025e8c5aaSvikram 	if (lh == NULL || cookie == NULL || callb == NULL || id == NULL) {
316125e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: Invalid args"));
316225e8c5aaSvikram 		return (LDI_EV_FAILURE);
316325e8c5aaSvikram 	}
316425e8c5aaSvikram 
316525e8c5aaSvikram 	if (callb->cb_vers != LDI_EV_CB_VERS) {
316625e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: Invalid vers"));
316725e8c5aaSvikram 		return (LDI_EV_FAILURE);
316825e8c5aaSvikram 	}
316925e8c5aaSvikram 
317025e8c5aaSvikram 	if (callb->cb_notify == NULL && callb->cb_finalize == NULL) {
317125e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: NULL callb"));
317225e8c5aaSvikram 		return (LDI_EV_FAILURE);
317325e8c5aaSvikram 	}
317425e8c5aaSvikram 
317525e8c5aaSvikram 	*id = 0;
317625e8c5aaSvikram 
317725e8c5aaSvikram 	dev = lhp->lh_vp->v_rdev;
317825e8c5aaSvikram 	csp = VTOCS(lhp->lh_vp);
317925e8c5aaSvikram 	mutex_enter(&csp->s_lock);
318025e8c5aaSvikram 	if ((dip = csp->s_dip) != NULL)
318125e8c5aaSvikram 		e_ddi_hold_devi(dip);
318225e8c5aaSvikram 	mutex_exit(&csp->s_lock);
318325e8c5aaSvikram 	if (dip == NULL)
318425e8c5aaSvikram 		dip = e_ddi_hold_devi_by_dev(dev, 0);
318525e8c5aaSvikram 
318625e8c5aaSvikram 	if (dip == NULL) {
318725e8c5aaSvikram 		cmn_err(CE_WARN, "ldi_ev_register: No devinfo node for "
318825e8c5aaSvikram 		    "LDI handle: %p", (void *)lhp);
318925e8c5aaSvikram 		return (LDI_EV_FAILURE);
319025e8c5aaSvikram 	}
319125e8c5aaSvikram 
319225e8c5aaSvikram 	lecp = kmem_zalloc(sizeof (ldi_ev_callback_impl_t), KM_SLEEP);
319325e8c5aaSvikram 
319425e8c5aaSvikram 	ddi_event = 0;
319525e8c5aaSvikram 	if (!ldi_native_cookie(cookie)) {
319625e8c5aaSvikram 		if (callb->cb_notify || callb->cb_finalize == NULL) {
319725e8c5aaSvikram 			/*
319825e8c5aaSvikram 			 * NDI event services only accept finalize
319925e8c5aaSvikram 			 */
320025e8c5aaSvikram 			cmn_err(CE_WARN, "%s: module: %s: NDI event cookie. "
320125e8c5aaSvikram 			    "Only finalize"
320225e8c5aaSvikram 			    " callback supported with this cookie",
320325e8c5aaSvikram 			    "ldi_ev_register_callbacks",
320425e8c5aaSvikram 			    lhp->lh_ident->li_modname);
320525e8c5aaSvikram 			kmem_free(lecp, sizeof (ldi_ev_callback_impl_t));
320625e8c5aaSvikram 			ddi_release_devi(dip);
320725e8c5aaSvikram 			return (LDI_EV_FAILURE);
320825e8c5aaSvikram 		}
320925e8c5aaSvikram 
321025e8c5aaSvikram 		if (ddi_add_event_handler(dip, (ddi_eventcookie_t)cookie,
321125e8c5aaSvikram 		    i_ldi_ev_callback, (void *)lecp,
321225e8c5aaSvikram 		    (ddi_callback_id_t *)&lecp->lec_id)
321325e8c5aaSvikram 		    != DDI_SUCCESS) {
321425e8c5aaSvikram 			kmem_free(lecp, sizeof (ldi_ev_callback_impl_t));
321525e8c5aaSvikram 			ddi_release_devi(dip);
321625e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks(): "
321725e8c5aaSvikram 			    "ddi_add_event_handler failed"));
321825e8c5aaSvikram 			return (LDI_EV_FAILURE);
321925e8c5aaSvikram 		}
322025e8c5aaSvikram 		ddi_event = 1;
322125e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks(): "
322225e8c5aaSvikram 		    "ddi_add_event_handler success"));
322325e8c5aaSvikram 	}
322425e8c5aaSvikram 
322525e8c5aaSvikram 
322625e8c5aaSvikram 
322725e8c5aaSvikram 	ldi_ev_lock();
322825e8c5aaSvikram 
322925e8c5aaSvikram 	/*
323025e8c5aaSvikram 	 * Add the notify/finalize callback to the LDI's list of callbacks.
323125e8c5aaSvikram 	 */
323225e8c5aaSvikram 	lecp->lec_lhp = lhp;
323325e8c5aaSvikram 	lecp->lec_dev = lhp->lh_vp->v_rdev;
3234349dcea3SGarrett D'Amore 	lecp->lec_spec = VTYP_TO_STYP(lhp->lh_vp->v_type);
323525e8c5aaSvikram 	lecp->lec_notify = callb->cb_notify;
323625e8c5aaSvikram 	lecp->lec_finalize = callb->cb_finalize;
323725e8c5aaSvikram 	lecp->lec_arg = arg;
323825e8c5aaSvikram 	lecp->lec_cookie = cookie;
323925e8c5aaSvikram 	if (!ddi_event)
324025e8c5aaSvikram 		lecp->lec_id = (void *)(uintptr_t)(++ldi_ev_id_pool);
324125e8c5aaSvikram 	else
324225e8c5aaSvikram 		ASSERT(lecp->lec_id);
324325e8c5aaSvikram 	lecp->lec_dip = dip;
324425e8c5aaSvikram 	list_insert_tail(&ldi_ev_callback_list.le_head, lecp);
324525e8c5aaSvikram 
324625e8c5aaSvikram 	*id = (ldi_callback_id_t)lecp->lec_id;
324725e8c5aaSvikram 
324825e8c5aaSvikram 	ldi_ev_unlock();
324925e8c5aaSvikram 
325025e8c5aaSvikram 	ddi_release_devi(dip);
325125e8c5aaSvikram 
325225e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_register_callbacks: registered "
325325e8c5aaSvikram 	    "notify/finalize"));
325425e8c5aaSvikram 
325525e8c5aaSvikram 	return (LDI_EV_SUCCESS);
325625e8c5aaSvikram }
325725e8c5aaSvikram 
325825e8c5aaSvikram static int
325925e8c5aaSvikram ldi_ev_device_match(ldi_ev_callback_impl_t *lecp, dev_info_t *dip,
326025e8c5aaSvikram     dev_t dev, int spec_type)
326125e8c5aaSvikram {
326225e8c5aaSvikram 	ASSERT(lecp);
326325e8c5aaSvikram 	ASSERT(dip);
326425e8c5aaSvikram 	ASSERT(dev != DDI_DEV_T_NONE);
326525e8c5aaSvikram 	ASSERT(dev != NODEV);
326625e8c5aaSvikram 	ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
326725e8c5aaSvikram 	    (spec_type == S_IFCHR || spec_type == S_IFBLK));
326825e8c5aaSvikram 	ASSERT(lecp->lec_dip);
326925e8c5aaSvikram 	ASSERT(lecp->lec_spec == S_IFCHR || lecp->lec_spec == S_IFBLK);
327025e8c5aaSvikram 	ASSERT(lecp->lec_dev != DDI_DEV_T_ANY);
327125e8c5aaSvikram 	ASSERT(lecp->lec_dev != DDI_DEV_T_NONE);
327225e8c5aaSvikram 	ASSERT(lecp->lec_dev != NODEV);
327325e8c5aaSvikram 
327425e8c5aaSvikram 	if (dip != lecp->lec_dip)
327525e8c5aaSvikram 		return (0);
327625e8c5aaSvikram 
327725e8c5aaSvikram 	if (dev != DDI_DEV_T_ANY) {
327825e8c5aaSvikram 		if (dev != lecp->lec_dev || spec_type != lecp->lec_spec)
327925e8c5aaSvikram 			return (0);
328025e8c5aaSvikram 	}
328125e8c5aaSvikram 
328225e8c5aaSvikram 	LDI_EVTRC((CE_NOTE, "ldi_ev_device_match: MATCH dip=%p", (void *)dip));
328325e8c5aaSvikram 
328425e8c5aaSvikram 	return (1);
328525e8c5aaSvikram }
328625e8c5aaSvikram 
328725e8c5aaSvikram /*
328825e8c5aaSvikram  * LDI framework function to post a "notify" event to all layered drivers
328925e8c5aaSvikram  * that have registered for that event
329025e8c5aaSvikram  *
329125e8c5aaSvikram  * Returns:
329225e8c5aaSvikram  *		LDI_EV_SUCCESS - registered callbacks allow event
329325e8c5aaSvikram  *		LDI_EV_FAILURE - registered callbacks block event
329425e8c5aaSvikram  *		LDI_EV_NONE    - No matching LDI callbacks
329525e8c5aaSvikram  *
329625e8c5aaSvikram  * This function is *not* to be called by layered drivers. It is for I/O
329725e8c5aaSvikram  * framework code in Solaris, such as the I/O retire code and DR code
329825e8c5aaSvikram  * to call while servicing a device event such as offline or degraded.
329925e8c5aaSvikram  */
330025e8c5aaSvikram int
330125e8c5aaSvikram ldi_invoke_notify(dev_info_t *dip, dev_t dev, int spec_type, char *event,
330225e8c5aaSvikram     void *ev_data)
330325e8c5aaSvikram {
330425e8c5aaSvikram 	ldi_ev_callback_impl_t *lecp;
330525e8c5aaSvikram 	list_t	*listp;
330625e8c5aaSvikram 	int	ret;
330725e8c5aaSvikram 	char	*lec_event;
330825e8c5aaSvikram 
330925e8c5aaSvikram 	ASSERT(dip);
331025e8c5aaSvikram 	ASSERT(dev != DDI_DEV_T_NONE);
331125e8c5aaSvikram 	ASSERT(dev != NODEV);
331225e8c5aaSvikram 	ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
331325e8c5aaSvikram 	    (spec_type == S_IFCHR || spec_type == S_IFBLK));
331425e8c5aaSvikram 	ASSERT(event);
331525e8c5aaSvikram 	ASSERT(ldi_native_event(event));
331625e8c5aaSvikram 	ASSERT(ldi_ev_sync_event(event));
331725e8c5aaSvikram 
331825e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): entered: dip=%p, ev=%s",
331925e8c5aaSvikram 	    (void *)dip, event));
332025e8c5aaSvikram 
332125e8c5aaSvikram 	ret = LDI_EV_NONE;
332225e8c5aaSvikram 	ldi_ev_lock();
332325e8c5aaSvikram 	listp = &ldi_ev_callback_list.le_head;
332425e8c5aaSvikram 	for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
332525e8c5aaSvikram 
332625e8c5aaSvikram 		/* Check if matching device */
332725e8c5aaSvikram 		if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
332825e8c5aaSvikram 			continue;
332925e8c5aaSvikram 
333025e8c5aaSvikram 		if (lecp->lec_lhp == NULL) {
333125e8c5aaSvikram 			/*
333225e8c5aaSvikram 			 * Consumer has unregistered the handle and so
333325e8c5aaSvikram 			 * is no longer interested in notify events.
333425e8c5aaSvikram 			 */
333525e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): No LDI "
333625e8c5aaSvikram 			    "handle, skipping"));
333725e8c5aaSvikram 			continue;
333825e8c5aaSvikram 		}
333925e8c5aaSvikram 
334025e8c5aaSvikram 		if (lecp->lec_notify == NULL) {
334125e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): No notify "
334225e8c5aaSvikram 			    "callback. skipping"));
334325e8c5aaSvikram 			continue;	/* not interested in notify */
334425e8c5aaSvikram 		}
334525e8c5aaSvikram 
334625e8c5aaSvikram 		/*
334725e8c5aaSvikram 		 * Check if matching event
334825e8c5aaSvikram 		 */
334925e8c5aaSvikram 		lec_event = ldi_ev_get_type(lecp->lec_cookie);
335025e8c5aaSvikram 		if (strcmp(event, lec_event) != 0) {
335125e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): Not matching"
335225e8c5aaSvikram 			    " event {%s,%s}. skipping", event, lec_event));
335325e8c5aaSvikram 			continue;
335425e8c5aaSvikram 		}
335525e8c5aaSvikram 
335625e8c5aaSvikram 		lecp->lec_lhp->lh_flags |= LH_FLAGS_NOTIFY;
335725e8c5aaSvikram 		if (lecp->lec_notify(lecp->lec_lhp, lecp->lec_cookie,
335825e8c5aaSvikram 		    lecp->lec_arg, ev_data) != LDI_EV_SUCCESS) {
335925e8c5aaSvikram 			ret = LDI_EV_FAILURE;
336025e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): notify"
336125e8c5aaSvikram 			    " FAILURE"));
336225e8c5aaSvikram 			break;
336325e8c5aaSvikram 		}
336425e8c5aaSvikram 
336525e8c5aaSvikram 		/* We have a matching callback that allows the event to occur */
336625e8c5aaSvikram 		ret = LDI_EV_SUCCESS;
336725e8c5aaSvikram 
336825e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): 1 consumer success"));
336925e8c5aaSvikram 	}
337025e8c5aaSvikram 
337125e8c5aaSvikram 	if (ret != LDI_EV_FAILURE)
337225e8c5aaSvikram 		goto out;
337325e8c5aaSvikram 
337425e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): undoing notify"));
337525e8c5aaSvikram 
337625e8c5aaSvikram 	/*
337725e8c5aaSvikram 	 * Undo notifies already sent
337825e8c5aaSvikram 	 */
337925e8c5aaSvikram 	lecp = list_prev(listp, lecp);
338025e8c5aaSvikram 	for (; lecp; lecp = list_prev(listp, lecp)) {
338125e8c5aaSvikram 
338225e8c5aaSvikram 		/*
338325e8c5aaSvikram 		 * Check if matching device
338425e8c5aaSvikram 		 */
338525e8c5aaSvikram 		if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
338625e8c5aaSvikram 			continue;
338725e8c5aaSvikram 
338825e8c5aaSvikram 
338925e8c5aaSvikram 		if (lecp->lec_finalize == NULL) {
339025e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no finalize, "
339125e8c5aaSvikram 			    "skipping"));
339225e8c5aaSvikram 			continue;	/* not interested in finalize */
339325e8c5aaSvikram 		}
339425e8c5aaSvikram 
339525e8c5aaSvikram 		/*
339625e8c5aaSvikram 		 * it is possible that in response to a notify event a
339725e8c5aaSvikram 		 * layered driver closed its LDI handle so it is ok
339825e8c5aaSvikram 		 * to have a NULL LDI handle for finalize. The layered
339925e8c5aaSvikram 		 * driver is expected to maintain state in its "arg"
340025e8c5aaSvikram 		 * parameter to keep track of the closed device.
340125e8c5aaSvikram 		 */
340225e8c5aaSvikram 
340325e8c5aaSvikram 		/* Check if matching event */
340425e8c5aaSvikram 		lec_event = ldi_ev_get_type(lecp->lec_cookie);
340525e8c5aaSvikram 		if (strcmp(event, lec_event) != 0) {
340625e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): not matching "
340725e8c5aaSvikram 			    "event: %s,%s, skipping", event, lec_event));
340825e8c5aaSvikram 			continue;
340925e8c5aaSvikram 		}
341025e8c5aaSvikram 
341125e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): calling finalize"));
341225e8c5aaSvikram 
341325e8c5aaSvikram 		lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
341425e8c5aaSvikram 		    LDI_EV_FAILURE, lecp->lec_arg, ev_data);
341525e8c5aaSvikram 
341625e8c5aaSvikram 		/*
341725e8c5aaSvikram 		 * If LDI native event and LDI handle closed in context
341825e8c5aaSvikram 		 * of notify, NULL out the finalize callback as we have
341925e8c5aaSvikram 		 * already called the 1 finalize above allowed in this situation
342025e8c5aaSvikram 		 */
342125e8c5aaSvikram 		if (lecp->lec_lhp == NULL &&
342225e8c5aaSvikram 		    ldi_native_cookie(lecp->lec_cookie)) {
342325e8c5aaSvikram 			LDI_EVDBG((CE_NOTE,
342425e8c5aaSvikram 			    "ldi_invoke_notify(): NULL-ing finalize after "
342525e8c5aaSvikram 			    "calling 1 finalize following ldi_close"));
342625e8c5aaSvikram 			lecp->lec_finalize = NULL;
342725e8c5aaSvikram 		}
342825e8c5aaSvikram 	}
342925e8c5aaSvikram 
343025e8c5aaSvikram out:
343125e8c5aaSvikram 	ldi_ev_unlock();
343225e8c5aaSvikram 
343325e8c5aaSvikram 	if (ret == LDI_EV_NONE) {
343425e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_invoke_notify(): no matching "
343525e8c5aaSvikram 		    "LDI callbacks"));
343625e8c5aaSvikram 	}
343725e8c5aaSvikram 
343825e8c5aaSvikram 	return (ret);
343925e8c5aaSvikram }
344025e8c5aaSvikram 
344125e8c5aaSvikram /*
344225e8c5aaSvikram  * Framework function to be called from a layered driver to propagate
344325e8c5aaSvikram  * LDI "notify" events to exported minors.
344425e8c5aaSvikram  *
344525e8c5aaSvikram  * This function is a public interface exported by the LDI framework
344625e8c5aaSvikram  * for use by layered drivers to propagate device events up the software
344725e8c5aaSvikram  * stack.
344825e8c5aaSvikram  */
344925e8c5aaSvikram int
345025e8c5aaSvikram ldi_ev_notify(dev_info_t *dip, minor_t minor, int spec_type,
345125e8c5aaSvikram     ldi_ev_cookie_t cookie, void *ev_data)
345225e8c5aaSvikram {
345325e8c5aaSvikram 	char		*evname = ldi_ev_get_type(cookie);
345425e8c5aaSvikram 	uint_t		ct_evtype;
345525e8c5aaSvikram 	dev_t		dev;
345625e8c5aaSvikram 	major_t		major;
345725e8c5aaSvikram 	int		retc;
345825e8c5aaSvikram 	int		retl;
345925e8c5aaSvikram 
346025e8c5aaSvikram 	ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
346125e8c5aaSvikram 	ASSERT(dip);
346225e8c5aaSvikram 	ASSERT(ldi_native_cookie(cookie));
346325e8c5aaSvikram 
346425e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): entered: event=%s, dip=%p",
346525e8c5aaSvikram 	    evname, (void *)dip));
346625e8c5aaSvikram 
346725e8c5aaSvikram 	if (!ldi_ev_sync_event(evname)) {
346825e8c5aaSvikram 		cmn_err(CE_PANIC, "ldi_ev_notify(): %s not a "
346925e8c5aaSvikram 		    "negotiatable event", evname);
347025e8c5aaSvikram 		return (LDI_EV_SUCCESS);
347125e8c5aaSvikram 	}
347225e8c5aaSvikram 
347325e8c5aaSvikram 	major = ddi_driver_major(dip);
3474a204de77Scth 	if (major == DDI_MAJOR_T_NONE) {
347525e8c5aaSvikram 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
347625e8c5aaSvikram 		(void) ddi_pathname(dip, path);
347725e8c5aaSvikram 		cmn_err(CE_WARN, "ldi_ev_notify: cannot derive major number "
347825e8c5aaSvikram 		    "for device %s", path);
347925e8c5aaSvikram 		kmem_free(path, MAXPATHLEN);
348025e8c5aaSvikram 		return (LDI_EV_FAILURE);
348125e8c5aaSvikram 	}
348225e8c5aaSvikram 	dev = makedevice(major, minor);
348325e8c5aaSvikram 
348425e8c5aaSvikram 	/*
348525e8c5aaSvikram 	 * Generate negotiation contract events on contracts (if any) associated
348625e8c5aaSvikram 	 * with this minor.
348725e8c5aaSvikram 	 */
348825e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): calling contract nego."));
348925e8c5aaSvikram 	ct_evtype = ldi_contract_event(evname);
349025e8c5aaSvikram 	retc = contract_device_negotiate(dip, dev, spec_type, ct_evtype);
349125e8c5aaSvikram 	if (retc == CT_NACK) {
349225e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): contract neg. NACK"));
349325e8c5aaSvikram 		return (LDI_EV_FAILURE);
349425e8c5aaSvikram 	}
349525e8c5aaSvikram 
349625e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): LDI invoke notify"));
349725e8c5aaSvikram 	retl = ldi_invoke_notify(dip, dev, spec_type, evname, ev_data);
349825e8c5aaSvikram 	if (retl == LDI_EV_FAILURE) {
349925e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): ldi_invoke_notify "
350025e8c5aaSvikram 		    "returned FAILURE. Calling contract negend"));
350125e8c5aaSvikram 		contract_device_negend(dip, dev, spec_type, CT_EV_FAILURE);
350225e8c5aaSvikram 		return (LDI_EV_FAILURE);
350325e8c5aaSvikram 	}
350425e8c5aaSvikram 
350525e8c5aaSvikram 	/*
350625e8c5aaSvikram 	 * The very fact that we are here indicates that there is a
350725e8c5aaSvikram 	 * LDI callback (and hence a constraint) for the retire of the
350825e8c5aaSvikram 	 * HW device. So we just return success even if there are no
350925e8c5aaSvikram 	 * contracts or LDI callbacks against the minors layered on top
351025e8c5aaSvikram 	 * of the HW minors
351125e8c5aaSvikram 	 */
351225e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): returning SUCCESS"));
351325e8c5aaSvikram 	return (LDI_EV_SUCCESS);
351425e8c5aaSvikram }
351525e8c5aaSvikram 
351625e8c5aaSvikram /*
351725e8c5aaSvikram  * LDI framework function to invoke "finalize" callbacks for all layered
351825e8c5aaSvikram  * drivers that have registered callbacks for that event.
351925e8c5aaSvikram  *
352025e8c5aaSvikram  * This function is *not* to be called by layered drivers. It is for I/O
352125e8c5aaSvikram  * framework code in Solaris, such as the I/O retire code and DR code
352225e8c5aaSvikram  * to call while servicing a device event such as offline or degraded.
352325e8c5aaSvikram  */
352425e8c5aaSvikram void
352525e8c5aaSvikram ldi_invoke_finalize(dev_info_t *dip, dev_t dev, int spec_type, char *event,
352625e8c5aaSvikram     int ldi_result, void *ev_data)
352725e8c5aaSvikram {
352825e8c5aaSvikram 	ldi_ev_callback_impl_t *lecp;
352925e8c5aaSvikram 	list_t	*listp;
353025e8c5aaSvikram 	char	*lec_event;
353125e8c5aaSvikram 	int	found = 0;
353225e8c5aaSvikram 
353325e8c5aaSvikram 	ASSERT(dip);
353425e8c5aaSvikram 	ASSERT(dev != DDI_DEV_T_NONE);
353525e8c5aaSvikram 	ASSERT(dev != NODEV);
353625e8c5aaSvikram 	ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
353725e8c5aaSvikram 	    (spec_type == S_IFCHR || spec_type == S_IFBLK));
353825e8c5aaSvikram 	ASSERT(event);
353925e8c5aaSvikram 	ASSERT(ldi_native_event(event));
354025e8c5aaSvikram 	ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
354125e8c5aaSvikram 
354225e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): entered: dip=%p, result=%d"
354325e8c5aaSvikram 	    " event=%s", (void *)dip, ldi_result, event));
354425e8c5aaSvikram 
354525e8c5aaSvikram 	ldi_ev_lock();
354625e8c5aaSvikram 	listp = &ldi_ev_callback_list.le_head;
354725e8c5aaSvikram 	for (lecp = list_head(listp); lecp; lecp = list_next(listp, lecp)) {
354825e8c5aaSvikram 
354925e8c5aaSvikram 		if (lecp->lec_finalize == NULL) {
355025e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): No "
355125e8c5aaSvikram 			    "finalize. Skipping"));
355225e8c5aaSvikram 			continue;	/* Not interested in finalize */
355325e8c5aaSvikram 		}
355425e8c5aaSvikram 
355525e8c5aaSvikram 		/*
355625e8c5aaSvikram 		 * Check if matching device
355725e8c5aaSvikram 		 */
355825e8c5aaSvikram 		if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
355925e8c5aaSvikram 			continue;
356025e8c5aaSvikram 
356125e8c5aaSvikram 		/*
356225e8c5aaSvikram 		 * It is valid for the LDI handle to be NULL during finalize.
356325e8c5aaSvikram 		 * The layered driver may have done an LDI close in the notify
356425e8c5aaSvikram 		 * callback.
356525e8c5aaSvikram 		 */
356625e8c5aaSvikram 
356725e8c5aaSvikram 		/*
356825e8c5aaSvikram 		 * Check if matching event
356925e8c5aaSvikram 		 */
357025e8c5aaSvikram 		lec_event = ldi_ev_get_type(lecp->lec_cookie);
357125e8c5aaSvikram 		if (strcmp(event, lec_event) != 0) {
357225e8c5aaSvikram 			LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): Not "
357325e8c5aaSvikram 			    "matching event {%s,%s}. Skipping",
357425e8c5aaSvikram 			    event, lec_event));
357525e8c5aaSvikram 			continue;
357625e8c5aaSvikram 		}
357725e8c5aaSvikram 
357825e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): calling finalize"));
357925e8c5aaSvikram 
358025e8c5aaSvikram 		found = 1;
358125e8c5aaSvikram 
358225e8c5aaSvikram 		lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
358325e8c5aaSvikram 		    ldi_result, lecp->lec_arg, ev_data);
358425e8c5aaSvikram 
358525e8c5aaSvikram 		/*
358625e8c5aaSvikram 		 * If LDI native event and LDI handle closed in context
358725e8c5aaSvikram 		 * of notify, NULL out the finalize callback as we have
358825e8c5aaSvikram 		 * already called the 1 finalize above allowed in this situation
358925e8c5aaSvikram 		 */
359025e8c5aaSvikram 		if (lecp->lec_lhp == NULL &&
359125e8c5aaSvikram 		    ldi_native_cookie(lecp->lec_cookie)) {
359225e8c5aaSvikram 			LDI_EVDBG((CE_NOTE,
359325e8c5aaSvikram 			    "ldi_invoke_finalize(): NULLing finalize after "
359425e8c5aaSvikram 			    "calling 1 finalize following ldi_close"));
359525e8c5aaSvikram 			lecp->lec_finalize = NULL;
359625e8c5aaSvikram 		}
359725e8c5aaSvikram 	}
359825e8c5aaSvikram 	ldi_ev_unlock();
359925e8c5aaSvikram 
360025e8c5aaSvikram 	if (found)
360125e8c5aaSvikram 		return;
360225e8c5aaSvikram 
360325e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): no matching callbacks"));
360425e8c5aaSvikram }
360525e8c5aaSvikram 
360625e8c5aaSvikram /*
360725e8c5aaSvikram  * Framework function to be called from a layered driver to propagate
360825e8c5aaSvikram  * LDI "finalize" events to exported minors.
360925e8c5aaSvikram  *
361025e8c5aaSvikram  * This function is a public interface exported by the LDI framework
361125e8c5aaSvikram  * for use by layered drivers to propagate device events up the software
361225e8c5aaSvikram  * stack.
361325e8c5aaSvikram  */
361425e8c5aaSvikram void
361525e8c5aaSvikram ldi_ev_finalize(dev_info_t *dip, minor_t minor, int spec_type, int ldi_result,
361625e8c5aaSvikram     ldi_ev_cookie_t cookie, void *ev_data)
361725e8c5aaSvikram {
361825e8c5aaSvikram 	dev_t dev;
361925e8c5aaSvikram 	major_t major;
362025e8c5aaSvikram 	char *evname;
362125e8c5aaSvikram 	int ct_result = (ldi_result == LDI_EV_SUCCESS) ?
362225e8c5aaSvikram 	    CT_EV_SUCCESS : CT_EV_FAILURE;
362325e8c5aaSvikram 	uint_t ct_evtype;
362425e8c5aaSvikram 
362525e8c5aaSvikram 	ASSERT(dip);
362625e8c5aaSvikram 	ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
362725e8c5aaSvikram 	ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
362825e8c5aaSvikram 	ASSERT(ldi_native_cookie(cookie));
362925e8c5aaSvikram 
363025e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: entered: dip=%p", (void *)dip));
363125e8c5aaSvikram 
363225e8c5aaSvikram 	major = ddi_driver_major(dip);
3633a204de77Scth 	if (major == DDI_MAJOR_T_NONE) {
363425e8c5aaSvikram 		char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
363525e8c5aaSvikram 		(void) ddi_pathname(dip, path);
363625e8c5aaSvikram 		cmn_err(CE_WARN, "ldi_ev_finalize: cannot derive major number "
363725e8c5aaSvikram 		    "for device %s", path);
363825e8c5aaSvikram 		kmem_free(path, MAXPATHLEN);
363925e8c5aaSvikram 		return;
364025e8c5aaSvikram 	}
364125e8c5aaSvikram 	dev = makedevice(major, minor);
364225e8c5aaSvikram 
364325e8c5aaSvikram 	evname = ldi_ev_get_type(cookie);
364425e8c5aaSvikram 
364525e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: calling contracts"));
364625e8c5aaSvikram 	ct_evtype = ldi_contract_event(evname);
364725e8c5aaSvikram 	contract_device_finalize(dip, dev, spec_type, ct_evtype, ct_result);
364825e8c5aaSvikram 
364925e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: calling ldi_invoke_finalize"));
365025e8c5aaSvikram 	ldi_invoke_finalize(dip, dev, spec_type, evname, ldi_result, ev_data);
365125e8c5aaSvikram }
365225e8c5aaSvikram 
365325e8c5aaSvikram int
365425e8c5aaSvikram ldi_ev_remove_callbacks(ldi_callback_id_t id)
365525e8c5aaSvikram {
365625e8c5aaSvikram 	ldi_ev_callback_impl_t	*lecp;
365725e8c5aaSvikram 	ldi_ev_callback_impl_t	*next;
365825e8c5aaSvikram 	ldi_ev_callback_impl_t	*found;
365925e8c5aaSvikram 	list_t			*listp;
366025e8c5aaSvikram 
366125e8c5aaSvikram 	ASSERT(!servicing_interrupt());
366225e8c5aaSvikram 
366325e8c5aaSvikram 	if (id == 0) {
366425e8c5aaSvikram 		cmn_err(CE_WARN, "ldi_ev_remove_callbacks: Invalid ID 0");
366525e8c5aaSvikram 		return (LDI_EV_FAILURE);
366625e8c5aaSvikram 	}
366725e8c5aaSvikram 
366825e8c5aaSvikram 	LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: entered: id=%p",
366925e8c5aaSvikram 	    (void *)id));
367025e8c5aaSvikram 
367125e8c5aaSvikram 	ldi_ev_lock();
367225e8c5aaSvikram 
367325e8c5aaSvikram 	listp = &ldi_ev_callback_list.le_head;
367425e8c5aaSvikram 	next = found = NULL;
367525e8c5aaSvikram 	for (lecp = list_head(listp); lecp; lecp = next) {
367625e8c5aaSvikram 		next = list_next(listp, lecp);
367725e8c5aaSvikram 		if (lecp->lec_id == id) {
367825e8c5aaSvikram 			ASSERT(found == NULL);
367925e8c5aaSvikram 			list_remove(listp, lecp);
368025e8c5aaSvikram 			found = lecp;
368125e8c5aaSvikram 		}
368225e8c5aaSvikram 	}
368325e8c5aaSvikram 	ldi_ev_unlock();
368425e8c5aaSvikram 
368525e8c5aaSvikram 	if (found == NULL) {
368625e8c5aaSvikram 		cmn_err(CE_WARN, "No LDI event handler for id (%p)",
368725e8c5aaSvikram 		    (void *)id);
368825e8c5aaSvikram 		return (LDI_EV_SUCCESS);
368925e8c5aaSvikram 	}
369025e8c5aaSvikram 
369125e8c5aaSvikram 	if (!ldi_native_cookie(found->lec_cookie)) {
369225e8c5aaSvikram 		ASSERT(found->lec_notify == NULL);
369325e8c5aaSvikram 		if (ddi_remove_event_handler((ddi_callback_id_t)id)
369425e8c5aaSvikram 		    != DDI_SUCCESS) {
369525e8c5aaSvikram 			cmn_err(CE_WARN, "failed to remove NDI event handler "
369625e8c5aaSvikram 			    "for id (%p)", (void *)id);
369725e8c5aaSvikram 			ldi_ev_lock();
369825e8c5aaSvikram 			list_insert_tail(listp, found);
369925e8c5aaSvikram 			ldi_ev_unlock();
370025e8c5aaSvikram 			return (LDI_EV_FAILURE);
370125e8c5aaSvikram 		}
370225e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: NDI event "
370325e8c5aaSvikram 		    "service removal succeeded"));
370425e8c5aaSvikram 	} else {
370525e8c5aaSvikram 		LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: removed "
370625e8c5aaSvikram 		    "LDI native callbacks"));
370725e8c5aaSvikram 	}
370825e8c5aaSvikram 	kmem_free(found, sizeof (ldi_ev_callback_impl_t));
370925e8c5aaSvikram 
371025e8c5aaSvikram 	return (LDI_EV_SUCCESS);
371125e8c5aaSvikram }
3712