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
ldi_init(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
ident_hash_func(modid_t modid,dev_info_t * dip,dev_t dev)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 **
ident_find_ref_nolock(modid_t modid,dev_info_t * dip,dev_t dev,major_t major)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 *
ident_alloc(char * mod_name,dev_info_t * dip,dev_t dev,major_t major)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
ident_hold(struct ldi_ident * lip)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
ident_release(struct ldi_ident * lip)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
handle_hash_func(void * vp)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 **
handle_find_ref_nolock(vnode_t * vp,struct ldi_ident * ident)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 *
handle_find(vnode_t * vp,struct ldi_ident * ident)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 *
handle_alloc(vnode_t * vp,struct ldi_ident * ident)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
handle_release(struct ldi_handle * lhp)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
handle_event_add(ldi_event_t * lep)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
handle_event_remove(ldi_event_t * lep)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
i_ldi_callback(dev_info_t * dip,ddi_eventcookie_t event_cookie,void * arg,void * bus_impldata)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
ldi_vp_from_dev(dev_t dev,int otyp,vnode_t ** vpp)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
ldi_vp_from_name(char * path,vnode_t ** vpp)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
ldi_devid_match(ddi_devid_t devid,dev_info_t * dip,dev_t dev)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
ldi_vp_from_devid(ddi_devid_t devid,char * minor_name,vnode_t ** vpp)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
ldi_open_by_vp(vnode_t ** vpp,int flag,cred_t * cr,ldi_handle_t * lhp,struct ldi_ident * li)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
i_ldi_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * lengthp)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
i_ldi_prop_op_free(struct prop_driver_data * pdd)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
i_ldi_prop_op_alloc(int prop_len)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
i_ldi_prop_op_typed(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t * datap,int * lengthp,int elem_size)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
i_check_string(char * str,int prop_len)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
i_pack_string_array(char * str_concat,int prop_len,char *** str_arrayp,int * nelemp)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
ldi_usage_count()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
ldi_usage_walker_tgt_helper(ldi_usage_t * ldi_usage,vnode_t * vp)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 }
10317c478bd9