17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
22*9093SRamana.Srikanth@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237836SJohn.Forte@Sun.COM * Use is subject to license terms.
247836SJohn.Forte@Sun.COM */
257836SJohn.Forte@Sun.COM
267836SJohn.Forte@Sun.COM /*
277836SJohn.Forte@Sun.COM * Storage Volume Character and Block Driver (SV)
287836SJohn.Forte@Sun.COM *
297836SJohn.Forte@Sun.COM * This driver implements a simplistic /dev/{r}dsk/ interface to a
307836SJohn.Forte@Sun.COM * specified disk volume that is otherwise managed by the Prism
317836SJohn.Forte@Sun.COM * software. The SV driver layers itself onto the underlying disk
327836SJohn.Forte@Sun.COM * device driver by changing function pointers in the cb_ops
337836SJohn.Forte@Sun.COM * structure.
347836SJohn.Forte@Sun.COM *
357836SJohn.Forte@Sun.COM * CONFIGURATION:
367836SJohn.Forte@Sun.COM *
377836SJohn.Forte@Sun.COM * 1. Configure the driver using the svadm utility.
387836SJohn.Forte@Sun.COM * 2. Access the device as before through /dev/rdsk/c?t?d?s?
397836SJohn.Forte@Sun.COM *
407836SJohn.Forte@Sun.COM * LIMITATIONS:
417836SJohn.Forte@Sun.COM *
427836SJohn.Forte@Sun.COM * This driver should NOT be used to share a device between another
437836SJohn.Forte@Sun.COM * DataServices user interface module (e.g., STE) and a user accessing
447836SJohn.Forte@Sun.COM * the device through the block device in O_WRITE mode. This is because
457836SJohn.Forte@Sun.COM * writes through the block device are asynchronous (due to the page
467836SJohn.Forte@Sun.COM * cache) and so consistency between the block device user and the
477836SJohn.Forte@Sun.COM * STE user cannot be guaranteed.
487836SJohn.Forte@Sun.COM *
497836SJohn.Forte@Sun.COM * Data is copied between system struct buf(9s) and nsc_vec_t. This is
507836SJohn.Forte@Sun.COM * wasteful and slow.
517836SJohn.Forte@Sun.COM */
527836SJohn.Forte@Sun.COM
537836SJohn.Forte@Sun.COM #include <sys/debug.h>
547836SJohn.Forte@Sun.COM #include <sys/types.h>
557836SJohn.Forte@Sun.COM
567836SJohn.Forte@Sun.COM #include <sys/ksynch.h>
577836SJohn.Forte@Sun.COM #include <sys/kmem.h>
587836SJohn.Forte@Sun.COM #include <sys/errno.h>
597836SJohn.Forte@Sun.COM #include <sys/varargs.h>
607836SJohn.Forte@Sun.COM #include <sys/file.h>
617836SJohn.Forte@Sun.COM #include <sys/open.h>
627836SJohn.Forte@Sun.COM #include <sys/conf.h>
637836SJohn.Forte@Sun.COM #include <sys/cred.h>
647836SJohn.Forte@Sun.COM #include <sys/buf.h>
657836SJohn.Forte@Sun.COM #include <sys/uio.h>
667836SJohn.Forte@Sun.COM #ifndef DS_DDICT
677836SJohn.Forte@Sun.COM #include <sys/pathname.h>
687836SJohn.Forte@Sun.COM #endif
697836SJohn.Forte@Sun.COM #include <sys/aio_req.h>
707836SJohn.Forte@Sun.COM #include <sys/dkio.h>
717836SJohn.Forte@Sun.COM #include <sys/vtoc.h>
727836SJohn.Forte@Sun.COM #include <sys/cmn_err.h>
737836SJohn.Forte@Sun.COM #include <sys/modctl.h>
747836SJohn.Forte@Sun.COM #include <sys/ddi.h>
757836SJohn.Forte@Sun.COM #include <sys/sunddi.h>
767836SJohn.Forte@Sun.COM #include <sys/sunldi.h>
777836SJohn.Forte@Sun.COM #include <sys/nsctl/nsvers.h>
787836SJohn.Forte@Sun.COM
797836SJohn.Forte@Sun.COM #include <sys/nsc_thread.h>
807836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_s.h>
817836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_s_k.h>
827836SJohn.Forte@Sun.COM #include <sys/unistat/spcs_errors.h>
837836SJohn.Forte@Sun.COM
847836SJohn.Forte@Sun.COM #ifdef DS_DDICT
857836SJohn.Forte@Sun.COM #include "../contract.h"
867836SJohn.Forte@Sun.COM #endif
877836SJohn.Forte@Sun.COM
887836SJohn.Forte@Sun.COM #include "../nsctl.h"
897836SJohn.Forte@Sun.COM
907836SJohn.Forte@Sun.COM
917836SJohn.Forte@Sun.COM #include <sys/sdt.h> /* dtrace is S10 or later */
927836SJohn.Forte@Sun.COM
937836SJohn.Forte@Sun.COM #include "sv.h"
947836SJohn.Forte@Sun.COM #include "sv_impl.h"
957836SJohn.Forte@Sun.COM #include "sv_efi.h"
967836SJohn.Forte@Sun.COM
977836SJohn.Forte@Sun.COM #define MAX_EINTR_COUNT 1000
987836SJohn.Forte@Sun.COM
997836SJohn.Forte@Sun.COM /*
1007836SJohn.Forte@Sun.COM * sv_mod_status
1017836SJohn.Forte@Sun.COM */
1027836SJohn.Forte@Sun.COM #define SV_PREVENT_UNLOAD 1
1037836SJohn.Forte@Sun.COM #define SV_ALLOW_UNLOAD 2
1047836SJohn.Forte@Sun.COM
1057836SJohn.Forte@Sun.COM static const int sv_major_rev = ISS_VERSION_MAJ; /* Major number */
1067836SJohn.Forte@Sun.COM static const int sv_minor_rev = ISS_VERSION_MIN; /* Minor number */
1077836SJohn.Forte@Sun.COM static const int sv_micro_rev = ISS_VERSION_MIC; /* Micro number */
1087836SJohn.Forte@Sun.COM static const int sv_baseline_rev = ISS_VERSION_NUM; /* Baseline number */
1097836SJohn.Forte@Sun.COM
1107836SJohn.Forte@Sun.COM #ifdef DKIOCPARTITION
1117836SJohn.Forte@Sun.COM /*
1127836SJohn.Forte@Sun.COM * CRC32 polynomial table needed for computing the checksums
1137836SJohn.Forte@Sun.COM * in an EFI vtoc.
1147836SJohn.Forte@Sun.COM */
1157836SJohn.Forte@Sun.COM static const uint32_t sv_crc32_table[256] = { CRC32_TABLE };
1167836SJohn.Forte@Sun.COM #endif
1177836SJohn.Forte@Sun.COM
1187836SJohn.Forte@Sun.COM static clock_t sv_config_time; /* Time of successful {en,dis}able */
1197836SJohn.Forte@Sun.COM static int sv_debug; /* Set non-zero for debug to syslog */
1207836SJohn.Forte@Sun.COM static int sv_mod_status; /* Set to prevent modunload */
1217836SJohn.Forte@Sun.COM
1227836SJohn.Forte@Sun.COM static dev_info_t *sv_dip; /* Single DIP for driver */
1237836SJohn.Forte@Sun.COM static kmutex_t sv_mutex; /* Protect global lists, etc. */
1247836SJohn.Forte@Sun.COM
1257836SJohn.Forte@Sun.COM static nsc_mem_t *sv_mem; /* nsctl memory allocator token */
1267836SJohn.Forte@Sun.COM
1277836SJohn.Forte@Sun.COM
1287836SJohn.Forte@Sun.COM /*
1297836SJohn.Forte@Sun.COM * Per device and per major state.
1307836SJohn.Forte@Sun.COM */
1317836SJohn.Forte@Sun.COM
1327836SJohn.Forte@Sun.COM #ifndef _SunOS_5_6
1337836SJohn.Forte@Sun.COM #define UNSAFE_ENTER()
1347836SJohn.Forte@Sun.COM #define UNSAFE_EXIT()
1357836SJohn.Forte@Sun.COM #else
1367836SJohn.Forte@Sun.COM #define UNSAFE_ENTER() mutex_enter(&unsafe_driver)
1377836SJohn.Forte@Sun.COM #define UNSAFE_EXIT() mutex_exit(&unsafe_driver)
1387836SJohn.Forte@Sun.COM #endif
1397836SJohn.Forte@Sun.COM
1407836SJohn.Forte@Sun.COM /* hash table of major dev structures */
1417836SJohn.Forte@Sun.COM static sv_maj_t *sv_majors[SV_MAJOR_HASH_CNT] = {0};
1427836SJohn.Forte@Sun.COM static sv_dev_t *sv_devs; /* array of per device structures */
1437836SJohn.Forte@Sun.COM static int sv_max_devices; /* SV version of nsc_max_devices() */
1447836SJohn.Forte@Sun.COM static int sv_ndevices; /* number of SV enabled devices */
1457836SJohn.Forte@Sun.COM
1467836SJohn.Forte@Sun.COM /*
1477836SJohn.Forte@Sun.COM * Threading.
1487836SJohn.Forte@Sun.COM */
1497836SJohn.Forte@Sun.COM
1507836SJohn.Forte@Sun.COM int sv_threads_max = 1024; /* maximum # to dynamically alloc */
1517836SJohn.Forte@Sun.COM int sv_threads = 32; /* # to pre-allocate (see sv.conf) */
1527836SJohn.Forte@Sun.COM int sv_threads_extra = 0; /* addl # we would have alloc'ed */
1537836SJohn.Forte@Sun.COM
1547836SJohn.Forte@Sun.COM static nstset_t *sv_tset; /* the threadset pointer */
1557836SJohn.Forte@Sun.COM
1567836SJohn.Forte@Sun.COM static int sv_threads_hysteresis = 4; /* hysteresis for threadset resizing */
1577836SJohn.Forte@Sun.COM static int sv_threads_dev = 2; /* # of threads to alloc per device */
1587836SJohn.Forte@Sun.COM static int sv_threads_inc = 8; /* increment for changing the set */
1597836SJohn.Forte@Sun.COM static int sv_threads_needed; /* number of threads needed */
1607836SJohn.Forte@Sun.COM static int sv_no_threads; /* number of nsc_create errors */
1617836SJohn.Forte@Sun.COM static int sv_max_nlive; /* max number of threads running */
1627836SJohn.Forte@Sun.COM
1637836SJohn.Forte@Sun.COM
1647836SJohn.Forte@Sun.COM
1657836SJohn.Forte@Sun.COM /*
1667836SJohn.Forte@Sun.COM * nsctl fd callbacks.
1677836SJohn.Forte@Sun.COM */
1687836SJohn.Forte@Sun.COM
1697836SJohn.Forte@Sun.COM static int svattach_fd(blind_t);
1707836SJohn.Forte@Sun.COM static int svdetach_fd(blind_t);
1717836SJohn.Forte@Sun.COM
1727836SJohn.Forte@Sun.COM static nsc_def_t sv_fd_def[] = {
1737836SJohn.Forte@Sun.COM { "Attach", (uintptr_t)svattach_fd, },
1747836SJohn.Forte@Sun.COM { "Detach", (uintptr_t)svdetach_fd, },
1757836SJohn.Forte@Sun.COM { 0, 0, }
1767836SJohn.Forte@Sun.COM };
1777836SJohn.Forte@Sun.COM
1787836SJohn.Forte@Sun.COM /*
1797836SJohn.Forte@Sun.COM * cb_ops functions.
1807836SJohn.Forte@Sun.COM */
1817836SJohn.Forte@Sun.COM
1827836SJohn.Forte@Sun.COM static int svopen(dev_t *, int, int, cred_t *);
1837836SJohn.Forte@Sun.COM static int svclose(dev_t, int, int, cred_t *);
1847836SJohn.Forte@Sun.COM static int svioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1857836SJohn.Forte@Sun.COM static int svprint(dev_t, char *);
1867836SJohn.Forte@Sun.COM
1877836SJohn.Forte@Sun.COM /*
1887836SJohn.Forte@Sun.COM * These next functions are layered into the underlying driver's devops.
1897836SJohn.Forte@Sun.COM */
1907836SJohn.Forte@Sun.COM
1917836SJohn.Forte@Sun.COM static int sv_lyr_open(dev_t *, int, int, cred_t *);
1927836SJohn.Forte@Sun.COM static int sv_lyr_close(dev_t, int, int, cred_t *);
1937836SJohn.Forte@Sun.COM static int sv_lyr_strategy(struct buf *);
1947836SJohn.Forte@Sun.COM static int sv_lyr_read(dev_t, struct uio *, cred_t *);
1957836SJohn.Forte@Sun.COM static int sv_lyr_write(dev_t, struct uio *, cred_t *);
1967836SJohn.Forte@Sun.COM static int sv_lyr_aread(dev_t, struct aio_req *, cred_t *);
1977836SJohn.Forte@Sun.COM static int sv_lyr_awrite(dev_t, struct aio_req *, cred_t *);
1987836SJohn.Forte@Sun.COM static int sv_lyr_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
1997836SJohn.Forte@Sun.COM
2007836SJohn.Forte@Sun.COM static struct cb_ops sv_cb_ops = {
2017836SJohn.Forte@Sun.COM svopen, /* open */
2027836SJohn.Forte@Sun.COM svclose, /* close */
2037836SJohn.Forte@Sun.COM nulldev, /* strategy */
2047836SJohn.Forte@Sun.COM svprint,
2057836SJohn.Forte@Sun.COM nodev, /* dump */
2067836SJohn.Forte@Sun.COM nodev, /* read */
2077836SJohn.Forte@Sun.COM nodev, /* write */
2087836SJohn.Forte@Sun.COM svioctl,
2097836SJohn.Forte@Sun.COM nodev, /* devmap */
2107836SJohn.Forte@Sun.COM nodev, /* mmap */
2117836SJohn.Forte@Sun.COM nodev, /* segmap */
2127836SJohn.Forte@Sun.COM nochpoll, /* poll */
2137836SJohn.Forte@Sun.COM ddi_prop_op,
2147836SJohn.Forte@Sun.COM NULL, /* NOT a stream */
2157836SJohn.Forte@Sun.COM D_NEW | D_MP | D_64BIT,
2167836SJohn.Forte@Sun.COM CB_REV,
2177836SJohn.Forte@Sun.COM nodev, /* aread */
2187836SJohn.Forte@Sun.COM nodev, /* awrite */
2197836SJohn.Forte@Sun.COM };
2207836SJohn.Forte@Sun.COM
2217836SJohn.Forte@Sun.COM
2227836SJohn.Forte@Sun.COM /*
2237836SJohn.Forte@Sun.COM * dev_ops functions.
2247836SJohn.Forte@Sun.COM */
2257836SJohn.Forte@Sun.COM
2267836SJohn.Forte@Sun.COM static int sv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
2277836SJohn.Forte@Sun.COM static int sv_attach(dev_info_t *, ddi_attach_cmd_t);
2287836SJohn.Forte@Sun.COM static int sv_detach(dev_info_t *, ddi_detach_cmd_t);
2297836SJohn.Forte@Sun.COM
2307836SJohn.Forte@Sun.COM static struct dev_ops sv_ops = {
2317836SJohn.Forte@Sun.COM DEVO_REV,
2327836SJohn.Forte@Sun.COM 0,
2337836SJohn.Forte@Sun.COM sv_getinfo,
2347836SJohn.Forte@Sun.COM nulldev, /* identify */
2357836SJohn.Forte@Sun.COM nulldev, /* probe */
2367836SJohn.Forte@Sun.COM sv_attach,
2377836SJohn.Forte@Sun.COM sv_detach,
2387836SJohn.Forte@Sun.COM nodev, /* reset */
2397836SJohn.Forte@Sun.COM &sv_cb_ops,
2407836SJohn.Forte@Sun.COM (struct bus_ops *)0
2417836SJohn.Forte@Sun.COM };
2427836SJohn.Forte@Sun.COM
2437836SJohn.Forte@Sun.COM /*
2447836SJohn.Forte@Sun.COM * Module linkage.
2457836SJohn.Forte@Sun.COM */
2467836SJohn.Forte@Sun.COM
2477836SJohn.Forte@Sun.COM extern struct mod_ops mod_driverops;
2487836SJohn.Forte@Sun.COM
2497836SJohn.Forte@Sun.COM static struct modldrv modldrv = {
2507836SJohn.Forte@Sun.COM &mod_driverops,
2517836SJohn.Forte@Sun.COM "nws:Storage Volume:" ISS_VERSION_STR,
2527836SJohn.Forte@Sun.COM &sv_ops
2537836SJohn.Forte@Sun.COM };
2547836SJohn.Forte@Sun.COM
2557836SJohn.Forte@Sun.COM static struct modlinkage modlinkage = {
2567836SJohn.Forte@Sun.COM MODREV_1,
2577836SJohn.Forte@Sun.COM &modldrv,
2587836SJohn.Forte@Sun.COM 0
2597836SJohn.Forte@Sun.COM };
2607836SJohn.Forte@Sun.COM
2617836SJohn.Forte@Sun.COM
2627836SJohn.Forte@Sun.COM int
_init(void)2637836SJohn.Forte@Sun.COM _init(void)
2647836SJohn.Forte@Sun.COM {
2657836SJohn.Forte@Sun.COM int error;
2667836SJohn.Forte@Sun.COM
2677836SJohn.Forte@Sun.COM mutex_init(&sv_mutex, NULL, MUTEX_DRIVER, NULL);
2687836SJohn.Forte@Sun.COM
2697836SJohn.Forte@Sun.COM if ((error = mod_install(&modlinkage)) != 0) {
2707836SJohn.Forte@Sun.COM mutex_destroy(&sv_mutex);
2717836SJohn.Forte@Sun.COM return (error);
2727836SJohn.Forte@Sun.COM }
2737836SJohn.Forte@Sun.COM
2747836SJohn.Forte@Sun.COM #ifdef DEBUG
275*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!sv (revision %d.%d.%d.%d, %s, %s)\n",
2767836SJohn.Forte@Sun.COM sv_major_rev, sv_minor_rev, sv_micro_rev, sv_baseline_rev,
2777836SJohn.Forte@Sun.COM ISS_VERSION_STR, BUILD_DATE_STR);
2787836SJohn.Forte@Sun.COM #else
2797836SJohn.Forte@Sun.COM if (sv_micro_rev) {
280*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!sv (revision %d.%d.%d, %s, %s)\n",
2817836SJohn.Forte@Sun.COM sv_major_rev, sv_minor_rev, sv_micro_rev,
2827836SJohn.Forte@Sun.COM ISS_VERSION_STR, BUILD_DATE_STR);
2837836SJohn.Forte@Sun.COM } else {
284*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!sv (revision %d.%d, %s, %s)\n",
2857836SJohn.Forte@Sun.COM sv_major_rev, sv_minor_rev,
2867836SJohn.Forte@Sun.COM ISS_VERSION_STR, BUILD_DATE_STR);
2877836SJohn.Forte@Sun.COM }
2887836SJohn.Forte@Sun.COM #endif
2897836SJohn.Forte@Sun.COM
2907836SJohn.Forte@Sun.COM return (error);
2917836SJohn.Forte@Sun.COM }
2927836SJohn.Forte@Sun.COM
2937836SJohn.Forte@Sun.COM
2947836SJohn.Forte@Sun.COM int
_fini(void)2957836SJohn.Forte@Sun.COM _fini(void)
2967836SJohn.Forte@Sun.COM {
2977836SJohn.Forte@Sun.COM int error;
2987836SJohn.Forte@Sun.COM
2997836SJohn.Forte@Sun.COM if ((error = mod_remove(&modlinkage)) != 0)
3007836SJohn.Forte@Sun.COM return (error);
3017836SJohn.Forte@Sun.COM
3027836SJohn.Forte@Sun.COM mutex_destroy(&sv_mutex);
3037836SJohn.Forte@Sun.COM
3047836SJohn.Forte@Sun.COM return (error);
3057836SJohn.Forte@Sun.COM }
3067836SJohn.Forte@Sun.COM
3077836SJohn.Forte@Sun.COM
3087836SJohn.Forte@Sun.COM int
_info(struct modinfo * modinfop)3097836SJohn.Forte@Sun.COM _info(struct modinfo *modinfop)
3107836SJohn.Forte@Sun.COM {
3117836SJohn.Forte@Sun.COM return (mod_info(&modlinkage, modinfop));
3127836SJohn.Forte@Sun.COM }
3137836SJohn.Forte@Sun.COM
3147836SJohn.Forte@Sun.COM
3157836SJohn.Forte@Sun.COM /*
3167836SJohn.Forte@Sun.COM * Locking & State.
3177836SJohn.Forte@Sun.COM *
3187836SJohn.Forte@Sun.COM * sv_mutex protects config information - sv_maj_t and sv_dev_t lists;
3197836SJohn.Forte@Sun.COM * threadset creation and sizing; sv_ndevices.
3207836SJohn.Forte@Sun.COM *
3217836SJohn.Forte@Sun.COM * If we need to hold both sv_mutex and sv_lock, then the sv_mutex
3227836SJohn.Forte@Sun.COM * must be acquired first.
3237836SJohn.Forte@Sun.COM *
3247836SJohn.Forte@Sun.COM * sv_lock protects the sv_dev_t structure for an individual device.
3257836SJohn.Forte@Sun.COM *
3267836SJohn.Forte@Sun.COM * sv_olock protects the otyp/open members of the sv_dev_t. If we need
3277836SJohn.Forte@Sun.COM * to hold both sv_lock and sv_olock, then the sv_lock must be acquired
3287836SJohn.Forte@Sun.COM * first.
3297836SJohn.Forte@Sun.COM *
3307836SJohn.Forte@Sun.COM * nsc_reserve/nsc_release are used in NSC_MULTI mode to allow multiple
3317836SJohn.Forte@Sun.COM * I/O operations to a device simultaneously, as above.
3327836SJohn.Forte@Sun.COM *
3337836SJohn.Forte@Sun.COM * All nsc_open/nsc_close/nsc_reserve/nsc_release operations that occur
3347836SJohn.Forte@Sun.COM * with sv_lock write-locked must be done with (sv_state == SV_PENDING)
3357836SJohn.Forte@Sun.COM * and (sv_pending == curthread) so that any recursion through
3367836SJohn.Forte@Sun.COM * sv_lyr_open/sv_lyr_close can be detected.
3377836SJohn.Forte@Sun.COM */
3387836SJohn.Forte@Sun.COM
3397836SJohn.Forte@Sun.COM
3407836SJohn.Forte@Sun.COM static int
sv_init_devs(void)3417836SJohn.Forte@Sun.COM sv_init_devs(void)
3427836SJohn.Forte@Sun.COM {
3437836SJohn.Forte@Sun.COM int i;
3447836SJohn.Forte@Sun.COM
3457836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&sv_mutex));
3467836SJohn.Forte@Sun.COM
3477836SJohn.Forte@Sun.COM if (sv_max_devices > 0)
3487836SJohn.Forte@Sun.COM return (0);
3497836SJohn.Forte@Sun.COM
3507836SJohn.Forte@Sun.COM sv_max_devices = nsc_max_devices();
3517836SJohn.Forte@Sun.COM
3527836SJohn.Forte@Sun.COM if (sv_max_devices <= 0) {
3537836SJohn.Forte@Sun.COM /* nsctl is not attached (nskernd not running) */
3547836SJohn.Forte@Sun.COM if (sv_debug > 0)
355*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!sv: nsc_max_devices = 0\n");
3567836SJohn.Forte@Sun.COM return (EAGAIN);
3577836SJohn.Forte@Sun.COM }
3587836SJohn.Forte@Sun.COM
3597836SJohn.Forte@Sun.COM sv_devs = nsc_kmem_zalloc((sv_max_devices * sizeof (*sv_devs)),
3607836SJohn.Forte@Sun.COM KM_NOSLEEP, sv_mem);
3617836SJohn.Forte@Sun.COM
3627836SJohn.Forte@Sun.COM if (sv_devs == NULL) {
363*9093SRamana.Srikanth@Sun.COM cmn_err(CE_WARN, "!sv: could not allocate sv_devs array");
3647836SJohn.Forte@Sun.COM return (ENOMEM);
3657836SJohn.Forte@Sun.COM }
3667836SJohn.Forte@Sun.COM
3677836SJohn.Forte@Sun.COM for (i = 0; i < sv_max_devices; i++) {
3687836SJohn.Forte@Sun.COM mutex_init(&sv_devs[i].sv_olock, NULL, MUTEX_DRIVER, NULL);
3697836SJohn.Forte@Sun.COM rw_init(&sv_devs[i].sv_lock, NULL, RW_DRIVER, NULL);
3707836SJohn.Forte@Sun.COM }
3717836SJohn.Forte@Sun.COM
3727836SJohn.Forte@Sun.COM if (sv_debug > 0)
373*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!sv: sv_init_devs successful\n");
3747836SJohn.Forte@Sun.COM
3757836SJohn.Forte@Sun.COM return (0);
3767836SJohn.Forte@Sun.COM }
3777836SJohn.Forte@Sun.COM
3787836SJohn.Forte@Sun.COM
3797836SJohn.Forte@Sun.COM static int
sv_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)3807836SJohn.Forte@Sun.COM sv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3817836SJohn.Forte@Sun.COM {
3827836SJohn.Forte@Sun.COM int rc;
3837836SJohn.Forte@Sun.COM
3847836SJohn.Forte@Sun.COM switch (cmd) {
3857836SJohn.Forte@Sun.COM
3867836SJohn.Forte@Sun.COM case DDI_ATTACH:
3877836SJohn.Forte@Sun.COM sv_dip = dip;
3887836SJohn.Forte@Sun.COM
3897836SJohn.Forte@Sun.COM if (ddi_create_minor_node(dip, "sv", S_IFCHR,
390*9093SRamana.Srikanth@Sun.COM 0, DDI_PSEUDO, 0) != DDI_SUCCESS)
3917836SJohn.Forte@Sun.COM goto failed;
3927836SJohn.Forte@Sun.COM
3937836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
3947836SJohn.Forte@Sun.COM
3957836SJohn.Forte@Sun.COM sv_mem = nsc_register_mem("SV", NSC_MEM_LOCAL, 0);
3967836SJohn.Forte@Sun.COM if (sv_mem == NULL) {
3977836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
3987836SJohn.Forte@Sun.COM goto failed;
3997836SJohn.Forte@Sun.COM }
4007836SJohn.Forte@Sun.COM
4017836SJohn.Forte@Sun.COM rc = sv_init_devs();
4027836SJohn.Forte@Sun.COM if (rc != 0 && rc != EAGAIN) {
4037836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
4047836SJohn.Forte@Sun.COM goto failed;
4057836SJohn.Forte@Sun.COM }
4067836SJohn.Forte@Sun.COM
4077836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
4087836SJohn.Forte@Sun.COM
4097836SJohn.Forte@Sun.COM
4107836SJohn.Forte@Sun.COM ddi_report_dev(dip);
4117836SJohn.Forte@Sun.COM
4127836SJohn.Forte@Sun.COM sv_threads = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
4137836SJohn.Forte@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
4147836SJohn.Forte@Sun.COM "sv_threads", sv_threads);
4157836SJohn.Forte@Sun.COM
4167836SJohn.Forte@Sun.COM if (sv_debug > 0)
417*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!sv: sv_threads=%d\n", sv_threads);
4187836SJohn.Forte@Sun.COM
4197836SJohn.Forte@Sun.COM if (sv_threads > sv_threads_max)
4207836SJohn.Forte@Sun.COM sv_threads_max = sv_threads;
4217836SJohn.Forte@Sun.COM
4227836SJohn.Forte@Sun.COM return (DDI_SUCCESS);
4237836SJohn.Forte@Sun.COM
4247836SJohn.Forte@Sun.COM default:
4257836SJohn.Forte@Sun.COM return (DDI_FAILURE);
4267836SJohn.Forte@Sun.COM }
4277836SJohn.Forte@Sun.COM
4287836SJohn.Forte@Sun.COM failed:
4297836SJohn.Forte@Sun.COM DTRACE_PROBE(sv_attach_failed);
4307836SJohn.Forte@Sun.COM (void) sv_detach(dip, DDI_DETACH);
4317836SJohn.Forte@Sun.COM return (DDI_FAILURE);
4327836SJohn.Forte@Sun.COM }
4337836SJohn.Forte@Sun.COM
4347836SJohn.Forte@Sun.COM
4357836SJohn.Forte@Sun.COM static int
sv_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)4367836SJohn.Forte@Sun.COM sv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4377836SJohn.Forte@Sun.COM {
4387836SJohn.Forte@Sun.COM sv_dev_t *svp;
4397836SJohn.Forte@Sun.COM int i;
4407836SJohn.Forte@Sun.COM
4417836SJohn.Forte@Sun.COM switch (cmd) {
4427836SJohn.Forte@Sun.COM
4437836SJohn.Forte@Sun.COM case DDI_DETACH:
4447836SJohn.Forte@Sun.COM
4457836SJohn.Forte@Sun.COM /*
4467836SJohn.Forte@Sun.COM * Check that everything is disabled.
4477836SJohn.Forte@Sun.COM */
4487836SJohn.Forte@Sun.COM
4497836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
4507836SJohn.Forte@Sun.COM
4517836SJohn.Forte@Sun.COM if (sv_mod_status == SV_PREVENT_UNLOAD) {
4527836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
4537836SJohn.Forte@Sun.COM DTRACE_PROBE(sv_detach_err_prevent);
4547836SJohn.Forte@Sun.COM return (DDI_FAILURE);
4557836SJohn.Forte@Sun.COM }
4567836SJohn.Forte@Sun.COM
4577836SJohn.Forte@Sun.COM for (i = 0; sv_devs && i < sv_max_devices; i++) {
4587836SJohn.Forte@Sun.COM svp = &sv_devs[i];
4597836SJohn.Forte@Sun.COM
4607836SJohn.Forte@Sun.COM if (svp->sv_state != SV_DISABLE) {
4617836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
4627836SJohn.Forte@Sun.COM DTRACE_PROBE(sv_detach_err_busy);
4637836SJohn.Forte@Sun.COM return (DDI_FAILURE);
4647836SJohn.Forte@Sun.COM }
4657836SJohn.Forte@Sun.COM }
4667836SJohn.Forte@Sun.COM
4677836SJohn.Forte@Sun.COM
4687836SJohn.Forte@Sun.COM for (i = 0; sv_devs && i < sv_max_devices; i++) {
4697836SJohn.Forte@Sun.COM mutex_destroy(&sv_devs[i].sv_olock);
4707836SJohn.Forte@Sun.COM rw_destroy(&sv_devs[i].sv_lock);
4717836SJohn.Forte@Sun.COM }
4727836SJohn.Forte@Sun.COM
4737836SJohn.Forte@Sun.COM if (sv_devs) {
4747836SJohn.Forte@Sun.COM nsc_kmem_free(sv_devs,
4757836SJohn.Forte@Sun.COM (sv_max_devices * sizeof (*sv_devs)));
4767836SJohn.Forte@Sun.COM sv_devs = NULL;
4777836SJohn.Forte@Sun.COM }
4787836SJohn.Forte@Sun.COM sv_max_devices = 0;
4797836SJohn.Forte@Sun.COM
4807836SJohn.Forte@Sun.COM if (sv_mem) {
4817836SJohn.Forte@Sun.COM nsc_unregister_mem(sv_mem);
4827836SJohn.Forte@Sun.COM sv_mem = NULL;
4837836SJohn.Forte@Sun.COM }
4847836SJohn.Forte@Sun.COM
4857836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
4867836SJohn.Forte@Sun.COM
4877836SJohn.Forte@Sun.COM /*
4887836SJohn.Forte@Sun.COM * Remove all minor nodes.
4897836SJohn.Forte@Sun.COM */
4907836SJohn.Forte@Sun.COM
4917836SJohn.Forte@Sun.COM ddi_remove_minor_node(dip, NULL);
4927836SJohn.Forte@Sun.COM sv_dip = NULL;
4937836SJohn.Forte@Sun.COM
4947836SJohn.Forte@Sun.COM return (DDI_SUCCESS);
4957836SJohn.Forte@Sun.COM
4967836SJohn.Forte@Sun.COM default:
4977836SJohn.Forte@Sun.COM return (DDI_FAILURE);
4987836SJohn.Forte@Sun.COM }
4997836SJohn.Forte@Sun.COM }
5007836SJohn.Forte@Sun.COM
5017836SJohn.Forte@Sun.COM static sv_maj_t *
sv_getmajor(const dev_t dev)5027836SJohn.Forte@Sun.COM sv_getmajor(const dev_t dev)
5037836SJohn.Forte@Sun.COM {
5047836SJohn.Forte@Sun.COM sv_maj_t **insert, *maj;
5057836SJohn.Forte@Sun.COM major_t umaj = getmajor(dev);
5067836SJohn.Forte@Sun.COM
5077836SJohn.Forte@Sun.COM /*
5087836SJohn.Forte@Sun.COM * See if the hash table entry, or one of the hash chains
5097836SJohn.Forte@Sun.COM * is already allocated for this major number
5107836SJohn.Forte@Sun.COM */
5117836SJohn.Forte@Sun.COM if ((maj = sv_majors[SV_MAJOR_HASH(umaj)]) != 0) {
5127836SJohn.Forte@Sun.COM do {
5137836SJohn.Forte@Sun.COM if (maj->sm_major == umaj)
5147836SJohn.Forte@Sun.COM return (maj);
5157836SJohn.Forte@Sun.COM } while ((maj = maj->sm_next) != 0);
5167836SJohn.Forte@Sun.COM }
5177836SJohn.Forte@Sun.COM
5187836SJohn.Forte@Sun.COM /*
5197836SJohn.Forte@Sun.COM * If the sv_mutex is held, there is design flaw, as the only non-mutex
5207836SJohn.Forte@Sun.COM * held callers can be sv_enable() or sv_dev_to_sv()
5217836SJohn.Forte@Sun.COM * Return an error, instead of panicing the system
5227836SJohn.Forte@Sun.COM */
5237836SJohn.Forte@Sun.COM if (MUTEX_HELD(&sv_mutex)) {
524*9093SRamana.Srikanth@Sun.COM cmn_err(CE_WARN, "!sv: could not allocate sv_maj_t");
5257836SJohn.Forte@Sun.COM return (NULL);
5267836SJohn.Forte@Sun.COM }
5277836SJohn.Forte@Sun.COM
5287836SJohn.Forte@Sun.COM /*
5297836SJohn.Forte@Sun.COM * Determine where to allocate a new element in the hash table
5307836SJohn.Forte@Sun.COM */
5317836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
5327836SJohn.Forte@Sun.COM insert = &(sv_majors[SV_MAJOR_HASH(umaj)]);
5337836SJohn.Forte@Sun.COM for (maj = *insert; maj; maj = maj->sm_next) {
5347836SJohn.Forte@Sun.COM
5357836SJohn.Forte@Sun.COM /* Did another thread beat us to it? */
5367836SJohn.Forte@Sun.COM if (maj->sm_major == umaj)
5377836SJohn.Forte@Sun.COM return (maj);
5387836SJohn.Forte@Sun.COM
5397836SJohn.Forte@Sun.COM /* Find a NULL insert point? */
5407836SJohn.Forte@Sun.COM if (maj->sm_next == NULL)
5417836SJohn.Forte@Sun.COM insert = &maj->sm_next;
5427836SJohn.Forte@Sun.COM }
5437836SJohn.Forte@Sun.COM
5447836SJohn.Forte@Sun.COM /*
5457836SJohn.Forte@Sun.COM * Located the new insert point
5467836SJohn.Forte@Sun.COM */
5477836SJohn.Forte@Sun.COM *insert = nsc_kmem_zalloc(sizeof (*maj), KM_NOSLEEP, sv_mem);
5487836SJohn.Forte@Sun.COM if ((maj = *insert) != 0)
5497836SJohn.Forte@Sun.COM maj->sm_major = umaj;
5507836SJohn.Forte@Sun.COM else
551*9093SRamana.Srikanth@Sun.COM cmn_err(CE_WARN, "!sv: could not allocate sv_maj_t");
5527836SJohn.Forte@Sun.COM
5537836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
5547836SJohn.Forte@Sun.COM
5557836SJohn.Forte@Sun.COM return (maj);
5567836SJohn.Forte@Sun.COM }
5577836SJohn.Forte@Sun.COM
5587836SJohn.Forte@Sun.COM /* ARGSUSED */
5597836SJohn.Forte@Sun.COM
5607836SJohn.Forte@Sun.COM static int
sv_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)5617836SJohn.Forte@Sun.COM sv_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
5627836SJohn.Forte@Sun.COM {
5637836SJohn.Forte@Sun.COM int rc = DDI_FAILURE;
5647836SJohn.Forte@Sun.COM
5657836SJohn.Forte@Sun.COM switch (infocmd) {
5667836SJohn.Forte@Sun.COM
5677836SJohn.Forte@Sun.COM case DDI_INFO_DEVT2DEVINFO:
5687836SJohn.Forte@Sun.COM *result = sv_dip;
5697836SJohn.Forte@Sun.COM rc = DDI_SUCCESS;
5707836SJohn.Forte@Sun.COM break;
5717836SJohn.Forte@Sun.COM
5727836SJohn.Forte@Sun.COM case DDI_INFO_DEVT2INSTANCE:
5737836SJohn.Forte@Sun.COM /*
5747836SJohn.Forte@Sun.COM * We only have a single instance.
5757836SJohn.Forte@Sun.COM */
5767836SJohn.Forte@Sun.COM *result = 0;
5777836SJohn.Forte@Sun.COM rc = DDI_SUCCESS;
5787836SJohn.Forte@Sun.COM break;
5797836SJohn.Forte@Sun.COM
5807836SJohn.Forte@Sun.COM default:
5817836SJohn.Forte@Sun.COM break;
5827836SJohn.Forte@Sun.COM }
5837836SJohn.Forte@Sun.COM
5847836SJohn.Forte@Sun.COM return (rc);
5857836SJohn.Forte@Sun.COM }
5867836SJohn.Forte@Sun.COM
5877836SJohn.Forte@Sun.COM
5887836SJohn.Forte@Sun.COM /*
5897836SJohn.Forte@Sun.COM * Hashing of devices onto major device structures.
5907836SJohn.Forte@Sun.COM *
5917836SJohn.Forte@Sun.COM * Individual device structures are hashed onto one of the sm_hash[]
5927836SJohn.Forte@Sun.COM * buckets in the relevant major device structure.
5937836SJohn.Forte@Sun.COM *
5947836SJohn.Forte@Sun.COM * Hash insertion and deletion -must- be done with sv_mutex held. Hash
5957836SJohn.Forte@Sun.COM * searching does not require the mutex because of the sm_seq member.
5967836SJohn.Forte@Sun.COM * sm_seq is incremented on each insertion (-after- hash chain pointer
5977836SJohn.Forte@Sun.COM * manipulation) and each deletion (-before- hash chain pointer
5987836SJohn.Forte@Sun.COM * manipulation). When searching the hash chain, the seq number is
5997836SJohn.Forte@Sun.COM * checked before accessing each device structure, if the seq number has
6007836SJohn.Forte@Sun.COM * changed, then we restart the search from the top of the hash chain.
6017836SJohn.Forte@Sun.COM * If we restart more than SV_HASH_RETRY times, we take sv_mutex and search
6027836SJohn.Forte@Sun.COM * the hash chain (we are guaranteed that this search cannot be
6037836SJohn.Forte@Sun.COM * interrupted).
6047836SJohn.Forte@Sun.COM */
6057836SJohn.Forte@Sun.COM
6067836SJohn.Forte@Sun.COM #define SV_HASH_RETRY 16
6077836SJohn.Forte@Sun.COM
6087836SJohn.Forte@Sun.COM static sv_dev_t *
sv_dev_to_sv(const dev_t dev,sv_maj_t ** majpp)6097836SJohn.Forte@Sun.COM sv_dev_to_sv(const dev_t dev, sv_maj_t **majpp)
6107836SJohn.Forte@Sun.COM {
6117836SJohn.Forte@Sun.COM minor_t umin = getminor(dev);
6127836SJohn.Forte@Sun.COM sv_dev_t **hb, *next, *svp;
6137836SJohn.Forte@Sun.COM sv_maj_t *maj;
6147836SJohn.Forte@Sun.COM int seq;
6157836SJohn.Forte@Sun.COM int try;
6167836SJohn.Forte@Sun.COM
6177836SJohn.Forte@Sun.COM /* Get major hash table */
6187836SJohn.Forte@Sun.COM maj = sv_getmajor(dev);
6197836SJohn.Forte@Sun.COM if (majpp)
6207836SJohn.Forte@Sun.COM *majpp = maj;
6217836SJohn.Forte@Sun.COM if (maj == NULL)
6227836SJohn.Forte@Sun.COM return (NULL);
6237836SJohn.Forte@Sun.COM
6247836SJohn.Forte@Sun.COM if (maj->sm_inuse == 0) {
6257836SJohn.Forte@Sun.COM DTRACE_PROBE1(
6267836SJohn.Forte@Sun.COM sv_dev_to_sv_end,
6277836SJohn.Forte@Sun.COM dev_t, dev);
6287836SJohn.Forte@Sun.COM return (NULL);
6297836SJohn.Forte@Sun.COM }
6307836SJohn.Forte@Sun.COM
6317836SJohn.Forte@Sun.COM hb = &(maj->sm_hash[SV_MINOR_HASH(umin)]);
6327836SJohn.Forte@Sun.COM try = 0;
6337836SJohn.Forte@Sun.COM
6347836SJohn.Forte@Sun.COM retry:
6357836SJohn.Forte@Sun.COM if (try > SV_HASH_RETRY)
6367836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
6377836SJohn.Forte@Sun.COM
6387836SJohn.Forte@Sun.COM seq = maj->sm_seq;
6397836SJohn.Forte@Sun.COM for (svp = *hb; svp; svp = next) {
6407836SJohn.Forte@Sun.COM next = svp->sv_hash;
6417836SJohn.Forte@Sun.COM
6427836SJohn.Forte@Sun.COM nsc_membar_stld(); /* preserve register load order */
6437836SJohn.Forte@Sun.COM
6447836SJohn.Forte@Sun.COM if (maj->sm_seq != seq) {
645*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dev_to_sv_retry, dev_t, dev);
6467836SJohn.Forte@Sun.COM try++;
6477836SJohn.Forte@Sun.COM goto retry;
6487836SJohn.Forte@Sun.COM }
6497836SJohn.Forte@Sun.COM
6507836SJohn.Forte@Sun.COM if (svp->sv_dev == dev)
6517836SJohn.Forte@Sun.COM break;
6527836SJohn.Forte@Sun.COM }
6537836SJohn.Forte@Sun.COM
6547836SJohn.Forte@Sun.COM if (try > SV_HASH_RETRY)
6557836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
6567836SJohn.Forte@Sun.COM
6577836SJohn.Forte@Sun.COM return (svp);
6587836SJohn.Forte@Sun.COM }
6597836SJohn.Forte@Sun.COM
6607836SJohn.Forte@Sun.COM
6617836SJohn.Forte@Sun.COM /*
6627836SJohn.Forte@Sun.COM * Must be called with sv_mutex held.
6637836SJohn.Forte@Sun.COM */
6647836SJohn.Forte@Sun.COM
6657836SJohn.Forte@Sun.COM static int
sv_get_state(const dev_t udev,sv_dev_t ** svpp)6667836SJohn.Forte@Sun.COM sv_get_state(const dev_t udev, sv_dev_t **svpp)
6677836SJohn.Forte@Sun.COM {
6687836SJohn.Forte@Sun.COM sv_dev_t **hb, **insert, *svp;
6697836SJohn.Forte@Sun.COM sv_maj_t *maj;
6707836SJohn.Forte@Sun.COM minor_t umin;
6717836SJohn.Forte@Sun.COM int i;
6727836SJohn.Forte@Sun.COM
6737836SJohn.Forte@Sun.COM /* Get major hash table */
6747836SJohn.Forte@Sun.COM if ((maj = sv_getmajor(udev)) == NULL)
6757836SJohn.Forte@Sun.COM return (NULL);
6767836SJohn.Forte@Sun.COM
6777836SJohn.Forte@Sun.COM /* Determine which minor hash table */
6787836SJohn.Forte@Sun.COM umin = getminor(udev);
6797836SJohn.Forte@Sun.COM hb = &(maj->sm_hash[SV_MINOR_HASH(umin)]);
6807836SJohn.Forte@Sun.COM
6817836SJohn.Forte@Sun.COM /* look for clash */
6827836SJohn.Forte@Sun.COM
6837836SJohn.Forte@Sun.COM insert = hb;
6847836SJohn.Forte@Sun.COM
6857836SJohn.Forte@Sun.COM for (svp = *hb; svp; svp = svp->sv_hash) {
6867836SJohn.Forte@Sun.COM if (svp->sv_dev == udev)
6877836SJohn.Forte@Sun.COM break;
6887836SJohn.Forte@Sun.COM
6897836SJohn.Forte@Sun.COM if (svp->sv_hash == NULL)
6907836SJohn.Forte@Sun.COM insert = &svp->sv_hash;
6917836SJohn.Forte@Sun.COM }
6927836SJohn.Forte@Sun.COM
6937836SJohn.Forte@Sun.COM if (svp) {
6947836SJohn.Forte@Sun.COM DTRACE_PROBE1(
6957836SJohn.Forte@Sun.COM sv_get_state_enabled,
6967836SJohn.Forte@Sun.COM dev_t, udev);
6977836SJohn.Forte@Sun.COM return (SV_EENABLED);
6987836SJohn.Forte@Sun.COM }
6997836SJohn.Forte@Sun.COM
7007836SJohn.Forte@Sun.COM /* look for spare sv_devs slot */
7017836SJohn.Forte@Sun.COM
7027836SJohn.Forte@Sun.COM for (i = 0; i < sv_max_devices; i++) {
7037836SJohn.Forte@Sun.COM svp = &sv_devs[i];
7047836SJohn.Forte@Sun.COM
7057836SJohn.Forte@Sun.COM if (svp->sv_state == SV_DISABLE)
7067836SJohn.Forte@Sun.COM break;
7077836SJohn.Forte@Sun.COM }
7087836SJohn.Forte@Sun.COM
7097836SJohn.Forte@Sun.COM if (i >= sv_max_devices) {
7107836SJohn.Forte@Sun.COM DTRACE_PROBE1(
7117836SJohn.Forte@Sun.COM sv_get_state_noslots,
7127836SJohn.Forte@Sun.COM dev_t, udev);
7137836SJohn.Forte@Sun.COM return (SV_ENOSLOTS);
7147836SJohn.Forte@Sun.COM }
7157836SJohn.Forte@Sun.COM
7167836SJohn.Forte@Sun.COM svp->sv_state = SV_PENDING;
7177836SJohn.Forte@Sun.COM svp->sv_pending = curthread;
7187836SJohn.Forte@Sun.COM
7197836SJohn.Forte@Sun.COM *insert = svp;
7207836SJohn.Forte@Sun.COM svp->sv_hash = NULL;
7217836SJohn.Forte@Sun.COM maj->sm_seq++; /* must be after the store to the hash chain */
7227836SJohn.Forte@Sun.COM
7237836SJohn.Forte@Sun.COM *svpp = svp;
7247836SJohn.Forte@Sun.COM
7257836SJohn.Forte@Sun.COM /*
7267836SJohn.Forte@Sun.COM * We do not know the size of the underlying device at
7277836SJohn.Forte@Sun.COM * this stage, so initialise "nblocks" property to
7287836SJohn.Forte@Sun.COM * zero, and update it whenever we succeed in
7297836SJohn.Forte@Sun.COM * nsc_reserve'ing the underlying nsc_fd_t.
7307836SJohn.Forte@Sun.COM */
7317836SJohn.Forte@Sun.COM
7327836SJohn.Forte@Sun.COM svp->sv_nblocks = 0;
7337836SJohn.Forte@Sun.COM
7347836SJohn.Forte@Sun.COM return (0);
7357836SJohn.Forte@Sun.COM }
7367836SJohn.Forte@Sun.COM
7377836SJohn.Forte@Sun.COM
7387836SJohn.Forte@Sun.COM /*
7397836SJohn.Forte@Sun.COM * Remove a device structure from it's hash chain.
7407836SJohn.Forte@Sun.COM * Must be called with sv_mutex held.
7417836SJohn.Forte@Sun.COM */
7427836SJohn.Forte@Sun.COM
7437836SJohn.Forte@Sun.COM static void
sv_rm_hash(sv_dev_t * svp)7447836SJohn.Forte@Sun.COM sv_rm_hash(sv_dev_t *svp)
7457836SJohn.Forte@Sun.COM {
7467836SJohn.Forte@Sun.COM sv_dev_t **svpp;
7477836SJohn.Forte@Sun.COM sv_maj_t *maj;
7487836SJohn.Forte@Sun.COM
7497836SJohn.Forte@Sun.COM /* Get major hash table */
7507836SJohn.Forte@Sun.COM if ((maj = sv_getmajor(svp->sv_dev)) == NULL)
7517836SJohn.Forte@Sun.COM return;
7527836SJohn.Forte@Sun.COM
7537836SJohn.Forte@Sun.COM /* remove svp from hash chain */
7547836SJohn.Forte@Sun.COM
7557836SJohn.Forte@Sun.COM svpp = &(maj->sm_hash[SV_MINOR_HASH(getminor(svp->sv_dev))]);
7567836SJohn.Forte@Sun.COM while (*svpp) {
7577836SJohn.Forte@Sun.COM if (*svpp == svp) {
7587836SJohn.Forte@Sun.COM /*
7597836SJohn.Forte@Sun.COM * increment of sm_seq must be before the
7607836SJohn.Forte@Sun.COM * removal from the hash chain
7617836SJohn.Forte@Sun.COM */
7627836SJohn.Forte@Sun.COM maj->sm_seq++;
7637836SJohn.Forte@Sun.COM *svpp = svp->sv_hash;
7647836SJohn.Forte@Sun.COM break;
7657836SJohn.Forte@Sun.COM }
7667836SJohn.Forte@Sun.COM
7677836SJohn.Forte@Sun.COM svpp = &(*svpp)->sv_hash;
7687836SJohn.Forte@Sun.COM }
7697836SJohn.Forte@Sun.COM
7707836SJohn.Forte@Sun.COM svp->sv_hash = NULL;
7717836SJohn.Forte@Sun.COM }
7727836SJohn.Forte@Sun.COM
7737836SJohn.Forte@Sun.COM /*
7747836SJohn.Forte@Sun.COM * Free (disable) a device structure.
7757836SJohn.Forte@Sun.COM * Must be called with sv_lock(RW_WRITER) and sv_mutex held, and will
7767836SJohn.Forte@Sun.COM * perform the exits during its processing.
7777836SJohn.Forte@Sun.COM */
7787836SJohn.Forte@Sun.COM
7797836SJohn.Forte@Sun.COM static int
sv_free(sv_dev_t * svp,const int error)7807836SJohn.Forte@Sun.COM sv_free(sv_dev_t *svp, const int error)
7817836SJohn.Forte@Sun.COM {
7827836SJohn.Forte@Sun.COM struct cb_ops *cb_ops;
7837836SJohn.Forte@Sun.COM sv_maj_t *maj;
7847836SJohn.Forte@Sun.COM
7857836SJohn.Forte@Sun.COM /* Get major hash table */
7867836SJohn.Forte@Sun.COM if ((maj = sv_getmajor(svp->sv_dev)) == NULL)
7877836SJohn.Forte@Sun.COM return (NULL);
7887836SJohn.Forte@Sun.COM
7897836SJohn.Forte@Sun.COM svp->sv_state = SV_PENDING;
7907836SJohn.Forte@Sun.COM svp->sv_pending = curthread;
7917836SJohn.Forte@Sun.COM
7927836SJohn.Forte@Sun.COM /*
7937836SJohn.Forte@Sun.COM * Close the fd's before removing from the hash or swapping
7947836SJohn.Forte@Sun.COM * back the cb_ops pointers so that the cache flushes before new
7957836SJohn.Forte@Sun.COM * io can come in.
7967836SJohn.Forte@Sun.COM */
7977836SJohn.Forte@Sun.COM
7987836SJohn.Forte@Sun.COM if (svp->sv_fd) {
7997836SJohn.Forte@Sun.COM (void) nsc_close(svp->sv_fd);
8007836SJohn.Forte@Sun.COM svp->sv_fd = 0;
8017836SJohn.Forte@Sun.COM }
8027836SJohn.Forte@Sun.COM
8037836SJohn.Forte@Sun.COM sv_rm_hash(svp);
8047836SJohn.Forte@Sun.COM
8057836SJohn.Forte@Sun.COM if (error != SV_ESDOPEN &&
8067836SJohn.Forte@Sun.COM error != SV_ELYROPEN && --maj->sm_inuse == 0) {
8077836SJohn.Forte@Sun.COM
8087836SJohn.Forte@Sun.COM if (maj->sm_dev_ops)
8097836SJohn.Forte@Sun.COM cb_ops = maj->sm_dev_ops->devo_cb_ops;
8107836SJohn.Forte@Sun.COM else
8117836SJohn.Forte@Sun.COM cb_ops = NULL;
8127836SJohn.Forte@Sun.COM
8137836SJohn.Forte@Sun.COM if (cb_ops && maj->sm_strategy != NULL) {
8147836SJohn.Forte@Sun.COM cb_ops->cb_strategy = maj->sm_strategy;
8157836SJohn.Forte@Sun.COM cb_ops->cb_close = maj->sm_close;
8167836SJohn.Forte@Sun.COM cb_ops->cb_ioctl = maj->sm_ioctl;
8177836SJohn.Forte@Sun.COM cb_ops->cb_write = maj->sm_write;
8187836SJohn.Forte@Sun.COM cb_ops->cb_open = maj->sm_open;
8197836SJohn.Forte@Sun.COM cb_ops->cb_read = maj->sm_read;
8207836SJohn.Forte@Sun.COM cb_ops->cb_flag = maj->sm_flag;
8217836SJohn.Forte@Sun.COM
8227836SJohn.Forte@Sun.COM if (maj->sm_awrite)
8237836SJohn.Forte@Sun.COM cb_ops->cb_awrite = maj->sm_awrite;
8247836SJohn.Forte@Sun.COM
8257836SJohn.Forte@Sun.COM if (maj->sm_aread)
8267836SJohn.Forte@Sun.COM cb_ops->cb_aread = maj->sm_aread;
8277836SJohn.Forte@Sun.COM
8287836SJohn.Forte@Sun.COM /*
8297836SJohn.Forte@Sun.COM * corbin XXX
8307836SJohn.Forte@Sun.COM * Leave backing device ops in maj->sm_*
8317836SJohn.Forte@Sun.COM * to handle any requests that might come
8327836SJohn.Forte@Sun.COM * in during the disable. This could be
8337836SJohn.Forte@Sun.COM * a problem however if the backing device
8347836SJohn.Forte@Sun.COM * driver is changed while we process these
8357836SJohn.Forte@Sun.COM * requests.
8367836SJohn.Forte@Sun.COM *
8377836SJohn.Forte@Sun.COM * maj->sm_strategy = 0;
8387836SJohn.Forte@Sun.COM * maj->sm_awrite = 0;
8397836SJohn.Forte@Sun.COM * maj->sm_write = 0;
8407836SJohn.Forte@Sun.COM * maj->sm_ioctl = 0;
8417836SJohn.Forte@Sun.COM * maj->sm_close = 0;
8427836SJohn.Forte@Sun.COM * maj->sm_aread = 0;
8437836SJohn.Forte@Sun.COM * maj->sm_read = 0;
8447836SJohn.Forte@Sun.COM * maj->sm_open = 0;
8457836SJohn.Forte@Sun.COM * maj->sm_flag = 0;
8467836SJohn.Forte@Sun.COM *
8477836SJohn.Forte@Sun.COM */
8487836SJohn.Forte@Sun.COM }
8497836SJohn.Forte@Sun.COM
8507836SJohn.Forte@Sun.COM if (maj->sm_dev_ops) {
8517836SJohn.Forte@Sun.COM maj->sm_dev_ops = 0;
8527836SJohn.Forte@Sun.COM }
8537836SJohn.Forte@Sun.COM }
8547836SJohn.Forte@Sun.COM
8557836SJohn.Forte@Sun.COM if (svp->sv_lh) {
8567836SJohn.Forte@Sun.COM cred_t *crp = ddi_get_cred();
8577836SJohn.Forte@Sun.COM
8587836SJohn.Forte@Sun.COM /*
8597836SJohn.Forte@Sun.COM * Close the protective layered driver open using the
8607836SJohn.Forte@Sun.COM * Sun Private layered driver i/f.
8617836SJohn.Forte@Sun.COM */
8627836SJohn.Forte@Sun.COM
8637836SJohn.Forte@Sun.COM (void) ldi_close(svp->sv_lh, FREAD|FWRITE, crp);
8647836SJohn.Forte@Sun.COM svp->sv_lh = NULL;
8657836SJohn.Forte@Sun.COM }
8667836SJohn.Forte@Sun.COM
8677836SJohn.Forte@Sun.COM svp->sv_timestamp = nsc_lbolt();
8687836SJohn.Forte@Sun.COM svp->sv_state = SV_DISABLE;
8697836SJohn.Forte@Sun.COM svp->sv_pending = NULL;
8707836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
8717836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
8727836SJohn.Forte@Sun.COM
8737836SJohn.Forte@Sun.COM return (error);
8747836SJohn.Forte@Sun.COM }
8757836SJohn.Forte@Sun.COM
8767836SJohn.Forte@Sun.COM /*
8777836SJohn.Forte@Sun.COM * Reserve the device, taking into account the possibility that
8787836SJohn.Forte@Sun.COM * the reserve might have to be retried.
8797836SJohn.Forte@Sun.COM */
8807836SJohn.Forte@Sun.COM static int
sv_reserve(nsc_fd_t * fd,int flags)8817836SJohn.Forte@Sun.COM sv_reserve(nsc_fd_t *fd, int flags)
8827836SJohn.Forte@Sun.COM {
8837836SJohn.Forte@Sun.COM int eintr_count;
8847836SJohn.Forte@Sun.COM int rc;
8857836SJohn.Forte@Sun.COM
8867836SJohn.Forte@Sun.COM eintr_count = 0;
8877836SJohn.Forte@Sun.COM do {
8887836SJohn.Forte@Sun.COM rc = nsc_reserve(fd, flags);
8897836SJohn.Forte@Sun.COM if (rc == EINTR) {
8907836SJohn.Forte@Sun.COM ++eintr_count;
8917836SJohn.Forte@Sun.COM delay(2);
8927836SJohn.Forte@Sun.COM }
8937836SJohn.Forte@Sun.COM } while ((rc == EINTR) && (eintr_count < MAX_EINTR_COUNT));
8947836SJohn.Forte@Sun.COM
8957836SJohn.Forte@Sun.COM return (rc);
8967836SJohn.Forte@Sun.COM }
8977836SJohn.Forte@Sun.COM
8987836SJohn.Forte@Sun.COM static int
sv_enable(const caddr_t path,const int flag,const dev_t udev,spcs_s_info_t kstatus)8997836SJohn.Forte@Sun.COM sv_enable(const caddr_t path, const int flag,
9007836SJohn.Forte@Sun.COM const dev_t udev, spcs_s_info_t kstatus)
9017836SJohn.Forte@Sun.COM {
9027836SJohn.Forte@Sun.COM struct dev_ops *dev_ops;
9037836SJohn.Forte@Sun.COM struct cb_ops *cb_ops;
9047836SJohn.Forte@Sun.COM sv_dev_t *svp;
9057836SJohn.Forte@Sun.COM sv_maj_t *maj;
9067836SJohn.Forte@Sun.COM nsc_size_t nblocks;
9077836SJohn.Forte@Sun.COM int rc;
9087836SJohn.Forte@Sun.COM cred_t *crp;
9097836SJohn.Forte@Sun.COM ldi_ident_t li;
9107836SJohn.Forte@Sun.COM
9117836SJohn.Forte@Sun.COM if (udev == (dev_t)-1 || udev == 0) {
9127836SJohn.Forte@Sun.COM DTRACE_PROBE1(
9137836SJohn.Forte@Sun.COM sv_enable_err_baddev,
9147836SJohn.Forte@Sun.COM dev_t, udev);
9157836SJohn.Forte@Sun.COM return (SV_EBADDEV);
9167836SJohn.Forte@Sun.COM }
9177836SJohn.Forte@Sun.COM
9187836SJohn.Forte@Sun.COM if ((flag & ~(NSC_CACHE|NSC_DEVICE)) != 0) {
9197836SJohn.Forte@Sun.COM DTRACE_PROBE1(sv_enable_err_amode, dev_t, udev);
9207836SJohn.Forte@Sun.COM return (SV_EAMODE);
9217836SJohn.Forte@Sun.COM }
9227836SJohn.Forte@Sun.COM
9237836SJohn.Forte@Sun.COM /* Get major hash table */
9247836SJohn.Forte@Sun.COM if ((maj = sv_getmajor(udev)) == NULL)
9257836SJohn.Forte@Sun.COM return (SV_EBADDEV);
9267836SJohn.Forte@Sun.COM
9277836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
9287836SJohn.Forte@Sun.COM
9297836SJohn.Forte@Sun.COM rc = sv_get_state(udev, &svp);
9307836SJohn.Forte@Sun.COM if (rc) {
9317836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
932*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_enable_err_state, dev_t, udev);
9337836SJohn.Forte@Sun.COM return (rc);
9347836SJohn.Forte@Sun.COM }
9357836SJohn.Forte@Sun.COM
9367836SJohn.Forte@Sun.COM rw_enter(&svp->sv_lock, RW_WRITER);
9377836SJohn.Forte@Sun.COM
9387836SJohn.Forte@Sun.COM /*
9397836SJohn.Forte@Sun.COM * Get real fd used for io
9407836SJohn.Forte@Sun.COM */
9417836SJohn.Forte@Sun.COM
9427836SJohn.Forte@Sun.COM svp->sv_dev = udev;
9437836SJohn.Forte@Sun.COM svp->sv_flag = flag;
9447836SJohn.Forte@Sun.COM
9457836SJohn.Forte@Sun.COM /*
9467836SJohn.Forte@Sun.COM * OR in NSC_DEVICE to ensure that nskern grabs the real strategy
9477836SJohn.Forte@Sun.COM * function pointer before sv swaps them out.
9487836SJohn.Forte@Sun.COM */
9497836SJohn.Forte@Sun.COM
9507836SJohn.Forte@Sun.COM svp->sv_fd = nsc_open(path, (svp->sv_flag | NSC_DEVICE),
951*9093SRamana.Srikanth@Sun.COM sv_fd_def, (blind_t)udev, &rc);
9527836SJohn.Forte@Sun.COM
9537836SJohn.Forte@Sun.COM if (svp->sv_fd == NULL) {
9547836SJohn.Forte@Sun.COM if (kstatus)
9557836SJohn.Forte@Sun.COM spcs_s_add(kstatus, rc);
956*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_enable_err_fd, dev_t, udev);
9577836SJohn.Forte@Sun.COM return (sv_free(svp, SV_ESDOPEN));
9587836SJohn.Forte@Sun.COM }
9597836SJohn.Forte@Sun.COM
9607836SJohn.Forte@Sun.COM /*
9617836SJohn.Forte@Sun.COM * Perform a layered driver open using the Sun Private layered
9627836SJohn.Forte@Sun.COM * driver i/f to ensure that the cb_ops structure for the driver
9637836SJohn.Forte@Sun.COM * is not detached out from under us whilst sv is enabled.
9647836SJohn.Forte@Sun.COM *
9657836SJohn.Forte@Sun.COM */
9667836SJohn.Forte@Sun.COM
9677836SJohn.Forte@Sun.COM crp = ddi_get_cred();
9687836SJohn.Forte@Sun.COM svp->sv_lh = NULL;
9697836SJohn.Forte@Sun.COM
9707836SJohn.Forte@Sun.COM if ((rc = ldi_ident_from_dev(svp->sv_dev, &li)) == 0) {
9717836SJohn.Forte@Sun.COM rc = ldi_open_by_dev(&svp->sv_dev,
9727836SJohn.Forte@Sun.COM OTYP_BLK, FREAD|FWRITE, crp, &svp->sv_lh, li);
9737836SJohn.Forte@Sun.COM }
9747836SJohn.Forte@Sun.COM
9757836SJohn.Forte@Sun.COM if (rc != 0) {
9767836SJohn.Forte@Sun.COM if (kstatus)
9777836SJohn.Forte@Sun.COM spcs_s_add(kstatus, rc);
978*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_enable_err_lyr_open, dev_t, udev);
9797836SJohn.Forte@Sun.COM return (sv_free(svp, SV_ELYROPEN));
9807836SJohn.Forte@Sun.COM }
9817836SJohn.Forte@Sun.COM
9827836SJohn.Forte@Sun.COM /*
9837836SJohn.Forte@Sun.COM * Do layering if required - must happen after nsc_open().
9847836SJohn.Forte@Sun.COM */
9857836SJohn.Forte@Sun.COM
9867836SJohn.Forte@Sun.COM if (maj->sm_inuse++ == 0) {
9877836SJohn.Forte@Sun.COM maj->sm_dev_ops = nsc_get_devops(getmajor(udev));
9887836SJohn.Forte@Sun.COM
9897836SJohn.Forte@Sun.COM if (maj->sm_dev_ops == NULL ||
990*9093SRamana.Srikanth@Sun.COM maj->sm_dev_ops->devo_cb_ops == NULL) {
991*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_enable_err_load, dev_t, udev);
9927836SJohn.Forte@Sun.COM return (sv_free(svp, SV_ELOAD));
9937836SJohn.Forte@Sun.COM }
9947836SJohn.Forte@Sun.COM
9957836SJohn.Forte@Sun.COM dev_ops = maj->sm_dev_ops;
9967836SJohn.Forte@Sun.COM cb_ops = dev_ops->devo_cb_ops;
9977836SJohn.Forte@Sun.COM
9987836SJohn.Forte@Sun.COM if (cb_ops->cb_strategy == NULL ||
9997836SJohn.Forte@Sun.COM cb_ops->cb_strategy == nodev ||
10007836SJohn.Forte@Sun.COM cb_ops->cb_strategy == nulldev) {
1001*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_enable_err_nostrategy, dev_t, udev);
10027836SJohn.Forte@Sun.COM return (sv_free(svp, SV_ELOAD));
10037836SJohn.Forte@Sun.COM }
10047836SJohn.Forte@Sun.COM
10057836SJohn.Forte@Sun.COM if (cb_ops->cb_strategy == sv_lyr_strategy) {
1006*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_enable_err_svstrategy, dev_t, udev);
10077836SJohn.Forte@Sun.COM return (sv_free(svp, SV_ESTRATEGY));
10087836SJohn.Forte@Sun.COM }
10097836SJohn.Forte@Sun.COM
10107836SJohn.Forte@Sun.COM maj->sm_strategy = cb_ops->cb_strategy;
10117836SJohn.Forte@Sun.COM maj->sm_close = cb_ops->cb_close;
10127836SJohn.Forte@Sun.COM maj->sm_ioctl = cb_ops->cb_ioctl;
10137836SJohn.Forte@Sun.COM maj->sm_write = cb_ops->cb_write;
10147836SJohn.Forte@Sun.COM maj->sm_open = cb_ops->cb_open;
10157836SJohn.Forte@Sun.COM maj->sm_read = cb_ops->cb_read;
10167836SJohn.Forte@Sun.COM maj->sm_flag = cb_ops->cb_flag;
10177836SJohn.Forte@Sun.COM
10187836SJohn.Forte@Sun.COM cb_ops->cb_flag = cb_ops->cb_flag | D_MP;
10197836SJohn.Forte@Sun.COM cb_ops->cb_strategy = sv_lyr_strategy;
10207836SJohn.Forte@Sun.COM cb_ops->cb_close = sv_lyr_close;
10217836SJohn.Forte@Sun.COM cb_ops->cb_ioctl = sv_lyr_ioctl;
10227836SJohn.Forte@Sun.COM cb_ops->cb_write = sv_lyr_write;
10237836SJohn.Forte@Sun.COM cb_ops->cb_open = sv_lyr_open;
10247836SJohn.Forte@Sun.COM cb_ops->cb_read = sv_lyr_read;
10257836SJohn.Forte@Sun.COM
10267836SJohn.Forte@Sun.COM /*
10277836SJohn.Forte@Sun.COM * Check that the driver has async I/O entry points
10287836SJohn.Forte@Sun.COM * before changing them.
10297836SJohn.Forte@Sun.COM */
10307836SJohn.Forte@Sun.COM
10317836SJohn.Forte@Sun.COM if (dev_ops->devo_rev < 3 || cb_ops->cb_rev < 1) {
10327836SJohn.Forte@Sun.COM maj->sm_awrite = 0;
10337836SJohn.Forte@Sun.COM maj->sm_aread = 0;
10347836SJohn.Forte@Sun.COM } else {
10357836SJohn.Forte@Sun.COM maj->sm_awrite = cb_ops->cb_awrite;
10367836SJohn.Forte@Sun.COM maj->sm_aread = cb_ops->cb_aread;
10377836SJohn.Forte@Sun.COM
10387836SJohn.Forte@Sun.COM cb_ops->cb_awrite = sv_lyr_awrite;
10397836SJohn.Forte@Sun.COM cb_ops->cb_aread = sv_lyr_aread;
10407836SJohn.Forte@Sun.COM }
10417836SJohn.Forte@Sun.COM
10427836SJohn.Forte@Sun.COM /*
10437836SJohn.Forte@Sun.COM * Bug 4645743
10447836SJohn.Forte@Sun.COM *
10457836SJohn.Forte@Sun.COM * Prevent sv from ever unloading after it has interposed
10467836SJohn.Forte@Sun.COM * on a major device because there is a race between
10477836SJohn.Forte@Sun.COM * sv removing its layered entry points from the target
10487836SJohn.Forte@Sun.COM * dev_ops, a client coming in and accessing the driver,
10497836SJohn.Forte@Sun.COM * and the kernel modunloading the sv text.
10507836SJohn.Forte@Sun.COM *
10517836SJohn.Forte@Sun.COM * To allow unload, do svboot -u, which only happens in
10527836SJohn.Forte@Sun.COM * pkgrm time.
10537836SJohn.Forte@Sun.COM */
10547836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&sv_mutex));
10557836SJohn.Forte@Sun.COM sv_mod_status = SV_PREVENT_UNLOAD;
10567836SJohn.Forte@Sun.COM }
10577836SJohn.Forte@Sun.COM
10587836SJohn.Forte@Sun.COM
10597836SJohn.Forte@Sun.COM svp->sv_timestamp = nsc_lbolt();
10607836SJohn.Forte@Sun.COM svp->sv_state = SV_ENABLE;
10617836SJohn.Forte@Sun.COM svp->sv_pending = NULL;
10627836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
10637836SJohn.Forte@Sun.COM
10647836SJohn.Forte@Sun.COM sv_ndevices++;
10657836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
10667836SJohn.Forte@Sun.COM
10677836SJohn.Forte@Sun.COM nblocks = 0;
10687836SJohn.Forte@Sun.COM if (sv_reserve(svp->sv_fd, NSC_READ|NSC_MULTI|NSC_PCATCH) == 0) {
10697836SJohn.Forte@Sun.COM nblocks = svp->sv_nblocks;
10707836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
10717836SJohn.Forte@Sun.COM }
10727836SJohn.Forte@Sun.COM
10737836SJohn.Forte@Sun.COM cmn_err(CE_CONT, "!sv: rdev 0x%lx, nblocks %" NSC_SZFMT "\n",
10747836SJohn.Forte@Sun.COM svp->sv_dev, nblocks);
10757836SJohn.Forte@Sun.COM
10767836SJohn.Forte@Sun.COM return (0);
10777836SJohn.Forte@Sun.COM }
10787836SJohn.Forte@Sun.COM
10797836SJohn.Forte@Sun.COM
10807836SJohn.Forte@Sun.COM static int
sv_prepare_unload()10817836SJohn.Forte@Sun.COM sv_prepare_unload()
10827836SJohn.Forte@Sun.COM {
10837836SJohn.Forte@Sun.COM int rc = 0;
10847836SJohn.Forte@Sun.COM
10857836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
10867836SJohn.Forte@Sun.COM
10877836SJohn.Forte@Sun.COM if (sv_mod_status == SV_PREVENT_UNLOAD) {
10887836SJohn.Forte@Sun.COM if ((sv_ndevices != 0) || (sv_tset != NULL)) {
10897836SJohn.Forte@Sun.COM rc = EBUSY;
10907836SJohn.Forte@Sun.COM } else {
10917836SJohn.Forte@Sun.COM sv_mod_status = SV_ALLOW_UNLOAD;
10927836SJohn.Forte@Sun.COM delay(SV_WAIT_UNLOAD * drv_usectohz(1000000));
10937836SJohn.Forte@Sun.COM }
10947836SJohn.Forte@Sun.COM }
10957836SJohn.Forte@Sun.COM
10967836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
10977836SJohn.Forte@Sun.COM return (rc);
10987836SJohn.Forte@Sun.COM }
10997836SJohn.Forte@Sun.COM
11007836SJohn.Forte@Sun.COM static int
svattach_fd(blind_t arg)11017836SJohn.Forte@Sun.COM svattach_fd(blind_t arg)
11027836SJohn.Forte@Sun.COM {
11037836SJohn.Forte@Sun.COM dev_t dev = (dev_t)arg;
11047836SJohn.Forte@Sun.COM sv_dev_t *svp = sv_dev_to_sv(dev, NULL);
11057836SJohn.Forte@Sun.COM int rc;
11067836SJohn.Forte@Sun.COM
11077836SJohn.Forte@Sun.COM if (sv_debug > 0)
1108*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!svattach_fd(%p, %p)\n", arg, (void *)svp);
11097836SJohn.Forte@Sun.COM
11107836SJohn.Forte@Sun.COM if (svp == NULL) {
11117836SJohn.Forte@Sun.COM cmn_err(CE_WARN, "!svattach_fd: no state (arg %p)", arg);
11127836SJohn.Forte@Sun.COM return (0);
11137836SJohn.Forte@Sun.COM }
11147836SJohn.Forte@Sun.COM
11157836SJohn.Forte@Sun.COM if ((rc = nsc_partsize(svp->sv_fd, &svp->sv_nblocks)) != 0) {
11167836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
11177836SJohn.Forte@Sun.COM "!svattach_fd: nsc_partsize() failed, rc %d", rc);
11187836SJohn.Forte@Sun.COM svp->sv_nblocks = 0;
11197836SJohn.Forte@Sun.COM }
11207836SJohn.Forte@Sun.COM
11217836SJohn.Forte@Sun.COM if ((rc = nsc_maxfbas(svp->sv_fd, 0, &svp->sv_maxfbas)) != 0) {
11227836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
11237836SJohn.Forte@Sun.COM "!svattach_fd: nsc_maxfbas() failed, rc %d", rc);
11247836SJohn.Forte@Sun.COM svp->sv_maxfbas = 0;
11257836SJohn.Forte@Sun.COM }
11267836SJohn.Forte@Sun.COM
11277836SJohn.Forte@Sun.COM if (sv_debug > 0) {
11287836SJohn.Forte@Sun.COM cmn_err(CE_CONT,
1129*9093SRamana.Srikanth@Sun.COM "!svattach_fd(%p): size %" NSC_SZFMT ", "
11307836SJohn.Forte@Sun.COM "maxfbas %" NSC_SZFMT "\n",
11317836SJohn.Forte@Sun.COM arg, svp->sv_nblocks, svp->sv_maxfbas);
11327836SJohn.Forte@Sun.COM }
11337836SJohn.Forte@Sun.COM
11347836SJohn.Forte@Sun.COM return (0);
11357836SJohn.Forte@Sun.COM }
11367836SJohn.Forte@Sun.COM
11377836SJohn.Forte@Sun.COM
11387836SJohn.Forte@Sun.COM static int
svdetach_fd(blind_t arg)11397836SJohn.Forte@Sun.COM svdetach_fd(blind_t arg)
11407836SJohn.Forte@Sun.COM {
11417836SJohn.Forte@Sun.COM dev_t dev = (dev_t)arg;
11427836SJohn.Forte@Sun.COM sv_dev_t *svp = sv_dev_to_sv(dev, NULL);
11437836SJohn.Forte@Sun.COM
11447836SJohn.Forte@Sun.COM if (sv_debug > 0)
1145*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!svdetach_fd(%p, %p)\n", arg, (void *)svp);
11467836SJohn.Forte@Sun.COM
11477836SJohn.Forte@Sun.COM /* svp can be NULL during disable of an sv */
11487836SJohn.Forte@Sun.COM if (svp == NULL)
11497836SJohn.Forte@Sun.COM return (0);
11507836SJohn.Forte@Sun.COM
11517836SJohn.Forte@Sun.COM svp->sv_maxfbas = 0;
11527836SJohn.Forte@Sun.COM svp->sv_nblocks = 0;
11537836SJohn.Forte@Sun.COM return (0);
11547836SJohn.Forte@Sun.COM }
11557836SJohn.Forte@Sun.COM
11567836SJohn.Forte@Sun.COM
11577836SJohn.Forte@Sun.COM /*
11587836SJohn.Forte@Sun.COM * Side effect: if called with (guard != 0), then expects both sv_mutex
11597836SJohn.Forte@Sun.COM * and sv_lock(RW_WRITER) to be held, and will release them before returning.
11607836SJohn.Forte@Sun.COM */
11617836SJohn.Forte@Sun.COM
11627836SJohn.Forte@Sun.COM /* ARGSUSED */
11637836SJohn.Forte@Sun.COM static int
sv_disable(dev_t dev,spcs_s_info_t kstatus)11647836SJohn.Forte@Sun.COM sv_disable(dev_t dev, spcs_s_info_t kstatus)
11657836SJohn.Forte@Sun.COM {
11667836SJohn.Forte@Sun.COM sv_dev_t *svp = sv_dev_to_sv(dev, NULL);
11677836SJohn.Forte@Sun.COM
11687836SJohn.Forte@Sun.COM if (svp == NULL) {
11697836SJohn.Forte@Sun.COM
11707836SJohn.Forte@Sun.COM DTRACE_PROBE1(sv_disable_err_nodev, sv_dev_t *, svp);
11717836SJohn.Forte@Sun.COM return (SV_ENODEV);
11727836SJohn.Forte@Sun.COM }
11737836SJohn.Forte@Sun.COM
11747836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
11757836SJohn.Forte@Sun.COM rw_enter(&svp->sv_lock, RW_WRITER);
11767836SJohn.Forte@Sun.COM
11777836SJohn.Forte@Sun.COM if (svp->sv_fd == NULL || svp->sv_state != SV_ENABLE) {
11787836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
11797836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
11807836SJohn.Forte@Sun.COM
11817836SJohn.Forte@Sun.COM DTRACE_PROBE1(sv_disable_err_disabled, sv_dev_t *, svp);
11827836SJohn.Forte@Sun.COM return (SV_EDISABLED);
11837836SJohn.Forte@Sun.COM }
11847836SJohn.Forte@Sun.COM
11857836SJohn.Forte@Sun.COM
11867836SJohn.Forte@Sun.COM sv_ndevices--;
11877836SJohn.Forte@Sun.COM return (sv_free(svp, 0));
11887836SJohn.Forte@Sun.COM }
11897836SJohn.Forte@Sun.COM
11907836SJohn.Forte@Sun.COM
11917836SJohn.Forte@Sun.COM
11927836SJohn.Forte@Sun.COM static int
sv_lyr_open(dev_t * devp,int flag,int otyp,cred_t * crp)11937836SJohn.Forte@Sun.COM sv_lyr_open(dev_t *devp, int flag, int otyp, cred_t *crp)
11947836SJohn.Forte@Sun.COM {
11957836SJohn.Forte@Sun.COM nsc_buf_t *tmph;
11967836SJohn.Forte@Sun.COM sv_dev_t *svp;
11977836SJohn.Forte@Sun.COM sv_maj_t *maj;
11987836SJohn.Forte@Sun.COM int (*fn)();
11997836SJohn.Forte@Sun.COM dev_t odev;
12007836SJohn.Forte@Sun.COM int ret;
12017836SJohn.Forte@Sun.COM int rc;
12027836SJohn.Forte@Sun.COM
12037836SJohn.Forte@Sun.COM svp = sv_dev_to_sv(*devp, &maj);
12047836SJohn.Forte@Sun.COM
12057836SJohn.Forte@Sun.COM if (svp) {
12067836SJohn.Forte@Sun.COM if (svp->sv_state == SV_PENDING &&
12077836SJohn.Forte@Sun.COM svp->sv_pending == curthread) {
12087836SJohn.Forte@Sun.COM /*
12097836SJohn.Forte@Sun.COM * This is a recursive open from a call to
12107836SJohn.Forte@Sun.COM * ddi_lyr_open_by_devt and so we just want
12117836SJohn.Forte@Sun.COM * to pass it straight through to the
12127836SJohn.Forte@Sun.COM * underlying driver.
12137836SJohn.Forte@Sun.COM */
12147836SJohn.Forte@Sun.COM DTRACE_PROBE2(sv_lyr_open_recursive,
12157836SJohn.Forte@Sun.COM sv_dev_t *, svp,
12167836SJohn.Forte@Sun.COM dev_t, *devp);
12177836SJohn.Forte@Sun.COM svp = NULL;
12187836SJohn.Forte@Sun.COM } else
12197836SJohn.Forte@Sun.COM rw_enter(&svp->sv_lock, RW_READER);
12207836SJohn.Forte@Sun.COM }
12217836SJohn.Forte@Sun.COM
12227836SJohn.Forte@Sun.COM odev = *devp;
12237836SJohn.Forte@Sun.COM
12247836SJohn.Forte@Sun.COM if (maj && (fn = maj->sm_open) != 0) {
12257836SJohn.Forte@Sun.COM if (!(maj->sm_flag & D_MP)) {
12267836SJohn.Forte@Sun.COM UNSAFE_ENTER();
12277836SJohn.Forte@Sun.COM ret = (*fn)(devp, flag, otyp, crp);
12287836SJohn.Forte@Sun.COM UNSAFE_EXIT();
12297836SJohn.Forte@Sun.COM } else {
12307836SJohn.Forte@Sun.COM ret = (*fn)(devp, flag, otyp, crp);
12317836SJohn.Forte@Sun.COM }
12327836SJohn.Forte@Sun.COM
12337836SJohn.Forte@Sun.COM if (ret == 0) {
12347836SJohn.Forte@Sun.COM /*
12357836SJohn.Forte@Sun.COM * Re-acquire svp if the driver changed *devp.
12367836SJohn.Forte@Sun.COM */
12377836SJohn.Forte@Sun.COM
12387836SJohn.Forte@Sun.COM if (*devp != odev) {
12397836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
12407836SJohn.Forte@Sun.COM
12417836SJohn.Forte@Sun.COM svp = sv_dev_to_sv(*devp, NULL);
12427836SJohn.Forte@Sun.COM
12437836SJohn.Forte@Sun.COM if (svp) {
12447836SJohn.Forte@Sun.COM rw_enter(&svp->sv_lock, RW_READER);
12457836SJohn.Forte@Sun.COM }
12467836SJohn.Forte@Sun.COM }
12477836SJohn.Forte@Sun.COM }
12487836SJohn.Forte@Sun.COM } else {
12497836SJohn.Forte@Sun.COM ret = ENODEV;
12507836SJohn.Forte@Sun.COM }
12517836SJohn.Forte@Sun.COM
12527836SJohn.Forte@Sun.COM if (svp && ret != 0 && svp->sv_state == SV_ENABLE) {
12537836SJohn.Forte@Sun.COM /*
12547836SJohn.Forte@Sun.COM * Underlying DDI open failed, but we have this
12557836SJohn.Forte@Sun.COM * device SV enabled. If we can read some data
12567836SJohn.Forte@Sun.COM * from the device, fake a successful open (this
12577836SJohn.Forte@Sun.COM * probably means that this device is RDC'd and we
12587836SJohn.Forte@Sun.COM * are getting the data from the secondary node).
12597836SJohn.Forte@Sun.COM *
12607836SJohn.Forte@Sun.COM * The reserve must be done with NSC_TRY|NSC_NOWAIT to
12617836SJohn.Forte@Sun.COM * ensure that it does not deadlock if this open is
12627836SJohn.Forte@Sun.COM * coming from nskernd:get_bsize().
12637836SJohn.Forte@Sun.COM */
12647836SJohn.Forte@Sun.COM rc = sv_reserve(svp->sv_fd,
1265*9093SRamana.Srikanth@Sun.COM NSC_TRY | NSC_NOWAIT | NSC_MULTI | NSC_PCATCH);
12667836SJohn.Forte@Sun.COM if (rc == 0) {
12677836SJohn.Forte@Sun.COM tmph = NULL;
12687836SJohn.Forte@Sun.COM
12697836SJohn.Forte@Sun.COM rc = nsc_alloc_buf(svp->sv_fd, 0, 1, NSC_READ, &tmph);
12707836SJohn.Forte@Sun.COM if (rc <= 0) {
12717836SJohn.Forte@Sun.COM /* success */
12727836SJohn.Forte@Sun.COM ret = 0;
12737836SJohn.Forte@Sun.COM }
12747836SJohn.Forte@Sun.COM
12757836SJohn.Forte@Sun.COM if (tmph) {
12767836SJohn.Forte@Sun.COM (void) nsc_free_buf(tmph);
12777836SJohn.Forte@Sun.COM tmph = NULL;
12787836SJohn.Forte@Sun.COM }
12797836SJohn.Forte@Sun.COM
12807836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
12817836SJohn.Forte@Sun.COM
12827836SJohn.Forte@Sun.COM /*
12837836SJohn.Forte@Sun.COM * Count the number of layered opens that we
12847836SJohn.Forte@Sun.COM * fake since we have to fake a matching number
12857836SJohn.Forte@Sun.COM * of closes (OTYP_LYR open/close calls must be
12867836SJohn.Forte@Sun.COM * paired).
12877836SJohn.Forte@Sun.COM */
12887836SJohn.Forte@Sun.COM
12897836SJohn.Forte@Sun.COM if (ret == 0 && otyp == OTYP_LYR) {
12907836SJohn.Forte@Sun.COM mutex_enter(&svp->sv_olock);
12917836SJohn.Forte@Sun.COM svp->sv_openlcnt++;
12927836SJohn.Forte@Sun.COM mutex_exit(&svp->sv_olock);
12937836SJohn.Forte@Sun.COM }
12947836SJohn.Forte@Sun.COM }
12957836SJohn.Forte@Sun.COM }
12967836SJohn.Forte@Sun.COM
12977836SJohn.Forte@Sun.COM if (svp) {
12987836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
12997836SJohn.Forte@Sun.COM }
13007836SJohn.Forte@Sun.COM
13017836SJohn.Forte@Sun.COM return (ret);
13027836SJohn.Forte@Sun.COM }
13037836SJohn.Forte@Sun.COM
13047836SJohn.Forte@Sun.COM
13057836SJohn.Forte@Sun.COM static int
sv_lyr_close(dev_t dev,int flag,int otyp,cred_t * crp)13067836SJohn.Forte@Sun.COM sv_lyr_close(dev_t dev, int flag, int otyp, cred_t *crp)
13077836SJohn.Forte@Sun.COM {
13087836SJohn.Forte@Sun.COM sv_dev_t *svp;
13097836SJohn.Forte@Sun.COM sv_maj_t *maj;
13107836SJohn.Forte@Sun.COM int (*fn)();
13117836SJohn.Forte@Sun.COM int ret;
13127836SJohn.Forte@Sun.COM
13137836SJohn.Forte@Sun.COM svp = sv_dev_to_sv(dev, &maj);
13147836SJohn.Forte@Sun.COM
13157836SJohn.Forte@Sun.COM if (svp &&
13167836SJohn.Forte@Sun.COM svp->sv_state == SV_PENDING &&
13177836SJohn.Forte@Sun.COM svp->sv_pending == curthread) {
13187836SJohn.Forte@Sun.COM /*
13197836SJohn.Forte@Sun.COM * This is a recursive open from a call to
13207836SJohn.Forte@Sun.COM * ddi_lyr_close and so we just want
13217836SJohn.Forte@Sun.COM * to pass it straight through to the
13227836SJohn.Forte@Sun.COM * underlying driver.
13237836SJohn.Forte@Sun.COM */
1324*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE2(sv_lyr_close_recursive, sv_dev_t *, svp,
1325*9093SRamana.Srikanth@Sun.COM dev_t, dev);
13267836SJohn.Forte@Sun.COM svp = NULL;
13277836SJohn.Forte@Sun.COM }
13287836SJohn.Forte@Sun.COM
13297836SJohn.Forte@Sun.COM if (svp) {
13307836SJohn.Forte@Sun.COM rw_enter(&svp->sv_lock, RW_READER);
13317836SJohn.Forte@Sun.COM
13327836SJohn.Forte@Sun.COM if (otyp == OTYP_LYR) {
13337836SJohn.Forte@Sun.COM mutex_enter(&svp->sv_olock);
13347836SJohn.Forte@Sun.COM
13357836SJohn.Forte@Sun.COM if (svp->sv_openlcnt) {
13367836SJohn.Forte@Sun.COM /*
13377836SJohn.Forte@Sun.COM * Consume sufficient layered closes to
13387836SJohn.Forte@Sun.COM * account for the opens that we faked
13397836SJohn.Forte@Sun.COM * whilst the device was failed.
13407836SJohn.Forte@Sun.COM */
13417836SJohn.Forte@Sun.COM svp->sv_openlcnt--;
13427836SJohn.Forte@Sun.COM mutex_exit(&svp->sv_olock);
13437836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
13447836SJohn.Forte@Sun.COM
1345*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_close_end, dev_t, dev);
13467836SJohn.Forte@Sun.COM
13477836SJohn.Forte@Sun.COM return (0);
13487836SJohn.Forte@Sun.COM }
13497836SJohn.Forte@Sun.COM
13507836SJohn.Forte@Sun.COM mutex_exit(&svp->sv_olock);
13517836SJohn.Forte@Sun.COM }
13527836SJohn.Forte@Sun.COM }
13537836SJohn.Forte@Sun.COM
13547836SJohn.Forte@Sun.COM if (maj && (fn = maj->sm_close) != 0) {
13557836SJohn.Forte@Sun.COM if (!(maj->sm_flag & D_MP)) {
13567836SJohn.Forte@Sun.COM UNSAFE_ENTER();
13577836SJohn.Forte@Sun.COM ret = (*fn)(dev, flag, otyp, crp);
13587836SJohn.Forte@Sun.COM UNSAFE_EXIT();
13597836SJohn.Forte@Sun.COM } else {
13607836SJohn.Forte@Sun.COM ret = (*fn)(dev, flag, otyp, crp);
13617836SJohn.Forte@Sun.COM }
13627836SJohn.Forte@Sun.COM } else {
13637836SJohn.Forte@Sun.COM ret = ENODEV;
13647836SJohn.Forte@Sun.COM }
13657836SJohn.Forte@Sun.COM
13667836SJohn.Forte@Sun.COM if (svp) {
13677836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
13687836SJohn.Forte@Sun.COM }
13697836SJohn.Forte@Sun.COM
13707836SJohn.Forte@Sun.COM return (ret);
13717836SJohn.Forte@Sun.COM }
13727836SJohn.Forte@Sun.COM
13737836SJohn.Forte@Sun.COM
13747836SJohn.Forte@Sun.COM /*
13757836SJohn.Forte@Sun.COM * Convert the specified dev_t into a locked and enabled sv_dev_t, or
13767836SJohn.Forte@Sun.COM * return NULL.
13777836SJohn.Forte@Sun.COM */
13787836SJohn.Forte@Sun.COM static sv_dev_t *
sv_find_enabled(const dev_t dev,sv_maj_t ** majpp)13797836SJohn.Forte@Sun.COM sv_find_enabled(const dev_t dev, sv_maj_t **majpp)
13807836SJohn.Forte@Sun.COM {
13817836SJohn.Forte@Sun.COM sv_dev_t *svp;
13827836SJohn.Forte@Sun.COM
13837836SJohn.Forte@Sun.COM while ((svp = sv_dev_to_sv(dev, majpp)) != NULL) {
13847836SJohn.Forte@Sun.COM rw_enter(&svp->sv_lock, RW_READER);
13857836SJohn.Forte@Sun.COM
13867836SJohn.Forte@Sun.COM if (svp->sv_state == SV_ENABLE) {
13877836SJohn.Forte@Sun.COM /* locked and enabled */
13887836SJohn.Forte@Sun.COM break;
13897836SJohn.Forte@Sun.COM }
13907836SJohn.Forte@Sun.COM
13917836SJohn.Forte@Sun.COM /*
13927836SJohn.Forte@Sun.COM * State was changed while waiting on the lock.
13937836SJohn.Forte@Sun.COM * Wait for a stable state.
13947836SJohn.Forte@Sun.COM */
13957836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
13967836SJohn.Forte@Sun.COM
1397*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_find_enabled_retry, dev_t, dev);
13987836SJohn.Forte@Sun.COM
13997836SJohn.Forte@Sun.COM delay(2);
14007836SJohn.Forte@Sun.COM }
14017836SJohn.Forte@Sun.COM
14027836SJohn.Forte@Sun.COM return (svp);
14037836SJohn.Forte@Sun.COM }
14047836SJohn.Forte@Sun.COM
14057836SJohn.Forte@Sun.COM
14067836SJohn.Forte@Sun.COM static int
sv_lyr_uio(dev_t dev,uio_t * uiop,cred_t * crp,int rw)14077836SJohn.Forte@Sun.COM sv_lyr_uio(dev_t dev, uio_t *uiop, cred_t *crp, int rw)
14087836SJohn.Forte@Sun.COM {
14097836SJohn.Forte@Sun.COM sv_dev_t *svp;
14107836SJohn.Forte@Sun.COM sv_maj_t *maj;
14117836SJohn.Forte@Sun.COM int (*fn)();
14127836SJohn.Forte@Sun.COM int rc;
14137836SJohn.Forte@Sun.COM
14147836SJohn.Forte@Sun.COM svp = sv_find_enabled(dev, &maj);
14157836SJohn.Forte@Sun.COM if (svp == NULL) {
14167836SJohn.Forte@Sun.COM if (maj) {
14177836SJohn.Forte@Sun.COM if (rw == NSC_READ)
14187836SJohn.Forte@Sun.COM fn = maj->sm_read;
14197836SJohn.Forte@Sun.COM else
14207836SJohn.Forte@Sun.COM fn = maj->sm_write;
14217836SJohn.Forte@Sun.COM
14227836SJohn.Forte@Sun.COM if (fn != 0) {
14237836SJohn.Forte@Sun.COM if (!(maj->sm_flag & D_MP)) {
14247836SJohn.Forte@Sun.COM UNSAFE_ENTER();
14257836SJohn.Forte@Sun.COM rc = (*fn)(dev, uiop, crp);
14267836SJohn.Forte@Sun.COM UNSAFE_EXIT();
14277836SJohn.Forte@Sun.COM } else {
14287836SJohn.Forte@Sun.COM rc = (*fn)(dev, uiop, crp);
14297836SJohn.Forte@Sun.COM }
14307836SJohn.Forte@Sun.COM }
14317836SJohn.Forte@Sun.COM
14327836SJohn.Forte@Sun.COM return (rc);
14337836SJohn.Forte@Sun.COM } else {
14347836SJohn.Forte@Sun.COM return (ENODEV);
14357836SJohn.Forte@Sun.COM }
14367836SJohn.Forte@Sun.COM }
14377836SJohn.Forte@Sun.COM
14387836SJohn.Forte@Sun.COM ASSERT(RW_READ_HELD(&svp->sv_lock));
14397836SJohn.Forte@Sun.COM
14407836SJohn.Forte@Sun.COM if (svp->sv_flag == 0) {
14417836SJohn.Forte@Sun.COM /*
14427836SJohn.Forte@Sun.COM * guard access mode
14437836SJohn.Forte@Sun.COM * - prevent user level access to the device
14447836SJohn.Forte@Sun.COM */
1445*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_uio_err_guard, uio_t *, uiop);
14467836SJohn.Forte@Sun.COM rc = EPERM;
14477836SJohn.Forte@Sun.COM goto out;
14487836SJohn.Forte@Sun.COM }
14497836SJohn.Forte@Sun.COM
14507836SJohn.Forte@Sun.COM if ((rc = sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH)) != 0) {
1451*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_uio_err_rsrv, uio_t *, uiop);
14527836SJohn.Forte@Sun.COM goto out;
14537836SJohn.Forte@Sun.COM }
14547836SJohn.Forte@Sun.COM
14557836SJohn.Forte@Sun.COM if (rw == NSC_READ)
14567836SJohn.Forte@Sun.COM rc = nsc_uread(svp->sv_fd, uiop, crp);
14577836SJohn.Forte@Sun.COM else
14587836SJohn.Forte@Sun.COM rc = nsc_uwrite(svp->sv_fd, uiop, crp);
14597836SJohn.Forte@Sun.COM
14607836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
14617836SJohn.Forte@Sun.COM
14627836SJohn.Forte@Sun.COM out:
14637836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
14647836SJohn.Forte@Sun.COM
14657836SJohn.Forte@Sun.COM return (rc);
14667836SJohn.Forte@Sun.COM }
14677836SJohn.Forte@Sun.COM
14687836SJohn.Forte@Sun.COM
14697836SJohn.Forte@Sun.COM static int
sv_lyr_read(dev_t dev,uio_t * uiop,cred_t * crp)14707836SJohn.Forte@Sun.COM sv_lyr_read(dev_t dev, uio_t *uiop, cred_t *crp)
14717836SJohn.Forte@Sun.COM {
14727836SJohn.Forte@Sun.COM return (sv_lyr_uio(dev, uiop, crp, NSC_READ));
14737836SJohn.Forte@Sun.COM }
14747836SJohn.Forte@Sun.COM
14757836SJohn.Forte@Sun.COM
14767836SJohn.Forte@Sun.COM static int
sv_lyr_write(dev_t dev,uio_t * uiop,cred_t * crp)14777836SJohn.Forte@Sun.COM sv_lyr_write(dev_t dev, uio_t *uiop, cred_t *crp)
14787836SJohn.Forte@Sun.COM {
14797836SJohn.Forte@Sun.COM return (sv_lyr_uio(dev, uiop, crp, NSC_WRITE));
14807836SJohn.Forte@Sun.COM }
14817836SJohn.Forte@Sun.COM
14827836SJohn.Forte@Sun.COM
14837836SJohn.Forte@Sun.COM /* ARGSUSED */
14847836SJohn.Forte@Sun.COM
14857836SJohn.Forte@Sun.COM static int
sv_lyr_aread(dev_t dev,struct aio_req * aio,cred_t * crp)14867836SJohn.Forte@Sun.COM sv_lyr_aread(dev_t dev, struct aio_req *aio, cred_t *crp)
14877836SJohn.Forte@Sun.COM {
14887836SJohn.Forte@Sun.COM return (aphysio(sv_lyr_strategy,
14897836SJohn.Forte@Sun.COM anocancel, dev, B_READ, minphys, aio));
14907836SJohn.Forte@Sun.COM }
14917836SJohn.Forte@Sun.COM
14927836SJohn.Forte@Sun.COM
14937836SJohn.Forte@Sun.COM /* ARGSUSED */
14947836SJohn.Forte@Sun.COM
14957836SJohn.Forte@Sun.COM static int
sv_lyr_awrite(dev_t dev,struct aio_req * aio,cred_t * crp)14967836SJohn.Forte@Sun.COM sv_lyr_awrite(dev_t dev, struct aio_req *aio, cred_t *crp)
14977836SJohn.Forte@Sun.COM {
14987836SJohn.Forte@Sun.COM return (aphysio(sv_lyr_strategy,
14997836SJohn.Forte@Sun.COM anocancel, dev, B_WRITE, minphys, aio));
15007836SJohn.Forte@Sun.COM }
15017836SJohn.Forte@Sun.COM
15027836SJohn.Forte@Sun.COM
15037836SJohn.Forte@Sun.COM /*
15047836SJohn.Forte@Sun.COM * Set up an array containing the list of raw path names
15057836SJohn.Forte@Sun.COM * The array for the paths is svl and the size of the array is
15067836SJohn.Forte@Sun.COM * in size.
15077836SJohn.Forte@Sun.COM *
15087836SJohn.Forte@Sun.COM * If there are more layered devices than will fit in the array,
15097836SJohn.Forte@Sun.COM * the number of extra layered devices is returned. Otherwise
15107836SJohn.Forte@Sun.COM * zero is return.
15117836SJohn.Forte@Sun.COM *
15127836SJohn.Forte@Sun.COM * Input:
15137836SJohn.Forte@Sun.COM * svn : array for paths
15147836SJohn.Forte@Sun.COM * size : size of the array
15157836SJohn.Forte@Sun.COM *
15167836SJohn.Forte@Sun.COM * Output (extra):
15177836SJohn.Forte@Sun.COM * zero : All paths fit in array
15187836SJohn.Forte@Sun.COM * >0 : Number of defined layered devices don't fit in array
15197836SJohn.Forte@Sun.COM */
15207836SJohn.Forte@Sun.COM
15217836SJohn.Forte@Sun.COM static int
sv_list(void * ptr,const int size,int * extra,const int ilp32)15227836SJohn.Forte@Sun.COM sv_list(void *ptr, const int size, int *extra, const int ilp32)
15237836SJohn.Forte@Sun.COM {
15247836SJohn.Forte@Sun.COM sv_name32_t *svn32;
15257836SJohn.Forte@Sun.COM sv_name_t *svn;
15267836SJohn.Forte@Sun.COM sv_dev_t *svp;
15277836SJohn.Forte@Sun.COM int *mode, *nblocks;
15287836SJohn.Forte@Sun.COM int i, index;
15297836SJohn.Forte@Sun.COM char *path;
15307836SJohn.Forte@Sun.COM
15317836SJohn.Forte@Sun.COM *extra = 0;
15327836SJohn.Forte@Sun.COM index = 0;
15337836SJohn.Forte@Sun.COM
15347836SJohn.Forte@Sun.COM if (ilp32)
15357836SJohn.Forte@Sun.COM svn32 = ptr;
15367836SJohn.Forte@Sun.COM else
15377836SJohn.Forte@Sun.COM svn = ptr;
15387836SJohn.Forte@Sun.COM
15397836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
15407836SJohn.Forte@Sun.COM for (i = 0; i < sv_max_devices; i++) {
15417836SJohn.Forte@Sun.COM svp = &sv_devs[i];
15427836SJohn.Forte@Sun.COM
15437836SJohn.Forte@Sun.COM rw_enter(&svp->sv_lock, RW_READER);
15447836SJohn.Forte@Sun.COM
15457836SJohn.Forte@Sun.COM if (svp->sv_state != SV_ENABLE) {
15467836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
15477836SJohn.Forte@Sun.COM continue;
15487836SJohn.Forte@Sun.COM }
15497836SJohn.Forte@Sun.COM
15507836SJohn.Forte@Sun.COM if ((*extra) != 0 || ptr == NULL) {
15517836SJohn.Forte@Sun.COM /* Another overflow entry */
15527836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
15537836SJohn.Forte@Sun.COM (*extra)++;
15547836SJohn.Forte@Sun.COM continue;
15557836SJohn.Forte@Sun.COM }
15567836SJohn.Forte@Sun.COM
15577836SJohn.Forte@Sun.COM if (ilp32) {
15587836SJohn.Forte@Sun.COM nblocks = &svn32->svn_nblocks;
15597836SJohn.Forte@Sun.COM mode = &svn32->svn_mode;
15607836SJohn.Forte@Sun.COM path = svn32->svn_path;
15617836SJohn.Forte@Sun.COM
15627836SJohn.Forte@Sun.COM svn32->svn_timestamp = (uint32_t)svp->sv_timestamp;
15637836SJohn.Forte@Sun.COM svn32++;
15647836SJohn.Forte@Sun.COM } else {
15657836SJohn.Forte@Sun.COM nblocks = &svn->svn_nblocks;
15667836SJohn.Forte@Sun.COM mode = &svn->svn_mode;
15677836SJohn.Forte@Sun.COM path = svn->svn_path;
15687836SJohn.Forte@Sun.COM
15697836SJohn.Forte@Sun.COM svn->svn_timestamp = svp->sv_timestamp;
15707836SJohn.Forte@Sun.COM svn++;
15717836SJohn.Forte@Sun.COM }
15727836SJohn.Forte@Sun.COM
15737836SJohn.Forte@Sun.COM (void) strcpy(path, nsc_pathname(svp->sv_fd));
15747836SJohn.Forte@Sun.COM *nblocks = svp->sv_nblocks;
15757836SJohn.Forte@Sun.COM *mode = svp->sv_flag;
15767836SJohn.Forte@Sun.COM
15777836SJohn.Forte@Sun.COM if (*nblocks == 0) {
15787836SJohn.Forte@Sun.COM if (sv_debug > 3)
1579*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!sv_list: need to reserve\n");
1580*9093SRamana.Srikanth@Sun.COM
1581*9093SRamana.Srikanth@Sun.COM if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
15827836SJohn.Forte@Sun.COM *nblocks = svp->sv_nblocks;
15837836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
15847836SJohn.Forte@Sun.COM }
15857836SJohn.Forte@Sun.COM }
15867836SJohn.Forte@Sun.COM
15877836SJohn.Forte@Sun.COM if (++index >= size) {
15887836SJohn.Forte@Sun.COM /* Out of space */
15897836SJohn.Forte@Sun.COM (*extra)++;
15907836SJohn.Forte@Sun.COM }
15917836SJohn.Forte@Sun.COM
15927836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
15937836SJohn.Forte@Sun.COM }
15947836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
15957836SJohn.Forte@Sun.COM
15967836SJohn.Forte@Sun.COM if (index < size) {
15977836SJohn.Forte@Sun.COM /* NULL terminated list */
15987836SJohn.Forte@Sun.COM if (ilp32)
15997836SJohn.Forte@Sun.COM svn32->svn_path[0] = '\0';
16007836SJohn.Forte@Sun.COM else
16017836SJohn.Forte@Sun.COM svn->svn_path[0] = '\0';
16027836SJohn.Forte@Sun.COM }
16037836SJohn.Forte@Sun.COM
16047836SJohn.Forte@Sun.COM return (0);
16057836SJohn.Forte@Sun.COM }
16067836SJohn.Forte@Sun.COM
16077836SJohn.Forte@Sun.COM
16087836SJohn.Forte@Sun.COM static void
sv_thread_tune(int threads)16097836SJohn.Forte@Sun.COM sv_thread_tune(int threads)
16107836SJohn.Forte@Sun.COM {
16117836SJohn.Forte@Sun.COM int incr = (threads > 0) ? 1 : -1;
16127836SJohn.Forte@Sun.COM int change = 0;
16137836SJohn.Forte@Sun.COM int nthreads;
16147836SJohn.Forte@Sun.COM
16157836SJohn.Forte@Sun.COM ASSERT(MUTEX_HELD(&sv_mutex));
16167836SJohn.Forte@Sun.COM
16177836SJohn.Forte@Sun.COM if (sv_threads_extra) {
16187836SJohn.Forte@Sun.COM /* keep track of any additional threads requested */
16197836SJohn.Forte@Sun.COM if (threads > 0) {
16207836SJohn.Forte@Sun.COM sv_threads_extra += threads;
16217836SJohn.Forte@Sun.COM return;
16227836SJohn.Forte@Sun.COM }
16237836SJohn.Forte@Sun.COM threads = -threads;
16247836SJohn.Forte@Sun.COM if (threads >= sv_threads_extra) {
16257836SJohn.Forte@Sun.COM threads -= sv_threads_extra;
16267836SJohn.Forte@Sun.COM sv_threads_extra = 0;
16277836SJohn.Forte@Sun.COM /* fall through to while loop */
16287836SJohn.Forte@Sun.COM } else {
16297836SJohn.Forte@Sun.COM sv_threads_extra -= threads;
16307836SJohn.Forte@Sun.COM return;
16317836SJohn.Forte@Sun.COM }
16327836SJohn.Forte@Sun.COM } else if (threads > 0) {
16337836SJohn.Forte@Sun.COM /*
16347836SJohn.Forte@Sun.COM * do not increase the number of threads beyond
16357836SJohn.Forte@Sun.COM * sv_threads_max when doing dynamic thread tuning
16367836SJohn.Forte@Sun.COM */
16377836SJohn.Forte@Sun.COM nthreads = nst_nthread(sv_tset);
16387836SJohn.Forte@Sun.COM if ((nthreads + threads) > sv_threads_max) {
16397836SJohn.Forte@Sun.COM sv_threads_extra = nthreads + threads - sv_threads_max;
16407836SJohn.Forte@Sun.COM threads = sv_threads_max - nthreads;
16417836SJohn.Forte@Sun.COM if (threads <= 0)
16427836SJohn.Forte@Sun.COM return;
16437836SJohn.Forte@Sun.COM }
16447836SJohn.Forte@Sun.COM }
16457836SJohn.Forte@Sun.COM
16467836SJohn.Forte@Sun.COM if (threads < 0)
16477836SJohn.Forte@Sun.COM threads = -threads;
16487836SJohn.Forte@Sun.COM
16497836SJohn.Forte@Sun.COM while (threads--) {
16507836SJohn.Forte@Sun.COM nthreads = nst_nthread(sv_tset);
16517836SJohn.Forte@Sun.COM sv_threads_needed += incr;
16527836SJohn.Forte@Sun.COM
16537836SJohn.Forte@Sun.COM if (sv_threads_needed >= nthreads)
16547836SJohn.Forte@Sun.COM change += nst_add_thread(sv_tset, sv_threads_inc);
16557836SJohn.Forte@Sun.COM else if ((sv_threads_needed <
16567836SJohn.Forte@Sun.COM (nthreads - (sv_threads_inc + sv_threads_hysteresis))) &&
16577836SJohn.Forte@Sun.COM ((nthreads - sv_threads_inc) >= sv_threads))
16587836SJohn.Forte@Sun.COM change -= nst_del_thread(sv_tset, sv_threads_inc);
16597836SJohn.Forte@Sun.COM }
16607836SJohn.Forte@Sun.COM
16617836SJohn.Forte@Sun.COM #ifdef DEBUG
16627836SJohn.Forte@Sun.COM if (change) {
16637836SJohn.Forte@Sun.COM cmn_err(CE_NOTE,
1664*9093SRamana.Srikanth@Sun.COM "!sv_thread_tune: threads needed %d, nthreads %d, "
16657836SJohn.Forte@Sun.COM "nthreads change %d",
16667836SJohn.Forte@Sun.COM sv_threads_needed, nst_nthread(sv_tset), change);
16677836SJohn.Forte@Sun.COM }
16687836SJohn.Forte@Sun.COM #endif
16697836SJohn.Forte@Sun.COM }
16707836SJohn.Forte@Sun.COM
16717836SJohn.Forte@Sun.COM
16727836SJohn.Forte@Sun.COM /* ARGSUSED */
16737836SJohn.Forte@Sun.COM static int
svopen(dev_t * devp,int flag,int otyp,cred_t * crp)16747836SJohn.Forte@Sun.COM svopen(dev_t *devp, int flag, int otyp, cred_t *crp)
16757836SJohn.Forte@Sun.COM {
16767836SJohn.Forte@Sun.COM int rc;
16777836SJohn.Forte@Sun.COM
16787836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
16797836SJohn.Forte@Sun.COM rc = sv_init_devs();
16807836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
16817836SJohn.Forte@Sun.COM
16827836SJohn.Forte@Sun.COM return (rc);
16837836SJohn.Forte@Sun.COM }
16847836SJohn.Forte@Sun.COM
16857836SJohn.Forte@Sun.COM
16867836SJohn.Forte@Sun.COM /* ARGSUSED */
16877836SJohn.Forte@Sun.COM static int
svclose(dev_t dev,int flag,int otyp,cred_t * crp)16887836SJohn.Forte@Sun.COM svclose(dev_t dev, int flag, int otyp, cred_t *crp)
16897836SJohn.Forte@Sun.COM {
16907836SJohn.Forte@Sun.COM const int secs = HZ * 5;
16917836SJohn.Forte@Sun.COM const int ticks = HZ / 10;
16927836SJohn.Forte@Sun.COM int loops = secs / ticks;
16937836SJohn.Forte@Sun.COM
16947836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
16957836SJohn.Forte@Sun.COM while (sv_ndevices <= 0 && sv_tset != NULL && loops > 0) {
16967836SJohn.Forte@Sun.COM if (nst_nlive(sv_tset) <= 0) {
16977836SJohn.Forte@Sun.COM nst_destroy(sv_tset);
16987836SJohn.Forte@Sun.COM sv_tset = NULL;
16997836SJohn.Forte@Sun.COM break;
17007836SJohn.Forte@Sun.COM }
17017836SJohn.Forte@Sun.COM
17027836SJohn.Forte@Sun.COM /* threads still active - wait for them to exit */
17037836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
17047836SJohn.Forte@Sun.COM delay(ticks);
17057836SJohn.Forte@Sun.COM loops--;
17067836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
17077836SJohn.Forte@Sun.COM }
17087836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
17097836SJohn.Forte@Sun.COM
17107836SJohn.Forte@Sun.COM if (loops <= 0) {
17117836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
17127836SJohn.Forte@Sun.COM #ifndef DEBUG
17137836SJohn.Forte@Sun.COM /* do not write to console when non-DEBUG */
17147836SJohn.Forte@Sun.COM "!"
17157836SJohn.Forte@Sun.COM #endif
17167836SJohn.Forte@Sun.COM "sv:svclose: threads still active "
17177836SJohn.Forte@Sun.COM "after %d sec - leaking thread set", secs);
17187836SJohn.Forte@Sun.COM }
17197836SJohn.Forte@Sun.COM
17207836SJohn.Forte@Sun.COM return (0);
17217836SJohn.Forte@Sun.COM }
17227836SJohn.Forte@Sun.COM
17237836SJohn.Forte@Sun.COM
17247836SJohn.Forte@Sun.COM static int
svioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * crp,int * rvalp)17257836SJohn.Forte@Sun.COM svioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvalp)
17267836SJohn.Forte@Sun.COM {
17277836SJohn.Forte@Sun.COM char itmp1[12], itmp2[12]; /* temp char array for editing ints */
17287836SJohn.Forte@Sun.COM spcs_s_info_t kstatus; /* Kernel version of spcs status */
17297836SJohn.Forte@Sun.COM spcs_s_info_t ustatus; /* Address of user version of spcs status */
17307836SJohn.Forte@Sun.COM sv_list32_t svl32; /* 32 bit Initial structure for SVIOC_LIST */
17317836SJohn.Forte@Sun.COM sv_version_t svv; /* Version structure */
17327836SJohn.Forte@Sun.COM sv_conf_t svc; /* User config structure */
17337836SJohn.Forte@Sun.COM sv_list_t svl; /* Initial structure for SVIOC_LIST */
17347836SJohn.Forte@Sun.COM void *usvn; /* Address of user sv_name_t */
17357836SJohn.Forte@Sun.COM void *svn = NULL; /* Array for SVIOC_LIST */
17367836SJohn.Forte@Sun.COM uint64_t phash; /* pathname hash */
17377836SJohn.Forte@Sun.COM int rc = 0; /* Return code -- errno */
17387836SJohn.Forte@Sun.COM int size; /* Number of items in array */
17397836SJohn.Forte@Sun.COM int bytes; /* Byte size of array */
17407836SJohn.Forte@Sun.COM int ilp32; /* Convert data structures for ilp32 userland */
17417836SJohn.Forte@Sun.COM
17427836SJohn.Forte@Sun.COM *rvalp = 0;
17437836SJohn.Forte@Sun.COM
17447836SJohn.Forte@Sun.COM /*
17457836SJohn.Forte@Sun.COM * If sv_mod_status is 0 or SV_PREVENT_UNLOAD, then it will continue.
17467836SJohn.Forte@Sun.COM * else it means it previously was SV_PREVENT_UNLOAD, and now it's
17477836SJohn.Forte@Sun.COM * SV_ALLOW_UNLOAD, expecting the driver to eventually unload.
17487836SJohn.Forte@Sun.COM *
17497836SJohn.Forte@Sun.COM * SV_ALLOW_UNLOAD is final state, so no need to grab sv_mutex.
17507836SJohn.Forte@Sun.COM */
17517836SJohn.Forte@Sun.COM if (sv_mod_status == SV_ALLOW_UNLOAD) {
17527836SJohn.Forte@Sun.COM return (EBUSY);
17537836SJohn.Forte@Sun.COM }
17547836SJohn.Forte@Sun.COM
17557836SJohn.Forte@Sun.COM if ((cmd != SVIOC_LIST) && ((rc = drv_priv(crp)) != 0))
17567836SJohn.Forte@Sun.COM return (rc);
17577836SJohn.Forte@Sun.COM
17587836SJohn.Forte@Sun.COM kstatus = spcs_s_kcreate();
17597836SJohn.Forte@Sun.COM if (!kstatus) {
1760*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_ioctl_err_kcreate, dev_t, dev);
17617836SJohn.Forte@Sun.COM return (ENOMEM);
17627836SJohn.Forte@Sun.COM }
17637836SJohn.Forte@Sun.COM
17647836SJohn.Forte@Sun.COM ilp32 = (ddi_model_convert_from((mode & FMODELS)) == DDI_MODEL_ILP32);
17657836SJohn.Forte@Sun.COM
17667836SJohn.Forte@Sun.COM switch (cmd) {
17677836SJohn.Forte@Sun.COM
17687836SJohn.Forte@Sun.COM case SVIOC_ENABLE:
17697836SJohn.Forte@Sun.COM
17707836SJohn.Forte@Sun.COM if (ilp32) {
17717836SJohn.Forte@Sun.COM sv_conf32_t svc32;
17727836SJohn.Forte@Sun.COM
17737836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &svc32,
1774*9093SRamana.Srikanth@Sun.COM sizeof (svc32), mode) < 0) {
17757836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
17767836SJohn.Forte@Sun.COM return (EFAULT);
17777836SJohn.Forte@Sun.COM }
17787836SJohn.Forte@Sun.COM
17797836SJohn.Forte@Sun.COM svc.svc_error = (spcs_s_info_t)svc32.svc_error;
17807836SJohn.Forte@Sun.COM (void) strcpy(svc.svc_path, svc32.svc_path);
17817836SJohn.Forte@Sun.COM svc.svc_flag = svc32.svc_flag;
17827836SJohn.Forte@Sun.COM svc.svc_major = svc32.svc_major;
17837836SJohn.Forte@Sun.COM svc.svc_minor = svc32.svc_minor;
17847836SJohn.Forte@Sun.COM } else {
17857836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &svc,
1786*9093SRamana.Srikanth@Sun.COM sizeof (svc), mode) < 0) {
17877836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
17887836SJohn.Forte@Sun.COM return (EFAULT);
17897836SJohn.Forte@Sun.COM }
17907836SJohn.Forte@Sun.COM }
17917836SJohn.Forte@Sun.COM
17927836SJohn.Forte@Sun.COM /* force to raw access */
17937836SJohn.Forte@Sun.COM svc.svc_flag = NSC_DEVICE;
17947836SJohn.Forte@Sun.COM
17957836SJohn.Forte@Sun.COM if (sv_tset == NULL) {
17967836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
17977836SJohn.Forte@Sun.COM
17987836SJohn.Forte@Sun.COM if (sv_tset == NULL) {
17997836SJohn.Forte@Sun.COM sv_tset = nst_init("sv_thr", sv_threads);
18007836SJohn.Forte@Sun.COM }
18017836SJohn.Forte@Sun.COM
18027836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
18037836SJohn.Forte@Sun.COM
18047836SJohn.Forte@Sun.COM if (sv_tset == NULL) {
18057836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
1806*9093SRamana.Srikanth@Sun.COM "!sv: could not allocate %d threads",
18077836SJohn.Forte@Sun.COM sv_threads);
18087836SJohn.Forte@Sun.COM }
18097836SJohn.Forte@Sun.COM }
18107836SJohn.Forte@Sun.COM
18117836SJohn.Forte@Sun.COM rc = sv_enable(svc.svc_path, svc.svc_flag,
1812*9093SRamana.Srikanth@Sun.COM makedevice(svc.svc_major, svc.svc_minor), kstatus);
18137836SJohn.Forte@Sun.COM
18147836SJohn.Forte@Sun.COM if (rc == 0) {
18157836SJohn.Forte@Sun.COM sv_config_time = nsc_lbolt();
18167836SJohn.Forte@Sun.COM
18177836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
18187836SJohn.Forte@Sun.COM sv_thread_tune(sv_threads_dev);
18197836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
18207836SJohn.Forte@Sun.COM }
18217836SJohn.Forte@Sun.COM
1822*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE3(sv_ioctl_end, dev_t, dev, int, *rvalp, int, rc);
18237836SJohn.Forte@Sun.COM
18247836SJohn.Forte@Sun.COM return (spcs_s_ocopyoutf(&kstatus, svc.svc_error, rc));
18257836SJohn.Forte@Sun.COM /* NOTREACHED */
18267836SJohn.Forte@Sun.COM
18277836SJohn.Forte@Sun.COM case SVIOC_DISABLE:
18287836SJohn.Forte@Sun.COM
18297836SJohn.Forte@Sun.COM if (ilp32) {
18307836SJohn.Forte@Sun.COM sv_conf32_t svc32;
18317836SJohn.Forte@Sun.COM
18327836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &svc32,
1833*9093SRamana.Srikanth@Sun.COM sizeof (svc32), mode) < 0) {
18347836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
18357836SJohn.Forte@Sun.COM return (EFAULT);
18367836SJohn.Forte@Sun.COM }
18377836SJohn.Forte@Sun.COM
18387836SJohn.Forte@Sun.COM svc.svc_error = (spcs_s_info_t)svc32.svc_error;
18397836SJohn.Forte@Sun.COM svc.svc_major = svc32.svc_major;
18407836SJohn.Forte@Sun.COM svc.svc_minor = svc32.svc_minor;
18417836SJohn.Forte@Sun.COM (void) strcpy(svc.svc_path, svc32.svc_path);
18427836SJohn.Forte@Sun.COM svc.svc_flag = svc32.svc_flag;
18437836SJohn.Forte@Sun.COM } else {
18447836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &svc,
1845*9093SRamana.Srikanth@Sun.COM sizeof (svc), mode) < 0) {
18467836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
18477836SJohn.Forte@Sun.COM return (EFAULT);
18487836SJohn.Forte@Sun.COM }
18497836SJohn.Forte@Sun.COM }
18507836SJohn.Forte@Sun.COM
18517836SJohn.Forte@Sun.COM if (svc.svc_major == (major_t)-1 &&
18527836SJohn.Forte@Sun.COM svc.svc_minor == (minor_t)-1) {
18537836SJohn.Forte@Sun.COM sv_dev_t *svp;
18547836SJohn.Forte@Sun.COM int i;
18557836SJohn.Forte@Sun.COM
18567836SJohn.Forte@Sun.COM /*
18577836SJohn.Forte@Sun.COM * User level could not find the minor device
18587836SJohn.Forte@Sun.COM * node, so do this the slow way by searching
18597836SJohn.Forte@Sun.COM * the entire sv config for a matching pathname.
18607836SJohn.Forte@Sun.COM */
18617836SJohn.Forte@Sun.COM
18627836SJohn.Forte@Sun.COM phash = nsc_strhash(svc.svc_path);
18637836SJohn.Forte@Sun.COM
18647836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
18657836SJohn.Forte@Sun.COM
18667836SJohn.Forte@Sun.COM for (i = 0; i < sv_max_devices; i++) {
18677836SJohn.Forte@Sun.COM svp = &sv_devs[i];
18687836SJohn.Forte@Sun.COM
18697836SJohn.Forte@Sun.COM if (svp->sv_state == SV_DISABLE ||
18707836SJohn.Forte@Sun.COM svp->sv_fd == NULL)
18717836SJohn.Forte@Sun.COM continue;
18727836SJohn.Forte@Sun.COM
18737836SJohn.Forte@Sun.COM if (nsc_fdpathcmp(svp->sv_fd, phash,
18747836SJohn.Forte@Sun.COM svc.svc_path) == 0) {
18757836SJohn.Forte@Sun.COM svc.svc_major = getmajor(svp->sv_dev);
18767836SJohn.Forte@Sun.COM svc.svc_minor = getminor(svp->sv_dev);
18777836SJohn.Forte@Sun.COM break;
18787836SJohn.Forte@Sun.COM }
18797836SJohn.Forte@Sun.COM }
18807836SJohn.Forte@Sun.COM
18817836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
18827836SJohn.Forte@Sun.COM
18837836SJohn.Forte@Sun.COM if (svc.svc_major == (major_t)-1 &&
18847836SJohn.Forte@Sun.COM svc.svc_minor == (minor_t)-1)
18857836SJohn.Forte@Sun.COM return (spcs_s_ocopyoutf(&kstatus,
1886*9093SRamana.Srikanth@Sun.COM svc.svc_error, SV_ENODEV));
18877836SJohn.Forte@Sun.COM }
18887836SJohn.Forte@Sun.COM
18897836SJohn.Forte@Sun.COM rc = sv_disable(makedevice(svc.svc_major, svc.svc_minor),
1890*9093SRamana.Srikanth@Sun.COM kstatus);
18917836SJohn.Forte@Sun.COM
18927836SJohn.Forte@Sun.COM if (rc == 0) {
18937836SJohn.Forte@Sun.COM sv_config_time = nsc_lbolt();
18947836SJohn.Forte@Sun.COM
18957836SJohn.Forte@Sun.COM mutex_enter(&sv_mutex);
18967836SJohn.Forte@Sun.COM sv_thread_tune(-sv_threads_dev);
18977836SJohn.Forte@Sun.COM mutex_exit(&sv_mutex);
18987836SJohn.Forte@Sun.COM }
18997836SJohn.Forte@Sun.COM
1900*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE3(sv_ioctl_2, dev_t, dev, int, *rvalp, int, rc);
19017836SJohn.Forte@Sun.COM
19027836SJohn.Forte@Sun.COM return (spcs_s_ocopyoutf(&kstatus, svc.svc_error, rc));
19037836SJohn.Forte@Sun.COM /* NOTREACHED */
19047836SJohn.Forte@Sun.COM
19057836SJohn.Forte@Sun.COM case SVIOC_LIST:
19067836SJohn.Forte@Sun.COM
19077836SJohn.Forte@Sun.COM if (ilp32) {
19087836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &svl32,
1909*9093SRamana.Srikanth@Sun.COM sizeof (svl32), mode) < 0) {
19107836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
19117836SJohn.Forte@Sun.COM return (EFAULT);
19127836SJohn.Forte@Sun.COM }
19137836SJohn.Forte@Sun.COM
19147836SJohn.Forte@Sun.COM ustatus = (spcs_s_info_t)svl32.svl_error;
19157836SJohn.Forte@Sun.COM size = svl32.svl_count;
19167836SJohn.Forte@Sun.COM usvn = (void *)(unsigned long)svl32.svl_names;
19177836SJohn.Forte@Sun.COM } else {
19187836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &svl,
1919*9093SRamana.Srikanth@Sun.COM sizeof (svl), mode) < 0) {
19207836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
19217836SJohn.Forte@Sun.COM return (EFAULT);
19227836SJohn.Forte@Sun.COM }
19237836SJohn.Forte@Sun.COM
19247836SJohn.Forte@Sun.COM ustatus = svl.svl_error;
19257836SJohn.Forte@Sun.COM size = svl.svl_count;
19267836SJohn.Forte@Sun.COM usvn = svl.svl_names;
19277836SJohn.Forte@Sun.COM }
19287836SJohn.Forte@Sun.COM
19297836SJohn.Forte@Sun.COM /* Do some boundary checking */
19307836SJohn.Forte@Sun.COM if ((size < 0) || (size > sv_max_devices)) {
19317836SJohn.Forte@Sun.COM /* Array size is out of range */
19327836SJohn.Forte@Sun.COM return (spcs_s_ocopyoutf(&kstatus, ustatus,
1933*9093SRamana.Srikanth@Sun.COM SV_EARRBOUNDS, "0",
1934*9093SRamana.Srikanth@Sun.COM spcs_s_inttostring(sv_max_devices, itmp1,
1935*9093SRamana.Srikanth@Sun.COM sizeof (itmp1), 0),
1936*9093SRamana.Srikanth@Sun.COM spcs_s_inttostring(size, itmp2,
1937*9093SRamana.Srikanth@Sun.COM sizeof (itmp2), 0)));
19387836SJohn.Forte@Sun.COM }
19397836SJohn.Forte@Sun.COM
19407836SJohn.Forte@Sun.COM if (ilp32)
19417836SJohn.Forte@Sun.COM bytes = size * sizeof (sv_name32_t);
19427836SJohn.Forte@Sun.COM else
19437836SJohn.Forte@Sun.COM bytes = size * sizeof (sv_name_t);
19447836SJohn.Forte@Sun.COM
19457836SJohn.Forte@Sun.COM /* Allocate memory for the array of structures */
19467836SJohn.Forte@Sun.COM if (bytes != 0) {
19477836SJohn.Forte@Sun.COM svn = kmem_zalloc(bytes, KM_SLEEP);
19487836SJohn.Forte@Sun.COM if (!svn) {
19497836SJohn.Forte@Sun.COM return (spcs_s_ocopyoutf(&kstatus,
19507836SJohn.Forte@Sun.COM ustatus, ENOMEM));
19517836SJohn.Forte@Sun.COM }
19527836SJohn.Forte@Sun.COM }
19537836SJohn.Forte@Sun.COM
19547836SJohn.Forte@Sun.COM rc = sv_list(svn, size, rvalp, ilp32);
19557836SJohn.Forte@Sun.COM if (rc) {
19567836SJohn.Forte@Sun.COM if (svn != NULL)
19577836SJohn.Forte@Sun.COM kmem_free(svn, bytes);
19587836SJohn.Forte@Sun.COM return (spcs_s_ocopyoutf(&kstatus, ustatus, rc));
19597836SJohn.Forte@Sun.COM }
19607836SJohn.Forte@Sun.COM
19617836SJohn.Forte@Sun.COM if (ilp32) {
19627836SJohn.Forte@Sun.COM svl32.svl_timestamp = (uint32_t)sv_config_time;
19637836SJohn.Forte@Sun.COM svl32.svl_maxdevs = (int32_t)sv_max_devices;
19647836SJohn.Forte@Sun.COM
19657836SJohn.Forte@Sun.COM /* Return the list structure */
19667836SJohn.Forte@Sun.COM if (ddi_copyout(&svl32, (void *)arg,
1967*9093SRamana.Srikanth@Sun.COM sizeof (svl32), mode) < 0) {
19687836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
19697836SJohn.Forte@Sun.COM if (svn != NULL)
19707836SJohn.Forte@Sun.COM kmem_free(svn, bytes);
19717836SJohn.Forte@Sun.COM return (EFAULT);
19727836SJohn.Forte@Sun.COM }
19737836SJohn.Forte@Sun.COM } else {
19747836SJohn.Forte@Sun.COM svl.svl_timestamp = sv_config_time;
19757836SJohn.Forte@Sun.COM svl.svl_maxdevs = sv_max_devices;
19767836SJohn.Forte@Sun.COM
19777836SJohn.Forte@Sun.COM /* Return the list structure */
19787836SJohn.Forte@Sun.COM if (ddi_copyout(&svl, (void *)arg,
1979*9093SRamana.Srikanth@Sun.COM sizeof (svl), mode) < 0) {
19807836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
19817836SJohn.Forte@Sun.COM if (svn != NULL)
19827836SJohn.Forte@Sun.COM kmem_free(svn, bytes);
19837836SJohn.Forte@Sun.COM return (EFAULT);
19847836SJohn.Forte@Sun.COM }
19857836SJohn.Forte@Sun.COM }
19867836SJohn.Forte@Sun.COM
19877836SJohn.Forte@Sun.COM /* Return the array */
19887836SJohn.Forte@Sun.COM if (svn != NULL) {
19897836SJohn.Forte@Sun.COM if (ddi_copyout(svn, usvn, bytes, mode) < 0) {
19907836SJohn.Forte@Sun.COM kmem_free(svn, bytes);
19917836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
19927836SJohn.Forte@Sun.COM return (EFAULT);
19937836SJohn.Forte@Sun.COM }
19947836SJohn.Forte@Sun.COM kmem_free(svn, bytes);
19957836SJohn.Forte@Sun.COM }
19967836SJohn.Forte@Sun.COM
1997*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE3(sv_ioctl_3, dev_t, dev, int, *rvalp, int, 0);
19987836SJohn.Forte@Sun.COM
19997836SJohn.Forte@Sun.COM return (spcs_s_ocopyoutf(&kstatus, ustatus, 0));
20007836SJohn.Forte@Sun.COM /* NOTREACHED */
20017836SJohn.Forte@Sun.COM
20027836SJohn.Forte@Sun.COM case SVIOC_VERSION:
20037836SJohn.Forte@Sun.COM
20047836SJohn.Forte@Sun.COM if (ilp32) {
20057836SJohn.Forte@Sun.COM sv_version32_t svv32;
20067836SJohn.Forte@Sun.COM
20077836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &svv32,
2008*9093SRamana.Srikanth@Sun.COM sizeof (svv32), mode) < 0) {
20097836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
20107836SJohn.Forte@Sun.COM return (EFAULT);
20117836SJohn.Forte@Sun.COM }
20127836SJohn.Forte@Sun.COM
20137836SJohn.Forte@Sun.COM svv32.svv_major_rev = sv_major_rev;
20147836SJohn.Forte@Sun.COM svv32.svv_minor_rev = sv_minor_rev;
20157836SJohn.Forte@Sun.COM svv32.svv_micro_rev = sv_micro_rev;
20167836SJohn.Forte@Sun.COM svv32.svv_baseline_rev = sv_baseline_rev;
20177836SJohn.Forte@Sun.COM
20187836SJohn.Forte@Sun.COM if (ddi_copyout(&svv32, (void *)arg,
2019*9093SRamana.Srikanth@Sun.COM sizeof (svv32), mode) < 0) {
20207836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
20217836SJohn.Forte@Sun.COM return (EFAULT);
20227836SJohn.Forte@Sun.COM }
20237836SJohn.Forte@Sun.COM
20247836SJohn.Forte@Sun.COM ustatus = (spcs_s_info_t)svv32.svv_error;
20257836SJohn.Forte@Sun.COM } else {
20267836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &svv,
2027*9093SRamana.Srikanth@Sun.COM sizeof (svv), mode) < 0) {
20287836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
20297836SJohn.Forte@Sun.COM return (EFAULT);
20307836SJohn.Forte@Sun.COM }
20317836SJohn.Forte@Sun.COM
20327836SJohn.Forte@Sun.COM svv.svv_major_rev = sv_major_rev;
20337836SJohn.Forte@Sun.COM svv.svv_minor_rev = sv_minor_rev;
20347836SJohn.Forte@Sun.COM svv.svv_micro_rev = sv_micro_rev;
20357836SJohn.Forte@Sun.COM svv.svv_baseline_rev = sv_baseline_rev;
20367836SJohn.Forte@Sun.COM
20377836SJohn.Forte@Sun.COM if (ddi_copyout(&svv, (void *)arg,
2038*9093SRamana.Srikanth@Sun.COM sizeof (svv), mode) < 0) {
20397836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
20407836SJohn.Forte@Sun.COM return (EFAULT);
20417836SJohn.Forte@Sun.COM }
20427836SJohn.Forte@Sun.COM
20437836SJohn.Forte@Sun.COM ustatus = svv.svv_error;
20447836SJohn.Forte@Sun.COM }
20457836SJohn.Forte@Sun.COM
2046*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE3(sv_ioctl_4, dev_t, dev, int, *rvalp, int, 0);
20477836SJohn.Forte@Sun.COM
20487836SJohn.Forte@Sun.COM return (spcs_s_ocopyoutf(&kstatus, ustatus, 0));
20497836SJohn.Forte@Sun.COM /* NOTREACHED */
20507836SJohn.Forte@Sun.COM
20517836SJohn.Forte@Sun.COM case SVIOC_UNLOAD:
20527836SJohn.Forte@Sun.COM rc = sv_prepare_unload();
20537836SJohn.Forte@Sun.COM
2054*9093SRamana.Srikanth@Sun.COM if (ddi_copyout(&rc, (void *)arg, sizeof (rc), mode) < 0) {
20557836SJohn.Forte@Sun.COM rc = EFAULT;
20567836SJohn.Forte@Sun.COM }
20577836SJohn.Forte@Sun.COM
20587836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
20597836SJohn.Forte@Sun.COM return (rc);
20607836SJohn.Forte@Sun.COM
20617836SJohn.Forte@Sun.COM default:
20627836SJohn.Forte@Sun.COM spcs_s_kfree(kstatus);
20637836SJohn.Forte@Sun.COM
2064*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE3(sv_ioctl_4, dev_t, dev, int, *rvalp, int, EINVAL);
20657836SJohn.Forte@Sun.COM
20667836SJohn.Forte@Sun.COM return (EINVAL);
20677836SJohn.Forte@Sun.COM /* NOTREACHED */
20687836SJohn.Forte@Sun.COM }
20697836SJohn.Forte@Sun.COM
20707836SJohn.Forte@Sun.COM /* NOTREACHED */
20717836SJohn.Forte@Sun.COM }
20727836SJohn.Forte@Sun.COM
20737836SJohn.Forte@Sun.COM
20747836SJohn.Forte@Sun.COM /* ARGSUSED */
20757836SJohn.Forte@Sun.COM static int
svprint(dev_t dev,char * str)20767836SJohn.Forte@Sun.COM svprint(dev_t dev, char *str)
20777836SJohn.Forte@Sun.COM {
20787836SJohn.Forte@Sun.COM int instance = ddi_get_instance(sv_dip);
2079*9093SRamana.Srikanth@Sun.COM cmn_err(CE_WARN, "!%s%d: %s", ddi_get_name(sv_dip), instance, str);
20807836SJohn.Forte@Sun.COM return (0);
20817836SJohn.Forte@Sun.COM }
20827836SJohn.Forte@Sun.COM
20837836SJohn.Forte@Sun.COM
20847836SJohn.Forte@Sun.COM static void
_sv_lyr_strategy(struct buf * bp)20857836SJohn.Forte@Sun.COM _sv_lyr_strategy(struct buf *bp)
20867836SJohn.Forte@Sun.COM {
20877836SJohn.Forte@Sun.COM caddr_t buf_addr; /* pointer to linear buffer in bp */
20887836SJohn.Forte@Sun.COM nsc_buf_t *bufh = NULL;
20897836SJohn.Forte@Sun.COM nsc_buf_t *hndl = NULL;
20907836SJohn.Forte@Sun.COM sv_dev_t *svp;
20917836SJohn.Forte@Sun.COM nsc_vec_t *v;
20927836SJohn.Forte@Sun.COM sv_maj_t *maj;
20937836SJohn.Forte@Sun.COM nsc_size_t fba_req, fba_len; /* FBA lengths */
20947836SJohn.Forte@Sun.COM nsc_off_t fba_off; /* FBA offset */
20957836SJohn.Forte@Sun.COM size_t tocopy, nbytes; /* byte lengths */
20967836SJohn.Forte@Sun.COM int rw, rc; /* flags and return codes */
20977836SJohn.Forte@Sun.COM int (*fn)();
20987836SJohn.Forte@Sun.COM
20997836SJohn.Forte@Sun.COM rc = 0;
21007836SJohn.Forte@Sun.COM
21017836SJohn.Forte@Sun.COM if (sv_debug > 5)
2102*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!_sv_lyr_strategy(%p)\n", (void *)bp);
21037836SJohn.Forte@Sun.COM
21047836SJohn.Forte@Sun.COM svp = sv_find_enabled(bp->b_edev, &maj);
21057836SJohn.Forte@Sun.COM if (svp == NULL) {
21067836SJohn.Forte@Sun.COM if (maj && (fn = maj->sm_strategy) != 0) {
21077836SJohn.Forte@Sun.COM if (!(maj->sm_flag & D_MP)) {
21087836SJohn.Forte@Sun.COM UNSAFE_ENTER();
21097836SJohn.Forte@Sun.COM rc = (*fn)(bp);
21107836SJohn.Forte@Sun.COM UNSAFE_EXIT();
21117836SJohn.Forte@Sun.COM } else {
21127836SJohn.Forte@Sun.COM rc = (*fn)(bp);
21137836SJohn.Forte@Sun.COM }
21147836SJohn.Forte@Sun.COM return;
21157836SJohn.Forte@Sun.COM } else {
21167836SJohn.Forte@Sun.COM bioerror(bp, ENODEV);
21177836SJohn.Forte@Sun.COM biodone(bp);
21187836SJohn.Forte@Sun.COM return;
21197836SJohn.Forte@Sun.COM }
21207836SJohn.Forte@Sun.COM }
21217836SJohn.Forte@Sun.COM
21227836SJohn.Forte@Sun.COM ASSERT(RW_READ_HELD(&svp->sv_lock));
21237836SJohn.Forte@Sun.COM
21247836SJohn.Forte@Sun.COM if (svp->sv_flag == 0) {
21257836SJohn.Forte@Sun.COM /*
21267836SJohn.Forte@Sun.COM * guard access mode
21277836SJohn.Forte@Sun.COM * - prevent user level access to the device
21287836SJohn.Forte@Sun.COM */
2129*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_err_guard, struct buf *, bp);
21307836SJohn.Forte@Sun.COM bioerror(bp, EPERM);
21317836SJohn.Forte@Sun.COM goto out;
21327836SJohn.Forte@Sun.COM }
21337836SJohn.Forte@Sun.COM
21347836SJohn.Forte@Sun.COM if ((rc = sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH)) != 0) {
2135*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_err_rsrv, struct buf *, bp);
21367836SJohn.Forte@Sun.COM
21377836SJohn.Forte@Sun.COM if (rc == EINTR)
2138*9093SRamana.Srikanth@Sun.COM cmn_err(CE_WARN, "!nsc_reserve() returned EINTR");
21397836SJohn.Forte@Sun.COM bioerror(bp, rc);
21407836SJohn.Forte@Sun.COM goto out;
21417836SJohn.Forte@Sun.COM }
21427836SJohn.Forte@Sun.COM
21437836SJohn.Forte@Sun.COM if (bp->b_lblkno >= (diskaddr_t)svp->sv_nblocks) {
2144*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_eof, struct buf *, bp);
21457836SJohn.Forte@Sun.COM
21467836SJohn.Forte@Sun.COM if (bp->b_flags & B_READ) {
21477836SJohn.Forte@Sun.COM /* return EOF, not an error */
21487836SJohn.Forte@Sun.COM bp->b_resid = bp->b_bcount;
21497836SJohn.Forte@Sun.COM bioerror(bp, 0);
21507836SJohn.Forte@Sun.COM } else
21517836SJohn.Forte@Sun.COM bioerror(bp, EINVAL);
21527836SJohn.Forte@Sun.COM
21537836SJohn.Forte@Sun.COM goto done;
21547836SJohn.Forte@Sun.COM }
21557836SJohn.Forte@Sun.COM
21567836SJohn.Forte@Sun.COM /*
21577836SJohn.Forte@Sun.COM * Preallocate a handle once per call to strategy.
21587836SJohn.Forte@Sun.COM * If this fails, then the nsc_alloc_buf() will allocate
21597836SJohn.Forte@Sun.COM * a temporary handle per allocation/free pair.
21607836SJohn.Forte@Sun.COM */
21617836SJohn.Forte@Sun.COM
2162*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_alloch_start, sv_dev_t *, svp);
21637836SJohn.Forte@Sun.COM
21647836SJohn.Forte@Sun.COM bufh = nsc_alloc_handle(svp->sv_fd, NULL, NULL, NULL);
21657836SJohn.Forte@Sun.COM
2166*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_alloch_end, sv_dev_t *, svp);
21677836SJohn.Forte@Sun.COM
21687836SJohn.Forte@Sun.COM if (bufh && (bufh->sb_flag & NSC_HACTIVE) != 0) {
2169*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_err_hactive, struct buf *, bp);
21707836SJohn.Forte@Sun.COM
21717836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
2172*9093SRamana.Srikanth@Sun.COM "!sv: allocated active handle (bufh %p, flags %x)",
2173*9093SRamana.Srikanth@Sun.COM (void *)bufh, bufh->sb_flag);
21747836SJohn.Forte@Sun.COM
21757836SJohn.Forte@Sun.COM bioerror(bp, ENXIO);
21767836SJohn.Forte@Sun.COM goto done;
21777836SJohn.Forte@Sun.COM }
21787836SJohn.Forte@Sun.COM
21797836SJohn.Forte@Sun.COM fba_req = FBA_LEN(bp->b_bcount);
21807836SJohn.Forte@Sun.COM if (fba_req + bp->b_lblkno > (diskaddr_t)svp->sv_nblocks)
21817836SJohn.Forte@Sun.COM fba_req = (nsc_size_t)(svp->sv_nblocks - bp->b_lblkno);
21827836SJohn.Forte@Sun.COM
21837836SJohn.Forte@Sun.COM rw = (bp->b_flags & B_READ) ? NSC_READ : NSC_WRITE;
21847836SJohn.Forte@Sun.COM
21857836SJohn.Forte@Sun.COM bp_mapin(bp);
21867836SJohn.Forte@Sun.COM
21877836SJohn.Forte@Sun.COM bp->b_resid = bp->b_bcount;
21887836SJohn.Forte@Sun.COM buf_addr = bp->b_un.b_addr;
21897836SJohn.Forte@Sun.COM fba_off = 0;
21907836SJohn.Forte@Sun.COM
21917836SJohn.Forte@Sun.COM /*
21927836SJohn.Forte@Sun.COM * fba_req - requested size of transfer in FBAs after
21937836SJohn.Forte@Sun.COM * truncation to device extent, and allowing for
21947836SJohn.Forte@Sun.COM * possible non-FBA bounded final chunk.
21957836SJohn.Forte@Sun.COM * fba_off - offset of start of chunk from start of bp in FBAs.
21967836SJohn.Forte@Sun.COM * fba_len - size of this chunk in FBAs.
21977836SJohn.Forte@Sun.COM */
21987836SJohn.Forte@Sun.COM
21997836SJohn.Forte@Sun.COM loop:
22007836SJohn.Forte@Sun.COM fba_len = min(fba_req, svp->sv_maxfbas);
22017836SJohn.Forte@Sun.COM hndl = bufh;
22027836SJohn.Forte@Sun.COM
22037836SJohn.Forte@Sun.COM DTRACE_PROBE4(sv_dbg_allocb_start,
22047836SJohn.Forte@Sun.COM sv_dev_t *, svp,
22057836SJohn.Forte@Sun.COM uint64_t, (uint64_t)(bp->b_lblkno + fba_off),
22067836SJohn.Forte@Sun.COM uint64_t, (uint64_t)fba_len,
22077836SJohn.Forte@Sun.COM int, rw);
22087836SJohn.Forte@Sun.COM
22097836SJohn.Forte@Sun.COM rc = nsc_alloc_buf(svp->sv_fd, (nsc_off_t)(bp->b_lblkno + fba_off),
2210*9093SRamana.Srikanth@Sun.COM fba_len, rw, &hndl);
2211*9093SRamana.Srikanth@Sun.COM
2212*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_allocb_end, sv_dev_t *, svp);
22137836SJohn.Forte@Sun.COM
22147836SJohn.Forte@Sun.COM if (rc > 0) {
2215*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_err_alloc, struct buf *, bp);
22167836SJohn.Forte@Sun.COM bioerror(bp, rc);
22177836SJohn.Forte@Sun.COM if (hndl != bufh)
22187836SJohn.Forte@Sun.COM (void) nsc_free_buf(hndl);
22197836SJohn.Forte@Sun.COM hndl = NULL;
22207836SJohn.Forte@Sun.COM goto done;
22217836SJohn.Forte@Sun.COM }
22227836SJohn.Forte@Sun.COM
22237836SJohn.Forte@Sun.COM tocopy = min(FBA_SIZE(fba_len), bp->b_resid);
22247836SJohn.Forte@Sun.COM v = hndl->sb_vec;
22257836SJohn.Forte@Sun.COM
22267836SJohn.Forte@Sun.COM if (rw == NSC_WRITE && FBA_OFF(tocopy) != 0) {
22277836SJohn.Forte@Sun.COM /*
22287836SJohn.Forte@Sun.COM * Not overwriting all of the last FBA, so read in the
22297836SJohn.Forte@Sun.COM * old contents now before we overwrite it with the new
22307836SJohn.Forte@Sun.COM * data.
22317836SJohn.Forte@Sun.COM */
22327836SJohn.Forte@Sun.COM
2233*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE2(sv_dbg_read_start, sv_dev_t *, svp,
2234*9093SRamana.Srikanth@Sun.COM uint64_t, (uint64_t)(hndl->sb_pos + hndl->sb_len - 1));
22357836SJohn.Forte@Sun.COM
22367836SJohn.Forte@Sun.COM rc = nsc_read(hndl, (hndl->sb_pos + hndl->sb_len - 1), 1, 0);
22377836SJohn.Forte@Sun.COM if (rc > 0) {
22387836SJohn.Forte@Sun.COM bioerror(bp, rc);
22397836SJohn.Forte@Sun.COM goto done;
22407836SJohn.Forte@Sun.COM }
22417836SJohn.Forte@Sun.COM
2242*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_read_end, sv_dev_t *, svp);
22437836SJohn.Forte@Sun.COM }
22447836SJohn.Forte@Sun.COM
2245*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_bcopy_start, sv_dev_t *, svp);
22467836SJohn.Forte@Sun.COM
22477836SJohn.Forte@Sun.COM while (tocopy > 0) {
22487836SJohn.Forte@Sun.COM nbytes = min(tocopy, (nsc_size_t)v->sv_len);
22497836SJohn.Forte@Sun.COM
22507836SJohn.Forte@Sun.COM if (bp->b_flags & B_READ)
22517836SJohn.Forte@Sun.COM (void) bcopy(v->sv_addr, buf_addr, nbytes);
22527836SJohn.Forte@Sun.COM else
22537836SJohn.Forte@Sun.COM (void) bcopy(buf_addr, v->sv_addr, nbytes);
22547836SJohn.Forte@Sun.COM
22557836SJohn.Forte@Sun.COM bp->b_resid -= nbytes;
22567836SJohn.Forte@Sun.COM buf_addr += nbytes;
22577836SJohn.Forte@Sun.COM tocopy -= nbytes;
22587836SJohn.Forte@Sun.COM v++;
22597836SJohn.Forte@Sun.COM }
22607836SJohn.Forte@Sun.COM
2261*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_bcopy_end, sv_dev_t *, svp);
22627836SJohn.Forte@Sun.COM
22637836SJohn.Forte@Sun.COM if ((bp->b_flags & B_READ) == 0) {
2264*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE3(sv_dbg_write_start, sv_dev_t *, svp,
22657836SJohn.Forte@Sun.COM uint64_t, (uint64_t)hndl->sb_pos,
22667836SJohn.Forte@Sun.COM uint64_t, (uint64_t)hndl->sb_len);
22677836SJohn.Forte@Sun.COM
22687836SJohn.Forte@Sun.COM rc = nsc_write(hndl, hndl->sb_pos, hndl->sb_len, 0);
22697836SJohn.Forte@Sun.COM
2270*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_write_end, sv_dev_t *, svp);
22717836SJohn.Forte@Sun.COM
22727836SJohn.Forte@Sun.COM if (rc > 0) {
22737836SJohn.Forte@Sun.COM bioerror(bp, rc);
22747836SJohn.Forte@Sun.COM goto done;
22757836SJohn.Forte@Sun.COM }
22767836SJohn.Forte@Sun.COM }
22777836SJohn.Forte@Sun.COM
22787836SJohn.Forte@Sun.COM /*
22797836SJohn.Forte@Sun.COM * Adjust FBA offset and requested (ie. remaining) length,
22807836SJohn.Forte@Sun.COM * loop if more data to transfer.
22817836SJohn.Forte@Sun.COM */
22827836SJohn.Forte@Sun.COM
22837836SJohn.Forte@Sun.COM fba_off += fba_len;
22847836SJohn.Forte@Sun.COM fba_req -= fba_len;
22857836SJohn.Forte@Sun.COM
22867836SJohn.Forte@Sun.COM if (fba_req > 0) {
2287*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_freeb_start, sv_dev_t *, svp);
22887836SJohn.Forte@Sun.COM
22897836SJohn.Forte@Sun.COM rc = nsc_free_buf(hndl);
22907836SJohn.Forte@Sun.COM
2291*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_freeb_end, sv_dev_t *, svp);
22927836SJohn.Forte@Sun.COM
22937836SJohn.Forte@Sun.COM if (rc > 0) {
22947836SJohn.Forte@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_err_free,
2295*9093SRamana.Srikanth@Sun.COM struct buf *, bp);
22967836SJohn.Forte@Sun.COM bioerror(bp, rc);
22977836SJohn.Forte@Sun.COM }
22987836SJohn.Forte@Sun.COM
22997836SJohn.Forte@Sun.COM hndl = NULL;
23007836SJohn.Forte@Sun.COM
23017836SJohn.Forte@Sun.COM if (rc <= 0)
23027836SJohn.Forte@Sun.COM goto loop;
23037836SJohn.Forte@Sun.COM }
23047836SJohn.Forte@Sun.COM
23057836SJohn.Forte@Sun.COM done:
23067836SJohn.Forte@Sun.COM if (hndl != NULL) {
2307*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_freeb_start, sv_dev_t *, svp);
23087836SJohn.Forte@Sun.COM
23097836SJohn.Forte@Sun.COM rc = nsc_free_buf(hndl);
23107836SJohn.Forte@Sun.COM
2311*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_freeb_end, sv_dev_t *, svp);
23127836SJohn.Forte@Sun.COM
23137836SJohn.Forte@Sun.COM if (rc > 0) {
23147836SJohn.Forte@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_err_free,
2315*9093SRamana.Srikanth@Sun.COM struct buf *, bp);
23167836SJohn.Forte@Sun.COM bioerror(bp, rc);
23177836SJohn.Forte@Sun.COM }
23187836SJohn.Forte@Sun.COM
23197836SJohn.Forte@Sun.COM hndl = NULL;
23207836SJohn.Forte@Sun.COM }
23217836SJohn.Forte@Sun.COM
23227836SJohn.Forte@Sun.COM if (bufh)
23237836SJohn.Forte@Sun.COM (void) nsc_free_handle(bufh);
23247836SJohn.Forte@Sun.COM
2325*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_rlse_start, sv_dev_t *, svp);
23267836SJohn.Forte@Sun.COM
23277836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
23287836SJohn.Forte@Sun.COM
2329*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_dbg_rlse_end, sv_dev_t *, svp);
23307836SJohn.Forte@Sun.COM
23317836SJohn.Forte@Sun.COM out:
23327836SJohn.Forte@Sun.COM if (sv_debug > 5) {
23337836SJohn.Forte@Sun.COM cmn_err(CE_CONT,
2334*9093SRamana.Srikanth@Sun.COM "!_sv_lyr_strategy: bp %p, bufh %p, bp->b_error %d\n",
23357836SJohn.Forte@Sun.COM (void *)bp, (void *)bufh, bp->b_error);
23367836SJohn.Forte@Sun.COM }
23377836SJohn.Forte@Sun.COM
2338*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE2(sv_lyr_strategy_end, struct buf *, bp, int, bp->b_error);
23397836SJohn.Forte@Sun.COM
23407836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
23417836SJohn.Forte@Sun.COM biodone(bp);
23427836SJohn.Forte@Sun.COM }
23437836SJohn.Forte@Sun.COM
23447836SJohn.Forte@Sun.COM
23457836SJohn.Forte@Sun.COM static void
sv_async_strategy(blind_t arg)23467836SJohn.Forte@Sun.COM sv_async_strategy(blind_t arg)
23477836SJohn.Forte@Sun.COM {
23487836SJohn.Forte@Sun.COM struct buf *bp = (struct buf *)arg;
23497836SJohn.Forte@Sun.COM _sv_lyr_strategy(bp);
23507836SJohn.Forte@Sun.COM }
23517836SJohn.Forte@Sun.COM
23527836SJohn.Forte@Sun.COM
23537836SJohn.Forte@Sun.COM static int
sv_lyr_strategy(struct buf * bp)23547836SJohn.Forte@Sun.COM sv_lyr_strategy(struct buf *bp)
23557836SJohn.Forte@Sun.COM {
23567836SJohn.Forte@Sun.COM nsthread_t *tp;
23577836SJohn.Forte@Sun.COM int nlive;
23587836SJohn.Forte@Sun.COM
23597836SJohn.Forte@Sun.COM /*
23607836SJohn.Forte@Sun.COM * If B_ASYNC was part of the DDI we could use it as a hint to
23617836SJohn.Forte@Sun.COM * not create a thread for synchronous i/o.
23627836SJohn.Forte@Sun.COM */
23637836SJohn.Forte@Sun.COM if (sv_dev_to_sv(bp->b_edev, NULL) == NULL) {
23647836SJohn.Forte@Sun.COM /* not sv enabled - just pass through */
2365*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_notsv, struct buf *, bp);
23667836SJohn.Forte@Sun.COM _sv_lyr_strategy(bp);
23677836SJohn.Forte@Sun.COM return (0);
23687836SJohn.Forte@Sun.COM }
23697836SJohn.Forte@Sun.COM
23707836SJohn.Forte@Sun.COM if (sv_debug > 4) {
2371*9093SRamana.Srikanth@Sun.COM cmn_err(CE_CONT, "!sv_lyr_strategy: nthread %d nlive %d\n",
23727836SJohn.Forte@Sun.COM nst_nthread(sv_tset), nst_nlive(sv_tset));
23737836SJohn.Forte@Sun.COM }
23747836SJohn.Forte@Sun.COM
23757836SJohn.Forte@Sun.COM /*
23767836SJohn.Forte@Sun.COM * If there are only guard devices enabled there
23777836SJohn.Forte@Sun.COM * won't be a threadset, so don't try and use it.
23787836SJohn.Forte@Sun.COM */
23797836SJohn.Forte@Sun.COM tp = NULL;
23807836SJohn.Forte@Sun.COM if (sv_tset != NULL) {
23817836SJohn.Forte@Sun.COM tp = nst_create(sv_tset, sv_async_strategy, (blind_t)bp, 0);
23827836SJohn.Forte@Sun.COM }
23837836SJohn.Forte@Sun.COM
23847836SJohn.Forte@Sun.COM if (tp == NULL) {
23857836SJohn.Forte@Sun.COM /*
23867836SJohn.Forte@Sun.COM * out of threads, so fall back to synchronous io.
23877836SJohn.Forte@Sun.COM */
23887836SJohn.Forte@Sun.COM if (sv_debug > 0) {
23897836SJohn.Forte@Sun.COM cmn_err(CE_CONT,
2390*9093SRamana.Srikanth@Sun.COM "!sv_lyr_strategy: thread alloc failed\n");
23917836SJohn.Forte@Sun.COM }
23927836SJohn.Forte@Sun.COM
23937836SJohn.Forte@Sun.COM DTRACE_PROBE1(sv_lyr_strategy_no_thread,
2394*9093SRamana.Srikanth@Sun.COM struct buf *, bp);
23957836SJohn.Forte@Sun.COM
23967836SJohn.Forte@Sun.COM _sv_lyr_strategy(bp);
23977836SJohn.Forte@Sun.COM sv_no_threads++;
23987836SJohn.Forte@Sun.COM } else {
23997836SJohn.Forte@Sun.COM nlive = nst_nlive(sv_tset);
24007836SJohn.Forte@Sun.COM if (nlive > sv_max_nlive) {
24017836SJohn.Forte@Sun.COM if (sv_debug > 0) {
24027836SJohn.Forte@Sun.COM cmn_err(CE_CONT,
2403*9093SRamana.Srikanth@Sun.COM "!sv_lyr_strategy: "
24047836SJohn.Forte@Sun.COM "new max nlive %d (nthread %d)\n",
24057836SJohn.Forte@Sun.COM nlive, nst_nthread(sv_tset));
24067836SJohn.Forte@Sun.COM }
24077836SJohn.Forte@Sun.COM
24087836SJohn.Forte@Sun.COM sv_max_nlive = nlive;
24097836SJohn.Forte@Sun.COM }
24107836SJohn.Forte@Sun.COM }
24117836SJohn.Forte@Sun.COM
24127836SJohn.Forte@Sun.COM return (0);
24137836SJohn.Forte@Sun.COM }
24147836SJohn.Forte@Sun.COM
24157836SJohn.Forte@Sun.COM
24167836SJohn.Forte@Sun.COM #ifndef offsetof
24177836SJohn.Forte@Sun.COM #define offsetof(s, m) ((size_t)(&((s *)0)->m))
24187836SJohn.Forte@Sun.COM #endif
24197836SJohn.Forte@Sun.COM
24207836SJohn.Forte@Sun.COM /*
24217836SJohn.Forte@Sun.COM * re-write the size of the current partition
24227836SJohn.Forte@Sun.COM */
24237836SJohn.Forte@Sun.COM static int
sv_fix_dkiocgvtoc(const intptr_t arg,const int mode,sv_dev_t * svp)24247836SJohn.Forte@Sun.COM sv_fix_dkiocgvtoc(const intptr_t arg, const int mode, sv_dev_t *svp)
24257836SJohn.Forte@Sun.COM {
24267836SJohn.Forte@Sun.COM size_t offset;
24277836SJohn.Forte@Sun.COM int ilp32;
24287836SJohn.Forte@Sun.COM int pnum;
24297836SJohn.Forte@Sun.COM int rc;
24307836SJohn.Forte@Sun.COM
24317836SJohn.Forte@Sun.COM ilp32 = (ddi_model_convert_from((mode & FMODELS)) == DDI_MODEL_ILP32);
24327836SJohn.Forte@Sun.COM
24337836SJohn.Forte@Sun.COM rc = nskern_partition(svp->sv_dev, &pnum);
24347836SJohn.Forte@Sun.COM if (rc != 0) {
24357836SJohn.Forte@Sun.COM return (rc);
24367836SJohn.Forte@Sun.COM }
24377836SJohn.Forte@Sun.COM
24387836SJohn.Forte@Sun.COM if (pnum < 0 || pnum >= V_NUMPAR) {
24397836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
2440*9093SRamana.Srikanth@Sun.COM "!sv_gvtoc: unable to determine partition number "
24417836SJohn.Forte@Sun.COM "for dev %lx", svp->sv_dev);
24427836SJohn.Forte@Sun.COM return (EINVAL);
24437836SJohn.Forte@Sun.COM }
24447836SJohn.Forte@Sun.COM
24457836SJohn.Forte@Sun.COM if (ilp32) {
24467836SJohn.Forte@Sun.COM int32_t p_size;
24477836SJohn.Forte@Sun.COM
24487836SJohn.Forte@Sun.COM #ifdef _SunOS_5_6
24497836SJohn.Forte@Sun.COM offset = offsetof(struct vtoc, v_part);
24507836SJohn.Forte@Sun.COM offset += sizeof (struct partition) * pnum;
24517836SJohn.Forte@Sun.COM offset += offsetof(struct partition, p_size);
24527836SJohn.Forte@Sun.COM #else
24537836SJohn.Forte@Sun.COM offset = offsetof(struct vtoc32, v_part);
24547836SJohn.Forte@Sun.COM offset += sizeof (struct partition32) * pnum;
24557836SJohn.Forte@Sun.COM offset += offsetof(struct partition32, p_size);
24567836SJohn.Forte@Sun.COM #endif
24577836SJohn.Forte@Sun.COM
24587836SJohn.Forte@Sun.COM p_size = (int32_t)svp->sv_nblocks;
24597836SJohn.Forte@Sun.COM if (p_size == 0) {
24607836SJohn.Forte@Sun.COM if (sv_reserve(svp->sv_fd,
24617836SJohn.Forte@Sun.COM NSC_MULTI|NSC_PCATCH) == 0) {
24627836SJohn.Forte@Sun.COM p_size = (int32_t)svp->sv_nblocks;
24637836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
24647836SJohn.Forte@Sun.COM } else {
24657836SJohn.Forte@Sun.COM rc = EINTR;
24667836SJohn.Forte@Sun.COM }
24677836SJohn.Forte@Sun.COM }
24687836SJohn.Forte@Sun.COM
24697836SJohn.Forte@Sun.COM if ((rc == 0) && ddi_copyout(&p_size, (void *)(arg + offset),
24707836SJohn.Forte@Sun.COM sizeof (p_size), mode) != 0) {
24717836SJohn.Forte@Sun.COM rc = EFAULT;
24727836SJohn.Forte@Sun.COM }
24737836SJohn.Forte@Sun.COM } else {
24747836SJohn.Forte@Sun.COM long p_size;
24757836SJohn.Forte@Sun.COM
24767836SJohn.Forte@Sun.COM offset = offsetof(struct vtoc, v_part);
24777836SJohn.Forte@Sun.COM offset += sizeof (struct partition) * pnum;
24787836SJohn.Forte@Sun.COM offset += offsetof(struct partition, p_size);
24797836SJohn.Forte@Sun.COM
24807836SJohn.Forte@Sun.COM p_size = (long)svp->sv_nblocks;
24817836SJohn.Forte@Sun.COM if (p_size == 0) {
24827836SJohn.Forte@Sun.COM if (sv_reserve(svp->sv_fd,
24837836SJohn.Forte@Sun.COM NSC_MULTI|NSC_PCATCH) == 0) {
24847836SJohn.Forte@Sun.COM p_size = (long)svp->sv_nblocks;
24857836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
24867836SJohn.Forte@Sun.COM } else {
24877836SJohn.Forte@Sun.COM rc = EINTR;
24887836SJohn.Forte@Sun.COM }
24897836SJohn.Forte@Sun.COM }
24907836SJohn.Forte@Sun.COM
24917836SJohn.Forte@Sun.COM if ((rc == 0) && ddi_copyout(&p_size, (void *)(arg + offset),
24927836SJohn.Forte@Sun.COM sizeof (p_size), mode) != 0) {
24937836SJohn.Forte@Sun.COM rc = EFAULT;
24947836SJohn.Forte@Sun.COM }
24957836SJohn.Forte@Sun.COM }
24967836SJohn.Forte@Sun.COM
24977836SJohn.Forte@Sun.COM return (rc);
24987836SJohn.Forte@Sun.COM }
24997836SJohn.Forte@Sun.COM
25007836SJohn.Forte@Sun.COM
25017836SJohn.Forte@Sun.COM #ifdef DKIOCPARTITION
25027836SJohn.Forte@Sun.COM /*
25037836SJohn.Forte@Sun.COM * re-write the size of the current partition
25047836SJohn.Forte@Sun.COM *
25057836SJohn.Forte@Sun.COM * arg is dk_efi_t.
25067836SJohn.Forte@Sun.COM *
25077836SJohn.Forte@Sun.COM * dk_efi_t->dki_data = (void *)(uintptr_t)efi.dki_data_64;
25087836SJohn.Forte@Sun.COM *
25097836SJohn.Forte@Sun.COM * dk_efi_t->dki_data --> efi_gpt_t (label header)
25107836SJohn.Forte@Sun.COM * dk_efi_t->dki_data + 1 --> efi_gpe_t[] (array of partitions)
25117836SJohn.Forte@Sun.COM *
25127836SJohn.Forte@Sun.COM * efi_gpt_t->efi_gpt_PartitionEntryArrayCRC32 --> CRC32 of array of parts
25137836SJohn.Forte@Sun.COM * efi_gpt_t->efi_gpt_HeaderCRC32 --> CRC32 of header itself
25147836SJohn.Forte@Sun.COM *
25157836SJohn.Forte@Sun.COM * This assumes that sizeof (efi_gpt_t) is the same as the size of a
25167836SJohn.Forte@Sun.COM * logical block on the disk.
25177836SJohn.Forte@Sun.COM *
25187836SJohn.Forte@Sun.COM * Everything is little endian (i.e. disk format).
25197836SJohn.Forte@Sun.COM */
25207836SJohn.Forte@Sun.COM static int
sv_fix_dkiocgetefi(const intptr_t arg,const int mode,sv_dev_t * svp)25217836SJohn.Forte@Sun.COM sv_fix_dkiocgetefi(const intptr_t arg, const int mode, sv_dev_t *svp)
25227836SJohn.Forte@Sun.COM {
25237836SJohn.Forte@Sun.COM dk_efi_t efi;
25247836SJohn.Forte@Sun.COM efi_gpt_t gpt;
25257836SJohn.Forte@Sun.COM efi_gpe_t *gpe = NULL;
25267836SJohn.Forte@Sun.COM size_t sgpe;
25277836SJohn.Forte@Sun.COM uint64_t p_size; /* virtual partition size from nsctl */
25287836SJohn.Forte@Sun.COM uint32_t crc;
25297836SJohn.Forte@Sun.COM int unparts; /* number of parts in user's array */
25307836SJohn.Forte@Sun.COM int pnum;
25317836SJohn.Forte@Sun.COM int rc;
25327836SJohn.Forte@Sun.COM
25337836SJohn.Forte@Sun.COM rc = nskern_partition(svp->sv_dev, &pnum);
25347836SJohn.Forte@Sun.COM if (rc != 0) {
25357836SJohn.Forte@Sun.COM return (rc);
25367836SJohn.Forte@Sun.COM }
25377836SJohn.Forte@Sun.COM
25387836SJohn.Forte@Sun.COM if (pnum < 0) {
25397836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
2540*9093SRamana.Srikanth@Sun.COM "!sv_efi: unable to determine partition number for dev %lx",
25417836SJohn.Forte@Sun.COM svp->sv_dev);
25427836SJohn.Forte@Sun.COM return (EINVAL);
25437836SJohn.Forte@Sun.COM }
25447836SJohn.Forte@Sun.COM
25457836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &efi, sizeof (efi), mode)) {
25467836SJohn.Forte@Sun.COM return (EFAULT);
25477836SJohn.Forte@Sun.COM }
25487836SJohn.Forte@Sun.COM
25497836SJohn.Forte@Sun.COM efi.dki_data = (void *)(uintptr_t)efi.dki_data_64;
25507836SJohn.Forte@Sun.COM
25517836SJohn.Forte@Sun.COM if (efi.dki_length < sizeof (gpt) + sizeof (gpe)) {
25527836SJohn.Forte@Sun.COM return (EINVAL);
25537836SJohn.Forte@Sun.COM }
25547836SJohn.Forte@Sun.COM
25557836SJohn.Forte@Sun.COM if (ddi_copyin((void *)efi.dki_data, &gpt, sizeof (gpt), mode)) {
25567836SJohn.Forte@Sun.COM rc = EFAULT;
25577836SJohn.Forte@Sun.COM goto out;
25587836SJohn.Forte@Sun.COM }
25597836SJohn.Forte@Sun.COM
25607836SJohn.Forte@Sun.COM if ((unparts = LE_32(gpt.efi_gpt_NumberOfPartitionEntries)) == 0)
25617836SJohn.Forte@Sun.COM unparts = 1;
25627836SJohn.Forte@Sun.COM else if (pnum >= unparts) {
25637836SJohn.Forte@Sun.COM cmn_err(CE_WARN,
2564*9093SRamana.Srikanth@Sun.COM "!sv_efi: partition# beyond end of user array (%d >= %d)",
25657836SJohn.Forte@Sun.COM pnum, unparts);
25667836SJohn.Forte@Sun.COM return (EINVAL);
25677836SJohn.Forte@Sun.COM }
25687836SJohn.Forte@Sun.COM
25697836SJohn.Forte@Sun.COM sgpe = sizeof (*gpe) * unparts;
25707836SJohn.Forte@Sun.COM gpe = kmem_alloc(sgpe, KM_SLEEP);
25717836SJohn.Forte@Sun.COM
25727836SJohn.Forte@Sun.COM if (ddi_copyin((void *)(efi.dki_data + 1), gpe, sgpe, mode)) {
25737836SJohn.Forte@Sun.COM rc = EFAULT;
25747836SJohn.Forte@Sun.COM goto out;
25757836SJohn.Forte@Sun.COM }
25767836SJohn.Forte@Sun.COM
25777836SJohn.Forte@Sun.COM p_size = svp->sv_nblocks;
25787836SJohn.Forte@Sun.COM if (p_size == 0) {
25797836SJohn.Forte@Sun.COM if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
25807836SJohn.Forte@Sun.COM p_size = (diskaddr_t)svp->sv_nblocks;
25817836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
25827836SJohn.Forte@Sun.COM } else {
25837836SJohn.Forte@Sun.COM rc = EINTR;
25847836SJohn.Forte@Sun.COM }
25857836SJohn.Forte@Sun.COM }
25867836SJohn.Forte@Sun.COM
25877836SJohn.Forte@Sun.COM gpe[pnum].efi_gpe_EndingLBA = LE_64(
25887836SJohn.Forte@Sun.COM LE_64(gpe[pnum].efi_gpe_StartingLBA) + p_size - 1);
25897836SJohn.Forte@Sun.COM
25907836SJohn.Forte@Sun.COM gpt.efi_gpt_PartitionEntryArrayCRC32 = 0;
25917836SJohn.Forte@Sun.COM CRC32(crc, gpe, sgpe, -1U, sv_crc32_table);
25927836SJohn.Forte@Sun.COM gpt.efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc);
25937836SJohn.Forte@Sun.COM
25947836SJohn.Forte@Sun.COM gpt.efi_gpt_HeaderCRC32 = 0;
25957836SJohn.Forte@Sun.COM CRC32(crc, &gpt, sizeof (gpt), -1U, sv_crc32_table);
25967836SJohn.Forte@Sun.COM gpt.efi_gpt_HeaderCRC32 = LE_32(~crc);
25977836SJohn.Forte@Sun.COM
25987836SJohn.Forte@Sun.COM if ((rc == 0) && ddi_copyout(&gpt, efi.dki_data, sizeof (gpt), mode)) {
25997836SJohn.Forte@Sun.COM rc = EFAULT;
26007836SJohn.Forte@Sun.COM goto out;
26017836SJohn.Forte@Sun.COM }
26027836SJohn.Forte@Sun.COM
26037836SJohn.Forte@Sun.COM if ((rc == 0) && ddi_copyout(gpe, efi.dki_data + 1, sgpe, mode)) {
26047836SJohn.Forte@Sun.COM rc = EFAULT;
26057836SJohn.Forte@Sun.COM goto out;
26067836SJohn.Forte@Sun.COM }
26077836SJohn.Forte@Sun.COM
26087836SJohn.Forte@Sun.COM out:
26097836SJohn.Forte@Sun.COM if (gpe) {
26107836SJohn.Forte@Sun.COM kmem_free(gpe, sgpe);
26117836SJohn.Forte@Sun.COM }
26127836SJohn.Forte@Sun.COM
26137836SJohn.Forte@Sun.COM return (rc);
26147836SJohn.Forte@Sun.COM }
26157836SJohn.Forte@Sun.COM
26167836SJohn.Forte@Sun.COM
26177836SJohn.Forte@Sun.COM /*
26187836SJohn.Forte@Sun.COM * Re-write the size of the partition specified by p_partno
26197836SJohn.Forte@Sun.COM *
26207836SJohn.Forte@Sun.COM * Note that if a DKIOCPARTITION is issued to an fd opened against a
26217836SJohn.Forte@Sun.COM * non-sv'd device, but p_partno requests the size for a different
26227836SJohn.Forte@Sun.COM * device that is sv'd, this function will *not* be called as sv is
26237836SJohn.Forte@Sun.COM * not interposed on the original device (the fd).
26247836SJohn.Forte@Sun.COM *
26257836SJohn.Forte@Sun.COM * It would not be easy to change this as we cannot get the partition
26267836SJohn.Forte@Sun.COM * number for the non-sv'd device, so cannot compute the dev_t of the
26277836SJohn.Forte@Sun.COM * (sv'd) p_partno device, and so cannot find out if it is sv'd or get
26287836SJohn.Forte@Sun.COM * its size from nsctl.
26297836SJohn.Forte@Sun.COM *
26307836SJohn.Forte@Sun.COM * See also the "Bug 4755783" comment in sv_lyr_ioctl().
26317836SJohn.Forte@Sun.COM */
26327836SJohn.Forte@Sun.COM static int
sv_fix_dkiocpartition(const intptr_t arg,const int mode,sv_dev_t * svp)26337836SJohn.Forte@Sun.COM sv_fix_dkiocpartition(const intptr_t arg, const int mode, sv_dev_t *svp)
26347836SJohn.Forte@Sun.COM {
26357836SJohn.Forte@Sun.COM struct partition64 p64;
26367836SJohn.Forte@Sun.COM sv_dev_t *nsvp = NULL;
26377836SJohn.Forte@Sun.COM diskaddr_t p_size;
26387836SJohn.Forte@Sun.COM minor_t nminor;
26397836SJohn.Forte@Sun.COM int pnum, rc;
26407836SJohn.Forte@Sun.COM dev_t ndev;
26417836SJohn.Forte@Sun.COM
26427836SJohn.Forte@Sun.COM rc = nskern_partition(svp->sv_dev, &pnum);
26437836SJohn.Forte@Sun.COM if (rc != 0) {
26447836SJohn.Forte@Sun.COM return (rc);
26457836SJohn.Forte@Sun.COM }
26467836SJohn.Forte@Sun.COM
26477836SJohn.Forte@Sun.COM if (ddi_copyin((void *)arg, &p64, sizeof (p64), mode)) {
26487836SJohn.Forte@Sun.COM return (EFAULT);
26497836SJohn.Forte@Sun.COM }
26507836SJohn.Forte@Sun.COM
26517836SJohn.Forte@Sun.COM if (p64.p_partno != pnum) {
26527836SJohn.Forte@Sun.COM /* switch to requested partition, not the current one */
26537836SJohn.Forte@Sun.COM nminor = getminor(svp->sv_dev) + (p64.p_partno - pnum);
26547836SJohn.Forte@Sun.COM ndev = makedevice(getmajor(svp->sv_dev), nminor);
26557836SJohn.Forte@Sun.COM nsvp = sv_find_enabled(ndev, NULL);
26567836SJohn.Forte@Sun.COM if (nsvp == NULL) {
26577836SJohn.Forte@Sun.COM /* not sv device - just return */
26587836SJohn.Forte@Sun.COM return (0);
26597836SJohn.Forte@Sun.COM }
26607836SJohn.Forte@Sun.COM
26617836SJohn.Forte@Sun.COM svp = nsvp;
26627836SJohn.Forte@Sun.COM }
26637836SJohn.Forte@Sun.COM
26647836SJohn.Forte@Sun.COM p_size = svp->sv_nblocks;
26657836SJohn.Forte@Sun.COM if (p_size == 0) {
26667836SJohn.Forte@Sun.COM if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
26677836SJohn.Forte@Sun.COM p_size = (diskaddr_t)svp->sv_nblocks;
26687836SJohn.Forte@Sun.COM nsc_release(svp->sv_fd);
26697836SJohn.Forte@Sun.COM } else {
26707836SJohn.Forte@Sun.COM rc = EINTR;
26717836SJohn.Forte@Sun.COM }
26727836SJohn.Forte@Sun.COM }
26737836SJohn.Forte@Sun.COM
26747836SJohn.Forte@Sun.COM if (nsvp != NULL) {
26757836SJohn.Forte@Sun.COM rw_exit(&nsvp->sv_lock);
26767836SJohn.Forte@Sun.COM }
26777836SJohn.Forte@Sun.COM
26787836SJohn.Forte@Sun.COM if ((rc == 0) && ddi_copyout(&p_size,
26797836SJohn.Forte@Sun.COM (void *)(arg + offsetof(struct partition64, p_size)),
26807836SJohn.Forte@Sun.COM sizeof (p_size), mode) != 0) {
26817836SJohn.Forte@Sun.COM return (EFAULT);
26827836SJohn.Forte@Sun.COM }
26837836SJohn.Forte@Sun.COM
26847836SJohn.Forte@Sun.COM return (rc);
26857836SJohn.Forte@Sun.COM }
26867836SJohn.Forte@Sun.COM #endif /* DKIOCPARTITION */
26877836SJohn.Forte@Sun.COM
26887836SJohn.Forte@Sun.COM
26897836SJohn.Forte@Sun.COM static int
sv_lyr_ioctl(const dev_t dev,const int cmd,const intptr_t arg,const int mode,cred_t * crp,int * rvalp)26907836SJohn.Forte@Sun.COM sv_lyr_ioctl(const dev_t dev, const int cmd, const intptr_t arg,
26917836SJohn.Forte@Sun.COM const int mode, cred_t *crp, int *rvalp)
26927836SJohn.Forte@Sun.COM {
26937836SJohn.Forte@Sun.COM sv_dev_t *svp;
26947836SJohn.Forte@Sun.COM sv_maj_t *maj;
26957836SJohn.Forte@Sun.COM int (*fn)();
26967836SJohn.Forte@Sun.COM int rc = 0;
26977836SJohn.Forte@Sun.COM
26987836SJohn.Forte@Sun.COM maj = 0;
26997836SJohn.Forte@Sun.COM fn = 0;
27007836SJohn.Forte@Sun.COM
27017836SJohn.Forte@Sun.COM /*
27027836SJohn.Forte@Sun.COM * If sv_mod_status is 0 or SV_PREVENT_UNLOAD, then it will continue.
27037836SJohn.Forte@Sun.COM * else it means it previously was SV_PREVENT_UNLOAD, and now it's
27047836SJohn.Forte@Sun.COM * SV_ALLOW_UNLOAD, expecting the driver to eventually unload.
27057836SJohn.Forte@Sun.COM *
27067836SJohn.Forte@Sun.COM * SV_ALLOW_UNLOAD is final state, so no need to grab sv_mutex.
27077836SJohn.Forte@Sun.COM */
27087836SJohn.Forte@Sun.COM if (sv_mod_status == SV_ALLOW_UNLOAD) {
27097836SJohn.Forte@Sun.COM return (EBUSY);
27107836SJohn.Forte@Sun.COM }
27117836SJohn.Forte@Sun.COM
27127836SJohn.Forte@Sun.COM svp = sv_find_enabled(dev, &maj);
27137836SJohn.Forte@Sun.COM if (svp != NULL) {
27147836SJohn.Forte@Sun.COM if (nskernd_isdaemon()) {
27157836SJohn.Forte@Sun.COM /*
27167836SJohn.Forte@Sun.COM * This is nskernd which always needs to see
27177836SJohn.Forte@Sun.COM * the underlying disk device accurately.
27187836SJohn.Forte@Sun.COM *
27197836SJohn.Forte@Sun.COM * So just pass the ioctl straight through
27207836SJohn.Forte@Sun.COM * to the underlying driver as though the device
27217836SJohn.Forte@Sun.COM * was not sv enabled.
27227836SJohn.Forte@Sun.COM */
2723*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE2(sv_lyr_ioctl_nskernd, sv_dev_t *, svp,
2724*9093SRamana.Srikanth@Sun.COM dev_t, dev);
27257836SJohn.Forte@Sun.COM
27267836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
27277836SJohn.Forte@Sun.COM svp = NULL;
27287836SJohn.Forte@Sun.COM } else {
27297836SJohn.Forte@Sun.COM ASSERT(RW_READ_HELD(&svp->sv_lock));
27307836SJohn.Forte@Sun.COM }
27317836SJohn.Forte@Sun.COM }
27327836SJohn.Forte@Sun.COM
27337836SJohn.Forte@Sun.COM /*
27347836SJohn.Forte@Sun.COM * We now have a locked and enabled SV device, or a non-SV device.
27357836SJohn.Forte@Sun.COM */
27367836SJohn.Forte@Sun.COM
27377836SJohn.Forte@Sun.COM switch (cmd) {
27387836SJohn.Forte@Sun.COM /*
27397836SJohn.Forte@Sun.COM * DKIOCGVTOC, DKIOCSVTOC, DKIOCPARTITION, DKIOCGETEFI
27407836SJohn.Forte@Sun.COM * and DKIOCSETEFI are intercepted and faked up as some
27417836SJohn.Forte@Sun.COM * i/o providers emulate volumes of a different size to
27427836SJohn.Forte@Sun.COM * the underlying volume.
27437836SJohn.Forte@Sun.COM *
27447836SJohn.Forte@Sun.COM * Setting the size by rewriting the vtoc is not permitted.
27457836SJohn.Forte@Sun.COM */
27467836SJohn.Forte@Sun.COM
27477836SJohn.Forte@Sun.COM case DKIOCSVTOC:
27487836SJohn.Forte@Sun.COM #ifdef DKIOCPARTITION
27497836SJohn.Forte@Sun.COM case DKIOCSETEFI:
27507836SJohn.Forte@Sun.COM #endif
27517836SJohn.Forte@Sun.COM if (svp == NULL) {
27527836SJohn.Forte@Sun.COM /* not intercepted -- allow ioctl through */
27537836SJohn.Forte@Sun.COM break;
27547836SJohn.Forte@Sun.COM }
27557836SJohn.Forte@Sun.COM
27567836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
27577836SJohn.Forte@Sun.COM
2758*9093SRamana.Srikanth@Sun.COM DTRACE_PROBE2(sv_lyr_ioctl_svtoc, dev_t, dev, int, EPERM);
27597836SJohn.Forte@Sun.COM
27607836SJohn.Forte@Sun.COM return (EPERM);
27617836SJohn.Forte@Sun.COM
27627836SJohn.Forte@Sun.COM default:
27637836SJohn.Forte@Sun.COM break;
27647836SJohn.Forte@Sun.COM }
27657836SJohn.Forte@Sun.COM
27667836SJohn.Forte@Sun.COM /*
27677836SJohn.Forte@Sun.COM * Pass through the real ioctl command.
27687836SJohn.Forte@Sun.COM */
27697836SJohn.Forte@Sun.COM
27707836SJohn.Forte@Sun.COM if (maj && (fn = maj->sm_ioctl) != 0) {
27717836SJohn.Forte@Sun.COM if (!(maj->sm_flag & D_MP)) {
27727836SJohn.Forte@Sun.COM UNSAFE_ENTER();
27737836SJohn.Forte@Sun.COM rc = (*fn)(dev, cmd, arg, mode, crp, rvalp);
27747836SJohn.Forte@Sun.COM UNSAFE_EXIT();
27757836SJohn.Forte@Sun.COM } else {
27767836SJohn.Forte@Sun.COM rc = (*fn)(dev, cmd, arg, mode, crp, rvalp);
27777836SJohn.Forte@Sun.COM }
27787836SJohn.Forte@Sun.COM } else {
27797836SJohn.Forte@Sun.COM rc = ENODEV;
27807836SJohn.Forte@Sun.COM }
27817836SJohn.Forte@Sun.COM
27827836SJohn.Forte@Sun.COM /*
27837836SJohn.Forte@Sun.COM * Bug 4755783
27847836SJohn.Forte@Sun.COM * Fix up the size of the current partition to allow
27857836SJohn.Forte@Sun.COM * for the virtual volume to be a different size to the
27867836SJohn.Forte@Sun.COM * physical volume (e.g. for II compact dependent shadows).
27877836SJohn.Forte@Sun.COM *
27887836SJohn.Forte@Sun.COM * Note that this only attempts to fix up the current partition
27897836SJohn.Forte@Sun.COM * - the one that the ioctl was issued against. There could be
27907836SJohn.Forte@Sun.COM * other sv'd partitions in the same vtoc, but we cannot tell
27917836SJohn.Forte@Sun.COM * so we don't attempt to fix them up.
27927836SJohn.Forte@Sun.COM */
27937836SJohn.Forte@Sun.COM
27947836SJohn.Forte@Sun.COM if (svp != NULL && rc == 0) {
27957836SJohn.Forte@Sun.COM switch (cmd) {
27967836SJohn.Forte@Sun.COM case DKIOCGVTOC:
27977836SJohn.Forte@Sun.COM rc = sv_fix_dkiocgvtoc(arg, mode, svp);
27987836SJohn.Forte@Sun.COM break;
27997836SJohn.Forte@Sun.COM
28007836SJohn.Forte@Sun.COM #ifdef DKIOCPARTITION
28017836SJohn.Forte@Sun.COM case DKIOCGETEFI:
28027836SJohn.Forte@Sun.COM rc = sv_fix_dkiocgetefi(arg, mode, svp);
28037836SJohn.Forte@Sun.COM break;
28047836SJohn.Forte@Sun.COM
28057836SJohn.Forte@Sun.COM case DKIOCPARTITION:
28067836SJohn.Forte@Sun.COM rc = sv_fix_dkiocpartition(arg, mode, svp);
28077836SJohn.Forte@Sun.COM break;
28087836SJohn.Forte@Sun.COM #endif /* DKIOCPARTITION */
28097836SJohn.Forte@Sun.COM }
28107836SJohn.Forte@Sun.COM }
28117836SJohn.Forte@Sun.COM
28127836SJohn.Forte@Sun.COM if (svp != NULL) {
28137836SJohn.Forte@Sun.COM rw_exit(&svp->sv_lock);
28147836SJohn.Forte@Sun.COM }
28157836SJohn.Forte@Sun.COM
28167836SJohn.Forte@Sun.COM return (rc);
28177836SJohn.Forte@Sun.COM }
2818