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 /*
2520aa1b4dSJoshua M. Clulow * Copyright (c) 2013, Joyent, Inc. All rights reserved.
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 "
3777c478bd9Sstevel@tonic-gate "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
3783123e98aSSuhasini Peddada (void *)retlhp, (void *)ident, (void *)vp,
3797c478bd9Sstevel@tonic-gate mod_major_to_name(getmajor(vp->v_rdev)),
3807c478bd9Sstevel@tonic-gate 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;
411*1a5e258fSJosef 'Jeff' Sipek atomic_inc_ulong(&ldi_handle_hash_count);
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate LDI_ALLOCFREE((CE_WARN, "ldi handle alloc: new "
4147c478bd9Sstevel@tonic-gate "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
4157c478bd9Sstevel@tonic-gate (void *)lhp, (void *)ident, (void *)vp,
4167c478bd9Sstevel@tonic-gate mod_major_to_name(getmajor(vp->v_rdev)),
4177c478bd9Sstevel@tonic-gate 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: "
4357c478bd9Sstevel@tonic-gate "lh=0x%p, ident=0x%p, vp=0x%p, drv=%s, minor=0x%x",
4367c478bd9Sstevel@tonic-gate (void *)lhp, (void *)lhp->lh_ident, (void *)lhp->lh_vp,
4377c478bd9Sstevel@tonic-gate mod_major_to_name(getmajor(lhp->lh_vp->v_rdev)),
4387c478bd9Sstevel@tonic-gate 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;
451*1a5e258fSJosef '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",
7797c478bd9Sstevel@tonic-gate "ldi clone open", (void *)nlhp));
7807c478bd9Sstevel@tonic-gate } else {
7817c478bd9Sstevel@tonic-gate LDI_OPENCLOSE((CE_WARN, "%s: lh=0x%p",
7827c478bd9Sstevel@tonic-gate "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 }
10317c478bd9Sstevel@tonic-gate
10327c478bd9Sstevel@tonic-gate
10337c478bd9Sstevel@tonic-gate static int
ldi_usage_walker_helper(struct ldi_ident * lip,vnode_t * vp,void * arg,int (* callback)(const ldi_usage_t *,void *))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
ldi_usage_walker(void * arg,int (* callback)(const ldi_usage_t *,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
ldi_mlink_lh(vnode_t * vp,int cmd,intptr_t arg,cred_t * crp,int * rvalp)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
ldi_mlink_fp(struct stdata * stp,file_t * fpdown,int lhlink,int type)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 "
12777c478bd9Sstevel@tonic-gate "stp=0x%p, fpdown=0x%p", "ldi_mlink_fp",
12787c478bd9Sstevel@tonic-gate (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
ldi_munlink_fp(struct stdata * stp,file_t * fpdown,int type)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 "
13927c478bd9Sstevel@tonic-gate "stp=0x%p, fpdown=0x%p", "ldi_munlink_fp",
13937c478bd9Sstevel@tonic-gate (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
ldi_ident_from_mod(struct modlinkage * modlp,ldi_ident_t * lip)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",
14537c478bd9Sstevel@tonic-gate "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
ldi_ident_from_anon()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",
14687c478bd9Sstevel@tonic-gate "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
ldi_ident_from_stream(struct queue * sq,ldi_ident_t * lip)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,
15007c478bd9Sstevel@tonic-gate "%s: li=0x%p, mod=%s, minor=0x%x, stp=0x%p",
15017c478bd9Sstevel@tonic-gate "ldi_ident_from_stream", (void *)*lip, name, getminor(dev),
15027c478bd9Sstevel@tonic-gate (void *)stp));
15037c478bd9Sstevel@tonic-gate
15047c478bd9Sstevel@tonic-gate return (0);
15057c478bd9Sstevel@tonic-gate }
15067c478bd9Sstevel@tonic-gate
15077c478bd9Sstevel@tonic-gate int
ldi_ident_from_dev(dev_t dev,ldi_ident_t * lip)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,
15237c478bd9Sstevel@tonic-gate "%s: li=0x%p, mod=%s, minor=0x%x",
15247c478bd9Sstevel@tonic-gate "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
ldi_ident_from_dip(dev_info_t * dip,ldi_ident_t * lip)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,
15467c478bd9Sstevel@tonic-gate "%s: li=0x%p, mod=%s, dip=0x%p",
15477c478bd9Sstevel@tonic-gate "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
ldi_ident_from_major(major_t major,ldi_ident_t * lip)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,
15687c478bd9Sstevel@tonic-gate "%s: li=0x%p, mod=%s",
15697c478bd9Sstevel@tonic-gate "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
ldi_ident_release(ldi_ident_t li)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,
15887c478bd9Sstevel@tonic-gate "%s: li=0x%p, mod=%s",
15897c478bd9Sstevel@tonic-gate "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
ldi_open_by_dev(dev_t * devp,int otyp,int flag,cred_t * cr,ldi_handle_t * lhp,ldi_ident_t li)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;
16007c478bd9Sstevel@tonic-gate 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
ldi_open_by_name(char * pathname,int flag,cred_t * cr,ldi_handle_t * lhp,ldi_ident_t li)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;
16277c478bd9Sstevel@tonic-gate 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
ldi_open_by_devid(ddi_devid_t devid,char * minor_name,int flag,cred_t * cr,ldi_handle_t * lhp,ldi_ident_t li)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
ldi_close(ldi_handle_t lh,int flag,cred_t * cr)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;
16767c478bd9Sstevel@tonic-gate 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
17207c478bd9Sstevel@tonic-gate /*
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
175425e8c5aaSvikram /*
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
ldi_read(ldi_handle_t lh,struct uio * uiop,cred_t * credp)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
ldi_write(ldi_handle_t lh,struct uio * uiop,cred_t * credp)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
ldi_get_size(ldi_handle_t lh,uint64_t * sizep)18167c478bd9Sstevel@tonic-gate ldi_get_size(ldi_handle_t lh, uint64_t *sizep)
18177c478bd9Sstevel@tonic-gate {
18187c478bd9Sstevel@tonic-gate 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,
18437c478bd9Sstevel@tonic-gate 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,
18737c478bd9Sstevel@tonic-gate 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,
19047c478bd9Sstevel@tonic-gate 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,
19137c478bd9Sstevel@tonic-gate 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
ldi_ioctl(ldi_handle_t lh,int cmd,intptr_t arg,int mode,cred_t * cr,int * rvalp)19267c478bd9Sstevel@tonic-gate ldi_ioctl(ldi_handle_t lh, int cmd, intptr_t arg, int mode,
19277c478bd9Sstevel@tonic-gate 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
ldi_poll(ldi_handle_t lh,short events,int anyyet,short * reventsp,struct pollhead ** phpp)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
ldi_prop_op(ldi_handle_t lh,ddi_prop_op_t prop_op,int flags,char * name,caddr_t valuep,int * length)20017c478bd9Sstevel@tonic-gate ldi_prop_op(ldi_handle_t lh, ddi_prop_op_t prop_op,
20027c478bd9Sstevel@tonic-gate 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
ldi_strategy(ldi_handle_t lh,struct buf * bp)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
ldi_dump(ldi_handle_t lh,caddr_t addr,daddr_t blkno,int nblk)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
ldi_devmap(ldi_handle_t lh,devmap_cookie_t dhp,offset_t off,size_t len,size_t * maplen,uint_t model)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
ldi_aread(ldi_handle_t lh,struct aio_req * aio_reqp,cred_t * cr)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
ldi_awrite(ldi_handle_t lh,struct aio_req * aio_reqp,cred_t * cr)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
ldi_putmsg(ldi_handle_t lh,mblk_t * smp)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,
21757c478bd9Sstevel@tonic-gate 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
ldi_getmsg(ldi_handle_t lh,mblk_t ** rmp,timestruc_t * timeo)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,
22097c478bd9Sstevel@tonic-gate rmp, NULL, &pri, &pflag, timout, &rval);
22107c478bd9Sstevel@tonic-gate return (ret);
22117c478bd9Sstevel@tonic-gate }
22127c478bd9Sstevel@tonic-gate
22137c478bd9Sstevel@tonic-gate int
ldi_get_dev(ldi_handle_t lh,dev_t * devp)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
ldi_get_otyp(ldi_handle_t lh,int * otyp)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
ldi_get_devid(ldi_handle_t lh,ddi_devid_t * devid)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
ldi_get_minor_name(ldi_handle_t lh,char ** minor_name)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
ldi_prop_lookup_int_array(ldi_handle_t lh,uint_t flags,char * name,int ** data,uint_t * nelements)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
ldi_prop_lookup_int64_array(ldi_handle_t lh,uint_t flags,char * name,int64_t ** data,uint_t * nelements)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
ldi_prop_lookup_string_array(ldi_handle_t lh,uint_t flags,char * name,char *** data,uint_t * nelements)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,
24367c478bd9Sstevel@tonic-gate &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
ldi_prop_lookup_string(ldi_handle_t lh,uint_t flags,char * name,char ** data)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
ldi_prop_lookup_byte_array(ldi_handle_t lh,uint_t flags,char * name,uchar_t ** data,uint_t * nelements)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
ldi_prop_get_int(ldi_handle_t lh,uint_t flags,char * name,int defvalue)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
ldi_prop_get_int64(ldi_handle_t lh,uint_t flags,char * name,int64_t defvalue)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
ldi_prop_exists(ldi_handle_t lh,uint_t flags,char * name)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;
27257c478bd9Sstevel@tonic-gate dev_info_t *dip;
27267c478bd9Sstevel@tonic-gate 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
ldi_get_eventcookie(ldi_handle_t lh,char * name,ddi_eventcookie_t * ecp)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
ldi_add_event_handler(ldi_handle_t lh,ddi_eventcookie_t ec,void (* handler)(ldi_handle_t,ddi_eventcookie_t,void *,void *),void * arg,ldi_callback_id_t * id)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
ldi_remove_event_handler(ldi_handle_t lh,ldi_callback_id_t id)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
ldi_native_event(const char * evname)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
ldi_ev_sync_event(const char * evname)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
ldi_contract_event(const char * evname)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 *
ldi_ev_get_type(ldi_ev_cookie_t cookie)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
ldi_native_cookie(ldi_ev_cookie_t cookie)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
ldi_get_native_cookie(const char * evname)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
ldi_ev_lock(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
ldi_ev_unlock(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
ldi_ev_get_cookie(ldi_handle_t lh,char * evname,ldi_ev_cookie_t * cookiep)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
i_ldi_ev_callback(dev_info_t * dip,ddi_eventcookie_t event_cookie,void * arg,void * ev_data)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
ldi_ev_register_callbacks(ldi_handle_t lh,ldi_ev_cookie_t cookie,ldi_ev_callback_t * callb,void * arg,ldi_callback_id_t * id)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
ldi_ev_device_match(ldi_ev_callback_impl_t * lecp,dev_info_t * dip,dev_t dev,int spec_type)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
ldi_invoke_notify(dev_info_t * dip,dev_t dev,int spec_type,char * event,void * ev_data)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
ldi_ev_notify(dev_info_t * dip,minor_t minor,int spec_type,ldi_ev_cookie_t cookie,void * ev_data)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 return (LDI_EV_SUCCESS);
349725e8c5aaSvikram }
349825e8c5aaSvikram
349925e8c5aaSvikram major = ddi_driver_major(dip);
3500a204de77Scth if (major == DDI_MAJOR_T_NONE) {
350125e8c5aaSvikram char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
350225e8c5aaSvikram (void) ddi_pathname(dip, path);
350325e8c5aaSvikram cmn_err(CE_WARN, "ldi_ev_notify: cannot derive major number "
350425e8c5aaSvikram "for device %s", path);
350525e8c5aaSvikram kmem_free(path, MAXPATHLEN);
350625e8c5aaSvikram return (LDI_EV_FAILURE);
350725e8c5aaSvikram }
350825e8c5aaSvikram dev = makedevice(major, minor);
350925e8c5aaSvikram
351025e8c5aaSvikram /*
351125e8c5aaSvikram * Generate negotiation contract events on contracts (if any) associated
351225e8c5aaSvikram * with this minor.
351325e8c5aaSvikram */
351425e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): calling contract nego."));
351525e8c5aaSvikram ct_evtype = ldi_contract_event(evname);
351625e8c5aaSvikram retc = contract_device_negotiate(dip, dev, spec_type, ct_evtype);
351725e8c5aaSvikram if (retc == CT_NACK) {
351825e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): contract neg. NACK"));
351925e8c5aaSvikram return (LDI_EV_FAILURE);
352025e8c5aaSvikram }
352125e8c5aaSvikram
352225e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): LDI invoke notify"));
352325e8c5aaSvikram retl = ldi_invoke_notify(dip, dev, spec_type, evname, ev_data);
352425e8c5aaSvikram if (retl == LDI_EV_FAILURE) {
352525e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): ldi_invoke_notify "
352625e8c5aaSvikram "returned FAILURE. Calling contract negend"));
352725e8c5aaSvikram contract_device_negend(dip, dev, spec_type, CT_EV_FAILURE);
352825e8c5aaSvikram return (LDI_EV_FAILURE);
352925e8c5aaSvikram }
353025e8c5aaSvikram
353125e8c5aaSvikram /*
353225e8c5aaSvikram * The very fact that we are here indicates that there is a
353325e8c5aaSvikram * LDI callback (and hence a constraint) for the retire of the
353425e8c5aaSvikram * HW device. So we just return success even if there are no
353525e8c5aaSvikram * contracts or LDI callbacks against the minors layered on top
353625e8c5aaSvikram * of the HW minors
353725e8c5aaSvikram */
353825e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_notify(): returning SUCCESS"));
353925e8c5aaSvikram return (LDI_EV_SUCCESS);
354025e8c5aaSvikram }
354125e8c5aaSvikram
354225e8c5aaSvikram /*
354325e8c5aaSvikram * LDI framework function to invoke "finalize" callbacks for all layered
354425e8c5aaSvikram * drivers that have registered callbacks for that event.
354525e8c5aaSvikram *
354625e8c5aaSvikram * This function is *not* to be called by layered drivers. It is for I/O
354725e8c5aaSvikram * framework code in Solaris, such as the I/O retire code and DR code
354825e8c5aaSvikram * to call while servicing a device event such as offline or degraded.
354925e8c5aaSvikram */
355025e8c5aaSvikram void
ldi_invoke_finalize(dev_info_t * dip,dev_t dev,int spec_type,char * event,int ldi_result,void * ev_data)355125e8c5aaSvikram ldi_invoke_finalize(dev_info_t *dip, dev_t dev, int spec_type, char *event,
355225e8c5aaSvikram int ldi_result, void *ev_data)
355325e8c5aaSvikram {
355425e8c5aaSvikram ldi_ev_callback_impl_t *lecp;
355525e8c5aaSvikram list_t *listp;
355625e8c5aaSvikram char *lec_event;
355725e8c5aaSvikram int found = 0;
355825e8c5aaSvikram
355925e8c5aaSvikram ASSERT(dip);
356025e8c5aaSvikram ASSERT(dev != DDI_DEV_T_NONE);
356125e8c5aaSvikram ASSERT(dev != NODEV);
356225e8c5aaSvikram ASSERT((dev == DDI_DEV_T_ANY && spec_type == 0) ||
356325e8c5aaSvikram (spec_type == S_IFCHR || spec_type == S_IFBLK));
356425e8c5aaSvikram ASSERT(event);
356525e8c5aaSvikram ASSERT(ldi_native_event(event));
356625e8c5aaSvikram ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
356725e8c5aaSvikram
356825e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): entered: dip=%p, result=%d"
356925e8c5aaSvikram " event=%s", (void *)dip, ldi_result, event));
357025e8c5aaSvikram
357125e8c5aaSvikram ldi_ev_lock();
357220aa1b4dSJoshua M. Clulow VERIFY(ldi_ev_callback_list.le_walker_next == NULL);
357325e8c5aaSvikram listp = &ldi_ev_callback_list.le_head;
357420aa1b4dSJoshua M. Clulow for (lecp = list_head(listp); lecp; lecp =
357520aa1b4dSJoshua M. Clulow ldi_ev_callback_list.le_walker_next) {
357620aa1b4dSJoshua M. Clulow ldi_ev_callback_list.le_walker_next = list_next(listp, lecp);
357725e8c5aaSvikram
357825e8c5aaSvikram if (lecp->lec_finalize == NULL) {
357925e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): No "
358025e8c5aaSvikram "finalize. Skipping"));
358125e8c5aaSvikram continue; /* Not interested in finalize */
358225e8c5aaSvikram }
358325e8c5aaSvikram
358425e8c5aaSvikram /*
358525e8c5aaSvikram * Check if matching device
358625e8c5aaSvikram */
358725e8c5aaSvikram if (!ldi_ev_device_match(lecp, dip, dev, spec_type))
358825e8c5aaSvikram continue;
358925e8c5aaSvikram
359025e8c5aaSvikram /*
359125e8c5aaSvikram * It is valid for the LDI handle to be NULL during finalize.
359225e8c5aaSvikram * The layered driver may have done an LDI close in the notify
359325e8c5aaSvikram * callback.
359425e8c5aaSvikram */
359525e8c5aaSvikram
359625e8c5aaSvikram /*
359725e8c5aaSvikram * Check if matching event
359825e8c5aaSvikram */
359925e8c5aaSvikram lec_event = ldi_ev_get_type(lecp->lec_cookie);
360025e8c5aaSvikram if (strcmp(event, lec_event) != 0) {
360125e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): Not "
360225e8c5aaSvikram "matching event {%s,%s}. Skipping",
360325e8c5aaSvikram event, lec_event));
360425e8c5aaSvikram continue;
360525e8c5aaSvikram }
360625e8c5aaSvikram
360725e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): calling finalize"));
360825e8c5aaSvikram
360925e8c5aaSvikram found = 1;
361025e8c5aaSvikram
361125e8c5aaSvikram lecp->lec_finalize(lecp->lec_lhp, lecp->lec_cookie,
361225e8c5aaSvikram ldi_result, lecp->lec_arg, ev_data);
361325e8c5aaSvikram
361425e8c5aaSvikram /*
361525e8c5aaSvikram * If LDI native event and LDI handle closed in context
361625e8c5aaSvikram * of notify, NULL out the finalize callback as we have
361725e8c5aaSvikram * already called the 1 finalize above allowed in this situation
361825e8c5aaSvikram */
361925e8c5aaSvikram if (lecp->lec_lhp == NULL &&
362025e8c5aaSvikram ldi_native_cookie(lecp->lec_cookie)) {
362125e8c5aaSvikram LDI_EVDBG((CE_NOTE,
362225e8c5aaSvikram "ldi_invoke_finalize(): NULLing finalize after "
362325e8c5aaSvikram "calling 1 finalize following ldi_close"));
362425e8c5aaSvikram lecp->lec_finalize = NULL;
362525e8c5aaSvikram }
362625e8c5aaSvikram }
362720aa1b4dSJoshua M. Clulow ldi_ev_callback_list.le_walker_next = NULL;
362825e8c5aaSvikram ldi_ev_unlock();
362925e8c5aaSvikram
363025e8c5aaSvikram if (found)
363125e8c5aaSvikram return;
363225e8c5aaSvikram
363325e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_invoke_finalize(): no matching callbacks"));
363425e8c5aaSvikram }
363525e8c5aaSvikram
363625e8c5aaSvikram /*
363725e8c5aaSvikram * Framework function to be called from a layered driver to propagate
363825e8c5aaSvikram * LDI "finalize" events to exported minors.
363925e8c5aaSvikram *
364025e8c5aaSvikram * This function is a public interface exported by the LDI framework
364125e8c5aaSvikram * for use by layered drivers to propagate device events up the software
364225e8c5aaSvikram * stack.
364325e8c5aaSvikram */
364425e8c5aaSvikram void
ldi_ev_finalize(dev_info_t * dip,minor_t minor,int spec_type,int ldi_result,ldi_ev_cookie_t cookie,void * ev_data)364525e8c5aaSvikram ldi_ev_finalize(dev_info_t *dip, minor_t minor, int spec_type, int ldi_result,
364625e8c5aaSvikram ldi_ev_cookie_t cookie, void *ev_data)
364725e8c5aaSvikram {
364825e8c5aaSvikram dev_t dev;
364925e8c5aaSvikram major_t major;
365025e8c5aaSvikram char *evname;
365125e8c5aaSvikram int ct_result = (ldi_result == LDI_EV_SUCCESS) ?
365225e8c5aaSvikram CT_EV_SUCCESS : CT_EV_FAILURE;
365325e8c5aaSvikram uint_t ct_evtype;
365425e8c5aaSvikram
365525e8c5aaSvikram ASSERT(dip);
365625e8c5aaSvikram ASSERT(spec_type == S_IFBLK || spec_type == S_IFCHR);
365725e8c5aaSvikram ASSERT(ldi_result == LDI_EV_SUCCESS || ldi_result == LDI_EV_FAILURE);
365825e8c5aaSvikram ASSERT(ldi_native_cookie(cookie));
365925e8c5aaSvikram
366025e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: entered: dip=%p", (void *)dip));
366125e8c5aaSvikram
366225e8c5aaSvikram major = ddi_driver_major(dip);
3663a204de77Scth if (major == DDI_MAJOR_T_NONE) {
366425e8c5aaSvikram char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
366525e8c5aaSvikram (void) ddi_pathname(dip, path);
366625e8c5aaSvikram cmn_err(CE_WARN, "ldi_ev_finalize: cannot derive major number "
366725e8c5aaSvikram "for device %s", path);
366825e8c5aaSvikram kmem_free(path, MAXPATHLEN);
366925e8c5aaSvikram return;
367025e8c5aaSvikram }
367125e8c5aaSvikram dev = makedevice(major, minor);
367225e8c5aaSvikram
367325e8c5aaSvikram evname = ldi_ev_get_type(cookie);
367425e8c5aaSvikram
367525e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: calling contracts"));
367625e8c5aaSvikram ct_evtype = ldi_contract_event(evname);
367725e8c5aaSvikram contract_device_finalize(dip, dev, spec_type, ct_evtype, ct_result);
367825e8c5aaSvikram
367925e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_finalize: calling ldi_invoke_finalize"));
368025e8c5aaSvikram ldi_invoke_finalize(dip, dev, spec_type, evname, ldi_result, ev_data);
368125e8c5aaSvikram }
368225e8c5aaSvikram
368325e8c5aaSvikram int
ldi_ev_remove_callbacks(ldi_callback_id_t id)368425e8c5aaSvikram ldi_ev_remove_callbacks(ldi_callback_id_t id)
368525e8c5aaSvikram {
368625e8c5aaSvikram ldi_ev_callback_impl_t *lecp;
368725e8c5aaSvikram ldi_ev_callback_impl_t *next;
368825e8c5aaSvikram ldi_ev_callback_impl_t *found;
368925e8c5aaSvikram list_t *listp;
369025e8c5aaSvikram
369125e8c5aaSvikram ASSERT(!servicing_interrupt());
369225e8c5aaSvikram
369325e8c5aaSvikram if (id == 0) {
369425e8c5aaSvikram cmn_err(CE_WARN, "ldi_ev_remove_callbacks: Invalid ID 0");
369525e8c5aaSvikram return (LDI_EV_FAILURE);
369625e8c5aaSvikram }
369725e8c5aaSvikram
369825e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: entered: id=%p",
369925e8c5aaSvikram (void *)id));
370025e8c5aaSvikram
370125e8c5aaSvikram ldi_ev_lock();
370225e8c5aaSvikram
370325e8c5aaSvikram listp = &ldi_ev_callback_list.le_head;
370425e8c5aaSvikram next = found = NULL;
370525e8c5aaSvikram for (lecp = list_head(listp); lecp; lecp = next) {
370625e8c5aaSvikram next = list_next(listp, lecp);
370725e8c5aaSvikram if (lecp->lec_id == id) {
370820aa1b4dSJoshua M. Clulow VERIFY(found == NULL);
370920aa1b4dSJoshua M. Clulow
371020aa1b4dSJoshua M. Clulow /*
371120aa1b4dSJoshua M. Clulow * If there is a walk in progress, shift that walk
371220aa1b4dSJoshua M. Clulow * along to the next element so that we can remove
371320aa1b4dSJoshua M. Clulow * this one. This allows us to unregister an arbitrary
371420aa1b4dSJoshua M. Clulow * number of callbacks from within a callback.
371520aa1b4dSJoshua M. Clulow *
371620aa1b4dSJoshua M. Clulow * See the struct definition (in sunldi_impl.h) for
371720aa1b4dSJoshua M. Clulow * more information.
371820aa1b4dSJoshua M. Clulow */
371920aa1b4dSJoshua M. Clulow if (ldi_ev_callback_list.le_walker_next == lecp)
372020aa1b4dSJoshua M. Clulow ldi_ev_callback_list.le_walker_next = next;
372120aa1b4dSJoshua M. Clulow if (ldi_ev_callback_list.le_walker_prev == lecp)
372220aa1b4dSJoshua M. Clulow ldi_ev_callback_list.le_walker_prev = list_prev(
372320aa1b4dSJoshua M. Clulow listp, ldi_ev_callback_list.le_walker_prev);
372420aa1b4dSJoshua M. Clulow
372525e8c5aaSvikram list_remove(listp, lecp);
372625e8c5aaSvikram found = lecp;
372725e8c5aaSvikram }
372825e8c5aaSvikram }
372925e8c5aaSvikram ldi_ev_unlock();
373025e8c5aaSvikram
373125e8c5aaSvikram if (found == NULL) {
373225e8c5aaSvikram cmn_err(CE_WARN, "No LDI event handler for id (%p)",
373325e8c5aaSvikram (void *)id);
373425e8c5aaSvikram return (LDI_EV_SUCCESS);
373525e8c5aaSvikram }
373625e8c5aaSvikram
373725e8c5aaSvikram if (!ldi_native_cookie(found->lec_cookie)) {
373825e8c5aaSvikram ASSERT(found->lec_notify == NULL);
373925e8c5aaSvikram if (ddi_remove_event_handler((ddi_callback_id_t)id)
374025e8c5aaSvikram != DDI_SUCCESS) {
374125e8c5aaSvikram cmn_err(CE_WARN, "failed to remove NDI event handler "
374225e8c5aaSvikram "for id (%p)", (void *)id);
374325e8c5aaSvikram ldi_ev_lock();
374425e8c5aaSvikram list_insert_tail(listp, found);
374525e8c5aaSvikram ldi_ev_unlock();
374625e8c5aaSvikram return (LDI_EV_FAILURE);
374725e8c5aaSvikram }
374825e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: NDI event "
374925e8c5aaSvikram "service removal succeeded"));
375025e8c5aaSvikram } else {
375125e8c5aaSvikram LDI_EVDBG((CE_NOTE, "ldi_ev_remove_callbacks: removed "
375225e8c5aaSvikram "LDI native callbacks"));
375325e8c5aaSvikram }
375425e8c5aaSvikram kmem_free(found, sizeof (ldi_ev_callback_impl_t));
375525e8c5aaSvikram
375625e8c5aaSvikram return (LDI_EV_SUCCESS);
375725e8c5aaSvikram }
3758