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