1fcf3ce44SJohn Forte /* 2fcf3ce44SJohn Forte * CDDL HEADER START 3fcf3ce44SJohn Forte * 4fcf3ce44SJohn Forte * The contents of this file are subject to the terms of the 5fcf3ce44SJohn Forte * Common Development and Distribution License (the "License"). 6fcf3ce44SJohn Forte * You may not use this file except in compliance with the License. 7fcf3ce44SJohn Forte * 8fcf3ce44SJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fcf3ce44SJohn Forte * or http://www.opensolaris.org/os/licensing. 10fcf3ce44SJohn Forte * See the License for the specific language governing permissions 11fcf3ce44SJohn Forte * and limitations under the License. 12fcf3ce44SJohn Forte * 13fcf3ce44SJohn Forte * When distributing Covered Code, include this CDDL HEADER in each 14fcf3ce44SJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fcf3ce44SJohn Forte * If applicable, add the following below this CDDL HEADER, with the 16fcf3ce44SJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying 17fcf3ce44SJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner] 18fcf3ce44SJohn Forte * 19fcf3ce44SJohn Forte * CDDL HEADER END 20fcf3ce44SJohn Forte */ 21fcf3ce44SJohn Forte /* 223270659fSSrikanth, Ramana * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fcf3ce44SJohn Forte * Use is subject to license terms. 24b2514ea1SDan McDonald * 25b2514ea1SDan McDonald * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 26fcf3ce44SJohn Forte */ 27fcf3ce44SJohn Forte 28fcf3ce44SJohn Forte /* 29fcf3ce44SJohn Forte * Storage Volume Character and Block Driver (SV) 30fcf3ce44SJohn Forte * 31fcf3ce44SJohn Forte * This driver implements a simplistic /dev/{r}dsk/ interface to a 32fcf3ce44SJohn Forte * specified disk volume that is otherwise managed by the Prism 33fcf3ce44SJohn Forte * software. The SV driver layers itself onto the underlying disk 34fcf3ce44SJohn Forte * device driver by changing function pointers in the cb_ops 35fcf3ce44SJohn Forte * structure. 36fcf3ce44SJohn Forte * 37fcf3ce44SJohn Forte * CONFIGURATION: 38fcf3ce44SJohn Forte * 39fcf3ce44SJohn Forte * 1. Configure the driver using the svadm utility. 40fcf3ce44SJohn Forte * 2. Access the device as before through /dev/rdsk/c?t?d?s? 41fcf3ce44SJohn Forte * 42fcf3ce44SJohn Forte * LIMITATIONS: 43fcf3ce44SJohn Forte * 44fcf3ce44SJohn Forte * This driver should NOT be used to share a device between another 45fcf3ce44SJohn Forte * DataServices user interface module (e.g., STE) and a user accessing 46fcf3ce44SJohn Forte * the device through the block device in O_WRITE mode. This is because 47fcf3ce44SJohn Forte * writes through the block device are asynchronous (due to the page 48fcf3ce44SJohn Forte * cache) and so consistency between the block device user and the 49fcf3ce44SJohn Forte * STE user cannot be guaranteed. 50fcf3ce44SJohn Forte * 51fcf3ce44SJohn Forte * Data is copied between system struct buf(9s) and nsc_vec_t. This is 52fcf3ce44SJohn Forte * wasteful and slow. 53fcf3ce44SJohn Forte */ 54fcf3ce44SJohn Forte 55fcf3ce44SJohn Forte #include <sys/debug.h> 56fcf3ce44SJohn Forte #include <sys/types.h> 57fcf3ce44SJohn Forte 58fcf3ce44SJohn Forte #include <sys/ksynch.h> 59fcf3ce44SJohn Forte #include <sys/kmem.h> 60fcf3ce44SJohn Forte #include <sys/errno.h> 61fcf3ce44SJohn Forte #include <sys/varargs.h> 62fcf3ce44SJohn Forte #include <sys/file.h> 63fcf3ce44SJohn Forte #include <sys/open.h> 64fcf3ce44SJohn Forte #include <sys/conf.h> 65fcf3ce44SJohn Forte #include <sys/cred.h> 66fcf3ce44SJohn Forte #include <sys/buf.h> 67fcf3ce44SJohn Forte #include <sys/uio.h> 68fcf3ce44SJohn Forte #ifndef DS_DDICT 69fcf3ce44SJohn Forte #include <sys/pathname.h> 70fcf3ce44SJohn Forte #endif 71fcf3ce44SJohn Forte #include <sys/aio_req.h> 72fcf3ce44SJohn Forte #include <sys/dkio.h> 73fcf3ce44SJohn Forte #include <sys/vtoc.h> 74fcf3ce44SJohn Forte #include <sys/cmn_err.h> 75fcf3ce44SJohn Forte #include <sys/modctl.h> 76fcf3ce44SJohn Forte #include <sys/ddi.h> 77*5c5f1371SRichard Lowe #include <sys/sysmacros.h> 78fcf3ce44SJohn Forte #include <sys/sunddi.h> 79fcf3ce44SJohn Forte #include <sys/sunldi.h> 80fcf3ce44SJohn Forte #include <sys/nsctl/nsvers.h> 81fcf3ce44SJohn Forte 82fcf3ce44SJohn Forte #include <sys/nsc_thread.h> 83fcf3ce44SJohn Forte #include <sys/unistat/spcs_s.h> 84fcf3ce44SJohn Forte #include <sys/unistat/spcs_s_k.h> 85fcf3ce44SJohn Forte #include <sys/unistat/spcs_errors.h> 86fcf3ce44SJohn Forte 87fcf3ce44SJohn Forte #ifdef DS_DDICT 88fcf3ce44SJohn Forte #include "../contract.h" 89fcf3ce44SJohn Forte #endif 90fcf3ce44SJohn Forte 91fcf3ce44SJohn Forte #include "../nsctl.h" 92fcf3ce44SJohn Forte 93fcf3ce44SJohn Forte 94fcf3ce44SJohn Forte #include <sys/sdt.h> /* dtrace is S10 or later */ 95fcf3ce44SJohn Forte 96fcf3ce44SJohn Forte #include "sv.h" 97fcf3ce44SJohn Forte #include "sv_impl.h" 98fcf3ce44SJohn Forte #include "sv_efi.h" 99fcf3ce44SJohn Forte 100fcf3ce44SJohn Forte #define MAX_EINTR_COUNT 1000 101fcf3ce44SJohn Forte 102fcf3ce44SJohn Forte /* 103fcf3ce44SJohn Forte * sv_mod_status 104fcf3ce44SJohn Forte */ 105fcf3ce44SJohn Forte #define SV_PREVENT_UNLOAD 1 106fcf3ce44SJohn Forte #define SV_ALLOW_UNLOAD 2 107fcf3ce44SJohn Forte 108fcf3ce44SJohn Forte static const int sv_major_rev = ISS_VERSION_MAJ; /* Major number */ 109fcf3ce44SJohn Forte static const int sv_minor_rev = ISS_VERSION_MIN; /* Minor number */ 110fcf3ce44SJohn Forte static const int sv_micro_rev = ISS_VERSION_MIC; /* Micro number */ 111fcf3ce44SJohn Forte static const int sv_baseline_rev = ISS_VERSION_NUM; /* Baseline number */ 112fcf3ce44SJohn Forte 113fcf3ce44SJohn Forte #ifdef DKIOCPARTITION 114fcf3ce44SJohn Forte /* 115fcf3ce44SJohn Forte * CRC32 polynomial table needed for computing the checksums 116fcf3ce44SJohn Forte * in an EFI vtoc. 117fcf3ce44SJohn Forte */ 118fcf3ce44SJohn Forte static const uint32_t sv_crc32_table[256] = { CRC32_TABLE }; 119fcf3ce44SJohn Forte #endif 120fcf3ce44SJohn Forte 121fcf3ce44SJohn Forte static clock_t sv_config_time; /* Time of successful {en,dis}able */ 122fcf3ce44SJohn Forte static int sv_debug; /* Set non-zero for debug to syslog */ 123fcf3ce44SJohn Forte static int sv_mod_status; /* Set to prevent modunload */ 124fcf3ce44SJohn Forte 125fcf3ce44SJohn Forte static dev_info_t *sv_dip; /* Single DIP for driver */ 126fcf3ce44SJohn Forte static kmutex_t sv_mutex; /* Protect global lists, etc. */ 127fcf3ce44SJohn Forte 128fcf3ce44SJohn Forte static nsc_mem_t *sv_mem; /* nsctl memory allocator token */ 129fcf3ce44SJohn Forte 130fcf3ce44SJohn Forte 131fcf3ce44SJohn Forte /* 132fcf3ce44SJohn Forte * Per device and per major state. 133fcf3ce44SJohn Forte */ 134fcf3ce44SJohn Forte 135fcf3ce44SJohn Forte #ifndef _SunOS_5_6 136fcf3ce44SJohn Forte #define UNSAFE_ENTER() 137fcf3ce44SJohn Forte #define UNSAFE_EXIT() 138fcf3ce44SJohn Forte #else 139fcf3ce44SJohn Forte #define UNSAFE_ENTER() mutex_enter(&unsafe_driver) 140fcf3ce44SJohn Forte #define UNSAFE_EXIT() mutex_exit(&unsafe_driver) 141fcf3ce44SJohn Forte #endif 142fcf3ce44SJohn Forte 143fcf3ce44SJohn Forte /* hash table of major dev structures */ 144fcf3ce44SJohn Forte static sv_maj_t *sv_majors[SV_MAJOR_HASH_CNT] = {0}; 145fcf3ce44SJohn Forte static sv_dev_t *sv_devs; /* array of per device structures */ 146fcf3ce44SJohn Forte static int sv_max_devices; /* SV version of nsc_max_devices() */ 147fcf3ce44SJohn Forte static int sv_ndevices; /* number of SV enabled devices */ 148fcf3ce44SJohn Forte 149fcf3ce44SJohn Forte /* 150fcf3ce44SJohn Forte * Threading. 151fcf3ce44SJohn Forte */ 152fcf3ce44SJohn Forte 153fcf3ce44SJohn Forte int sv_threads_max = 1024; /* maximum # to dynamically alloc */ 154fcf3ce44SJohn Forte int sv_threads = 32; /* # to pre-allocate (see sv.conf) */ 155fcf3ce44SJohn Forte int sv_threads_extra = 0; /* addl # we would have alloc'ed */ 156fcf3ce44SJohn Forte 157fcf3ce44SJohn Forte static nstset_t *sv_tset; /* the threadset pointer */ 158fcf3ce44SJohn Forte 159fcf3ce44SJohn Forte static int sv_threads_hysteresis = 4; /* hysteresis for threadset resizing */ 160fcf3ce44SJohn Forte static int sv_threads_dev = 2; /* # of threads to alloc per device */ 161fcf3ce44SJohn Forte static int sv_threads_inc = 8; /* increment for changing the set */ 162fcf3ce44SJohn Forte static int sv_threads_needed; /* number of threads needed */ 163fcf3ce44SJohn Forte static int sv_no_threads; /* number of nsc_create errors */ 164fcf3ce44SJohn Forte static int sv_max_nlive; /* max number of threads running */ 165fcf3ce44SJohn Forte 166fcf3ce44SJohn Forte 167fcf3ce44SJohn Forte 168fcf3ce44SJohn Forte /* 169fcf3ce44SJohn Forte * nsctl fd callbacks. 170fcf3ce44SJohn Forte */ 171fcf3ce44SJohn Forte 172fcf3ce44SJohn Forte static int svattach_fd(blind_t); 173fcf3ce44SJohn Forte static int svdetach_fd(blind_t); 174fcf3ce44SJohn Forte 175fcf3ce44SJohn Forte static nsc_def_t sv_fd_def[] = { 176fcf3ce44SJohn Forte { "Attach", (uintptr_t)svattach_fd, }, 177fcf3ce44SJohn Forte { "Detach", (uintptr_t)svdetach_fd, }, 178fcf3ce44SJohn Forte { 0, 0, } 179fcf3ce44SJohn Forte }; 180fcf3ce44SJohn Forte 181fcf3ce44SJohn Forte /* 182fcf3ce44SJohn Forte * cb_ops functions. 183fcf3ce44SJohn Forte */ 184fcf3ce44SJohn Forte 185fcf3ce44SJohn Forte static int svopen(dev_t *, int, int, cred_t *); 186fcf3ce44SJohn Forte static int svclose(dev_t, int, int, cred_t *); 187fcf3ce44SJohn Forte static int svioctl(dev_t, int, intptr_t, int, cred_t *, int *); 188fcf3ce44SJohn Forte static int svprint(dev_t, char *); 189fcf3ce44SJohn Forte 190fcf3ce44SJohn Forte /* 191fcf3ce44SJohn Forte * These next functions are layered into the underlying driver's devops. 192fcf3ce44SJohn Forte */ 193fcf3ce44SJohn Forte 194fcf3ce44SJohn Forte static int sv_lyr_open(dev_t *, int, int, cred_t *); 195fcf3ce44SJohn Forte static int sv_lyr_close(dev_t, int, int, cred_t *); 196fcf3ce44SJohn Forte static int sv_lyr_strategy(struct buf *); 197fcf3ce44SJohn Forte static int sv_lyr_read(dev_t, struct uio *, cred_t *); 198fcf3ce44SJohn Forte static int sv_lyr_write(dev_t, struct uio *, cred_t *); 199fcf3ce44SJohn Forte static int sv_lyr_aread(dev_t, struct aio_req *, cred_t *); 200fcf3ce44SJohn Forte static int sv_lyr_awrite(dev_t, struct aio_req *, cred_t *); 201fcf3ce44SJohn Forte static int sv_lyr_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 202fcf3ce44SJohn Forte 203fcf3ce44SJohn Forte static struct cb_ops sv_cb_ops = { 204fcf3ce44SJohn Forte svopen, /* open */ 205fcf3ce44SJohn Forte svclose, /* close */ 206fcf3ce44SJohn Forte nulldev, /* strategy */ 207fcf3ce44SJohn Forte svprint, 208fcf3ce44SJohn Forte nodev, /* dump */ 209fcf3ce44SJohn Forte nodev, /* read */ 210fcf3ce44SJohn Forte nodev, /* write */ 211fcf3ce44SJohn Forte svioctl, 212fcf3ce44SJohn Forte nodev, /* devmap */ 213fcf3ce44SJohn Forte nodev, /* mmap */ 214fcf3ce44SJohn Forte nodev, /* segmap */ 215fcf3ce44SJohn Forte nochpoll, /* poll */ 216fcf3ce44SJohn Forte ddi_prop_op, 217fcf3ce44SJohn Forte NULL, /* NOT a stream */ 218fcf3ce44SJohn Forte D_NEW | D_MP | D_64BIT, 219fcf3ce44SJohn Forte CB_REV, 220fcf3ce44SJohn Forte nodev, /* aread */ 221fcf3ce44SJohn Forte nodev, /* awrite */ 222fcf3ce44SJohn Forte }; 223fcf3ce44SJohn Forte 224fcf3ce44SJohn Forte 225fcf3ce44SJohn Forte /* 226fcf3ce44SJohn Forte * dev_ops functions. 227fcf3ce44SJohn Forte */ 228fcf3ce44SJohn Forte 229fcf3ce44SJohn Forte static int sv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 230fcf3ce44SJohn Forte static int sv_attach(dev_info_t *, ddi_attach_cmd_t); 231fcf3ce44SJohn Forte static int sv_detach(dev_info_t *, ddi_detach_cmd_t); 232fcf3ce44SJohn Forte 233fcf3ce44SJohn Forte static struct dev_ops sv_ops = { 234fcf3ce44SJohn Forte DEVO_REV, 235fcf3ce44SJohn Forte 0, 236fcf3ce44SJohn Forte sv_getinfo, 237fcf3ce44SJohn Forte nulldev, /* identify */ 238fcf3ce44SJohn Forte nulldev, /* probe */ 239fcf3ce44SJohn Forte sv_attach, 240fcf3ce44SJohn Forte sv_detach, 241fcf3ce44SJohn Forte nodev, /* reset */ 242fcf3ce44SJohn Forte &sv_cb_ops, 243fcf3ce44SJohn Forte (struct bus_ops *)0 244fcf3ce44SJohn Forte }; 245fcf3ce44SJohn Forte 246fcf3ce44SJohn Forte /* 247fcf3ce44SJohn Forte * Module linkage. 248fcf3ce44SJohn Forte */ 249fcf3ce44SJohn Forte 250fcf3ce44SJohn Forte extern struct mod_ops mod_driverops; 251fcf3ce44SJohn Forte 252fcf3ce44SJohn Forte static struct modldrv modldrv = { 253fcf3ce44SJohn Forte &mod_driverops, 254fcf3ce44SJohn Forte "nws:Storage Volume:" ISS_VERSION_STR, 255fcf3ce44SJohn Forte &sv_ops 256fcf3ce44SJohn Forte }; 257fcf3ce44SJohn Forte 258fcf3ce44SJohn Forte static struct modlinkage modlinkage = { 259fcf3ce44SJohn Forte MODREV_1, 260fcf3ce44SJohn Forte &modldrv, 261fcf3ce44SJohn Forte 0 262fcf3ce44SJohn Forte }; 263fcf3ce44SJohn Forte 264fcf3ce44SJohn Forte 265fcf3ce44SJohn Forte int 266fcf3ce44SJohn Forte _init(void) 267fcf3ce44SJohn Forte { 268fcf3ce44SJohn Forte int error; 269fcf3ce44SJohn Forte 270fcf3ce44SJohn Forte mutex_init(&sv_mutex, NULL, MUTEX_DRIVER, NULL); 271fcf3ce44SJohn Forte 272fcf3ce44SJohn Forte if ((error = mod_install(&modlinkage)) != 0) { 273fcf3ce44SJohn Forte mutex_destroy(&sv_mutex); 274fcf3ce44SJohn Forte return (error); 275fcf3ce44SJohn Forte } 276fcf3ce44SJohn Forte 277fcf3ce44SJohn Forte #ifdef DEBUG 2783270659fSSrikanth, Ramana cmn_err(CE_CONT, "!sv (revision %d.%d.%d.%d, %s, %s)\n", 279fcf3ce44SJohn Forte sv_major_rev, sv_minor_rev, sv_micro_rev, sv_baseline_rev, 280fcf3ce44SJohn Forte ISS_VERSION_STR, BUILD_DATE_STR); 281fcf3ce44SJohn Forte #else 282fcf3ce44SJohn Forte if (sv_micro_rev) { 2833270659fSSrikanth, Ramana cmn_err(CE_CONT, "!sv (revision %d.%d.%d, %s, %s)\n", 284fcf3ce44SJohn Forte sv_major_rev, sv_minor_rev, sv_micro_rev, 285fcf3ce44SJohn Forte ISS_VERSION_STR, BUILD_DATE_STR); 286fcf3ce44SJohn Forte } else { 2873270659fSSrikanth, Ramana cmn_err(CE_CONT, "!sv (revision %d.%d, %s, %s)\n", 288fcf3ce44SJohn Forte sv_major_rev, sv_minor_rev, 289fcf3ce44SJohn Forte ISS_VERSION_STR, BUILD_DATE_STR); 290fcf3ce44SJohn Forte } 291fcf3ce44SJohn Forte #endif 292fcf3ce44SJohn Forte 293fcf3ce44SJohn Forte return (error); 294fcf3ce44SJohn Forte } 295fcf3ce44SJohn Forte 296fcf3ce44SJohn Forte 297fcf3ce44SJohn Forte int 298fcf3ce44SJohn Forte _fini(void) 299fcf3ce44SJohn Forte { 300fcf3ce44SJohn Forte int error; 301fcf3ce44SJohn Forte 302fcf3ce44SJohn Forte if ((error = mod_remove(&modlinkage)) != 0) 303fcf3ce44SJohn Forte return (error); 304fcf3ce44SJohn Forte 305fcf3ce44SJohn Forte mutex_destroy(&sv_mutex); 306fcf3ce44SJohn Forte 307fcf3ce44SJohn Forte return (error); 308fcf3ce44SJohn Forte } 309fcf3ce44SJohn Forte 310fcf3ce44SJohn Forte 311fcf3ce44SJohn Forte int 312fcf3ce44SJohn Forte _info(struct modinfo *modinfop) 313fcf3ce44SJohn Forte { 314fcf3ce44SJohn Forte return (mod_info(&modlinkage, modinfop)); 315fcf3ce44SJohn Forte } 316fcf3ce44SJohn Forte 317fcf3ce44SJohn Forte 318fcf3ce44SJohn Forte /* 319fcf3ce44SJohn Forte * Locking & State. 320fcf3ce44SJohn Forte * 321fcf3ce44SJohn Forte * sv_mutex protects config information - sv_maj_t and sv_dev_t lists; 322fcf3ce44SJohn Forte * threadset creation and sizing; sv_ndevices. 323fcf3ce44SJohn Forte * 324fcf3ce44SJohn Forte * If we need to hold both sv_mutex and sv_lock, then the sv_mutex 325fcf3ce44SJohn Forte * must be acquired first. 326fcf3ce44SJohn Forte * 327fcf3ce44SJohn Forte * sv_lock protects the sv_dev_t structure for an individual device. 328fcf3ce44SJohn Forte * 329fcf3ce44SJohn Forte * sv_olock protects the otyp/open members of the sv_dev_t. If we need 330fcf3ce44SJohn Forte * to hold both sv_lock and sv_olock, then the sv_lock must be acquired 331fcf3ce44SJohn Forte * first. 332fcf3ce44SJohn Forte * 333fcf3ce44SJohn Forte * nsc_reserve/nsc_release are used in NSC_MULTI mode to allow multiple 334fcf3ce44SJohn Forte * I/O operations to a device simultaneously, as above. 335fcf3ce44SJohn Forte * 336fcf3ce44SJohn Forte * All nsc_open/nsc_close/nsc_reserve/nsc_release operations that occur 337fcf3ce44SJohn Forte * with sv_lock write-locked must be done with (sv_state == SV_PENDING) 338fcf3ce44SJohn Forte * and (sv_pending == curthread) so that any recursion through 339fcf3ce44SJohn Forte * sv_lyr_open/sv_lyr_close can be detected. 340fcf3ce44SJohn Forte */ 341fcf3ce44SJohn Forte 342fcf3ce44SJohn Forte 343fcf3ce44SJohn Forte static int 344fcf3ce44SJohn Forte sv_init_devs(void) 345fcf3ce44SJohn Forte { 346fcf3ce44SJohn Forte int i; 347fcf3ce44SJohn Forte 348fcf3ce44SJohn Forte ASSERT(MUTEX_HELD(&sv_mutex)); 349fcf3ce44SJohn Forte 350fcf3ce44SJohn Forte if (sv_max_devices > 0) 351fcf3ce44SJohn Forte return (0); 352fcf3ce44SJohn Forte 353fcf3ce44SJohn Forte sv_max_devices = nsc_max_devices(); 354fcf3ce44SJohn Forte 355fcf3ce44SJohn Forte if (sv_max_devices <= 0) { 356fcf3ce44SJohn Forte /* nsctl is not attached (nskernd not running) */ 357fcf3ce44SJohn Forte if (sv_debug > 0) 3583270659fSSrikanth, Ramana cmn_err(CE_CONT, "!sv: nsc_max_devices = 0\n"); 359fcf3ce44SJohn Forte return (EAGAIN); 360fcf3ce44SJohn Forte } 361fcf3ce44SJohn Forte 362fcf3ce44SJohn Forte sv_devs = nsc_kmem_zalloc((sv_max_devices * sizeof (*sv_devs)), 363fcf3ce44SJohn Forte KM_NOSLEEP, sv_mem); 364fcf3ce44SJohn Forte 365fcf3ce44SJohn Forte if (sv_devs == NULL) { 3663270659fSSrikanth, Ramana cmn_err(CE_WARN, "!sv: could not allocate sv_devs array"); 367fcf3ce44SJohn Forte return (ENOMEM); 368fcf3ce44SJohn Forte } 369fcf3ce44SJohn Forte 370fcf3ce44SJohn Forte for (i = 0; i < sv_max_devices; i++) { 371fcf3ce44SJohn Forte mutex_init(&sv_devs[i].sv_olock, NULL, MUTEX_DRIVER, NULL); 372fcf3ce44SJohn Forte rw_init(&sv_devs[i].sv_lock, NULL, RW_DRIVER, NULL); 373fcf3ce44SJohn Forte } 374fcf3ce44SJohn Forte 375fcf3ce44SJohn Forte if (sv_debug > 0) 3763270659fSSrikanth, Ramana cmn_err(CE_CONT, "!sv: sv_init_devs successful\n"); 377fcf3ce44SJohn Forte 378fcf3ce44SJohn Forte return (0); 379fcf3ce44SJohn Forte } 380fcf3ce44SJohn Forte 381fcf3ce44SJohn Forte 382fcf3ce44SJohn Forte static int 383fcf3ce44SJohn Forte sv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 384fcf3ce44SJohn Forte { 385fcf3ce44SJohn Forte int rc; 386fcf3ce44SJohn Forte 387fcf3ce44SJohn Forte switch (cmd) { 388fcf3ce44SJohn Forte 389fcf3ce44SJohn Forte case DDI_ATTACH: 390fcf3ce44SJohn Forte sv_dip = dip; 391fcf3ce44SJohn Forte 392fcf3ce44SJohn Forte if (ddi_create_minor_node(dip, "sv", S_IFCHR, 393fcf3ce44SJohn Forte 0, DDI_PSEUDO, 0) != DDI_SUCCESS) 394fcf3ce44SJohn Forte goto failed; 395fcf3ce44SJohn Forte 396fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 397fcf3ce44SJohn Forte 398fcf3ce44SJohn Forte sv_mem = nsc_register_mem("SV", NSC_MEM_LOCAL, 0); 399fcf3ce44SJohn Forte if (sv_mem == NULL) { 400fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 401fcf3ce44SJohn Forte goto failed; 402fcf3ce44SJohn Forte } 403fcf3ce44SJohn Forte 404fcf3ce44SJohn Forte rc = sv_init_devs(); 405fcf3ce44SJohn Forte if (rc != 0 && rc != EAGAIN) { 406fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 407fcf3ce44SJohn Forte goto failed; 408fcf3ce44SJohn Forte } 409fcf3ce44SJohn Forte 410fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 411fcf3ce44SJohn Forte 412fcf3ce44SJohn Forte 413fcf3ce44SJohn Forte ddi_report_dev(dip); 414fcf3ce44SJohn Forte 415fcf3ce44SJohn Forte sv_threads = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 416fcf3ce44SJohn Forte DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 417fcf3ce44SJohn Forte "sv_threads", sv_threads); 418fcf3ce44SJohn Forte 419fcf3ce44SJohn Forte if (sv_debug > 0) 4203270659fSSrikanth, Ramana cmn_err(CE_CONT, "!sv: sv_threads=%d\n", sv_threads); 421fcf3ce44SJohn Forte 422fcf3ce44SJohn Forte if (sv_threads > sv_threads_max) 423fcf3ce44SJohn Forte sv_threads_max = sv_threads; 424fcf3ce44SJohn Forte 425fcf3ce44SJohn Forte return (DDI_SUCCESS); 426fcf3ce44SJohn Forte 427fcf3ce44SJohn Forte default: 428fcf3ce44SJohn Forte return (DDI_FAILURE); 429fcf3ce44SJohn Forte } 430fcf3ce44SJohn Forte 431fcf3ce44SJohn Forte failed: 432fcf3ce44SJohn Forte DTRACE_PROBE(sv_attach_failed); 433fcf3ce44SJohn Forte (void) sv_detach(dip, DDI_DETACH); 434fcf3ce44SJohn Forte return (DDI_FAILURE); 435fcf3ce44SJohn Forte } 436fcf3ce44SJohn Forte 437fcf3ce44SJohn Forte 438fcf3ce44SJohn Forte static int 439fcf3ce44SJohn Forte sv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 440fcf3ce44SJohn Forte { 441fcf3ce44SJohn Forte sv_dev_t *svp; 442fcf3ce44SJohn Forte int i; 443fcf3ce44SJohn Forte 444fcf3ce44SJohn Forte switch (cmd) { 445fcf3ce44SJohn Forte 446fcf3ce44SJohn Forte case DDI_DETACH: 447fcf3ce44SJohn Forte 448fcf3ce44SJohn Forte /* 449fcf3ce44SJohn Forte * Check that everything is disabled. 450fcf3ce44SJohn Forte */ 451fcf3ce44SJohn Forte 452fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 453fcf3ce44SJohn Forte 454fcf3ce44SJohn Forte if (sv_mod_status == SV_PREVENT_UNLOAD) { 455fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 456fcf3ce44SJohn Forte DTRACE_PROBE(sv_detach_err_prevent); 457fcf3ce44SJohn Forte return (DDI_FAILURE); 458fcf3ce44SJohn Forte } 459fcf3ce44SJohn Forte 460fcf3ce44SJohn Forte for (i = 0; sv_devs && i < sv_max_devices; i++) { 461fcf3ce44SJohn Forte svp = &sv_devs[i]; 462fcf3ce44SJohn Forte 463fcf3ce44SJohn Forte if (svp->sv_state != SV_DISABLE) { 464fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 465fcf3ce44SJohn Forte DTRACE_PROBE(sv_detach_err_busy); 466fcf3ce44SJohn Forte return (DDI_FAILURE); 467fcf3ce44SJohn Forte } 468fcf3ce44SJohn Forte } 469fcf3ce44SJohn Forte 470fcf3ce44SJohn Forte 471fcf3ce44SJohn Forte for (i = 0; sv_devs && i < sv_max_devices; i++) { 472fcf3ce44SJohn Forte mutex_destroy(&sv_devs[i].sv_olock); 473fcf3ce44SJohn Forte rw_destroy(&sv_devs[i].sv_lock); 474fcf3ce44SJohn Forte } 475fcf3ce44SJohn Forte 476fcf3ce44SJohn Forte if (sv_devs) { 477fcf3ce44SJohn Forte nsc_kmem_free(sv_devs, 478fcf3ce44SJohn Forte (sv_max_devices * sizeof (*sv_devs))); 479fcf3ce44SJohn Forte sv_devs = NULL; 480fcf3ce44SJohn Forte } 481fcf3ce44SJohn Forte sv_max_devices = 0; 482fcf3ce44SJohn Forte 483fcf3ce44SJohn Forte if (sv_mem) { 484fcf3ce44SJohn Forte nsc_unregister_mem(sv_mem); 485fcf3ce44SJohn Forte sv_mem = NULL; 486fcf3ce44SJohn Forte } 487fcf3ce44SJohn Forte 488fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 489fcf3ce44SJohn Forte 490fcf3ce44SJohn Forte /* 491fcf3ce44SJohn Forte * Remove all minor nodes. 492fcf3ce44SJohn Forte */ 493fcf3ce44SJohn Forte 494fcf3ce44SJohn Forte ddi_remove_minor_node(dip, NULL); 495fcf3ce44SJohn Forte sv_dip = NULL; 496fcf3ce44SJohn Forte 497fcf3ce44SJohn Forte return (DDI_SUCCESS); 498fcf3ce44SJohn Forte 499fcf3ce44SJohn Forte default: 500fcf3ce44SJohn Forte return (DDI_FAILURE); 501fcf3ce44SJohn Forte } 502fcf3ce44SJohn Forte } 503fcf3ce44SJohn Forte 504fcf3ce44SJohn Forte static sv_maj_t * 505fcf3ce44SJohn Forte sv_getmajor(const dev_t dev) 506fcf3ce44SJohn Forte { 507fcf3ce44SJohn Forte sv_maj_t **insert, *maj; 508fcf3ce44SJohn Forte major_t umaj = getmajor(dev); 509fcf3ce44SJohn Forte 510fcf3ce44SJohn Forte /* 511fcf3ce44SJohn Forte * See if the hash table entry, or one of the hash chains 512fcf3ce44SJohn Forte * is already allocated for this major number 513fcf3ce44SJohn Forte */ 514fcf3ce44SJohn Forte if ((maj = sv_majors[SV_MAJOR_HASH(umaj)]) != 0) { 515fcf3ce44SJohn Forte do { 516fcf3ce44SJohn Forte if (maj->sm_major == umaj) 517fcf3ce44SJohn Forte return (maj); 518fcf3ce44SJohn Forte } while ((maj = maj->sm_next) != 0); 519fcf3ce44SJohn Forte } 520fcf3ce44SJohn Forte 521fcf3ce44SJohn Forte /* 522fcf3ce44SJohn Forte * If the sv_mutex is held, there is design flaw, as the only non-mutex 523fcf3ce44SJohn Forte * held callers can be sv_enable() or sv_dev_to_sv() 524fcf3ce44SJohn Forte * Return an error, instead of panicing the system 525fcf3ce44SJohn Forte */ 526fcf3ce44SJohn Forte if (MUTEX_HELD(&sv_mutex)) { 5273270659fSSrikanth, Ramana cmn_err(CE_WARN, "!sv: could not allocate sv_maj_t"); 528fcf3ce44SJohn Forte return (NULL); 529fcf3ce44SJohn Forte } 530fcf3ce44SJohn Forte 531fcf3ce44SJohn Forte /* 532fcf3ce44SJohn Forte * Determine where to allocate a new element in the hash table 533fcf3ce44SJohn Forte */ 534fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 535fcf3ce44SJohn Forte insert = &(sv_majors[SV_MAJOR_HASH(umaj)]); 536fcf3ce44SJohn Forte for (maj = *insert; maj; maj = maj->sm_next) { 537fcf3ce44SJohn Forte 538fcf3ce44SJohn Forte /* Did another thread beat us to it? */ 539fcf3ce44SJohn Forte if (maj->sm_major == umaj) 540fcf3ce44SJohn Forte return (maj); 541fcf3ce44SJohn Forte 542fcf3ce44SJohn Forte /* Find a NULL insert point? */ 543fcf3ce44SJohn Forte if (maj->sm_next == NULL) 544fcf3ce44SJohn Forte insert = &maj->sm_next; 545fcf3ce44SJohn Forte } 546fcf3ce44SJohn Forte 547fcf3ce44SJohn Forte /* 548fcf3ce44SJohn Forte * Located the new insert point 549fcf3ce44SJohn Forte */ 550fcf3ce44SJohn Forte *insert = nsc_kmem_zalloc(sizeof (*maj), KM_NOSLEEP, sv_mem); 551fcf3ce44SJohn Forte if ((maj = *insert) != 0) 552fcf3ce44SJohn Forte maj->sm_major = umaj; 553fcf3ce44SJohn Forte else 5543270659fSSrikanth, Ramana cmn_err(CE_WARN, "!sv: could not allocate sv_maj_t"); 555fcf3ce44SJohn Forte 556fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 557fcf3ce44SJohn Forte 558fcf3ce44SJohn Forte return (maj); 559fcf3ce44SJohn Forte } 560fcf3ce44SJohn Forte 561fcf3ce44SJohn Forte /* ARGSUSED */ 562fcf3ce44SJohn Forte 563fcf3ce44SJohn Forte static int 564fcf3ce44SJohn Forte sv_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 565fcf3ce44SJohn Forte { 566fcf3ce44SJohn Forte int rc = DDI_FAILURE; 567fcf3ce44SJohn Forte 568fcf3ce44SJohn Forte switch (infocmd) { 569fcf3ce44SJohn Forte 570fcf3ce44SJohn Forte case DDI_INFO_DEVT2DEVINFO: 571fcf3ce44SJohn Forte *result = sv_dip; 572fcf3ce44SJohn Forte rc = DDI_SUCCESS; 573fcf3ce44SJohn Forte break; 574fcf3ce44SJohn Forte 575fcf3ce44SJohn Forte case DDI_INFO_DEVT2INSTANCE: 576fcf3ce44SJohn Forte /* 577fcf3ce44SJohn Forte * We only have a single instance. 578fcf3ce44SJohn Forte */ 579fcf3ce44SJohn Forte *result = 0; 580fcf3ce44SJohn Forte rc = DDI_SUCCESS; 581fcf3ce44SJohn Forte break; 582fcf3ce44SJohn Forte 583fcf3ce44SJohn Forte default: 584fcf3ce44SJohn Forte break; 585fcf3ce44SJohn Forte } 586fcf3ce44SJohn Forte 587fcf3ce44SJohn Forte return (rc); 588fcf3ce44SJohn Forte } 589fcf3ce44SJohn Forte 590fcf3ce44SJohn Forte 591fcf3ce44SJohn Forte /* 592fcf3ce44SJohn Forte * Hashing of devices onto major device structures. 593fcf3ce44SJohn Forte * 594fcf3ce44SJohn Forte * Individual device structures are hashed onto one of the sm_hash[] 595fcf3ce44SJohn Forte * buckets in the relevant major device structure. 596fcf3ce44SJohn Forte * 597fcf3ce44SJohn Forte * Hash insertion and deletion -must- be done with sv_mutex held. Hash 598fcf3ce44SJohn Forte * searching does not require the mutex because of the sm_seq member. 599fcf3ce44SJohn Forte * sm_seq is incremented on each insertion (-after- hash chain pointer 600fcf3ce44SJohn Forte * manipulation) and each deletion (-before- hash chain pointer 601fcf3ce44SJohn Forte * manipulation). When searching the hash chain, the seq number is 602fcf3ce44SJohn Forte * checked before accessing each device structure, if the seq number has 603fcf3ce44SJohn Forte * changed, then we restart the search from the top of the hash chain. 604fcf3ce44SJohn Forte * If we restart more than SV_HASH_RETRY times, we take sv_mutex and search 605fcf3ce44SJohn Forte * the hash chain (we are guaranteed that this search cannot be 606fcf3ce44SJohn Forte * interrupted). 607fcf3ce44SJohn Forte */ 608fcf3ce44SJohn Forte 609fcf3ce44SJohn Forte #define SV_HASH_RETRY 16 610fcf3ce44SJohn Forte 611fcf3ce44SJohn Forte static sv_dev_t * 612fcf3ce44SJohn Forte sv_dev_to_sv(const dev_t dev, sv_maj_t **majpp) 613fcf3ce44SJohn Forte { 614fcf3ce44SJohn Forte minor_t umin = getminor(dev); 615fcf3ce44SJohn Forte sv_dev_t **hb, *next, *svp; 616fcf3ce44SJohn Forte sv_maj_t *maj; 617fcf3ce44SJohn Forte int seq; 618fcf3ce44SJohn Forte int try; 619fcf3ce44SJohn Forte 620fcf3ce44SJohn Forte /* Get major hash table */ 621fcf3ce44SJohn Forte maj = sv_getmajor(dev); 622fcf3ce44SJohn Forte if (majpp) 623fcf3ce44SJohn Forte *majpp = maj; 624fcf3ce44SJohn Forte if (maj == NULL) 625fcf3ce44SJohn Forte return (NULL); 626fcf3ce44SJohn Forte 627fcf3ce44SJohn Forte if (maj->sm_inuse == 0) { 628fcf3ce44SJohn Forte DTRACE_PROBE1( 629fcf3ce44SJohn Forte sv_dev_to_sv_end, 630fcf3ce44SJohn Forte dev_t, dev); 631fcf3ce44SJohn Forte return (NULL); 632fcf3ce44SJohn Forte } 633fcf3ce44SJohn Forte 634fcf3ce44SJohn Forte hb = &(maj->sm_hash[SV_MINOR_HASH(umin)]); 635fcf3ce44SJohn Forte try = 0; 636fcf3ce44SJohn Forte 637fcf3ce44SJohn Forte retry: 638fcf3ce44SJohn Forte if (try > SV_HASH_RETRY) 639fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 640fcf3ce44SJohn Forte 641fcf3ce44SJohn Forte seq = maj->sm_seq; 642fcf3ce44SJohn Forte for (svp = *hb; svp; svp = next) { 643fcf3ce44SJohn Forte next = svp->sv_hash; 644fcf3ce44SJohn Forte 645fcf3ce44SJohn Forte nsc_membar_stld(); /* preserve register load order */ 646fcf3ce44SJohn Forte 647fcf3ce44SJohn Forte if (maj->sm_seq != seq) { 6483270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dev_to_sv_retry, dev_t, dev); 649fcf3ce44SJohn Forte try++; 650fcf3ce44SJohn Forte goto retry; 651fcf3ce44SJohn Forte } 652fcf3ce44SJohn Forte 653fcf3ce44SJohn Forte if (svp->sv_dev == dev) 654fcf3ce44SJohn Forte break; 655fcf3ce44SJohn Forte } 656fcf3ce44SJohn Forte 657fcf3ce44SJohn Forte if (try > SV_HASH_RETRY) 658fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 659fcf3ce44SJohn Forte 660fcf3ce44SJohn Forte return (svp); 661fcf3ce44SJohn Forte } 662fcf3ce44SJohn Forte 663fcf3ce44SJohn Forte 664fcf3ce44SJohn Forte /* 665fcf3ce44SJohn Forte * Must be called with sv_mutex held. 666fcf3ce44SJohn Forte */ 667fcf3ce44SJohn Forte 668fcf3ce44SJohn Forte static int 669fcf3ce44SJohn Forte sv_get_state(const dev_t udev, sv_dev_t **svpp) 670fcf3ce44SJohn Forte { 671fcf3ce44SJohn Forte sv_dev_t **hb, **insert, *svp; 672fcf3ce44SJohn Forte sv_maj_t *maj; 673fcf3ce44SJohn Forte minor_t umin; 674fcf3ce44SJohn Forte int i; 675fcf3ce44SJohn Forte 676fcf3ce44SJohn Forte /* Get major hash table */ 677fcf3ce44SJohn Forte if ((maj = sv_getmajor(udev)) == NULL) 678fcf3ce44SJohn Forte return (NULL); 679fcf3ce44SJohn Forte 680fcf3ce44SJohn Forte /* Determine which minor hash table */ 681fcf3ce44SJohn Forte umin = getminor(udev); 682fcf3ce44SJohn Forte hb = &(maj->sm_hash[SV_MINOR_HASH(umin)]); 683fcf3ce44SJohn Forte 684fcf3ce44SJohn Forte /* look for clash */ 685fcf3ce44SJohn Forte 686fcf3ce44SJohn Forte insert = hb; 687fcf3ce44SJohn Forte 688fcf3ce44SJohn Forte for (svp = *hb; svp; svp = svp->sv_hash) { 689fcf3ce44SJohn Forte if (svp->sv_dev == udev) 690fcf3ce44SJohn Forte break; 691fcf3ce44SJohn Forte 692fcf3ce44SJohn Forte if (svp->sv_hash == NULL) 693fcf3ce44SJohn Forte insert = &svp->sv_hash; 694fcf3ce44SJohn Forte } 695fcf3ce44SJohn Forte 696fcf3ce44SJohn Forte if (svp) { 697fcf3ce44SJohn Forte DTRACE_PROBE1( 698fcf3ce44SJohn Forte sv_get_state_enabled, 699fcf3ce44SJohn Forte dev_t, udev); 700fcf3ce44SJohn Forte return (SV_EENABLED); 701fcf3ce44SJohn Forte } 702fcf3ce44SJohn Forte 703fcf3ce44SJohn Forte /* look for spare sv_devs slot */ 704fcf3ce44SJohn Forte 705fcf3ce44SJohn Forte for (i = 0; i < sv_max_devices; i++) { 706fcf3ce44SJohn Forte svp = &sv_devs[i]; 707fcf3ce44SJohn Forte 708fcf3ce44SJohn Forte if (svp->sv_state == SV_DISABLE) 709fcf3ce44SJohn Forte break; 710fcf3ce44SJohn Forte } 711fcf3ce44SJohn Forte 712fcf3ce44SJohn Forte if (i >= sv_max_devices) { 713fcf3ce44SJohn Forte DTRACE_PROBE1( 714fcf3ce44SJohn Forte sv_get_state_noslots, 715fcf3ce44SJohn Forte dev_t, udev); 716fcf3ce44SJohn Forte return (SV_ENOSLOTS); 717fcf3ce44SJohn Forte } 718fcf3ce44SJohn Forte 719fcf3ce44SJohn Forte svp->sv_state = SV_PENDING; 720fcf3ce44SJohn Forte svp->sv_pending = curthread; 721fcf3ce44SJohn Forte 722fcf3ce44SJohn Forte *insert = svp; 723fcf3ce44SJohn Forte svp->sv_hash = NULL; 724fcf3ce44SJohn Forte maj->sm_seq++; /* must be after the store to the hash chain */ 725fcf3ce44SJohn Forte 726fcf3ce44SJohn Forte *svpp = svp; 727fcf3ce44SJohn Forte 728fcf3ce44SJohn Forte /* 729fcf3ce44SJohn Forte * We do not know the size of the underlying device at 730fcf3ce44SJohn Forte * this stage, so initialise "nblocks" property to 731fcf3ce44SJohn Forte * zero, and update it whenever we succeed in 732fcf3ce44SJohn Forte * nsc_reserve'ing the underlying nsc_fd_t. 733fcf3ce44SJohn Forte */ 734fcf3ce44SJohn Forte 735fcf3ce44SJohn Forte svp->sv_nblocks = 0; 736fcf3ce44SJohn Forte 737fcf3ce44SJohn Forte return (0); 738fcf3ce44SJohn Forte } 739fcf3ce44SJohn Forte 740fcf3ce44SJohn Forte 741fcf3ce44SJohn Forte /* 742fcf3ce44SJohn Forte * Remove a device structure from it's hash chain. 743fcf3ce44SJohn Forte * Must be called with sv_mutex held. 744fcf3ce44SJohn Forte */ 745fcf3ce44SJohn Forte 746fcf3ce44SJohn Forte static void 747fcf3ce44SJohn Forte sv_rm_hash(sv_dev_t *svp) 748fcf3ce44SJohn Forte { 749fcf3ce44SJohn Forte sv_dev_t **svpp; 750fcf3ce44SJohn Forte sv_maj_t *maj; 751fcf3ce44SJohn Forte 752fcf3ce44SJohn Forte /* Get major hash table */ 753fcf3ce44SJohn Forte if ((maj = sv_getmajor(svp->sv_dev)) == NULL) 754fcf3ce44SJohn Forte return; 755fcf3ce44SJohn Forte 756fcf3ce44SJohn Forte /* remove svp from hash chain */ 757fcf3ce44SJohn Forte 758fcf3ce44SJohn Forte svpp = &(maj->sm_hash[SV_MINOR_HASH(getminor(svp->sv_dev))]); 759fcf3ce44SJohn Forte while (*svpp) { 760fcf3ce44SJohn Forte if (*svpp == svp) { 761fcf3ce44SJohn Forte /* 762fcf3ce44SJohn Forte * increment of sm_seq must be before the 763fcf3ce44SJohn Forte * removal from the hash chain 764fcf3ce44SJohn Forte */ 765fcf3ce44SJohn Forte maj->sm_seq++; 766fcf3ce44SJohn Forte *svpp = svp->sv_hash; 767fcf3ce44SJohn Forte break; 768fcf3ce44SJohn Forte } 769fcf3ce44SJohn Forte 770fcf3ce44SJohn Forte svpp = &(*svpp)->sv_hash; 771fcf3ce44SJohn Forte } 772fcf3ce44SJohn Forte 773fcf3ce44SJohn Forte svp->sv_hash = NULL; 774fcf3ce44SJohn Forte } 775fcf3ce44SJohn Forte 776fcf3ce44SJohn Forte /* 777fcf3ce44SJohn Forte * Free (disable) a device structure. 778fcf3ce44SJohn Forte * Must be called with sv_lock(RW_WRITER) and sv_mutex held, and will 779fcf3ce44SJohn Forte * perform the exits during its processing. 780fcf3ce44SJohn Forte */ 781fcf3ce44SJohn Forte 782fcf3ce44SJohn Forte static int 783fcf3ce44SJohn Forte sv_free(sv_dev_t *svp, const int error) 784fcf3ce44SJohn Forte { 785fcf3ce44SJohn Forte struct cb_ops *cb_ops; 786fcf3ce44SJohn Forte sv_maj_t *maj; 787fcf3ce44SJohn Forte 788fcf3ce44SJohn Forte /* Get major hash table */ 789fcf3ce44SJohn Forte if ((maj = sv_getmajor(svp->sv_dev)) == NULL) 790fcf3ce44SJohn Forte return (NULL); 791fcf3ce44SJohn Forte 792fcf3ce44SJohn Forte svp->sv_state = SV_PENDING; 793fcf3ce44SJohn Forte svp->sv_pending = curthread; 794fcf3ce44SJohn Forte 795fcf3ce44SJohn Forte /* 796fcf3ce44SJohn Forte * Close the fd's before removing from the hash or swapping 797fcf3ce44SJohn Forte * back the cb_ops pointers so that the cache flushes before new 798fcf3ce44SJohn Forte * io can come in. 799fcf3ce44SJohn Forte */ 800fcf3ce44SJohn Forte 801fcf3ce44SJohn Forte if (svp->sv_fd) { 802fcf3ce44SJohn Forte (void) nsc_close(svp->sv_fd); 803fcf3ce44SJohn Forte svp->sv_fd = 0; 804fcf3ce44SJohn Forte } 805fcf3ce44SJohn Forte 806fcf3ce44SJohn Forte sv_rm_hash(svp); 807fcf3ce44SJohn Forte 808fcf3ce44SJohn Forte if (error != SV_ESDOPEN && 809fcf3ce44SJohn Forte error != SV_ELYROPEN && --maj->sm_inuse == 0) { 810fcf3ce44SJohn Forte 811fcf3ce44SJohn Forte if (maj->sm_dev_ops) 812fcf3ce44SJohn Forte cb_ops = maj->sm_dev_ops->devo_cb_ops; 813fcf3ce44SJohn Forte else 814fcf3ce44SJohn Forte cb_ops = NULL; 815fcf3ce44SJohn Forte 816fcf3ce44SJohn Forte if (cb_ops && maj->sm_strategy != NULL) { 817fcf3ce44SJohn Forte cb_ops->cb_strategy = maj->sm_strategy; 818fcf3ce44SJohn Forte cb_ops->cb_close = maj->sm_close; 819fcf3ce44SJohn Forte cb_ops->cb_ioctl = maj->sm_ioctl; 820fcf3ce44SJohn Forte cb_ops->cb_write = maj->sm_write; 821fcf3ce44SJohn Forte cb_ops->cb_open = maj->sm_open; 822fcf3ce44SJohn Forte cb_ops->cb_read = maj->sm_read; 823fcf3ce44SJohn Forte cb_ops->cb_flag = maj->sm_flag; 824fcf3ce44SJohn Forte 825fcf3ce44SJohn Forte if (maj->sm_awrite) 826fcf3ce44SJohn Forte cb_ops->cb_awrite = maj->sm_awrite; 827fcf3ce44SJohn Forte 828fcf3ce44SJohn Forte if (maj->sm_aread) 829fcf3ce44SJohn Forte cb_ops->cb_aread = maj->sm_aread; 830fcf3ce44SJohn Forte 831fcf3ce44SJohn Forte /* 832fcf3ce44SJohn Forte * corbin XXX 833fcf3ce44SJohn Forte * Leave backing device ops in maj->sm_* 834fcf3ce44SJohn Forte * to handle any requests that might come 835fcf3ce44SJohn Forte * in during the disable. This could be 836fcf3ce44SJohn Forte * a problem however if the backing device 837fcf3ce44SJohn Forte * driver is changed while we process these 838fcf3ce44SJohn Forte * requests. 839fcf3ce44SJohn Forte * 840fcf3ce44SJohn Forte * maj->sm_strategy = 0; 841fcf3ce44SJohn Forte * maj->sm_awrite = 0; 842fcf3ce44SJohn Forte * maj->sm_write = 0; 843fcf3ce44SJohn Forte * maj->sm_ioctl = 0; 844fcf3ce44SJohn Forte * maj->sm_close = 0; 845fcf3ce44SJohn Forte * maj->sm_aread = 0; 846fcf3ce44SJohn Forte * maj->sm_read = 0; 847fcf3ce44SJohn Forte * maj->sm_open = 0; 848fcf3ce44SJohn Forte * maj->sm_flag = 0; 849fcf3ce44SJohn Forte * 850fcf3ce44SJohn Forte */ 851fcf3ce44SJohn Forte } 852fcf3ce44SJohn Forte 853fcf3ce44SJohn Forte if (maj->sm_dev_ops) { 854fcf3ce44SJohn Forte maj->sm_dev_ops = 0; 855fcf3ce44SJohn Forte } 856fcf3ce44SJohn Forte } 857fcf3ce44SJohn Forte 858fcf3ce44SJohn Forte if (svp->sv_lh) { 859fcf3ce44SJohn Forte cred_t *crp = ddi_get_cred(); 860fcf3ce44SJohn Forte 861fcf3ce44SJohn Forte /* 862fcf3ce44SJohn Forte * Close the protective layered driver open using the 863fcf3ce44SJohn Forte * Sun Private layered driver i/f. 864fcf3ce44SJohn Forte */ 865fcf3ce44SJohn Forte 866fcf3ce44SJohn Forte (void) ldi_close(svp->sv_lh, FREAD|FWRITE, crp); 867fcf3ce44SJohn Forte svp->sv_lh = NULL; 868fcf3ce44SJohn Forte } 869fcf3ce44SJohn Forte 870fcf3ce44SJohn Forte svp->sv_timestamp = nsc_lbolt(); 871fcf3ce44SJohn Forte svp->sv_state = SV_DISABLE; 872fcf3ce44SJohn Forte svp->sv_pending = NULL; 873fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 874fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 875fcf3ce44SJohn Forte 876fcf3ce44SJohn Forte return (error); 877fcf3ce44SJohn Forte } 878fcf3ce44SJohn Forte 879fcf3ce44SJohn Forte /* 880fcf3ce44SJohn Forte * Reserve the device, taking into account the possibility that 881fcf3ce44SJohn Forte * the reserve might have to be retried. 882fcf3ce44SJohn Forte */ 883fcf3ce44SJohn Forte static int 884fcf3ce44SJohn Forte sv_reserve(nsc_fd_t *fd, int flags) 885fcf3ce44SJohn Forte { 886fcf3ce44SJohn Forte int eintr_count; 887fcf3ce44SJohn Forte int rc; 888fcf3ce44SJohn Forte 889fcf3ce44SJohn Forte eintr_count = 0; 890fcf3ce44SJohn Forte do { 891fcf3ce44SJohn Forte rc = nsc_reserve(fd, flags); 892fcf3ce44SJohn Forte if (rc == EINTR) { 893fcf3ce44SJohn Forte ++eintr_count; 894fcf3ce44SJohn Forte delay(2); 895fcf3ce44SJohn Forte } 896fcf3ce44SJohn Forte } while ((rc == EINTR) && (eintr_count < MAX_EINTR_COUNT)); 897fcf3ce44SJohn Forte 898fcf3ce44SJohn Forte return (rc); 899fcf3ce44SJohn Forte } 900fcf3ce44SJohn Forte 901fcf3ce44SJohn Forte static int 902fcf3ce44SJohn Forte sv_enable(const caddr_t path, const int flag, 903fcf3ce44SJohn Forte const dev_t udev, spcs_s_info_t kstatus) 904fcf3ce44SJohn Forte { 905fcf3ce44SJohn Forte struct dev_ops *dev_ops; 906fcf3ce44SJohn Forte struct cb_ops *cb_ops; 907fcf3ce44SJohn Forte sv_dev_t *svp; 908fcf3ce44SJohn Forte sv_maj_t *maj; 909fcf3ce44SJohn Forte nsc_size_t nblocks; 910fcf3ce44SJohn Forte int rc; 911fcf3ce44SJohn Forte cred_t *crp; 912fcf3ce44SJohn Forte ldi_ident_t li; 913fcf3ce44SJohn Forte 914fcf3ce44SJohn Forte if (udev == (dev_t)-1 || udev == 0) { 915fcf3ce44SJohn Forte DTRACE_PROBE1( 916fcf3ce44SJohn Forte sv_enable_err_baddev, 917fcf3ce44SJohn Forte dev_t, udev); 918fcf3ce44SJohn Forte return (SV_EBADDEV); 919fcf3ce44SJohn Forte } 920fcf3ce44SJohn Forte 921fcf3ce44SJohn Forte if ((flag & ~(NSC_CACHE|NSC_DEVICE)) != 0) { 922fcf3ce44SJohn Forte DTRACE_PROBE1(sv_enable_err_amode, dev_t, udev); 923fcf3ce44SJohn Forte return (SV_EAMODE); 924fcf3ce44SJohn Forte } 925fcf3ce44SJohn Forte 926fcf3ce44SJohn Forte /* Get major hash table */ 927fcf3ce44SJohn Forte if ((maj = sv_getmajor(udev)) == NULL) 928fcf3ce44SJohn Forte return (SV_EBADDEV); 929fcf3ce44SJohn Forte 930fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 931fcf3ce44SJohn Forte 932fcf3ce44SJohn Forte rc = sv_get_state(udev, &svp); 933fcf3ce44SJohn Forte if (rc) { 934fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 9353270659fSSrikanth, Ramana DTRACE_PROBE1(sv_enable_err_state, dev_t, udev); 936fcf3ce44SJohn Forte return (rc); 937fcf3ce44SJohn Forte } 938fcf3ce44SJohn Forte 939fcf3ce44SJohn Forte rw_enter(&svp->sv_lock, RW_WRITER); 940fcf3ce44SJohn Forte 941fcf3ce44SJohn Forte /* 942fcf3ce44SJohn Forte * Get real fd used for io 943fcf3ce44SJohn Forte */ 944fcf3ce44SJohn Forte 945fcf3ce44SJohn Forte svp->sv_dev = udev; 946fcf3ce44SJohn Forte svp->sv_flag = flag; 947fcf3ce44SJohn Forte 948fcf3ce44SJohn Forte /* 949fcf3ce44SJohn Forte * OR in NSC_DEVICE to ensure that nskern grabs the real strategy 950fcf3ce44SJohn Forte * function pointer before sv swaps them out. 951fcf3ce44SJohn Forte */ 952fcf3ce44SJohn Forte 953fcf3ce44SJohn Forte svp->sv_fd = nsc_open(path, (svp->sv_flag | NSC_DEVICE), 954fcf3ce44SJohn Forte sv_fd_def, (blind_t)udev, &rc); 955fcf3ce44SJohn Forte 956fcf3ce44SJohn Forte if (svp->sv_fd == NULL) { 957fcf3ce44SJohn Forte if (kstatus) 958fcf3ce44SJohn Forte spcs_s_add(kstatus, rc); 9593270659fSSrikanth, Ramana DTRACE_PROBE1(sv_enable_err_fd, dev_t, udev); 960fcf3ce44SJohn Forte return (sv_free(svp, SV_ESDOPEN)); 961fcf3ce44SJohn Forte } 962fcf3ce44SJohn Forte 963fcf3ce44SJohn Forte /* 964fcf3ce44SJohn Forte * Perform a layered driver open using the Sun Private layered 965fcf3ce44SJohn Forte * driver i/f to ensure that the cb_ops structure for the driver 966fcf3ce44SJohn Forte * is not detached out from under us whilst sv is enabled. 967fcf3ce44SJohn Forte * 968fcf3ce44SJohn Forte */ 969fcf3ce44SJohn Forte 970fcf3ce44SJohn Forte crp = ddi_get_cred(); 971fcf3ce44SJohn Forte svp->sv_lh = NULL; 972fcf3ce44SJohn Forte 973fcf3ce44SJohn Forte if ((rc = ldi_ident_from_dev(svp->sv_dev, &li)) == 0) { 974fcf3ce44SJohn Forte rc = ldi_open_by_dev(&svp->sv_dev, 975fcf3ce44SJohn Forte OTYP_BLK, FREAD|FWRITE, crp, &svp->sv_lh, li); 976fcf3ce44SJohn Forte } 977fcf3ce44SJohn Forte 978fcf3ce44SJohn Forte if (rc != 0) { 979fcf3ce44SJohn Forte if (kstatus) 980fcf3ce44SJohn Forte spcs_s_add(kstatus, rc); 9813270659fSSrikanth, Ramana DTRACE_PROBE1(sv_enable_err_lyr_open, dev_t, udev); 982fcf3ce44SJohn Forte return (sv_free(svp, SV_ELYROPEN)); 983fcf3ce44SJohn Forte } 984fcf3ce44SJohn Forte 985fcf3ce44SJohn Forte /* 986fcf3ce44SJohn Forte * Do layering if required - must happen after nsc_open(). 987fcf3ce44SJohn Forte */ 988fcf3ce44SJohn Forte 989fcf3ce44SJohn Forte if (maj->sm_inuse++ == 0) { 990fcf3ce44SJohn Forte maj->sm_dev_ops = nsc_get_devops(getmajor(udev)); 991fcf3ce44SJohn Forte 992fcf3ce44SJohn Forte if (maj->sm_dev_ops == NULL || 993fcf3ce44SJohn Forte maj->sm_dev_ops->devo_cb_ops == NULL) { 9943270659fSSrikanth, Ramana DTRACE_PROBE1(sv_enable_err_load, dev_t, udev); 995fcf3ce44SJohn Forte return (sv_free(svp, SV_ELOAD)); 996fcf3ce44SJohn Forte } 997fcf3ce44SJohn Forte 998fcf3ce44SJohn Forte dev_ops = maj->sm_dev_ops; 999fcf3ce44SJohn Forte cb_ops = dev_ops->devo_cb_ops; 1000fcf3ce44SJohn Forte 1001fcf3ce44SJohn Forte if (cb_ops->cb_strategy == NULL || 1002fcf3ce44SJohn Forte cb_ops->cb_strategy == nodev || 1003fcf3ce44SJohn Forte cb_ops->cb_strategy == nulldev) { 10043270659fSSrikanth, Ramana DTRACE_PROBE1(sv_enable_err_nostrategy, dev_t, udev); 1005fcf3ce44SJohn Forte return (sv_free(svp, SV_ELOAD)); 1006fcf3ce44SJohn Forte } 1007fcf3ce44SJohn Forte 1008fcf3ce44SJohn Forte if (cb_ops->cb_strategy == sv_lyr_strategy) { 10093270659fSSrikanth, Ramana DTRACE_PROBE1(sv_enable_err_svstrategy, dev_t, udev); 1010fcf3ce44SJohn Forte return (sv_free(svp, SV_ESTRATEGY)); 1011fcf3ce44SJohn Forte } 1012fcf3ce44SJohn Forte 1013fcf3ce44SJohn Forte maj->sm_strategy = cb_ops->cb_strategy; 1014fcf3ce44SJohn Forte maj->sm_close = cb_ops->cb_close; 1015fcf3ce44SJohn Forte maj->sm_ioctl = cb_ops->cb_ioctl; 1016fcf3ce44SJohn Forte maj->sm_write = cb_ops->cb_write; 1017fcf3ce44SJohn Forte maj->sm_open = cb_ops->cb_open; 1018fcf3ce44SJohn Forte maj->sm_read = cb_ops->cb_read; 1019fcf3ce44SJohn Forte maj->sm_flag = cb_ops->cb_flag; 1020fcf3ce44SJohn Forte 1021fcf3ce44SJohn Forte cb_ops->cb_flag = cb_ops->cb_flag | D_MP; 1022fcf3ce44SJohn Forte cb_ops->cb_strategy = sv_lyr_strategy; 1023fcf3ce44SJohn Forte cb_ops->cb_close = sv_lyr_close; 1024fcf3ce44SJohn Forte cb_ops->cb_ioctl = sv_lyr_ioctl; 1025fcf3ce44SJohn Forte cb_ops->cb_write = sv_lyr_write; 1026fcf3ce44SJohn Forte cb_ops->cb_open = sv_lyr_open; 1027fcf3ce44SJohn Forte cb_ops->cb_read = sv_lyr_read; 1028fcf3ce44SJohn Forte 1029fcf3ce44SJohn Forte /* 1030fcf3ce44SJohn Forte * Check that the driver has async I/O entry points 1031fcf3ce44SJohn Forte * before changing them. 1032fcf3ce44SJohn Forte */ 1033fcf3ce44SJohn Forte 1034fcf3ce44SJohn Forte if (dev_ops->devo_rev < 3 || cb_ops->cb_rev < 1) { 1035fcf3ce44SJohn Forte maj->sm_awrite = 0; 1036fcf3ce44SJohn Forte maj->sm_aread = 0; 1037fcf3ce44SJohn Forte } else { 1038fcf3ce44SJohn Forte maj->sm_awrite = cb_ops->cb_awrite; 1039fcf3ce44SJohn Forte maj->sm_aread = cb_ops->cb_aread; 1040fcf3ce44SJohn Forte 1041fcf3ce44SJohn Forte cb_ops->cb_awrite = sv_lyr_awrite; 1042fcf3ce44SJohn Forte cb_ops->cb_aread = sv_lyr_aread; 1043fcf3ce44SJohn Forte } 1044fcf3ce44SJohn Forte 1045fcf3ce44SJohn Forte /* 1046fcf3ce44SJohn Forte * Bug 4645743 1047fcf3ce44SJohn Forte * 1048fcf3ce44SJohn Forte * Prevent sv from ever unloading after it has interposed 1049fcf3ce44SJohn Forte * on a major device because there is a race between 1050fcf3ce44SJohn Forte * sv removing its layered entry points from the target 1051fcf3ce44SJohn Forte * dev_ops, a client coming in and accessing the driver, 1052fcf3ce44SJohn Forte * and the kernel modunloading the sv text. 1053fcf3ce44SJohn Forte * 1054fcf3ce44SJohn Forte * To allow unload, do svboot -u, which only happens in 1055fcf3ce44SJohn Forte * pkgrm time. 1056fcf3ce44SJohn Forte */ 1057fcf3ce44SJohn Forte ASSERT(MUTEX_HELD(&sv_mutex)); 1058fcf3ce44SJohn Forte sv_mod_status = SV_PREVENT_UNLOAD; 1059fcf3ce44SJohn Forte } 1060fcf3ce44SJohn Forte 1061fcf3ce44SJohn Forte 1062fcf3ce44SJohn Forte svp->sv_timestamp = nsc_lbolt(); 1063fcf3ce44SJohn Forte svp->sv_state = SV_ENABLE; 1064fcf3ce44SJohn Forte svp->sv_pending = NULL; 1065fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1066fcf3ce44SJohn Forte 1067fcf3ce44SJohn Forte sv_ndevices++; 1068fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1069fcf3ce44SJohn Forte 1070fcf3ce44SJohn Forte nblocks = 0; 1071fcf3ce44SJohn Forte if (sv_reserve(svp->sv_fd, NSC_READ|NSC_MULTI|NSC_PCATCH) == 0) { 1072fcf3ce44SJohn Forte nblocks = svp->sv_nblocks; 1073fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 1074fcf3ce44SJohn Forte } 1075fcf3ce44SJohn Forte 1076fcf3ce44SJohn Forte cmn_err(CE_CONT, "!sv: rdev 0x%lx, nblocks %" NSC_SZFMT "\n", 1077fcf3ce44SJohn Forte svp->sv_dev, nblocks); 1078fcf3ce44SJohn Forte 1079fcf3ce44SJohn Forte return (0); 1080fcf3ce44SJohn Forte } 1081fcf3ce44SJohn Forte 1082fcf3ce44SJohn Forte 1083fcf3ce44SJohn Forte static int 1084fcf3ce44SJohn Forte sv_prepare_unload() 1085fcf3ce44SJohn Forte { 1086fcf3ce44SJohn Forte int rc = 0; 1087fcf3ce44SJohn Forte 1088fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1089fcf3ce44SJohn Forte 1090fcf3ce44SJohn Forte if (sv_mod_status == SV_PREVENT_UNLOAD) { 1091fcf3ce44SJohn Forte if ((sv_ndevices != 0) || (sv_tset != NULL)) { 1092fcf3ce44SJohn Forte rc = EBUSY; 1093fcf3ce44SJohn Forte } else { 1094fcf3ce44SJohn Forte sv_mod_status = SV_ALLOW_UNLOAD; 1095fcf3ce44SJohn Forte delay(SV_WAIT_UNLOAD * drv_usectohz(1000000)); 1096fcf3ce44SJohn Forte } 1097fcf3ce44SJohn Forte } 1098fcf3ce44SJohn Forte 1099fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1100fcf3ce44SJohn Forte return (rc); 1101fcf3ce44SJohn Forte } 1102fcf3ce44SJohn Forte 1103fcf3ce44SJohn Forte static int 1104fcf3ce44SJohn Forte svattach_fd(blind_t arg) 1105fcf3ce44SJohn Forte { 1106fcf3ce44SJohn Forte dev_t dev = (dev_t)arg; 1107fcf3ce44SJohn Forte sv_dev_t *svp = sv_dev_to_sv(dev, NULL); 1108fcf3ce44SJohn Forte int rc; 1109fcf3ce44SJohn Forte 1110fcf3ce44SJohn Forte if (sv_debug > 0) 11113270659fSSrikanth, Ramana cmn_err(CE_CONT, "!svattach_fd(%p, %p)\n", arg, (void *)svp); 1112fcf3ce44SJohn Forte 1113fcf3ce44SJohn Forte if (svp == NULL) { 1114fcf3ce44SJohn Forte cmn_err(CE_WARN, "!svattach_fd: no state (arg %p)", arg); 1115fcf3ce44SJohn Forte return (0); 1116fcf3ce44SJohn Forte } 1117fcf3ce44SJohn Forte 1118fcf3ce44SJohn Forte if ((rc = nsc_partsize(svp->sv_fd, &svp->sv_nblocks)) != 0) { 1119fcf3ce44SJohn Forte cmn_err(CE_WARN, 1120fcf3ce44SJohn Forte "!svattach_fd: nsc_partsize() failed, rc %d", rc); 1121fcf3ce44SJohn Forte svp->sv_nblocks = 0; 1122fcf3ce44SJohn Forte } 1123fcf3ce44SJohn Forte 1124fcf3ce44SJohn Forte if ((rc = nsc_maxfbas(svp->sv_fd, 0, &svp->sv_maxfbas)) != 0) { 1125fcf3ce44SJohn Forte cmn_err(CE_WARN, 1126fcf3ce44SJohn Forte "!svattach_fd: nsc_maxfbas() failed, rc %d", rc); 1127fcf3ce44SJohn Forte svp->sv_maxfbas = 0; 1128fcf3ce44SJohn Forte } 1129fcf3ce44SJohn Forte 1130fcf3ce44SJohn Forte if (sv_debug > 0) { 1131fcf3ce44SJohn Forte cmn_err(CE_CONT, 11323270659fSSrikanth, Ramana "!svattach_fd(%p): size %" NSC_SZFMT ", " 1133fcf3ce44SJohn Forte "maxfbas %" NSC_SZFMT "\n", 1134fcf3ce44SJohn Forte arg, svp->sv_nblocks, svp->sv_maxfbas); 1135fcf3ce44SJohn Forte } 1136fcf3ce44SJohn Forte 1137fcf3ce44SJohn Forte return (0); 1138fcf3ce44SJohn Forte } 1139fcf3ce44SJohn Forte 1140fcf3ce44SJohn Forte 1141fcf3ce44SJohn Forte static int 1142fcf3ce44SJohn Forte svdetach_fd(blind_t arg) 1143fcf3ce44SJohn Forte { 1144fcf3ce44SJohn Forte dev_t dev = (dev_t)arg; 1145fcf3ce44SJohn Forte sv_dev_t *svp = sv_dev_to_sv(dev, NULL); 1146fcf3ce44SJohn Forte 1147fcf3ce44SJohn Forte if (sv_debug > 0) 11483270659fSSrikanth, Ramana cmn_err(CE_CONT, "!svdetach_fd(%p, %p)\n", arg, (void *)svp); 1149fcf3ce44SJohn Forte 1150fcf3ce44SJohn Forte /* svp can be NULL during disable of an sv */ 1151fcf3ce44SJohn Forte if (svp == NULL) 1152fcf3ce44SJohn Forte return (0); 1153fcf3ce44SJohn Forte 1154fcf3ce44SJohn Forte svp->sv_maxfbas = 0; 1155fcf3ce44SJohn Forte svp->sv_nblocks = 0; 1156fcf3ce44SJohn Forte return (0); 1157fcf3ce44SJohn Forte } 1158fcf3ce44SJohn Forte 1159fcf3ce44SJohn Forte 1160fcf3ce44SJohn Forte /* 1161fcf3ce44SJohn Forte * Side effect: if called with (guard != 0), then expects both sv_mutex 1162fcf3ce44SJohn Forte * and sv_lock(RW_WRITER) to be held, and will release them before returning. 1163fcf3ce44SJohn Forte */ 1164fcf3ce44SJohn Forte 1165fcf3ce44SJohn Forte /* ARGSUSED */ 1166fcf3ce44SJohn Forte static int 1167fcf3ce44SJohn Forte sv_disable(dev_t dev, spcs_s_info_t kstatus) 1168fcf3ce44SJohn Forte { 1169fcf3ce44SJohn Forte sv_dev_t *svp = sv_dev_to_sv(dev, NULL); 1170fcf3ce44SJohn Forte 1171fcf3ce44SJohn Forte if (svp == NULL) { 1172fcf3ce44SJohn Forte 1173fcf3ce44SJohn Forte DTRACE_PROBE1(sv_disable_err_nodev, sv_dev_t *, svp); 1174fcf3ce44SJohn Forte return (SV_ENODEV); 1175fcf3ce44SJohn Forte } 1176fcf3ce44SJohn Forte 1177fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1178fcf3ce44SJohn Forte rw_enter(&svp->sv_lock, RW_WRITER); 1179fcf3ce44SJohn Forte 1180fcf3ce44SJohn Forte if (svp->sv_fd == NULL || svp->sv_state != SV_ENABLE) { 1181fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1182fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1183fcf3ce44SJohn Forte 1184fcf3ce44SJohn Forte DTRACE_PROBE1(sv_disable_err_disabled, sv_dev_t *, svp); 1185fcf3ce44SJohn Forte return (SV_EDISABLED); 1186fcf3ce44SJohn Forte } 1187fcf3ce44SJohn Forte 1188fcf3ce44SJohn Forte 1189fcf3ce44SJohn Forte sv_ndevices--; 1190fcf3ce44SJohn Forte return (sv_free(svp, 0)); 1191fcf3ce44SJohn Forte } 1192fcf3ce44SJohn Forte 1193fcf3ce44SJohn Forte 1194fcf3ce44SJohn Forte 1195fcf3ce44SJohn Forte static int 1196fcf3ce44SJohn Forte sv_lyr_open(dev_t *devp, int flag, int otyp, cred_t *crp) 1197fcf3ce44SJohn Forte { 1198fcf3ce44SJohn Forte nsc_buf_t *tmph; 1199fcf3ce44SJohn Forte sv_dev_t *svp; 1200fcf3ce44SJohn Forte sv_maj_t *maj; 1201fcf3ce44SJohn Forte int (*fn)(); 1202fcf3ce44SJohn Forte dev_t odev; 1203fcf3ce44SJohn Forte int ret; 1204fcf3ce44SJohn Forte int rc; 1205fcf3ce44SJohn Forte 1206fcf3ce44SJohn Forte svp = sv_dev_to_sv(*devp, &maj); 1207fcf3ce44SJohn Forte 1208fcf3ce44SJohn Forte if (svp) { 1209fcf3ce44SJohn Forte if (svp->sv_state == SV_PENDING && 1210fcf3ce44SJohn Forte svp->sv_pending == curthread) { 1211fcf3ce44SJohn Forte /* 1212fcf3ce44SJohn Forte * This is a recursive open from a call to 1213fcf3ce44SJohn Forte * ddi_lyr_open_by_devt and so we just want 1214fcf3ce44SJohn Forte * to pass it straight through to the 1215fcf3ce44SJohn Forte * underlying driver. 1216fcf3ce44SJohn Forte */ 1217fcf3ce44SJohn Forte DTRACE_PROBE2(sv_lyr_open_recursive, 1218fcf3ce44SJohn Forte sv_dev_t *, svp, 1219fcf3ce44SJohn Forte dev_t, *devp); 1220fcf3ce44SJohn Forte svp = NULL; 1221fcf3ce44SJohn Forte } else 1222fcf3ce44SJohn Forte rw_enter(&svp->sv_lock, RW_READER); 1223fcf3ce44SJohn Forte } 1224fcf3ce44SJohn Forte 1225fcf3ce44SJohn Forte odev = *devp; 1226fcf3ce44SJohn Forte 1227fcf3ce44SJohn Forte if (maj && (fn = maj->sm_open) != 0) { 1228fcf3ce44SJohn Forte if (!(maj->sm_flag & D_MP)) { 1229fcf3ce44SJohn Forte UNSAFE_ENTER(); 1230fcf3ce44SJohn Forte ret = (*fn)(devp, flag, otyp, crp); 1231fcf3ce44SJohn Forte UNSAFE_EXIT(); 1232fcf3ce44SJohn Forte } else { 1233fcf3ce44SJohn Forte ret = (*fn)(devp, flag, otyp, crp); 1234fcf3ce44SJohn Forte } 1235fcf3ce44SJohn Forte 1236fcf3ce44SJohn Forte if (ret == 0) { 1237fcf3ce44SJohn Forte /* 1238fcf3ce44SJohn Forte * Re-acquire svp if the driver changed *devp. 1239fcf3ce44SJohn Forte */ 1240fcf3ce44SJohn Forte 1241fcf3ce44SJohn Forte if (*devp != odev) { 1242b2514ea1SDan McDonald if (svp != NULL) 1243fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1244fcf3ce44SJohn Forte 1245fcf3ce44SJohn Forte svp = sv_dev_to_sv(*devp, NULL); 1246fcf3ce44SJohn Forte 1247fcf3ce44SJohn Forte if (svp) { 1248fcf3ce44SJohn Forte rw_enter(&svp->sv_lock, RW_READER); 1249fcf3ce44SJohn Forte } 1250fcf3ce44SJohn Forte } 1251fcf3ce44SJohn Forte } 1252fcf3ce44SJohn Forte } else { 1253fcf3ce44SJohn Forte ret = ENODEV; 1254fcf3ce44SJohn Forte } 1255fcf3ce44SJohn Forte 1256fcf3ce44SJohn Forte if (svp && ret != 0 && svp->sv_state == SV_ENABLE) { 1257fcf3ce44SJohn Forte /* 1258fcf3ce44SJohn Forte * Underlying DDI open failed, but we have this 1259fcf3ce44SJohn Forte * device SV enabled. If we can read some data 1260fcf3ce44SJohn Forte * from the device, fake a successful open (this 1261fcf3ce44SJohn Forte * probably means that this device is RDC'd and we 1262fcf3ce44SJohn Forte * are getting the data from the secondary node). 1263fcf3ce44SJohn Forte * 1264fcf3ce44SJohn Forte * The reserve must be done with NSC_TRY|NSC_NOWAIT to 1265fcf3ce44SJohn Forte * ensure that it does not deadlock if this open is 1266fcf3ce44SJohn Forte * coming from nskernd:get_bsize(). 1267fcf3ce44SJohn Forte */ 1268fcf3ce44SJohn Forte rc = sv_reserve(svp->sv_fd, 1269fcf3ce44SJohn Forte NSC_TRY | NSC_NOWAIT | NSC_MULTI | NSC_PCATCH); 1270fcf3ce44SJohn Forte if (rc == 0) { 1271fcf3ce44SJohn Forte tmph = NULL; 1272fcf3ce44SJohn Forte 1273fcf3ce44SJohn Forte rc = nsc_alloc_buf(svp->sv_fd, 0, 1, NSC_READ, &tmph); 1274fcf3ce44SJohn Forte if (rc <= 0) { 1275fcf3ce44SJohn Forte /* success */ 1276fcf3ce44SJohn Forte ret = 0; 1277fcf3ce44SJohn Forte } 1278fcf3ce44SJohn Forte 1279fcf3ce44SJohn Forte if (tmph) { 1280fcf3ce44SJohn Forte (void) nsc_free_buf(tmph); 1281fcf3ce44SJohn Forte tmph = NULL; 1282fcf3ce44SJohn Forte } 1283fcf3ce44SJohn Forte 1284fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 1285fcf3ce44SJohn Forte 1286fcf3ce44SJohn Forte /* 1287fcf3ce44SJohn Forte * Count the number of layered opens that we 1288fcf3ce44SJohn Forte * fake since we have to fake a matching number 1289fcf3ce44SJohn Forte * of closes (OTYP_LYR open/close calls must be 1290fcf3ce44SJohn Forte * paired). 1291fcf3ce44SJohn Forte */ 1292fcf3ce44SJohn Forte 1293fcf3ce44SJohn Forte if (ret == 0 && otyp == OTYP_LYR) { 1294fcf3ce44SJohn Forte mutex_enter(&svp->sv_olock); 1295fcf3ce44SJohn Forte svp->sv_openlcnt++; 1296fcf3ce44SJohn Forte mutex_exit(&svp->sv_olock); 1297fcf3ce44SJohn Forte } 1298fcf3ce44SJohn Forte } 1299fcf3ce44SJohn Forte } 1300fcf3ce44SJohn Forte 1301fcf3ce44SJohn Forte if (svp) { 1302fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1303fcf3ce44SJohn Forte } 1304fcf3ce44SJohn Forte 1305fcf3ce44SJohn Forte return (ret); 1306fcf3ce44SJohn Forte } 1307fcf3ce44SJohn Forte 1308fcf3ce44SJohn Forte 1309fcf3ce44SJohn Forte static int 1310fcf3ce44SJohn Forte sv_lyr_close(dev_t dev, int flag, int otyp, cred_t *crp) 1311fcf3ce44SJohn Forte { 1312fcf3ce44SJohn Forte sv_dev_t *svp; 1313fcf3ce44SJohn Forte sv_maj_t *maj; 1314fcf3ce44SJohn Forte int (*fn)(); 1315fcf3ce44SJohn Forte int ret; 1316fcf3ce44SJohn Forte 1317fcf3ce44SJohn Forte svp = sv_dev_to_sv(dev, &maj); 1318fcf3ce44SJohn Forte 1319fcf3ce44SJohn Forte if (svp && 1320fcf3ce44SJohn Forte svp->sv_state == SV_PENDING && 1321fcf3ce44SJohn Forte svp->sv_pending == curthread) { 1322fcf3ce44SJohn Forte /* 1323fcf3ce44SJohn Forte * This is a recursive open from a call to 1324fcf3ce44SJohn Forte * ddi_lyr_close and so we just want 1325fcf3ce44SJohn Forte * to pass it straight through to the 1326fcf3ce44SJohn Forte * underlying driver. 1327fcf3ce44SJohn Forte */ 13283270659fSSrikanth, Ramana DTRACE_PROBE2(sv_lyr_close_recursive, sv_dev_t *, svp, 1329fcf3ce44SJohn Forte dev_t, dev); 1330fcf3ce44SJohn Forte svp = NULL; 1331fcf3ce44SJohn Forte } 1332fcf3ce44SJohn Forte 1333fcf3ce44SJohn Forte if (svp) { 1334fcf3ce44SJohn Forte rw_enter(&svp->sv_lock, RW_READER); 1335fcf3ce44SJohn Forte 1336fcf3ce44SJohn Forte if (otyp == OTYP_LYR) { 1337fcf3ce44SJohn Forte mutex_enter(&svp->sv_olock); 1338fcf3ce44SJohn Forte 1339fcf3ce44SJohn Forte if (svp->sv_openlcnt) { 1340fcf3ce44SJohn Forte /* 1341fcf3ce44SJohn Forte * Consume sufficient layered closes to 1342fcf3ce44SJohn Forte * account for the opens that we faked 1343fcf3ce44SJohn Forte * whilst the device was failed. 1344fcf3ce44SJohn Forte */ 1345fcf3ce44SJohn Forte svp->sv_openlcnt--; 1346fcf3ce44SJohn Forte mutex_exit(&svp->sv_olock); 1347fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1348fcf3ce44SJohn Forte 13493270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_close_end, dev_t, dev); 1350fcf3ce44SJohn Forte 1351fcf3ce44SJohn Forte return (0); 1352fcf3ce44SJohn Forte } 1353fcf3ce44SJohn Forte 1354fcf3ce44SJohn Forte mutex_exit(&svp->sv_olock); 1355fcf3ce44SJohn Forte } 1356fcf3ce44SJohn Forte } 1357fcf3ce44SJohn Forte 1358fcf3ce44SJohn Forte if (maj && (fn = maj->sm_close) != 0) { 1359fcf3ce44SJohn Forte if (!(maj->sm_flag & D_MP)) { 1360fcf3ce44SJohn Forte UNSAFE_ENTER(); 1361fcf3ce44SJohn Forte ret = (*fn)(dev, flag, otyp, crp); 1362fcf3ce44SJohn Forte UNSAFE_EXIT(); 1363fcf3ce44SJohn Forte } else { 1364fcf3ce44SJohn Forte ret = (*fn)(dev, flag, otyp, crp); 1365fcf3ce44SJohn Forte } 1366fcf3ce44SJohn Forte } else { 1367fcf3ce44SJohn Forte ret = ENODEV; 1368fcf3ce44SJohn Forte } 1369fcf3ce44SJohn Forte 1370fcf3ce44SJohn Forte if (svp) { 1371fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1372fcf3ce44SJohn Forte } 1373fcf3ce44SJohn Forte 1374fcf3ce44SJohn Forte return (ret); 1375fcf3ce44SJohn Forte } 1376fcf3ce44SJohn Forte 1377fcf3ce44SJohn Forte 1378fcf3ce44SJohn Forte /* 1379fcf3ce44SJohn Forte * Convert the specified dev_t into a locked and enabled sv_dev_t, or 1380fcf3ce44SJohn Forte * return NULL. 1381fcf3ce44SJohn Forte */ 1382fcf3ce44SJohn Forte static sv_dev_t * 1383fcf3ce44SJohn Forte sv_find_enabled(const dev_t dev, sv_maj_t **majpp) 1384fcf3ce44SJohn Forte { 1385fcf3ce44SJohn Forte sv_dev_t *svp; 1386fcf3ce44SJohn Forte 1387fcf3ce44SJohn Forte while ((svp = sv_dev_to_sv(dev, majpp)) != NULL) { 1388fcf3ce44SJohn Forte rw_enter(&svp->sv_lock, RW_READER); 1389fcf3ce44SJohn Forte 1390fcf3ce44SJohn Forte if (svp->sv_state == SV_ENABLE) { 1391fcf3ce44SJohn Forte /* locked and enabled */ 1392fcf3ce44SJohn Forte break; 1393fcf3ce44SJohn Forte } 1394fcf3ce44SJohn Forte 1395fcf3ce44SJohn Forte /* 1396fcf3ce44SJohn Forte * State was changed while waiting on the lock. 1397fcf3ce44SJohn Forte * Wait for a stable state. 1398fcf3ce44SJohn Forte */ 1399fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1400fcf3ce44SJohn Forte 14013270659fSSrikanth, Ramana DTRACE_PROBE1(sv_find_enabled_retry, dev_t, dev); 1402fcf3ce44SJohn Forte 1403fcf3ce44SJohn Forte delay(2); 1404fcf3ce44SJohn Forte } 1405fcf3ce44SJohn Forte 1406fcf3ce44SJohn Forte return (svp); 1407fcf3ce44SJohn Forte } 1408fcf3ce44SJohn Forte 1409fcf3ce44SJohn Forte 1410fcf3ce44SJohn Forte static int 1411fcf3ce44SJohn Forte sv_lyr_uio(dev_t dev, uio_t *uiop, cred_t *crp, int rw) 1412fcf3ce44SJohn Forte { 1413fcf3ce44SJohn Forte sv_dev_t *svp; 1414fcf3ce44SJohn Forte sv_maj_t *maj; 1415fcf3ce44SJohn Forte int (*fn)(); 1416fcf3ce44SJohn Forte int rc; 1417fcf3ce44SJohn Forte 1418fcf3ce44SJohn Forte svp = sv_find_enabled(dev, &maj); 1419fcf3ce44SJohn Forte if (svp == NULL) { 1420fcf3ce44SJohn Forte if (maj) { 1421fcf3ce44SJohn Forte if (rw == NSC_READ) 1422fcf3ce44SJohn Forte fn = maj->sm_read; 1423fcf3ce44SJohn Forte else 1424fcf3ce44SJohn Forte fn = maj->sm_write; 1425fcf3ce44SJohn Forte 1426fcf3ce44SJohn Forte if (fn != 0) { 1427fcf3ce44SJohn Forte if (!(maj->sm_flag & D_MP)) { 1428fcf3ce44SJohn Forte UNSAFE_ENTER(); 1429fcf3ce44SJohn Forte rc = (*fn)(dev, uiop, crp); 1430fcf3ce44SJohn Forte UNSAFE_EXIT(); 1431fcf3ce44SJohn Forte } else { 1432fcf3ce44SJohn Forte rc = (*fn)(dev, uiop, crp); 1433fcf3ce44SJohn Forte } 1434fcf3ce44SJohn Forte } 1435fcf3ce44SJohn Forte 1436fcf3ce44SJohn Forte return (rc); 1437fcf3ce44SJohn Forte } else { 1438fcf3ce44SJohn Forte return (ENODEV); 1439fcf3ce44SJohn Forte } 1440fcf3ce44SJohn Forte } 1441fcf3ce44SJohn Forte 1442fcf3ce44SJohn Forte ASSERT(RW_READ_HELD(&svp->sv_lock)); 1443fcf3ce44SJohn Forte 1444fcf3ce44SJohn Forte if (svp->sv_flag == 0) { 1445fcf3ce44SJohn Forte /* 1446fcf3ce44SJohn Forte * guard access mode 1447fcf3ce44SJohn Forte * - prevent user level access to the device 1448fcf3ce44SJohn Forte */ 14493270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_uio_err_guard, uio_t *, uiop); 1450fcf3ce44SJohn Forte rc = EPERM; 1451fcf3ce44SJohn Forte goto out; 1452fcf3ce44SJohn Forte } 1453fcf3ce44SJohn Forte 1454fcf3ce44SJohn Forte if ((rc = sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH)) != 0) { 14553270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_uio_err_rsrv, uio_t *, uiop); 1456fcf3ce44SJohn Forte goto out; 1457fcf3ce44SJohn Forte } 1458fcf3ce44SJohn Forte 1459fcf3ce44SJohn Forte if (rw == NSC_READ) 1460fcf3ce44SJohn Forte rc = nsc_uread(svp->sv_fd, uiop, crp); 1461fcf3ce44SJohn Forte else 1462fcf3ce44SJohn Forte rc = nsc_uwrite(svp->sv_fd, uiop, crp); 1463fcf3ce44SJohn Forte 1464fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 1465fcf3ce44SJohn Forte 1466fcf3ce44SJohn Forte out: 1467fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1468fcf3ce44SJohn Forte 1469fcf3ce44SJohn Forte return (rc); 1470fcf3ce44SJohn Forte } 1471fcf3ce44SJohn Forte 1472fcf3ce44SJohn Forte 1473fcf3ce44SJohn Forte static int 1474fcf3ce44SJohn Forte sv_lyr_read(dev_t dev, uio_t *uiop, cred_t *crp) 1475fcf3ce44SJohn Forte { 1476fcf3ce44SJohn Forte return (sv_lyr_uio(dev, uiop, crp, NSC_READ)); 1477fcf3ce44SJohn Forte } 1478fcf3ce44SJohn Forte 1479fcf3ce44SJohn Forte 1480fcf3ce44SJohn Forte static int 1481fcf3ce44SJohn Forte sv_lyr_write(dev_t dev, uio_t *uiop, cred_t *crp) 1482fcf3ce44SJohn Forte { 1483fcf3ce44SJohn Forte return (sv_lyr_uio(dev, uiop, crp, NSC_WRITE)); 1484fcf3ce44SJohn Forte } 1485fcf3ce44SJohn Forte 1486fcf3ce44SJohn Forte 1487fcf3ce44SJohn Forte /* ARGSUSED */ 1488fcf3ce44SJohn Forte 1489fcf3ce44SJohn Forte static int 1490fcf3ce44SJohn Forte sv_lyr_aread(dev_t dev, struct aio_req *aio, cred_t *crp) 1491fcf3ce44SJohn Forte { 1492fcf3ce44SJohn Forte return (aphysio(sv_lyr_strategy, 1493fcf3ce44SJohn Forte anocancel, dev, B_READ, minphys, aio)); 1494fcf3ce44SJohn Forte } 1495fcf3ce44SJohn Forte 1496fcf3ce44SJohn Forte 1497fcf3ce44SJohn Forte /* ARGSUSED */ 1498fcf3ce44SJohn Forte 1499fcf3ce44SJohn Forte static int 1500fcf3ce44SJohn Forte sv_lyr_awrite(dev_t dev, struct aio_req *aio, cred_t *crp) 1501fcf3ce44SJohn Forte { 1502fcf3ce44SJohn Forte return (aphysio(sv_lyr_strategy, 1503fcf3ce44SJohn Forte anocancel, dev, B_WRITE, minphys, aio)); 1504fcf3ce44SJohn Forte } 1505fcf3ce44SJohn Forte 1506fcf3ce44SJohn Forte 1507fcf3ce44SJohn Forte /* 1508fcf3ce44SJohn Forte * Set up an array containing the list of raw path names 1509fcf3ce44SJohn Forte * The array for the paths is svl and the size of the array is 1510fcf3ce44SJohn Forte * in size. 1511fcf3ce44SJohn Forte * 1512fcf3ce44SJohn Forte * If there are more layered devices than will fit in the array, 1513fcf3ce44SJohn Forte * the number of extra layered devices is returned. Otherwise 1514fcf3ce44SJohn Forte * zero is return. 1515fcf3ce44SJohn Forte * 1516fcf3ce44SJohn Forte * Input: 1517fcf3ce44SJohn Forte * svn : array for paths 1518fcf3ce44SJohn Forte * size : size of the array 1519fcf3ce44SJohn Forte * 1520fcf3ce44SJohn Forte * Output (extra): 1521fcf3ce44SJohn Forte * zero : All paths fit in array 1522fcf3ce44SJohn Forte * >0 : Number of defined layered devices don't fit in array 1523fcf3ce44SJohn Forte */ 1524fcf3ce44SJohn Forte 1525fcf3ce44SJohn Forte static int 1526fcf3ce44SJohn Forte sv_list(void *ptr, const int size, int *extra, const int ilp32) 1527fcf3ce44SJohn Forte { 1528fcf3ce44SJohn Forte sv_name32_t *svn32; 1529fcf3ce44SJohn Forte sv_name_t *svn; 1530fcf3ce44SJohn Forte sv_dev_t *svp; 1531fcf3ce44SJohn Forte int *mode, *nblocks; 1532fcf3ce44SJohn Forte int i, index; 1533fcf3ce44SJohn Forte char *path; 1534fcf3ce44SJohn Forte 1535fcf3ce44SJohn Forte *extra = 0; 1536fcf3ce44SJohn Forte index = 0; 1537fcf3ce44SJohn Forte 1538fcf3ce44SJohn Forte if (ilp32) 1539fcf3ce44SJohn Forte svn32 = ptr; 1540fcf3ce44SJohn Forte else 1541fcf3ce44SJohn Forte svn = ptr; 1542fcf3ce44SJohn Forte 1543fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1544fcf3ce44SJohn Forte for (i = 0; i < sv_max_devices; i++) { 1545fcf3ce44SJohn Forte svp = &sv_devs[i]; 1546fcf3ce44SJohn Forte 1547fcf3ce44SJohn Forte rw_enter(&svp->sv_lock, RW_READER); 1548fcf3ce44SJohn Forte 1549fcf3ce44SJohn Forte if (svp->sv_state != SV_ENABLE) { 1550fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1551fcf3ce44SJohn Forte continue; 1552fcf3ce44SJohn Forte } 1553fcf3ce44SJohn Forte 1554fcf3ce44SJohn Forte if ((*extra) != 0 || ptr == NULL) { 1555fcf3ce44SJohn Forte /* Another overflow entry */ 1556fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1557fcf3ce44SJohn Forte (*extra)++; 1558fcf3ce44SJohn Forte continue; 1559fcf3ce44SJohn Forte } 1560fcf3ce44SJohn Forte 1561fcf3ce44SJohn Forte if (ilp32) { 1562fcf3ce44SJohn Forte nblocks = &svn32->svn_nblocks; 1563fcf3ce44SJohn Forte mode = &svn32->svn_mode; 1564fcf3ce44SJohn Forte path = svn32->svn_path; 1565fcf3ce44SJohn Forte 1566fcf3ce44SJohn Forte svn32->svn_timestamp = (uint32_t)svp->sv_timestamp; 1567fcf3ce44SJohn Forte svn32++; 1568fcf3ce44SJohn Forte } else { 1569fcf3ce44SJohn Forte nblocks = &svn->svn_nblocks; 1570fcf3ce44SJohn Forte mode = &svn->svn_mode; 1571fcf3ce44SJohn Forte path = svn->svn_path; 1572fcf3ce44SJohn Forte 1573fcf3ce44SJohn Forte svn->svn_timestamp = svp->sv_timestamp; 1574fcf3ce44SJohn Forte svn++; 1575fcf3ce44SJohn Forte } 1576fcf3ce44SJohn Forte 1577fcf3ce44SJohn Forte (void) strcpy(path, nsc_pathname(svp->sv_fd)); 1578fcf3ce44SJohn Forte *nblocks = svp->sv_nblocks; 1579fcf3ce44SJohn Forte *mode = svp->sv_flag; 1580fcf3ce44SJohn Forte 1581fcf3ce44SJohn Forte if (*nblocks == 0) { 1582fcf3ce44SJohn Forte if (sv_debug > 3) 15833270659fSSrikanth, Ramana cmn_err(CE_CONT, "!sv_list: need to reserve\n"); 1584fcf3ce44SJohn Forte 15853270659fSSrikanth, Ramana if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) { 1586fcf3ce44SJohn Forte *nblocks = svp->sv_nblocks; 1587fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 1588fcf3ce44SJohn Forte } 1589fcf3ce44SJohn Forte } 1590fcf3ce44SJohn Forte 1591fcf3ce44SJohn Forte if (++index >= size) { 1592fcf3ce44SJohn Forte /* Out of space */ 1593fcf3ce44SJohn Forte (*extra)++; 1594fcf3ce44SJohn Forte } 1595fcf3ce44SJohn Forte 1596fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 1597fcf3ce44SJohn Forte } 1598fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1599fcf3ce44SJohn Forte 1600fcf3ce44SJohn Forte if (index < size) { 1601fcf3ce44SJohn Forte /* NULL terminated list */ 1602fcf3ce44SJohn Forte if (ilp32) 1603fcf3ce44SJohn Forte svn32->svn_path[0] = '\0'; 1604fcf3ce44SJohn Forte else 1605fcf3ce44SJohn Forte svn->svn_path[0] = '\0'; 1606fcf3ce44SJohn Forte } 1607fcf3ce44SJohn Forte 1608fcf3ce44SJohn Forte return (0); 1609fcf3ce44SJohn Forte } 1610fcf3ce44SJohn Forte 1611fcf3ce44SJohn Forte 1612fcf3ce44SJohn Forte static void 1613fcf3ce44SJohn Forte sv_thread_tune(int threads) 1614fcf3ce44SJohn Forte { 1615fcf3ce44SJohn Forte int incr = (threads > 0) ? 1 : -1; 1616fcf3ce44SJohn Forte int change = 0; 1617fcf3ce44SJohn Forte int nthreads; 1618fcf3ce44SJohn Forte 1619fcf3ce44SJohn Forte ASSERT(MUTEX_HELD(&sv_mutex)); 1620fcf3ce44SJohn Forte 1621fcf3ce44SJohn Forte if (sv_threads_extra) { 1622fcf3ce44SJohn Forte /* keep track of any additional threads requested */ 1623fcf3ce44SJohn Forte if (threads > 0) { 1624fcf3ce44SJohn Forte sv_threads_extra += threads; 1625fcf3ce44SJohn Forte return; 1626fcf3ce44SJohn Forte } 1627fcf3ce44SJohn Forte threads = -threads; 1628fcf3ce44SJohn Forte if (threads >= sv_threads_extra) { 1629fcf3ce44SJohn Forte threads -= sv_threads_extra; 1630fcf3ce44SJohn Forte sv_threads_extra = 0; 1631fcf3ce44SJohn Forte /* fall through to while loop */ 1632fcf3ce44SJohn Forte } else { 1633fcf3ce44SJohn Forte sv_threads_extra -= threads; 1634fcf3ce44SJohn Forte return; 1635fcf3ce44SJohn Forte } 1636fcf3ce44SJohn Forte } else if (threads > 0) { 1637fcf3ce44SJohn Forte /* 1638fcf3ce44SJohn Forte * do not increase the number of threads beyond 1639fcf3ce44SJohn Forte * sv_threads_max when doing dynamic thread tuning 1640fcf3ce44SJohn Forte */ 1641fcf3ce44SJohn Forte nthreads = nst_nthread(sv_tset); 1642fcf3ce44SJohn Forte if ((nthreads + threads) > sv_threads_max) { 1643fcf3ce44SJohn Forte sv_threads_extra = nthreads + threads - sv_threads_max; 1644fcf3ce44SJohn Forte threads = sv_threads_max - nthreads; 1645fcf3ce44SJohn Forte if (threads <= 0) 1646fcf3ce44SJohn Forte return; 1647fcf3ce44SJohn Forte } 1648fcf3ce44SJohn Forte } 1649fcf3ce44SJohn Forte 1650fcf3ce44SJohn Forte if (threads < 0) 1651fcf3ce44SJohn Forte threads = -threads; 1652fcf3ce44SJohn Forte 1653fcf3ce44SJohn Forte while (threads--) { 1654fcf3ce44SJohn Forte nthreads = nst_nthread(sv_tset); 1655fcf3ce44SJohn Forte sv_threads_needed += incr; 1656fcf3ce44SJohn Forte 1657fcf3ce44SJohn Forte if (sv_threads_needed >= nthreads) 1658fcf3ce44SJohn Forte change += nst_add_thread(sv_tset, sv_threads_inc); 1659fcf3ce44SJohn Forte else if ((sv_threads_needed < 1660fcf3ce44SJohn Forte (nthreads - (sv_threads_inc + sv_threads_hysteresis))) && 1661fcf3ce44SJohn Forte ((nthreads - sv_threads_inc) >= sv_threads)) 1662fcf3ce44SJohn Forte change -= nst_del_thread(sv_tset, sv_threads_inc); 1663fcf3ce44SJohn Forte } 1664fcf3ce44SJohn Forte 1665fcf3ce44SJohn Forte #ifdef DEBUG 1666fcf3ce44SJohn Forte if (change) { 1667fcf3ce44SJohn Forte cmn_err(CE_NOTE, 16683270659fSSrikanth, Ramana "!sv_thread_tune: threads needed %d, nthreads %d, " 1669fcf3ce44SJohn Forte "nthreads change %d", 1670fcf3ce44SJohn Forte sv_threads_needed, nst_nthread(sv_tset), change); 1671fcf3ce44SJohn Forte } 1672fcf3ce44SJohn Forte #endif 1673fcf3ce44SJohn Forte } 1674fcf3ce44SJohn Forte 1675fcf3ce44SJohn Forte 1676fcf3ce44SJohn Forte /* ARGSUSED */ 1677fcf3ce44SJohn Forte static int 1678fcf3ce44SJohn Forte svopen(dev_t *devp, int flag, int otyp, cred_t *crp) 1679fcf3ce44SJohn Forte { 1680fcf3ce44SJohn Forte int rc; 1681fcf3ce44SJohn Forte 1682fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1683fcf3ce44SJohn Forte rc = sv_init_devs(); 1684fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1685fcf3ce44SJohn Forte 1686fcf3ce44SJohn Forte return (rc); 1687fcf3ce44SJohn Forte } 1688fcf3ce44SJohn Forte 1689fcf3ce44SJohn Forte 1690fcf3ce44SJohn Forte /* ARGSUSED */ 1691fcf3ce44SJohn Forte static int 1692fcf3ce44SJohn Forte svclose(dev_t dev, int flag, int otyp, cred_t *crp) 1693fcf3ce44SJohn Forte { 1694fcf3ce44SJohn Forte const int secs = HZ * 5; 1695fcf3ce44SJohn Forte const int ticks = HZ / 10; 1696fcf3ce44SJohn Forte int loops = secs / ticks; 1697fcf3ce44SJohn Forte 1698fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1699fcf3ce44SJohn Forte while (sv_ndevices <= 0 && sv_tset != NULL && loops > 0) { 1700fcf3ce44SJohn Forte if (nst_nlive(sv_tset) <= 0) { 1701fcf3ce44SJohn Forte nst_destroy(sv_tset); 1702fcf3ce44SJohn Forte sv_tset = NULL; 1703fcf3ce44SJohn Forte break; 1704fcf3ce44SJohn Forte } 1705fcf3ce44SJohn Forte 1706fcf3ce44SJohn Forte /* threads still active - wait for them to exit */ 1707fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1708fcf3ce44SJohn Forte delay(ticks); 1709fcf3ce44SJohn Forte loops--; 1710fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1711fcf3ce44SJohn Forte } 1712fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1713fcf3ce44SJohn Forte 1714fcf3ce44SJohn Forte if (loops <= 0) { 1715fcf3ce44SJohn Forte cmn_err(CE_WARN, 1716fcf3ce44SJohn Forte #ifndef DEBUG 1717fcf3ce44SJohn Forte /* do not write to console when non-DEBUG */ 1718fcf3ce44SJohn Forte "!" 1719fcf3ce44SJohn Forte #endif 1720fcf3ce44SJohn Forte "sv:svclose: threads still active " 1721fcf3ce44SJohn Forte "after %d sec - leaking thread set", secs); 1722fcf3ce44SJohn Forte } 1723fcf3ce44SJohn Forte 1724fcf3ce44SJohn Forte return (0); 1725fcf3ce44SJohn Forte } 1726fcf3ce44SJohn Forte 1727fcf3ce44SJohn Forte 1728fcf3ce44SJohn Forte static int 1729fcf3ce44SJohn Forte svioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvalp) 1730fcf3ce44SJohn Forte { 1731fcf3ce44SJohn Forte char itmp1[12], itmp2[12]; /* temp char array for editing ints */ 1732fcf3ce44SJohn Forte spcs_s_info_t kstatus; /* Kernel version of spcs status */ 1733fcf3ce44SJohn Forte spcs_s_info_t ustatus; /* Address of user version of spcs status */ 1734fcf3ce44SJohn Forte sv_list32_t svl32; /* 32 bit Initial structure for SVIOC_LIST */ 1735fcf3ce44SJohn Forte sv_version_t svv; /* Version structure */ 1736fcf3ce44SJohn Forte sv_conf_t svc; /* User config structure */ 1737fcf3ce44SJohn Forte sv_list_t svl; /* Initial structure for SVIOC_LIST */ 1738fcf3ce44SJohn Forte void *usvn; /* Address of user sv_name_t */ 1739fcf3ce44SJohn Forte void *svn = NULL; /* Array for SVIOC_LIST */ 1740fcf3ce44SJohn Forte uint64_t phash; /* pathname hash */ 1741fcf3ce44SJohn Forte int rc = 0; /* Return code -- errno */ 1742fcf3ce44SJohn Forte int size; /* Number of items in array */ 1743fcf3ce44SJohn Forte int bytes; /* Byte size of array */ 1744fcf3ce44SJohn Forte int ilp32; /* Convert data structures for ilp32 userland */ 1745fcf3ce44SJohn Forte 1746fcf3ce44SJohn Forte *rvalp = 0; 1747fcf3ce44SJohn Forte 1748fcf3ce44SJohn Forte /* 1749fcf3ce44SJohn Forte * If sv_mod_status is 0 or SV_PREVENT_UNLOAD, then it will continue. 1750fcf3ce44SJohn Forte * else it means it previously was SV_PREVENT_UNLOAD, and now it's 1751fcf3ce44SJohn Forte * SV_ALLOW_UNLOAD, expecting the driver to eventually unload. 1752fcf3ce44SJohn Forte * 1753fcf3ce44SJohn Forte * SV_ALLOW_UNLOAD is final state, so no need to grab sv_mutex. 1754fcf3ce44SJohn Forte */ 1755fcf3ce44SJohn Forte if (sv_mod_status == SV_ALLOW_UNLOAD) { 1756fcf3ce44SJohn Forte return (EBUSY); 1757fcf3ce44SJohn Forte } 1758fcf3ce44SJohn Forte 1759fcf3ce44SJohn Forte if ((cmd != SVIOC_LIST) && ((rc = drv_priv(crp)) != 0)) 1760fcf3ce44SJohn Forte return (rc); 1761fcf3ce44SJohn Forte 1762fcf3ce44SJohn Forte kstatus = spcs_s_kcreate(); 1763fcf3ce44SJohn Forte if (!kstatus) { 17643270659fSSrikanth, Ramana DTRACE_PROBE1(sv_ioctl_err_kcreate, dev_t, dev); 1765fcf3ce44SJohn Forte return (ENOMEM); 1766fcf3ce44SJohn Forte } 1767fcf3ce44SJohn Forte 1768fcf3ce44SJohn Forte ilp32 = (ddi_model_convert_from((mode & FMODELS)) == DDI_MODEL_ILP32); 1769fcf3ce44SJohn Forte 1770fcf3ce44SJohn Forte switch (cmd) { 1771fcf3ce44SJohn Forte 1772fcf3ce44SJohn Forte case SVIOC_ENABLE: 1773fcf3ce44SJohn Forte 1774fcf3ce44SJohn Forte if (ilp32) { 1775fcf3ce44SJohn Forte sv_conf32_t svc32; 1776fcf3ce44SJohn Forte 1777fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &svc32, 1778fcf3ce44SJohn Forte sizeof (svc32), mode) < 0) { 1779fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1780fcf3ce44SJohn Forte return (EFAULT); 1781fcf3ce44SJohn Forte } 1782fcf3ce44SJohn Forte 1783fcf3ce44SJohn Forte svc.svc_error = (spcs_s_info_t)svc32.svc_error; 1784fcf3ce44SJohn Forte (void) strcpy(svc.svc_path, svc32.svc_path); 1785fcf3ce44SJohn Forte svc.svc_flag = svc32.svc_flag; 1786fcf3ce44SJohn Forte svc.svc_major = svc32.svc_major; 1787fcf3ce44SJohn Forte svc.svc_minor = svc32.svc_minor; 1788fcf3ce44SJohn Forte } else { 1789fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &svc, 1790fcf3ce44SJohn Forte sizeof (svc), mode) < 0) { 1791fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1792fcf3ce44SJohn Forte return (EFAULT); 1793fcf3ce44SJohn Forte } 1794fcf3ce44SJohn Forte } 1795fcf3ce44SJohn Forte 1796fcf3ce44SJohn Forte /* force to raw access */ 1797fcf3ce44SJohn Forte svc.svc_flag = NSC_DEVICE; 1798fcf3ce44SJohn Forte 1799fcf3ce44SJohn Forte if (sv_tset == NULL) { 1800fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1801fcf3ce44SJohn Forte 1802fcf3ce44SJohn Forte if (sv_tset == NULL) { 1803fcf3ce44SJohn Forte sv_tset = nst_init("sv_thr", sv_threads); 1804fcf3ce44SJohn Forte } 1805fcf3ce44SJohn Forte 1806fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1807fcf3ce44SJohn Forte 1808fcf3ce44SJohn Forte if (sv_tset == NULL) { 1809fcf3ce44SJohn Forte cmn_err(CE_WARN, 18103270659fSSrikanth, Ramana "!sv: could not allocate %d threads", 1811fcf3ce44SJohn Forte sv_threads); 1812fcf3ce44SJohn Forte } 1813fcf3ce44SJohn Forte } 1814fcf3ce44SJohn Forte 1815fcf3ce44SJohn Forte rc = sv_enable(svc.svc_path, svc.svc_flag, 18163270659fSSrikanth, Ramana makedevice(svc.svc_major, svc.svc_minor), kstatus); 1817fcf3ce44SJohn Forte 1818fcf3ce44SJohn Forte if (rc == 0) { 1819fcf3ce44SJohn Forte sv_config_time = nsc_lbolt(); 1820fcf3ce44SJohn Forte 1821fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1822fcf3ce44SJohn Forte sv_thread_tune(sv_threads_dev); 1823fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1824fcf3ce44SJohn Forte } 1825fcf3ce44SJohn Forte 18263270659fSSrikanth, Ramana DTRACE_PROBE3(sv_ioctl_end, dev_t, dev, int, *rvalp, int, rc); 1827fcf3ce44SJohn Forte 1828fcf3ce44SJohn Forte return (spcs_s_ocopyoutf(&kstatus, svc.svc_error, rc)); 1829fcf3ce44SJohn Forte /* NOTREACHED */ 1830fcf3ce44SJohn Forte 1831fcf3ce44SJohn Forte case SVIOC_DISABLE: 1832fcf3ce44SJohn Forte 1833fcf3ce44SJohn Forte if (ilp32) { 1834fcf3ce44SJohn Forte sv_conf32_t svc32; 1835fcf3ce44SJohn Forte 1836fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &svc32, 1837fcf3ce44SJohn Forte sizeof (svc32), mode) < 0) { 1838fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1839fcf3ce44SJohn Forte return (EFAULT); 1840fcf3ce44SJohn Forte } 1841fcf3ce44SJohn Forte 1842fcf3ce44SJohn Forte svc.svc_error = (spcs_s_info_t)svc32.svc_error; 1843fcf3ce44SJohn Forte svc.svc_major = svc32.svc_major; 1844fcf3ce44SJohn Forte svc.svc_minor = svc32.svc_minor; 1845fcf3ce44SJohn Forte (void) strcpy(svc.svc_path, svc32.svc_path); 1846fcf3ce44SJohn Forte svc.svc_flag = svc32.svc_flag; 1847fcf3ce44SJohn Forte } else { 1848fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &svc, 1849fcf3ce44SJohn Forte sizeof (svc), mode) < 0) { 1850fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1851fcf3ce44SJohn Forte return (EFAULT); 1852fcf3ce44SJohn Forte } 1853fcf3ce44SJohn Forte } 1854fcf3ce44SJohn Forte 1855fcf3ce44SJohn Forte if (svc.svc_major == (major_t)-1 && 1856fcf3ce44SJohn Forte svc.svc_minor == (minor_t)-1) { 1857fcf3ce44SJohn Forte sv_dev_t *svp; 1858fcf3ce44SJohn Forte int i; 1859fcf3ce44SJohn Forte 1860fcf3ce44SJohn Forte /* 1861fcf3ce44SJohn Forte * User level could not find the minor device 1862fcf3ce44SJohn Forte * node, so do this the slow way by searching 1863fcf3ce44SJohn Forte * the entire sv config for a matching pathname. 1864fcf3ce44SJohn Forte */ 1865fcf3ce44SJohn Forte 1866fcf3ce44SJohn Forte phash = nsc_strhash(svc.svc_path); 1867fcf3ce44SJohn Forte 1868fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1869fcf3ce44SJohn Forte 1870fcf3ce44SJohn Forte for (i = 0; i < sv_max_devices; i++) { 1871fcf3ce44SJohn Forte svp = &sv_devs[i]; 1872fcf3ce44SJohn Forte 1873fcf3ce44SJohn Forte if (svp->sv_state == SV_DISABLE || 1874fcf3ce44SJohn Forte svp->sv_fd == NULL) 1875fcf3ce44SJohn Forte continue; 1876fcf3ce44SJohn Forte 1877fcf3ce44SJohn Forte if (nsc_fdpathcmp(svp->sv_fd, phash, 1878fcf3ce44SJohn Forte svc.svc_path) == 0) { 1879fcf3ce44SJohn Forte svc.svc_major = getmajor(svp->sv_dev); 1880fcf3ce44SJohn Forte svc.svc_minor = getminor(svp->sv_dev); 1881fcf3ce44SJohn Forte break; 1882fcf3ce44SJohn Forte } 1883fcf3ce44SJohn Forte } 1884fcf3ce44SJohn Forte 1885fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1886fcf3ce44SJohn Forte 1887fcf3ce44SJohn Forte if (svc.svc_major == (major_t)-1 && 1888fcf3ce44SJohn Forte svc.svc_minor == (minor_t)-1) 1889fcf3ce44SJohn Forte return (spcs_s_ocopyoutf(&kstatus, 1890fcf3ce44SJohn Forte svc.svc_error, SV_ENODEV)); 1891fcf3ce44SJohn Forte } 1892fcf3ce44SJohn Forte 1893fcf3ce44SJohn Forte rc = sv_disable(makedevice(svc.svc_major, svc.svc_minor), 1894fcf3ce44SJohn Forte kstatus); 1895fcf3ce44SJohn Forte 1896fcf3ce44SJohn Forte if (rc == 0) { 1897fcf3ce44SJohn Forte sv_config_time = nsc_lbolt(); 1898fcf3ce44SJohn Forte 1899fcf3ce44SJohn Forte mutex_enter(&sv_mutex); 1900fcf3ce44SJohn Forte sv_thread_tune(-sv_threads_dev); 1901fcf3ce44SJohn Forte mutex_exit(&sv_mutex); 1902fcf3ce44SJohn Forte } 1903fcf3ce44SJohn Forte 19043270659fSSrikanth, Ramana DTRACE_PROBE3(sv_ioctl_2, dev_t, dev, int, *rvalp, int, rc); 1905fcf3ce44SJohn Forte 1906fcf3ce44SJohn Forte return (spcs_s_ocopyoutf(&kstatus, svc.svc_error, rc)); 1907fcf3ce44SJohn Forte /* NOTREACHED */ 1908fcf3ce44SJohn Forte 1909fcf3ce44SJohn Forte case SVIOC_LIST: 1910fcf3ce44SJohn Forte 1911fcf3ce44SJohn Forte if (ilp32) { 1912fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &svl32, 1913fcf3ce44SJohn Forte sizeof (svl32), mode) < 0) { 1914fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1915fcf3ce44SJohn Forte return (EFAULT); 1916fcf3ce44SJohn Forte } 1917fcf3ce44SJohn Forte 1918fcf3ce44SJohn Forte ustatus = (spcs_s_info_t)svl32.svl_error; 1919fcf3ce44SJohn Forte size = svl32.svl_count; 1920fcf3ce44SJohn Forte usvn = (void *)(unsigned long)svl32.svl_names; 1921fcf3ce44SJohn Forte } else { 1922fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &svl, 1923fcf3ce44SJohn Forte sizeof (svl), mode) < 0) { 1924fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1925fcf3ce44SJohn Forte return (EFAULT); 1926fcf3ce44SJohn Forte } 1927fcf3ce44SJohn Forte 1928fcf3ce44SJohn Forte ustatus = svl.svl_error; 1929fcf3ce44SJohn Forte size = svl.svl_count; 1930fcf3ce44SJohn Forte usvn = svl.svl_names; 1931fcf3ce44SJohn Forte } 1932fcf3ce44SJohn Forte 1933fcf3ce44SJohn Forte /* Do some boundary checking */ 1934fcf3ce44SJohn Forte if ((size < 0) || (size > sv_max_devices)) { 1935fcf3ce44SJohn Forte /* Array size is out of range */ 1936fcf3ce44SJohn Forte return (spcs_s_ocopyoutf(&kstatus, ustatus, 1937fcf3ce44SJohn Forte SV_EARRBOUNDS, "0", 1938fcf3ce44SJohn Forte spcs_s_inttostring(sv_max_devices, itmp1, 1939fcf3ce44SJohn Forte sizeof (itmp1), 0), 1940fcf3ce44SJohn Forte spcs_s_inttostring(size, itmp2, 1941fcf3ce44SJohn Forte sizeof (itmp2), 0))); 1942fcf3ce44SJohn Forte } 1943fcf3ce44SJohn Forte 1944fcf3ce44SJohn Forte if (ilp32) 1945fcf3ce44SJohn Forte bytes = size * sizeof (sv_name32_t); 1946fcf3ce44SJohn Forte else 1947fcf3ce44SJohn Forte bytes = size * sizeof (sv_name_t); 1948fcf3ce44SJohn Forte 1949fcf3ce44SJohn Forte /* Allocate memory for the array of structures */ 1950fcf3ce44SJohn Forte if (bytes != 0) { 1951fcf3ce44SJohn Forte svn = kmem_zalloc(bytes, KM_SLEEP); 1952fcf3ce44SJohn Forte if (!svn) { 1953fcf3ce44SJohn Forte return (spcs_s_ocopyoutf(&kstatus, 1954fcf3ce44SJohn Forte ustatus, ENOMEM)); 1955fcf3ce44SJohn Forte } 1956fcf3ce44SJohn Forte } 1957fcf3ce44SJohn Forte 1958fcf3ce44SJohn Forte rc = sv_list(svn, size, rvalp, ilp32); 1959fcf3ce44SJohn Forte if (rc) { 1960fcf3ce44SJohn Forte if (svn != NULL) 1961fcf3ce44SJohn Forte kmem_free(svn, bytes); 1962fcf3ce44SJohn Forte return (spcs_s_ocopyoutf(&kstatus, ustatus, rc)); 1963fcf3ce44SJohn Forte } 1964fcf3ce44SJohn Forte 1965fcf3ce44SJohn Forte if (ilp32) { 1966fcf3ce44SJohn Forte svl32.svl_timestamp = (uint32_t)sv_config_time; 1967fcf3ce44SJohn Forte svl32.svl_maxdevs = (int32_t)sv_max_devices; 1968fcf3ce44SJohn Forte 1969fcf3ce44SJohn Forte /* Return the list structure */ 1970fcf3ce44SJohn Forte if (ddi_copyout(&svl32, (void *)arg, 1971fcf3ce44SJohn Forte sizeof (svl32), mode) < 0) { 1972fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1973fcf3ce44SJohn Forte if (svn != NULL) 1974fcf3ce44SJohn Forte kmem_free(svn, bytes); 1975fcf3ce44SJohn Forte return (EFAULT); 1976fcf3ce44SJohn Forte } 1977fcf3ce44SJohn Forte } else { 1978fcf3ce44SJohn Forte svl.svl_timestamp = sv_config_time; 1979fcf3ce44SJohn Forte svl.svl_maxdevs = sv_max_devices; 1980fcf3ce44SJohn Forte 1981fcf3ce44SJohn Forte /* Return the list structure */ 1982fcf3ce44SJohn Forte if (ddi_copyout(&svl, (void *)arg, 1983fcf3ce44SJohn Forte sizeof (svl), mode) < 0) { 1984fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1985fcf3ce44SJohn Forte if (svn != NULL) 1986fcf3ce44SJohn Forte kmem_free(svn, bytes); 1987fcf3ce44SJohn Forte return (EFAULT); 1988fcf3ce44SJohn Forte } 1989fcf3ce44SJohn Forte } 1990fcf3ce44SJohn Forte 1991fcf3ce44SJohn Forte /* Return the array */ 1992fcf3ce44SJohn Forte if (svn != NULL) { 1993fcf3ce44SJohn Forte if (ddi_copyout(svn, usvn, bytes, mode) < 0) { 1994fcf3ce44SJohn Forte kmem_free(svn, bytes); 1995fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 1996fcf3ce44SJohn Forte return (EFAULT); 1997fcf3ce44SJohn Forte } 1998fcf3ce44SJohn Forte kmem_free(svn, bytes); 1999fcf3ce44SJohn Forte } 2000fcf3ce44SJohn Forte 20013270659fSSrikanth, Ramana DTRACE_PROBE3(sv_ioctl_3, dev_t, dev, int, *rvalp, int, 0); 2002fcf3ce44SJohn Forte 2003fcf3ce44SJohn Forte return (spcs_s_ocopyoutf(&kstatus, ustatus, 0)); 2004fcf3ce44SJohn Forte /* NOTREACHED */ 2005fcf3ce44SJohn Forte 2006fcf3ce44SJohn Forte case SVIOC_VERSION: 2007fcf3ce44SJohn Forte 2008fcf3ce44SJohn Forte if (ilp32) { 2009fcf3ce44SJohn Forte sv_version32_t svv32; 2010fcf3ce44SJohn Forte 2011fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &svv32, 2012fcf3ce44SJohn Forte sizeof (svv32), mode) < 0) { 2013fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 2014fcf3ce44SJohn Forte return (EFAULT); 2015fcf3ce44SJohn Forte } 2016fcf3ce44SJohn Forte 2017fcf3ce44SJohn Forte svv32.svv_major_rev = sv_major_rev; 2018fcf3ce44SJohn Forte svv32.svv_minor_rev = sv_minor_rev; 2019fcf3ce44SJohn Forte svv32.svv_micro_rev = sv_micro_rev; 2020fcf3ce44SJohn Forte svv32.svv_baseline_rev = sv_baseline_rev; 2021fcf3ce44SJohn Forte 2022fcf3ce44SJohn Forte if (ddi_copyout(&svv32, (void *)arg, 2023fcf3ce44SJohn Forte sizeof (svv32), mode) < 0) { 2024fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 2025fcf3ce44SJohn Forte return (EFAULT); 2026fcf3ce44SJohn Forte } 2027fcf3ce44SJohn Forte 2028fcf3ce44SJohn Forte ustatus = (spcs_s_info_t)svv32.svv_error; 2029fcf3ce44SJohn Forte } else { 2030fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &svv, 2031fcf3ce44SJohn Forte sizeof (svv), mode) < 0) { 2032fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 2033fcf3ce44SJohn Forte return (EFAULT); 2034fcf3ce44SJohn Forte } 2035fcf3ce44SJohn Forte 2036fcf3ce44SJohn Forte svv.svv_major_rev = sv_major_rev; 2037fcf3ce44SJohn Forte svv.svv_minor_rev = sv_minor_rev; 2038fcf3ce44SJohn Forte svv.svv_micro_rev = sv_micro_rev; 2039fcf3ce44SJohn Forte svv.svv_baseline_rev = sv_baseline_rev; 2040fcf3ce44SJohn Forte 2041fcf3ce44SJohn Forte if (ddi_copyout(&svv, (void *)arg, 2042fcf3ce44SJohn Forte sizeof (svv), mode) < 0) { 2043fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 2044fcf3ce44SJohn Forte return (EFAULT); 2045fcf3ce44SJohn Forte } 2046fcf3ce44SJohn Forte 2047fcf3ce44SJohn Forte ustatus = svv.svv_error; 2048fcf3ce44SJohn Forte } 2049fcf3ce44SJohn Forte 20503270659fSSrikanth, Ramana DTRACE_PROBE3(sv_ioctl_4, dev_t, dev, int, *rvalp, int, 0); 2051fcf3ce44SJohn Forte 2052fcf3ce44SJohn Forte return (spcs_s_ocopyoutf(&kstatus, ustatus, 0)); 2053fcf3ce44SJohn Forte /* NOTREACHED */ 2054fcf3ce44SJohn Forte 2055fcf3ce44SJohn Forte case SVIOC_UNLOAD: 2056fcf3ce44SJohn Forte rc = sv_prepare_unload(); 2057fcf3ce44SJohn Forte 20583270659fSSrikanth, Ramana if (ddi_copyout(&rc, (void *)arg, sizeof (rc), mode) < 0) { 2059fcf3ce44SJohn Forte rc = EFAULT; 2060fcf3ce44SJohn Forte } 2061fcf3ce44SJohn Forte 2062fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 2063fcf3ce44SJohn Forte return (rc); 2064fcf3ce44SJohn Forte 2065fcf3ce44SJohn Forte default: 2066fcf3ce44SJohn Forte spcs_s_kfree(kstatus); 2067fcf3ce44SJohn Forte 20683270659fSSrikanth, Ramana DTRACE_PROBE3(sv_ioctl_4, dev_t, dev, int, *rvalp, int, EINVAL); 2069fcf3ce44SJohn Forte 2070fcf3ce44SJohn Forte return (EINVAL); 2071fcf3ce44SJohn Forte /* NOTREACHED */ 2072fcf3ce44SJohn Forte } 2073fcf3ce44SJohn Forte 2074fcf3ce44SJohn Forte /* NOTREACHED */ 2075fcf3ce44SJohn Forte } 2076fcf3ce44SJohn Forte 2077fcf3ce44SJohn Forte 2078fcf3ce44SJohn Forte /* ARGSUSED */ 2079fcf3ce44SJohn Forte static int 2080fcf3ce44SJohn Forte svprint(dev_t dev, char *str) 2081fcf3ce44SJohn Forte { 2082fcf3ce44SJohn Forte int instance = ddi_get_instance(sv_dip); 20833270659fSSrikanth, Ramana cmn_err(CE_WARN, "!%s%d: %s", ddi_get_name(sv_dip), instance, str); 2084fcf3ce44SJohn Forte return (0); 2085fcf3ce44SJohn Forte } 2086fcf3ce44SJohn Forte 2087fcf3ce44SJohn Forte 2088fcf3ce44SJohn Forte static void 2089fcf3ce44SJohn Forte _sv_lyr_strategy(struct buf *bp) 2090fcf3ce44SJohn Forte { 2091fcf3ce44SJohn Forte caddr_t buf_addr; /* pointer to linear buffer in bp */ 2092fcf3ce44SJohn Forte nsc_buf_t *bufh = NULL; 2093fcf3ce44SJohn Forte nsc_buf_t *hndl = NULL; 2094fcf3ce44SJohn Forte sv_dev_t *svp; 2095fcf3ce44SJohn Forte nsc_vec_t *v; 2096fcf3ce44SJohn Forte sv_maj_t *maj; 2097fcf3ce44SJohn Forte nsc_size_t fba_req, fba_len; /* FBA lengths */ 2098fcf3ce44SJohn Forte nsc_off_t fba_off; /* FBA offset */ 2099fcf3ce44SJohn Forte size_t tocopy, nbytes; /* byte lengths */ 2100fcf3ce44SJohn Forte int rw, rc; /* flags and return codes */ 2101fcf3ce44SJohn Forte int (*fn)(); 2102fcf3ce44SJohn Forte 2103fcf3ce44SJohn Forte rc = 0; 2104fcf3ce44SJohn Forte 2105fcf3ce44SJohn Forte if (sv_debug > 5) 21063270659fSSrikanth, Ramana cmn_err(CE_CONT, "!_sv_lyr_strategy(%p)\n", (void *)bp); 2107fcf3ce44SJohn Forte 2108fcf3ce44SJohn Forte svp = sv_find_enabled(bp->b_edev, &maj); 2109fcf3ce44SJohn Forte if (svp == NULL) { 2110fcf3ce44SJohn Forte if (maj && (fn = maj->sm_strategy) != 0) { 2111fcf3ce44SJohn Forte if (!(maj->sm_flag & D_MP)) { 2112fcf3ce44SJohn Forte UNSAFE_ENTER(); 2113fcf3ce44SJohn Forte rc = (*fn)(bp); 2114fcf3ce44SJohn Forte UNSAFE_EXIT(); 2115fcf3ce44SJohn Forte } else { 2116fcf3ce44SJohn Forte rc = (*fn)(bp); 2117fcf3ce44SJohn Forte } 2118fcf3ce44SJohn Forte return; 2119fcf3ce44SJohn Forte } else { 2120fcf3ce44SJohn Forte bioerror(bp, ENODEV); 2121fcf3ce44SJohn Forte biodone(bp); 2122fcf3ce44SJohn Forte return; 2123fcf3ce44SJohn Forte } 2124fcf3ce44SJohn Forte } 2125fcf3ce44SJohn Forte 2126fcf3ce44SJohn Forte ASSERT(RW_READ_HELD(&svp->sv_lock)); 2127fcf3ce44SJohn Forte 2128fcf3ce44SJohn Forte if (svp->sv_flag == 0) { 2129fcf3ce44SJohn Forte /* 2130fcf3ce44SJohn Forte * guard access mode 2131fcf3ce44SJohn Forte * - prevent user level access to the device 2132fcf3ce44SJohn Forte */ 21333270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_err_guard, struct buf *, bp); 2134fcf3ce44SJohn Forte bioerror(bp, EPERM); 2135fcf3ce44SJohn Forte goto out; 2136fcf3ce44SJohn Forte } 2137fcf3ce44SJohn Forte 2138fcf3ce44SJohn Forte if ((rc = sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH)) != 0) { 21393270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_err_rsrv, struct buf *, bp); 2140fcf3ce44SJohn Forte 2141fcf3ce44SJohn Forte if (rc == EINTR) 21423270659fSSrikanth, Ramana cmn_err(CE_WARN, "!nsc_reserve() returned EINTR"); 2143fcf3ce44SJohn Forte bioerror(bp, rc); 2144fcf3ce44SJohn Forte goto out; 2145fcf3ce44SJohn Forte } 2146fcf3ce44SJohn Forte 2147fcf3ce44SJohn Forte if (bp->b_lblkno >= (diskaddr_t)svp->sv_nblocks) { 21483270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_eof, struct buf *, bp); 2149fcf3ce44SJohn Forte 2150fcf3ce44SJohn Forte if (bp->b_flags & B_READ) { 2151fcf3ce44SJohn Forte /* return EOF, not an error */ 2152fcf3ce44SJohn Forte bp->b_resid = bp->b_bcount; 2153fcf3ce44SJohn Forte bioerror(bp, 0); 2154fcf3ce44SJohn Forte } else 2155fcf3ce44SJohn Forte bioerror(bp, EINVAL); 2156fcf3ce44SJohn Forte 2157fcf3ce44SJohn Forte goto done; 2158fcf3ce44SJohn Forte } 2159fcf3ce44SJohn Forte 2160fcf3ce44SJohn Forte /* 2161fcf3ce44SJohn Forte * Preallocate a handle once per call to strategy. 2162fcf3ce44SJohn Forte * If this fails, then the nsc_alloc_buf() will allocate 2163fcf3ce44SJohn Forte * a temporary handle per allocation/free pair. 2164fcf3ce44SJohn Forte */ 2165fcf3ce44SJohn Forte 21663270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_alloch_start, sv_dev_t *, svp); 2167fcf3ce44SJohn Forte 2168fcf3ce44SJohn Forte bufh = nsc_alloc_handle(svp->sv_fd, NULL, NULL, NULL); 2169fcf3ce44SJohn Forte 21703270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_alloch_end, sv_dev_t *, svp); 2171fcf3ce44SJohn Forte 2172fcf3ce44SJohn Forte if (bufh && (bufh->sb_flag & NSC_HACTIVE) != 0) { 21733270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_err_hactive, struct buf *, bp); 2174fcf3ce44SJohn Forte 2175fcf3ce44SJohn Forte cmn_err(CE_WARN, 21763270659fSSrikanth, Ramana "!sv: allocated active handle (bufh %p, flags %x)", 2177fcf3ce44SJohn Forte (void *)bufh, bufh->sb_flag); 2178fcf3ce44SJohn Forte 2179fcf3ce44SJohn Forte bioerror(bp, ENXIO); 2180fcf3ce44SJohn Forte goto done; 2181fcf3ce44SJohn Forte } 2182fcf3ce44SJohn Forte 2183fcf3ce44SJohn Forte fba_req = FBA_LEN(bp->b_bcount); 2184fcf3ce44SJohn Forte if (fba_req + bp->b_lblkno > (diskaddr_t)svp->sv_nblocks) 2185fcf3ce44SJohn Forte fba_req = (nsc_size_t)(svp->sv_nblocks - bp->b_lblkno); 2186fcf3ce44SJohn Forte 2187fcf3ce44SJohn Forte rw = (bp->b_flags & B_READ) ? NSC_READ : NSC_WRITE; 2188fcf3ce44SJohn Forte 2189fcf3ce44SJohn Forte bp_mapin(bp); 2190fcf3ce44SJohn Forte 2191fcf3ce44SJohn Forte bp->b_resid = bp->b_bcount; 2192fcf3ce44SJohn Forte buf_addr = bp->b_un.b_addr; 2193fcf3ce44SJohn Forte fba_off = 0; 2194fcf3ce44SJohn Forte 2195fcf3ce44SJohn Forte /* 2196fcf3ce44SJohn Forte * fba_req - requested size of transfer in FBAs after 2197fcf3ce44SJohn Forte * truncation to device extent, and allowing for 2198fcf3ce44SJohn Forte * possible non-FBA bounded final chunk. 2199fcf3ce44SJohn Forte * fba_off - offset of start of chunk from start of bp in FBAs. 2200fcf3ce44SJohn Forte * fba_len - size of this chunk in FBAs. 2201fcf3ce44SJohn Forte */ 2202fcf3ce44SJohn Forte 2203fcf3ce44SJohn Forte loop: 2204fcf3ce44SJohn Forte fba_len = min(fba_req, svp->sv_maxfbas); 2205fcf3ce44SJohn Forte hndl = bufh; 2206fcf3ce44SJohn Forte 2207fcf3ce44SJohn Forte DTRACE_PROBE4(sv_dbg_allocb_start, 2208fcf3ce44SJohn Forte sv_dev_t *, svp, 2209fcf3ce44SJohn Forte uint64_t, (uint64_t)(bp->b_lblkno + fba_off), 2210fcf3ce44SJohn Forte uint64_t, (uint64_t)fba_len, 2211fcf3ce44SJohn Forte int, rw); 2212fcf3ce44SJohn Forte 2213fcf3ce44SJohn Forte rc = nsc_alloc_buf(svp->sv_fd, (nsc_off_t)(bp->b_lblkno + fba_off), 2214fcf3ce44SJohn Forte fba_len, rw, &hndl); 2215fcf3ce44SJohn Forte 22163270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_allocb_end, sv_dev_t *, svp); 2217fcf3ce44SJohn Forte 2218fcf3ce44SJohn Forte if (rc > 0) { 22193270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_err_alloc, struct buf *, bp); 2220fcf3ce44SJohn Forte bioerror(bp, rc); 2221fcf3ce44SJohn Forte if (hndl != bufh) 2222fcf3ce44SJohn Forte (void) nsc_free_buf(hndl); 2223fcf3ce44SJohn Forte hndl = NULL; 2224fcf3ce44SJohn Forte goto done; 2225fcf3ce44SJohn Forte } 2226fcf3ce44SJohn Forte 2227fcf3ce44SJohn Forte tocopy = min(FBA_SIZE(fba_len), bp->b_resid); 2228fcf3ce44SJohn Forte v = hndl->sb_vec; 2229fcf3ce44SJohn Forte 2230fcf3ce44SJohn Forte if (rw == NSC_WRITE && FBA_OFF(tocopy) != 0) { 2231fcf3ce44SJohn Forte /* 2232fcf3ce44SJohn Forte * Not overwriting all of the last FBA, so read in the 2233fcf3ce44SJohn Forte * old contents now before we overwrite it with the new 2234fcf3ce44SJohn Forte * data. 2235fcf3ce44SJohn Forte */ 2236fcf3ce44SJohn Forte 22373270659fSSrikanth, Ramana DTRACE_PROBE2(sv_dbg_read_start, sv_dev_t *, svp, 2238fcf3ce44SJohn Forte uint64_t, (uint64_t)(hndl->sb_pos + hndl->sb_len - 1)); 2239fcf3ce44SJohn Forte 2240fcf3ce44SJohn Forte rc = nsc_read(hndl, (hndl->sb_pos + hndl->sb_len - 1), 1, 0); 2241fcf3ce44SJohn Forte if (rc > 0) { 2242fcf3ce44SJohn Forte bioerror(bp, rc); 2243fcf3ce44SJohn Forte goto done; 2244fcf3ce44SJohn Forte } 2245fcf3ce44SJohn Forte 22463270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_read_end, sv_dev_t *, svp); 2247fcf3ce44SJohn Forte } 2248fcf3ce44SJohn Forte 22493270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_bcopy_start, sv_dev_t *, svp); 2250fcf3ce44SJohn Forte 2251fcf3ce44SJohn Forte while (tocopy > 0) { 2252fcf3ce44SJohn Forte nbytes = min(tocopy, (nsc_size_t)v->sv_len); 2253fcf3ce44SJohn Forte 2254fcf3ce44SJohn Forte if (bp->b_flags & B_READ) 2255fcf3ce44SJohn Forte (void) bcopy(v->sv_addr, buf_addr, nbytes); 2256fcf3ce44SJohn Forte else 2257fcf3ce44SJohn Forte (void) bcopy(buf_addr, v->sv_addr, nbytes); 2258fcf3ce44SJohn Forte 2259fcf3ce44SJohn Forte bp->b_resid -= nbytes; 2260fcf3ce44SJohn Forte buf_addr += nbytes; 2261fcf3ce44SJohn Forte tocopy -= nbytes; 2262fcf3ce44SJohn Forte v++; 2263fcf3ce44SJohn Forte } 2264fcf3ce44SJohn Forte 22653270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_bcopy_end, sv_dev_t *, svp); 2266fcf3ce44SJohn Forte 2267fcf3ce44SJohn Forte if ((bp->b_flags & B_READ) == 0) { 22683270659fSSrikanth, Ramana DTRACE_PROBE3(sv_dbg_write_start, sv_dev_t *, svp, 2269fcf3ce44SJohn Forte uint64_t, (uint64_t)hndl->sb_pos, 2270fcf3ce44SJohn Forte uint64_t, (uint64_t)hndl->sb_len); 2271fcf3ce44SJohn Forte 2272fcf3ce44SJohn Forte rc = nsc_write(hndl, hndl->sb_pos, hndl->sb_len, 0); 2273fcf3ce44SJohn Forte 22743270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_write_end, sv_dev_t *, svp); 2275fcf3ce44SJohn Forte 2276fcf3ce44SJohn Forte if (rc > 0) { 2277fcf3ce44SJohn Forte bioerror(bp, rc); 2278fcf3ce44SJohn Forte goto done; 2279fcf3ce44SJohn Forte } 2280fcf3ce44SJohn Forte } 2281fcf3ce44SJohn Forte 2282fcf3ce44SJohn Forte /* 2283fcf3ce44SJohn Forte * Adjust FBA offset and requested (ie. remaining) length, 2284fcf3ce44SJohn Forte * loop if more data to transfer. 2285fcf3ce44SJohn Forte */ 2286fcf3ce44SJohn Forte 2287fcf3ce44SJohn Forte fba_off += fba_len; 2288fcf3ce44SJohn Forte fba_req -= fba_len; 2289fcf3ce44SJohn Forte 2290fcf3ce44SJohn Forte if (fba_req > 0) { 22913270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_freeb_start, sv_dev_t *, svp); 2292fcf3ce44SJohn Forte 2293fcf3ce44SJohn Forte rc = nsc_free_buf(hndl); 2294fcf3ce44SJohn Forte 22953270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_freeb_end, sv_dev_t *, svp); 2296fcf3ce44SJohn Forte 2297fcf3ce44SJohn Forte if (rc > 0) { 2298fcf3ce44SJohn Forte DTRACE_PROBE1(sv_lyr_strategy_err_free, 2299fcf3ce44SJohn Forte struct buf *, bp); 2300fcf3ce44SJohn Forte bioerror(bp, rc); 2301fcf3ce44SJohn Forte } 2302fcf3ce44SJohn Forte 2303fcf3ce44SJohn Forte hndl = NULL; 2304fcf3ce44SJohn Forte 2305fcf3ce44SJohn Forte if (rc <= 0) 2306fcf3ce44SJohn Forte goto loop; 2307fcf3ce44SJohn Forte } 2308fcf3ce44SJohn Forte 2309fcf3ce44SJohn Forte done: 2310fcf3ce44SJohn Forte if (hndl != NULL) { 23113270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_freeb_start, sv_dev_t *, svp); 2312fcf3ce44SJohn Forte 2313fcf3ce44SJohn Forte rc = nsc_free_buf(hndl); 2314fcf3ce44SJohn Forte 23153270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_freeb_end, sv_dev_t *, svp); 2316fcf3ce44SJohn Forte 2317fcf3ce44SJohn Forte if (rc > 0) { 2318fcf3ce44SJohn Forte DTRACE_PROBE1(sv_lyr_strategy_err_free, 2319fcf3ce44SJohn Forte struct buf *, bp); 2320fcf3ce44SJohn Forte bioerror(bp, rc); 2321fcf3ce44SJohn Forte } 2322fcf3ce44SJohn Forte 2323fcf3ce44SJohn Forte hndl = NULL; 2324fcf3ce44SJohn Forte } 2325fcf3ce44SJohn Forte 2326fcf3ce44SJohn Forte if (bufh) 2327fcf3ce44SJohn Forte (void) nsc_free_handle(bufh); 2328fcf3ce44SJohn Forte 23293270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_rlse_start, sv_dev_t *, svp); 2330fcf3ce44SJohn Forte 2331fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 2332fcf3ce44SJohn Forte 23333270659fSSrikanth, Ramana DTRACE_PROBE1(sv_dbg_rlse_end, sv_dev_t *, svp); 2334fcf3ce44SJohn Forte 2335fcf3ce44SJohn Forte out: 2336fcf3ce44SJohn Forte if (sv_debug > 5) { 2337fcf3ce44SJohn Forte cmn_err(CE_CONT, 23383270659fSSrikanth, Ramana "!_sv_lyr_strategy: bp %p, bufh %p, bp->b_error %d\n", 2339fcf3ce44SJohn Forte (void *)bp, (void *)bufh, bp->b_error); 2340fcf3ce44SJohn Forte } 2341fcf3ce44SJohn Forte 23423270659fSSrikanth, Ramana DTRACE_PROBE2(sv_lyr_strategy_end, struct buf *, bp, int, bp->b_error); 2343fcf3ce44SJohn Forte 2344fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 2345fcf3ce44SJohn Forte biodone(bp); 2346fcf3ce44SJohn Forte } 2347fcf3ce44SJohn Forte 2348fcf3ce44SJohn Forte 2349fcf3ce44SJohn Forte static void 2350fcf3ce44SJohn Forte sv_async_strategy(blind_t arg) 2351fcf3ce44SJohn Forte { 2352fcf3ce44SJohn Forte struct buf *bp = (struct buf *)arg; 2353fcf3ce44SJohn Forte _sv_lyr_strategy(bp); 2354fcf3ce44SJohn Forte } 2355fcf3ce44SJohn Forte 2356fcf3ce44SJohn Forte 2357fcf3ce44SJohn Forte static int 2358fcf3ce44SJohn Forte sv_lyr_strategy(struct buf *bp) 2359fcf3ce44SJohn Forte { 2360fcf3ce44SJohn Forte nsthread_t *tp; 2361fcf3ce44SJohn Forte int nlive; 2362fcf3ce44SJohn Forte 2363fcf3ce44SJohn Forte /* 2364fcf3ce44SJohn Forte * If B_ASYNC was part of the DDI we could use it as a hint to 2365fcf3ce44SJohn Forte * not create a thread for synchronous i/o. 2366fcf3ce44SJohn Forte */ 2367fcf3ce44SJohn Forte if (sv_dev_to_sv(bp->b_edev, NULL) == NULL) { 2368fcf3ce44SJohn Forte /* not sv enabled - just pass through */ 23693270659fSSrikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_notsv, struct buf *, bp); 2370fcf3ce44SJohn Forte _sv_lyr_strategy(bp); 2371fcf3ce44SJohn Forte return (0); 2372fcf3ce44SJohn Forte } 2373fcf3ce44SJohn Forte 2374fcf3ce44SJohn Forte if (sv_debug > 4) { 23753270659fSSrikanth, Ramana cmn_err(CE_CONT, "!sv_lyr_strategy: nthread %d nlive %d\n", 2376fcf3ce44SJohn Forte nst_nthread(sv_tset), nst_nlive(sv_tset)); 2377fcf3ce44SJohn Forte } 2378fcf3ce44SJohn Forte 2379fcf3ce44SJohn Forte /* 2380fcf3ce44SJohn Forte * If there are only guard devices enabled there 2381fcf3ce44SJohn Forte * won't be a threadset, so don't try and use it. 2382fcf3ce44SJohn Forte */ 2383fcf3ce44SJohn Forte tp = NULL; 2384fcf3ce44SJohn Forte if (sv_tset != NULL) { 2385fcf3ce44SJohn Forte tp = nst_create(sv_tset, sv_async_strategy, (blind_t)bp, 0); 2386fcf3ce44SJohn Forte } 2387fcf3ce44SJohn Forte 2388fcf3ce44SJohn Forte if (tp == NULL) { 2389fcf3ce44SJohn Forte /* 2390fcf3ce44SJohn Forte * out of threads, so fall back to synchronous io. 2391fcf3ce44SJohn Forte */ 2392fcf3ce44SJohn Forte if (sv_debug > 0) { 2393fcf3ce44SJohn Forte cmn_err(CE_CONT, 23943270659fSSrikanth, Ramana "!sv_lyr_strategy: thread alloc failed\n"); 2395fcf3ce44SJohn Forte } 2396fcf3ce44SJohn Forte 2397fcf3ce44SJohn Forte DTRACE_PROBE1(sv_lyr_strategy_no_thread, 2398fcf3ce44SJohn Forte struct buf *, bp); 2399fcf3ce44SJohn Forte 2400fcf3ce44SJohn Forte _sv_lyr_strategy(bp); 2401fcf3ce44SJohn Forte sv_no_threads++; 2402fcf3ce44SJohn Forte } else { 2403fcf3ce44SJohn Forte nlive = nst_nlive(sv_tset); 2404fcf3ce44SJohn Forte if (nlive > sv_max_nlive) { 2405fcf3ce44SJohn Forte if (sv_debug > 0) { 2406fcf3ce44SJohn Forte cmn_err(CE_CONT, 24073270659fSSrikanth, Ramana "!sv_lyr_strategy: " 2408fcf3ce44SJohn Forte "new max nlive %d (nthread %d)\n", 2409fcf3ce44SJohn Forte nlive, nst_nthread(sv_tset)); 2410fcf3ce44SJohn Forte } 2411fcf3ce44SJohn Forte 2412fcf3ce44SJohn Forte sv_max_nlive = nlive; 2413fcf3ce44SJohn Forte } 2414fcf3ce44SJohn Forte } 2415fcf3ce44SJohn Forte 2416fcf3ce44SJohn Forte return (0); 2417fcf3ce44SJohn Forte } 2418fcf3ce44SJohn Forte 2419fcf3ce44SJohn Forte /* 2420fcf3ce44SJohn Forte * re-write the size of the current partition 2421fcf3ce44SJohn Forte */ 2422fcf3ce44SJohn Forte static int 2423fcf3ce44SJohn Forte sv_fix_dkiocgvtoc(const intptr_t arg, const int mode, sv_dev_t *svp) 2424fcf3ce44SJohn Forte { 2425fcf3ce44SJohn Forte size_t offset; 2426fcf3ce44SJohn Forte int ilp32; 2427fcf3ce44SJohn Forte int pnum; 2428fcf3ce44SJohn Forte int rc; 2429fcf3ce44SJohn Forte 2430fcf3ce44SJohn Forte ilp32 = (ddi_model_convert_from((mode & FMODELS)) == DDI_MODEL_ILP32); 2431fcf3ce44SJohn Forte 2432fcf3ce44SJohn Forte rc = nskern_partition(svp->sv_dev, &pnum); 2433fcf3ce44SJohn Forte if (rc != 0) { 2434fcf3ce44SJohn Forte return (rc); 2435fcf3ce44SJohn Forte } 2436fcf3ce44SJohn Forte 2437fcf3ce44SJohn Forte if (pnum < 0 || pnum >= V_NUMPAR) { 2438fcf3ce44SJohn Forte cmn_err(CE_WARN, 24393270659fSSrikanth, Ramana "!sv_gvtoc: unable to determine partition number " 2440fcf3ce44SJohn Forte "for dev %lx", svp->sv_dev); 2441fcf3ce44SJohn Forte return (EINVAL); 2442fcf3ce44SJohn Forte } 2443fcf3ce44SJohn Forte 2444fcf3ce44SJohn Forte if (ilp32) { 2445fcf3ce44SJohn Forte int32_t p_size; 2446fcf3ce44SJohn Forte 2447fcf3ce44SJohn Forte #ifdef _SunOS_5_6 2448fcf3ce44SJohn Forte offset = offsetof(struct vtoc, v_part); 2449fcf3ce44SJohn Forte offset += sizeof (struct partition) * pnum; 2450fcf3ce44SJohn Forte offset += offsetof(struct partition, p_size); 2451fcf3ce44SJohn Forte #else 2452fcf3ce44SJohn Forte offset = offsetof(struct vtoc32, v_part); 2453fcf3ce44SJohn Forte offset += sizeof (struct partition32) * pnum; 2454fcf3ce44SJohn Forte offset += offsetof(struct partition32, p_size); 2455fcf3ce44SJohn Forte #endif 2456fcf3ce44SJohn Forte 2457fcf3ce44SJohn Forte p_size = (int32_t)svp->sv_nblocks; 2458fcf3ce44SJohn Forte if (p_size == 0) { 2459fcf3ce44SJohn Forte if (sv_reserve(svp->sv_fd, 2460fcf3ce44SJohn Forte NSC_MULTI|NSC_PCATCH) == 0) { 2461fcf3ce44SJohn Forte p_size = (int32_t)svp->sv_nblocks; 2462fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 2463fcf3ce44SJohn Forte } else { 2464fcf3ce44SJohn Forte rc = EINTR; 2465fcf3ce44SJohn Forte } 2466fcf3ce44SJohn Forte } 2467fcf3ce44SJohn Forte 2468fcf3ce44SJohn Forte if ((rc == 0) && ddi_copyout(&p_size, (void *)(arg + offset), 2469fcf3ce44SJohn Forte sizeof (p_size), mode) != 0) { 2470fcf3ce44SJohn Forte rc = EFAULT; 2471fcf3ce44SJohn Forte } 2472fcf3ce44SJohn Forte } else { 2473fcf3ce44SJohn Forte long p_size; 2474fcf3ce44SJohn Forte 2475fcf3ce44SJohn Forte offset = offsetof(struct vtoc, v_part); 2476fcf3ce44SJohn Forte offset += sizeof (struct partition) * pnum; 2477fcf3ce44SJohn Forte offset += offsetof(struct partition, p_size); 2478fcf3ce44SJohn Forte 2479fcf3ce44SJohn Forte p_size = (long)svp->sv_nblocks; 2480fcf3ce44SJohn Forte if (p_size == 0) { 2481fcf3ce44SJohn Forte if (sv_reserve(svp->sv_fd, 2482fcf3ce44SJohn Forte NSC_MULTI|NSC_PCATCH) == 0) { 2483fcf3ce44SJohn Forte p_size = (long)svp->sv_nblocks; 2484fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 2485fcf3ce44SJohn Forte } else { 2486fcf3ce44SJohn Forte rc = EINTR; 2487fcf3ce44SJohn Forte } 2488fcf3ce44SJohn Forte } 2489fcf3ce44SJohn Forte 2490fcf3ce44SJohn Forte if ((rc == 0) && ddi_copyout(&p_size, (void *)(arg + offset), 2491fcf3ce44SJohn Forte sizeof (p_size), mode) != 0) { 2492fcf3ce44SJohn Forte rc = EFAULT; 2493fcf3ce44SJohn Forte } 2494fcf3ce44SJohn Forte } 2495fcf3ce44SJohn Forte 2496fcf3ce44SJohn Forte return (rc); 2497fcf3ce44SJohn Forte } 2498fcf3ce44SJohn Forte 2499fcf3ce44SJohn Forte 2500fcf3ce44SJohn Forte #ifdef DKIOCPARTITION 2501fcf3ce44SJohn Forte /* 2502fcf3ce44SJohn Forte * re-write the size of the current partition 2503fcf3ce44SJohn Forte * 2504fcf3ce44SJohn Forte * arg is dk_efi_t. 2505fcf3ce44SJohn Forte * 2506fcf3ce44SJohn Forte * dk_efi_t->dki_data = (void *)(uintptr_t)efi.dki_data_64; 2507fcf3ce44SJohn Forte * 2508fcf3ce44SJohn Forte * dk_efi_t->dki_data --> efi_gpt_t (label header) 2509fcf3ce44SJohn Forte * dk_efi_t->dki_data + 1 --> efi_gpe_t[] (array of partitions) 2510fcf3ce44SJohn Forte * 2511fcf3ce44SJohn Forte * efi_gpt_t->efi_gpt_PartitionEntryArrayCRC32 --> CRC32 of array of parts 2512fcf3ce44SJohn Forte * efi_gpt_t->efi_gpt_HeaderCRC32 --> CRC32 of header itself 2513fcf3ce44SJohn Forte * 2514fcf3ce44SJohn Forte * This assumes that sizeof (efi_gpt_t) is the same as the size of a 2515fcf3ce44SJohn Forte * logical block on the disk. 2516fcf3ce44SJohn Forte * 2517fcf3ce44SJohn Forte * Everything is little endian (i.e. disk format). 2518fcf3ce44SJohn Forte */ 2519fcf3ce44SJohn Forte static int 2520fcf3ce44SJohn Forte sv_fix_dkiocgetefi(const intptr_t arg, const int mode, sv_dev_t *svp) 2521fcf3ce44SJohn Forte { 2522fcf3ce44SJohn Forte dk_efi_t efi; 2523fcf3ce44SJohn Forte efi_gpt_t gpt; 2524fcf3ce44SJohn Forte efi_gpe_t *gpe = NULL; 2525fcf3ce44SJohn Forte size_t sgpe; 2526fcf3ce44SJohn Forte uint64_t p_size; /* virtual partition size from nsctl */ 2527fcf3ce44SJohn Forte uint32_t crc; 2528fcf3ce44SJohn Forte int unparts; /* number of parts in user's array */ 2529fcf3ce44SJohn Forte int pnum; 2530fcf3ce44SJohn Forte int rc; 2531fcf3ce44SJohn Forte 2532fcf3ce44SJohn Forte rc = nskern_partition(svp->sv_dev, &pnum); 2533fcf3ce44SJohn Forte if (rc != 0) { 2534fcf3ce44SJohn Forte return (rc); 2535fcf3ce44SJohn Forte } 2536fcf3ce44SJohn Forte 2537fcf3ce44SJohn Forte if (pnum < 0) { 2538fcf3ce44SJohn Forte cmn_err(CE_WARN, 25393270659fSSrikanth, Ramana "!sv_efi: unable to determine partition number for dev %lx", 2540fcf3ce44SJohn Forte svp->sv_dev); 2541fcf3ce44SJohn Forte return (EINVAL); 2542fcf3ce44SJohn Forte } 2543fcf3ce44SJohn Forte 2544fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &efi, sizeof (efi), mode)) { 2545fcf3ce44SJohn Forte return (EFAULT); 2546fcf3ce44SJohn Forte } 2547fcf3ce44SJohn Forte 2548fcf3ce44SJohn Forte efi.dki_data = (void *)(uintptr_t)efi.dki_data_64; 2549fcf3ce44SJohn Forte 2550fcf3ce44SJohn Forte if (efi.dki_length < sizeof (gpt) + sizeof (gpe)) { 2551fcf3ce44SJohn Forte return (EINVAL); 2552fcf3ce44SJohn Forte } 2553fcf3ce44SJohn Forte 2554fcf3ce44SJohn Forte if (ddi_copyin((void *)efi.dki_data, &gpt, sizeof (gpt), mode)) { 2555fcf3ce44SJohn Forte rc = EFAULT; 2556fcf3ce44SJohn Forte goto out; 2557fcf3ce44SJohn Forte } 2558fcf3ce44SJohn Forte 2559fcf3ce44SJohn Forte if ((unparts = LE_32(gpt.efi_gpt_NumberOfPartitionEntries)) == 0) 2560fcf3ce44SJohn Forte unparts = 1; 2561fcf3ce44SJohn Forte else if (pnum >= unparts) { 2562fcf3ce44SJohn Forte cmn_err(CE_WARN, 25633270659fSSrikanth, Ramana "!sv_efi: partition# beyond end of user array (%d >= %d)", 2564fcf3ce44SJohn Forte pnum, unparts); 2565fcf3ce44SJohn Forte return (EINVAL); 2566fcf3ce44SJohn Forte } 2567fcf3ce44SJohn Forte 2568fcf3ce44SJohn Forte sgpe = sizeof (*gpe) * unparts; 2569fcf3ce44SJohn Forte gpe = kmem_alloc(sgpe, KM_SLEEP); 2570fcf3ce44SJohn Forte 2571fcf3ce44SJohn Forte if (ddi_copyin((void *)(efi.dki_data + 1), gpe, sgpe, mode)) { 2572fcf3ce44SJohn Forte rc = EFAULT; 2573fcf3ce44SJohn Forte goto out; 2574fcf3ce44SJohn Forte } 2575fcf3ce44SJohn Forte 2576fcf3ce44SJohn Forte p_size = svp->sv_nblocks; 2577fcf3ce44SJohn Forte if (p_size == 0) { 2578fcf3ce44SJohn Forte if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) { 2579fcf3ce44SJohn Forte p_size = (diskaddr_t)svp->sv_nblocks; 2580fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 2581fcf3ce44SJohn Forte } else { 2582fcf3ce44SJohn Forte rc = EINTR; 2583fcf3ce44SJohn Forte } 2584fcf3ce44SJohn Forte } 2585fcf3ce44SJohn Forte 2586fcf3ce44SJohn Forte gpe[pnum].efi_gpe_EndingLBA = LE_64( 2587fcf3ce44SJohn Forte LE_64(gpe[pnum].efi_gpe_StartingLBA) + p_size - 1); 2588fcf3ce44SJohn Forte 2589fcf3ce44SJohn Forte gpt.efi_gpt_PartitionEntryArrayCRC32 = 0; 2590fcf3ce44SJohn Forte CRC32(crc, gpe, sgpe, -1U, sv_crc32_table); 2591fcf3ce44SJohn Forte gpt.efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc); 2592fcf3ce44SJohn Forte 2593fcf3ce44SJohn Forte gpt.efi_gpt_HeaderCRC32 = 0; 2594fcf3ce44SJohn Forte CRC32(crc, &gpt, sizeof (gpt), -1U, sv_crc32_table); 2595fcf3ce44SJohn Forte gpt.efi_gpt_HeaderCRC32 = LE_32(~crc); 2596fcf3ce44SJohn Forte 2597fcf3ce44SJohn Forte if ((rc == 0) && ddi_copyout(&gpt, efi.dki_data, sizeof (gpt), mode)) { 2598fcf3ce44SJohn Forte rc = EFAULT; 2599fcf3ce44SJohn Forte goto out; 2600fcf3ce44SJohn Forte } 2601fcf3ce44SJohn Forte 2602fcf3ce44SJohn Forte if ((rc == 0) && ddi_copyout(gpe, efi.dki_data + 1, sgpe, mode)) { 2603fcf3ce44SJohn Forte rc = EFAULT; 2604fcf3ce44SJohn Forte goto out; 2605fcf3ce44SJohn Forte } 2606fcf3ce44SJohn Forte 2607fcf3ce44SJohn Forte out: 2608fcf3ce44SJohn Forte if (gpe) { 2609fcf3ce44SJohn Forte kmem_free(gpe, sgpe); 2610fcf3ce44SJohn Forte } 2611fcf3ce44SJohn Forte 2612fcf3ce44SJohn Forte return (rc); 2613fcf3ce44SJohn Forte } 2614fcf3ce44SJohn Forte 2615fcf3ce44SJohn Forte 2616fcf3ce44SJohn Forte /* 2617fcf3ce44SJohn Forte * Re-write the size of the partition specified by p_partno 2618fcf3ce44SJohn Forte * 2619fcf3ce44SJohn Forte * Note that if a DKIOCPARTITION is issued to an fd opened against a 2620fcf3ce44SJohn Forte * non-sv'd device, but p_partno requests the size for a different 2621fcf3ce44SJohn Forte * device that is sv'd, this function will *not* be called as sv is 2622fcf3ce44SJohn Forte * not interposed on the original device (the fd). 2623fcf3ce44SJohn Forte * 2624fcf3ce44SJohn Forte * It would not be easy to change this as we cannot get the partition 2625fcf3ce44SJohn Forte * number for the non-sv'd device, so cannot compute the dev_t of the 2626fcf3ce44SJohn Forte * (sv'd) p_partno device, and so cannot find out if it is sv'd or get 2627fcf3ce44SJohn Forte * its size from nsctl. 2628fcf3ce44SJohn Forte * 2629fcf3ce44SJohn Forte * See also the "Bug 4755783" comment in sv_lyr_ioctl(). 2630fcf3ce44SJohn Forte */ 2631fcf3ce44SJohn Forte static int 2632fcf3ce44SJohn Forte sv_fix_dkiocpartition(const intptr_t arg, const int mode, sv_dev_t *svp) 2633fcf3ce44SJohn Forte { 2634fcf3ce44SJohn Forte struct partition64 p64; 2635fcf3ce44SJohn Forte sv_dev_t *nsvp = NULL; 2636fcf3ce44SJohn Forte diskaddr_t p_size; 2637fcf3ce44SJohn Forte minor_t nminor; 2638fcf3ce44SJohn Forte int pnum, rc; 2639fcf3ce44SJohn Forte dev_t ndev; 2640fcf3ce44SJohn Forte 2641fcf3ce44SJohn Forte rc = nskern_partition(svp->sv_dev, &pnum); 2642fcf3ce44SJohn Forte if (rc != 0) { 2643fcf3ce44SJohn Forte return (rc); 2644fcf3ce44SJohn Forte } 2645fcf3ce44SJohn Forte 2646fcf3ce44SJohn Forte if (ddi_copyin((void *)arg, &p64, sizeof (p64), mode)) { 2647fcf3ce44SJohn Forte return (EFAULT); 2648fcf3ce44SJohn Forte } 2649fcf3ce44SJohn Forte 2650fcf3ce44SJohn Forte if (p64.p_partno != pnum) { 2651fcf3ce44SJohn Forte /* switch to requested partition, not the current one */ 2652fcf3ce44SJohn Forte nminor = getminor(svp->sv_dev) + (p64.p_partno - pnum); 2653fcf3ce44SJohn Forte ndev = makedevice(getmajor(svp->sv_dev), nminor); 2654fcf3ce44SJohn Forte nsvp = sv_find_enabled(ndev, NULL); 2655fcf3ce44SJohn Forte if (nsvp == NULL) { 2656fcf3ce44SJohn Forte /* not sv device - just return */ 2657fcf3ce44SJohn Forte return (0); 2658fcf3ce44SJohn Forte } 2659fcf3ce44SJohn Forte 2660fcf3ce44SJohn Forte svp = nsvp; 2661fcf3ce44SJohn Forte } 2662fcf3ce44SJohn Forte 2663fcf3ce44SJohn Forte p_size = svp->sv_nblocks; 2664fcf3ce44SJohn Forte if (p_size == 0) { 2665fcf3ce44SJohn Forte if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) { 2666fcf3ce44SJohn Forte p_size = (diskaddr_t)svp->sv_nblocks; 2667fcf3ce44SJohn Forte nsc_release(svp->sv_fd); 2668fcf3ce44SJohn Forte } else { 2669fcf3ce44SJohn Forte rc = EINTR; 2670fcf3ce44SJohn Forte } 2671fcf3ce44SJohn Forte } 2672fcf3ce44SJohn Forte 2673fcf3ce44SJohn Forte if (nsvp != NULL) { 2674fcf3ce44SJohn Forte rw_exit(&nsvp->sv_lock); 2675fcf3ce44SJohn Forte } 2676fcf3ce44SJohn Forte 2677fcf3ce44SJohn Forte if ((rc == 0) && ddi_copyout(&p_size, 2678fcf3ce44SJohn Forte (void *)(arg + offsetof(struct partition64, p_size)), 2679fcf3ce44SJohn Forte sizeof (p_size), mode) != 0) { 2680fcf3ce44SJohn Forte return (EFAULT); 2681fcf3ce44SJohn Forte } 2682fcf3ce44SJohn Forte 2683fcf3ce44SJohn Forte return (rc); 2684fcf3ce44SJohn Forte } 2685fcf3ce44SJohn Forte #endif /* DKIOCPARTITION */ 2686fcf3ce44SJohn Forte 2687fcf3ce44SJohn Forte 2688fcf3ce44SJohn Forte static int 2689fcf3ce44SJohn Forte sv_lyr_ioctl(const dev_t dev, const int cmd, const intptr_t arg, 2690fcf3ce44SJohn Forte const int mode, cred_t *crp, int *rvalp) 2691fcf3ce44SJohn Forte { 2692fcf3ce44SJohn Forte sv_dev_t *svp; 2693fcf3ce44SJohn Forte sv_maj_t *maj; 2694fcf3ce44SJohn Forte int (*fn)(); 2695fcf3ce44SJohn Forte int rc = 0; 2696fcf3ce44SJohn Forte 2697fcf3ce44SJohn Forte maj = 0; 2698fcf3ce44SJohn Forte fn = 0; 2699fcf3ce44SJohn Forte 2700fcf3ce44SJohn Forte /* 2701fcf3ce44SJohn Forte * If sv_mod_status is 0 or SV_PREVENT_UNLOAD, then it will continue. 2702fcf3ce44SJohn Forte * else it means it previously was SV_PREVENT_UNLOAD, and now it's 2703fcf3ce44SJohn Forte * SV_ALLOW_UNLOAD, expecting the driver to eventually unload. 2704fcf3ce44SJohn Forte * 2705fcf3ce44SJohn Forte * SV_ALLOW_UNLOAD is final state, so no need to grab sv_mutex. 2706fcf3ce44SJohn Forte */ 2707fcf3ce44SJohn Forte if (sv_mod_status == SV_ALLOW_UNLOAD) { 2708fcf3ce44SJohn Forte return (EBUSY); 2709fcf3ce44SJohn Forte } 2710fcf3ce44SJohn Forte 2711fcf3ce44SJohn Forte svp = sv_find_enabled(dev, &maj); 2712fcf3ce44SJohn Forte if (svp != NULL) { 2713fcf3ce44SJohn Forte if (nskernd_isdaemon()) { 2714fcf3ce44SJohn Forte /* 2715fcf3ce44SJohn Forte * This is nskernd which always needs to see 2716fcf3ce44SJohn Forte * the underlying disk device accurately. 2717fcf3ce44SJohn Forte * 2718fcf3ce44SJohn Forte * So just pass the ioctl straight through 2719fcf3ce44SJohn Forte * to the underlying driver as though the device 2720fcf3ce44SJohn Forte * was not sv enabled. 2721fcf3ce44SJohn Forte */ 27223270659fSSrikanth, Ramana DTRACE_PROBE2(sv_lyr_ioctl_nskernd, sv_dev_t *, svp, 2723fcf3ce44SJohn Forte dev_t, dev); 2724fcf3ce44SJohn Forte 2725fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 2726fcf3ce44SJohn Forte svp = NULL; 2727fcf3ce44SJohn Forte } else { 2728fcf3ce44SJohn Forte ASSERT(RW_READ_HELD(&svp->sv_lock)); 2729fcf3ce44SJohn Forte } 2730fcf3ce44SJohn Forte } 2731fcf3ce44SJohn Forte 2732fcf3ce44SJohn Forte /* 2733fcf3ce44SJohn Forte * We now have a locked and enabled SV device, or a non-SV device. 2734fcf3ce44SJohn Forte */ 2735fcf3ce44SJohn Forte 2736fcf3ce44SJohn Forte switch (cmd) { 2737fcf3ce44SJohn Forte /* 2738fcf3ce44SJohn Forte * DKIOCGVTOC, DKIOCSVTOC, DKIOCPARTITION, DKIOCGETEFI 2739fcf3ce44SJohn Forte * and DKIOCSETEFI are intercepted and faked up as some 2740fcf3ce44SJohn Forte * i/o providers emulate volumes of a different size to 2741fcf3ce44SJohn Forte * the underlying volume. 2742fcf3ce44SJohn Forte * 2743fcf3ce44SJohn Forte * Setting the size by rewriting the vtoc is not permitted. 2744fcf3ce44SJohn Forte */ 2745fcf3ce44SJohn Forte 2746fcf3ce44SJohn Forte case DKIOCSVTOC: 2747fcf3ce44SJohn Forte #ifdef DKIOCPARTITION 2748fcf3ce44SJohn Forte case DKIOCSETEFI: 2749fcf3ce44SJohn Forte #endif 2750fcf3ce44SJohn Forte if (svp == NULL) { 2751fcf3ce44SJohn Forte /* not intercepted -- allow ioctl through */ 2752fcf3ce44SJohn Forte break; 2753fcf3ce44SJohn Forte } 2754fcf3ce44SJohn Forte 2755fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 2756fcf3ce44SJohn Forte 27573270659fSSrikanth, Ramana DTRACE_PROBE2(sv_lyr_ioctl_svtoc, dev_t, dev, int, EPERM); 2758fcf3ce44SJohn Forte 2759fcf3ce44SJohn Forte return (EPERM); 2760fcf3ce44SJohn Forte 2761fcf3ce44SJohn Forte default: 2762fcf3ce44SJohn Forte break; 2763fcf3ce44SJohn Forte } 2764fcf3ce44SJohn Forte 2765fcf3ce44SJohn Forte /* 2766fcf3ce44SJohn Forte * Pass through the real ioctl command. 2767fcf3ce44SJohn Forte */ 2768fcf3ce44SJohn Forte 2769fcf3ce44SJohn Forte if (maj && (fn = maj->sm_ioctl) != 0) { 2770fcf3ce44SJohn Forte if (!(maj->sm_flag & D_MP)) { 2771fcf3ce44SJohn Forte UNSAFE_ENTER(); 2772fcf3ce44SJohn Forte rc = (*fn)(dev, cmd, arg, mode, crp, rvalp); 2773fcf3ce44SJohn Forte UNSAFE_EXIT(); 2774fcf3ce44SJohn Forte } else { 2775fcf3ce44SJohn Forte rc = (*fn)(dev, cmd, arg, mode, crp, rvalp); 2776fcf3ce44SJohn Forte } 2777fcf3ce44SJohn Forte } else { 2778fcf3ce44SJohn Forte rc = ENODEV; 2779fcf3ce44SJohn Forte } 2780fcf3ce44SJohn Forte 2781fcf3ce44SJohn Forte /* 2782fcf3ce44SJohn Forte * Bug 4755783 2783fcf3ce44SJohn Forte * Fix up the size of the current partition to allow 2784fcf3ce44SJohn Forte * for the virtual volume to be a different size to the 2785fcf3ce44SJohn Forte * physical volume (e.g. for II compact dependent shadows). 2786fcf3ce44SJohn Forte * 2787fcf3ce44SJohn Forte * Note that this only attempts to fix up the current partition 2788fcf3ce44SJohn Forte * - the one that the ioctl was issued against. There could be 2789fcf3ce44SJohn Forte * other sv'd partitions in the same vtoc, but we cannot tell 2790fcf3ce44SJohn Forte * so we don't attempt to fix them up. 2791fcf3ce44SJohn Forte */ 2792fcf3ce44SJohn Forte 2793fcf3ce44SJohn Forte if (svp != NULL && rc == 0) { 2794fcf3ce44SJohn Forte switch (cmd) { 2795fcf3ce44SJohn Forte case DKIOCGVTOC: 2796fcf3ce44SJohn Forte rc = sv_fix_dkiocgvtoc(arg, mode, svp); 2797fcf3ce44SJohn Forte break; 2798fcf3ce44SJohn Forte 2799fcf3ce44SJohn Forte #ifdef DKIOCPARTITION 2800fcf3ce44SJohn Forte case DKIOCGETEFI: 2801fcf3ce44SJohn Forte rc = sv_fix_dkiocgetefi(arg, mode, svp); 2802fcf3ce44SJohn Forte break; 2803fcf3ce44SJohn Forte 2804fcf3ce44SJohn Forte case DKIOCPARTITION: 2805fcf3ce44SJohn Forte rc = sv_fix_dkiocpartition(arg, mode, svp); 2806fcf3ce44SJohn Forte break; 2807fcf3ce44SJohn Forte #endif /* DKIOCPARTITION */ 2808fcf3ce44SJohn Forte } 2809fcf3ce44SJohn Forte } 2810fcf3ce44SJohn Forte 2811fcf3ce44SJohn Forte if (svp != NULL) { 2812fcf3ce44SJohn Forte rw_exit(&svp->sv_lock); 2813fcf3ce44SJohn Forte } 2814fcf3ce44SJohn Forte 2815fcf3ce44SJohn Forte return (rc); 2816fcf3ce44SJohn Forte } 2817