fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * CDDL HEADER START
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The contents of this file are subject to the terms of the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Common Development and Distribution License (the "License").
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * You may not use this file except in compliance with the License.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * See the License for the specific language governing permissions
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and limitations under the License.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * When distributing Covered Code, include this CDDL HEADER in each
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If applicable, add the following below this CDDL HEADER, with the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fields enclosed by brackets "[]" replaced with your own identifying
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * information: Portions Copyright [yyyy] [name of copyright owner]
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * CDDL HEADER END
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Use is subject to license terms.
b2514ea1e4c90e705852a2668ed730087a89f38cDan McDonald * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Storage Volume Character and Block Driver (SV)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This driver implements a simplistic /dev/{r}dsk/ interface to a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * specified disk volume that is otherwise managed by the Prism
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * software. The SV driver layers itself onto the underlying disk
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * device driver by changing function pointers in the cb_ops
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * structure.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * CONFIGURATION:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * 1. Configure the driver using the svadm utility.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * 2. Access the device as before through /dev/rdsk/c?t?d?s?
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * LIMITATIONS:
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This driver should NOT be used to share a device between another
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * DataServices user interface module (e.g., STE) and a user accessing
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the device through the block device in O_WRITE mode. This is because
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * writes through the block device are asynchronous (due to the page
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * cache) and so consistency between the block device user and the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * STE user cannot be guaranteed.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Data is copied between system struct buf(9s) and nsc_vec_t. This is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * wasteful and slow.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sv_mod_status
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic const int sv_major_rev = ISS_VERSION_MAJ; /* Major number */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic const int sv_minor_rev = ISS_VERSION_MIN; /* Minor number */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic const int sv_micro_rev = ISS_VERSION_MIC; /* Micro number */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic const int sv_baseline_rev = ISS_VERSION_NUM; /* Baseline number */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * CRC32 polynomial table needed for computing the checksums
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in an EFI vtoc.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic const uint32_t sv_crc32_table[256] = { CRC32_TABLE };
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic clock_t sv_config_time; /* Time of successful {en,dis}able */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_debug; /* Set non-zero for debug to syslog */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_mod_status; /* Set to prevent modunload */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic dev_info_t *sv_dip; /* Single DIP for driver */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic kmutex_t sv_mutex; /* Protect global lists, etc. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic nsc_mem_t *sv_mem; /* nsctl memory allocator token */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Per device and per major state.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#define UNSAFE_ENTER() mutex_enter(&unsafe_driver)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* hash table of major dev structures */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic sv_maj_t *sv_majors[SV_MAJOR_HASH_CNT] = {0};
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic sv_dev_t *sv_devs; /* array of per device structures */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_max_devices; /* SV version of nsc_max_devices() */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_ndevices; /* number of SV enabled devices */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Threading.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forteint sv_threads_max = 1024; /* maximum # to dynamically alloc */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forteint sv_threads = 32; /* # to pre-allocate (see sv.conf) */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forteint sv_threads_extra = 0; /* addl # we would have alloc'ed */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic nstset_t *sv_tset; /* the threadset pointer */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_threads_hysteresis = 4; /* hysteresis for threadset resizing */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_threads_dev = 2; /* # of threads to alloc per device */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_threads_inc = 8; /* increment for changing the set */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_threads_needed; /* number of threads needed */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_no_threads; /* number of nsc_create errors */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_max_nlive; /* max number of threads running */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nsctl fd callbacks.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * cb_ops functions.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int svioctl(dev_t, int, intptr_t, int, cred_t *, int *);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * These next functions are layered into the underlying driver's devops.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_lyr_open(dev_t *, int, int, cred_t *);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_lyr_close(dev_t, int, int, cred_t *);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_lyr_read(dev_t, struct uio *, cred_t *);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_lyr_write(dev_t, struct uio *, cred_t *);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_lyr_aread(dev_t, struct aio_req *, cred_t *);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_lyr_awrite(dev_t, struct aio_req *, cred_t *);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_lyr_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * dev_ops functions.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_attach(dev_info_t *, ddi_attach_cmd_t);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic int sv_detach(dev_info_t *, ddi_detach_cmd_t);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Module linkage.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!sv (revision %d.%d.%d.%d, %s, %s)\n",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sv_major_rev, sv_minor_rev, sv_micro_rev, sv_baseline_rev,
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!sv (revision %d.%d.%d, %s, %s)\n",
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!sv (revision %d.%d, %s, %s)\n",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Locking & State.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sv_mutex protects config information - sv_maj_t and sv_dev_t lists;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * threadset creation and sizing; sv_ndevices.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If we need to hold both sv_mutex and sv_lock, then the sv_mutex
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * must be acquired first.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sv_lock protects the sv_dev_t structure for an individual device.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sv_olock protects the otyp/open members of the sv_dev_t. If we need
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to hold both sv_lock and sv_olock, then the sv_lock must be acquired
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nsc_reserve/nsc_release are used in NSC_MULTI mode to allow multiple
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * I/O operations to a device simultaneously, as above.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * All nsc_open/nsc_close/nsc_reserve/nsc_release operations that occur
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * with sv_lock write-locked must be done with (sv_state == SV_PENDING)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and (sv_pending == curthread) so that any recursion through
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sv_lyr_open/sv_lyr_close can be detected.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* nsctl is not attached (nskernd not running) */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!sv: nsc_max_devices = 0\n");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sv_devs = nsc_kmem_zalloc((sv_max_devices * sizeof (*sv_devs)),
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!sv: could not allocate sv_devs array");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < sv_max_devices; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mutex_init(&sv_devs[i].sv_olock, NULL, MUTEX_DRIVER, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rw_init(&sv_devs[i].sv_lock, NULL, RW_DRIVER, NULL);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!sv: sv_init_devs successful\n");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sv_mem = nsc_register_mem("SV", NSC_MEM_LOCAL, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sv_threads = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!sv: sv_threads=%d\n", sv_threads);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Check that everything is disabled.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; sv_devs && i < sv_max_devices; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; sv_devs && i < sv_max_devices; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove all minor nodes.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * See if the hash table entry, or one of the hash chains
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is already allocated for this major number
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((maj = sv_majors[SV_MAJOR_HASH(umaj)]) != 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If the sv_mutex is held, there is design flaw, as the only non-mutex
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * held callers can be sv_enable() or sv_dev_to_sv()
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Return an error, instead of panicing the system
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!sv: could not allocate sv_maj_t");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Determine where to allocate a new element in the hash table
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Did another thread beat us to it? */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Find a NULL insert point? */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Located the new insert point
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte *insert = nsc_kmem_zalloc(sizeof (*maj), KM_NOSLEEP, sv_mem);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!sv: could not allocate sv_maj_t");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * We only have a single instance.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Hashing of devices onto major device structures.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Individual device structures are hashed onto one of the sm_hash[]
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * buckets in the relevant major device structure.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Hash insertion and deletion -must- be done with sv_mutex held. Hash
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * searching does not require the mutex because of the sm_seq member.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sm_seq is incremented on each insertion (-after- hash chain pointer
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * manipulation) and each deletion (-before- hash chain pointer
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * manipulation). When searching the hash chain, the seq number is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * checked before accessing each device structure, if the seq number has
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * changed, then we restart the search from the top of the hash chain.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If we restart more than SV_HASH_RETRY times, we take sv_mutex and search
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the hash chain (we are guaranteed that this search cannot be
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * interrupted).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Get major hash table */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte nsc_membar_stld(); /* preserve register load order */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dev_to_sv_retry, dev_t, dev);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Must be called with sv_mutex held.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Get major hash table */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Determine which minor hash table */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* look for clash */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* look for spare sv_devs slot */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < sv_max_devices; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte maj->sm_seq++; /* must be after the store to the hash chain */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * We do not know the size of the underlying device at
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * this stage, so initialise "nblocks" property to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * zero, and update it whenever we succeed in
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * nsc_reserve'ing the underlying nsc_fd_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Remove a device structure from it's hash chain.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Must be called with sv_mutex held.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Get major hash table */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* remove svp from hash chain */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte svpp = &(maj->sm_hash[SV_MINOR_HASH(getminor(svp->sv_dev))]);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * increment of sm_seq must be before the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * removal from the hash chain
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Free (disable) a device structure.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Must be called with sv_lock(RW_WRITER) and sv_mutex held, and will
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * perform the exits during its processing.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Get major hash table */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Close the fd's before removing from the hash or swapping
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * back the cb_ops pointers so that the cache flushes before new
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * io can come in.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * corbin XXX
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Leave backing device ops in maj->sm_*
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to handle any requests that might come
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * in during the disable. This could be
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * a problem however if the backing device
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * driver is changed while we process these
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_strategy = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_awrite = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_write = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_ioctl = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_close = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_aread = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_read = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_open = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * maj->sm_flag = 0;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Close the protective layered driver open using the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Sun Private layered driver i/f.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Reserve the device, taking into account the possibility that
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the reserve might have to be retried.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } while ((rc == EINTR) && (eintr_count < MAX_EINTR_COUNT));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Get major hash table */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_enable_err_state, dev_t, udev);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Get real fd used for io
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * OR in NSC_DEVICE to ensure that nskern grabs the real strategy
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * function pointer before sv swaps them out.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte svp->sv_fd = nsc_open(path, (svp->sv_flag | NSC_DEVICE),
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_enable_err_fd, dev_t, udev);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Perform a layered driver open using the Sun Private layered
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * driver i/f to ensure that the cb_ops structure for the driver
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * is not detached out from under us whilst sv is enabled.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc = ldi_ident_from_dev(svp->sv_dev, &li)) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc != 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_enable_err_lyr_open, dev_t, udev);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Do layering if required - must happen after nsc_open().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte maj->sm_dev_ops = nsc_get_devops(getmajor(udev));
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_enable_err_load, dev_t, udev);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_enable_err_nostrategy, dev_t, udev);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_enable_err_svstrategy, dev_t, udev);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Check that the driver has async I/O entry points
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * before changing them.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (dev_ops->devo_rev < 3 || cb_ops->cb_rev < 1) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Bug 4645743
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Prevent sv from ever unloading after it has interposed
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * on a major device because there is a race between
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sv removing its layered entry points from the target
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * dev_ops, a client coming in and accessing the driver,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and the kernel modunloading the sv text.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * To allow unload, do svboot -u, which only happens in
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * pkgrm time.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (sv_reserve(svp->sv_fd, NSC_READ|NSC_MULTI|NSC_PCATCH) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_CONT, "!sv: rdev 0x%lx, nblocks %" NSC_SZFMT "\n",
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!svattach_fd(%p, %p)\n", arg, (void *)svp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte cmn_err(CE_WARN, "!svattach_fd: no state (arg %p)", arg);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc = nsc_partsize(svp->sv_fd, &svp->sv_nblocks)) != 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "!svattach_fd: nsc_partsize() failed, rc %d", rc);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc = nsc_maxfbas(svp->sv_fd, 0, &svp->sv_maxfbas)) != 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "!svattach_fd: nsc_maxfbas() failed, rc %d", rc);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!svdetach_fd(%p, %p)\n", arg, (void *)svp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* svp can be NULL during disable of an sv */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Side effect: if called with (guard != 0), then expects both sv_mutex
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and sv_lock(RW_WRITER) to be held, and will release them before returning.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte DTRACE_PROBE1(sv_disable_err_nodev, sv_dev_t *, svp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (svp->sv_fd == NULL || svp->sv_state != SV_ENABLE) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte DTRACE_PROBE1(sv_disable_err_disabled, sv_dev_t *, svp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_lyr_open(dev_t *devp, int flag, int otyp, cred_t *crp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This is a recursive open from a call to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ddi_lyr_open_by_devt and so we just want
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to pass it straight through to the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * underlying driver.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Re-acquire svp if the driver changed *devp.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (svp && ret != 0 && svp->sv_state == SV_ENABLE) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Underlying DDI open failed, but we have this
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * device SV enabled. If we can read some data
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * from the device, fake a successful open (this
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * probably means that this device is RDC'd and we
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * are getting the data from the secondary node).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The reserve must be done with NSC_TRY|NSC_NOWAIT to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ensure that it does not deadlock if this open is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * coming from nskernd:get_bsize().
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana NSC_TRY | NSC_NOWAIT | NSC_MULTI | NSC_PCATCH);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rc = nsc_alloc_buf(svp->sv_fd, 0, 1, NSC_READ, &tmph);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc <= 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* success */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Count the number of layered opens that we
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fake since we have to fake a matching number
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * of closes (OTYP_LYR open/close calls must be
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_lyr_close(dev_t dev, int flag, int otyp, cred_t *crp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This is a recursive open from a call to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * ddi_lyr_close and so we just want
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to pass it straight through to the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * underlying driver.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(sv_lyr_close_recursive, sv_dev_t *, svp,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Consume sufficient layered closes to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * account for the opens that we faked
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * whilst the device was failed.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_close_end, dev_t, dev);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Convert the specified dev_t into a locked and enabled sv_dev_t, or
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * return NULL.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_find_enabled(const dev_t dev, sv_maj_t **majpp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while ((svp = sv_dev_to_sv(dev, majpp)) != NULL) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* locked and enabled */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * State was changed while waiting on the lock.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Wait for a stable state.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_find_enabled_retry, dev_t, dev);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_lyr_uio(dev_t dev, uio_t *uiop, cred_t *crp, int rw)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fn != 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * guard access mode
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * - prevent user level access to the device
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_uio_err_guard, uio_t *, uiop);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc = sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH)) != 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_uio_err_rsrv, uio_t *, uiop);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_lyr_aread(dev_t dev, struct aio_req *aio, cred_t *crp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_lyr_awrite(dev_t dev, struct aio_req *aio, cred_t *crp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Set up an array containing the list of raw path names
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * The array for the paths is svl and the size of the array is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If there are more layered devices than will fit in the array,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the number of extra layered devices is returned. Otherwise
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * zero is return.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * svn : array for paths
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * size : size of the array
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Output (extra):
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * zero : All paths fit in array
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * >0 : Number of defined layered devices don't fit in array
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_list(void *ptr, const int size, int *extra, const int ilp32)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < sv_max_devices; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Another overflow entry */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte svn32->svn_timestamp = (uint32_t)svp->sv_timestamp;
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!sv_list: need to reserve\n");
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Out of space */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* NULL terminated list */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* keep track of any additional threads requested */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* fall through to while loop */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte } else if (threads > 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * do not increase the number of threads beyond
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * sv_threads_max when doing dynamic thread tuning
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sv_threads_extra = nthreads + threads - sv_threads_max;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte change += nst_add_thread(sv_tset, sv_threads_inc);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (nthreads - (sv_threads_inc + sv_threads_hysteresis))) &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte change -= nst_del_thread(sv_tset, sv_threads_inc);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!sv_thread_tune: threads needed %d, nthreads %d, "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "nthreads change %d",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sv_threads_needed, nst_nthread(sv_tset), change);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesvopen(dev_t *devp, int flag, int otyp, cred_t *crp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesvclose(dev_t dev, int flag, int otyp, cred_t *crp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (sv_ndevices <= 0 && sv_tset != NULL && loops > 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* threads still active - wait for them to exit */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* do not write to console when non-DEBUG */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "sv:svclose: threads still active "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesvioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *crp, int *rvalp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte char itmp1[12], itmp2[12]; /* temp char array for editing ints */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte spcs_s_info_t kstatus; /* Kernel version of spcs status */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte spcs_s_info_t ustatus; /* Address of user version of spcs status */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sv_list32_t svl32; /* 32 bit Initial structure for SVIOC_LIST */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte sv_list_t svl; /* Initial structure for SVIOC_LIST */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte int ilp32; /* Convert data structures for ilp32 userland */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If sv_mod_status is 0 or SV_PREVENT_UNLOAD, then it will continue.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * else it means it previously was SV_PREVENT_UNLOAD, and now it's
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * SV_ALLOW_UNLOAD, expecting the driver to eventually unload.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * SV_ALLOW_UNLOAD is final state, so no need to grab sv_mutex.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((cmd != SVIOC_LIST) && ((rc = drv_priv(crp)) != 0))
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_ioctl_err_kcreate, dev_t, dev);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ilp32 = (ddi_model_convert_from((mode & FMODELS)) == DDI_MODEL_ILP32);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* force to raw access */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!sv: could not allocate %d threads",
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana makedevice(svc.svc_major, svc.svc_minor), kstatus);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc == 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE3(sv_ioctl_end, dev_t, dev, int, *rvalp, int, rc);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (spcs_s_ocopyoutf(&kstatus, svc.svc_error, rc));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* NOTREACHED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * User level could not find the minor device
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * node, so do this the slow way by searching
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the entire sv config for a matching pathname.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < sv_max_devices; i++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rc = sv_disable(makedevice(svc.svc_major, svc.svc_minor),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc == 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE3(sv_ioctl_2, dev_t, dev, int, *rvalp, int, rc);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (spcs_s_ocopyoutf(&kstatus, svc.svc_error, rc));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* NOTREACHED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Do some boundary checking */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Array size is out of range */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana sizeof (itmp2), 0)));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Allocate memory for the array of structures */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return (spcs_s_ocopyoutf(&kstatus, ustatus, rc));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Return the list structure */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Return the list structure */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* Return the array */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE3(sv_ioctl_3, dev_t, dev, int, *rvalp, int, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* NOTREACHED */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE3(sv_ioctl_4, dev_t, dev, int, *rvalp, int, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* NOTREACHED */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana if (ddi_copyout(&rc, (void *)arg, sizeof (rc), mode) < 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE3(sv_ioctl_4, dev_t, dev, int, *rvalp, int, EINVAL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* NOTREACHED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* NOTREACHED */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* ARGSUSED */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!%s%d: %s", ddi_get_name(sv_dip), instance, str);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte caddr_t buf_addr; /* pointer to linear buffer in bp */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!_sv_lyr_strategy(%p)\n", (void *)bp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * guard access mode
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * - prevent user level access to the device
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_err_guard, struct buf *, bp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc = sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH)) != 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_err_rsrv, struct buf *, bp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_WARN, "!nsc_reserve() returned EINTR");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (bp->b_lblkno >= (diskaddr_t)svp->sv_nblocks) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_eof, struct buf *, bp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* return EOF, not an error */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Preallocate a handle once per call to strategy.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If this fails, then the nsc_alloc_buf() will allocate
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * a temporary handle per allocation/free pair.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_alloch_start, sv_dev_t *, svp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte bufh = nsc_alloc_handle(svp->sv_fd, NULL, NULL, NULL);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_alloch_end, sv_dev_t *, svp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (bufh && (bufh->sb_flag & NSC_HACTIVE) != 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_err_hactive, struct buf *, bp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!sv: allocated active handle (bufh %p, flags %x)",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (fba_req + bp->b_lblkno > (diskaddr_t)svp->sv_nblocks)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte fba_req = (nsc_size_t)(svp->sv_nblocks - bp->b_lblkno);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rw = (bp->b_flags & B_READ) ? NSC_READ : NSC_WRITE;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fba_req - requested size of transfer in FBAs after
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * truncation to device extent, and allowing for
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * possible non-FBA bounded final chunk.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fba_off - offset of start of chunk from start of bp in FBAs.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * fba_len - size of this chunk in FBAs.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rc = nsc_alloc_buf(svp->sv_fd, (nsc_off_t)(bp->b_lblkno + fba_off),
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_allocb_end, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_err_alloc, struct buf *, bp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Not overwriting all of the last FBA, so read in the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * old contents now before we overwrite it with the new
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(sv_dbg_read_start, sv_dev_t *, svp,
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana uint64_t, (uint64_t)(hndl->sb_pos + hndl->sb_len - 1));
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rc = nsc_read(hndl, (hndl->sb_pos + hndl->sb_len - 1), 1, 0);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_read_end, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_bcopy_start, sv_dev_t *, svp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (tocopy > 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_bcopy_end, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE3(sv_dbg_write_start, sv_dev_t *, svp,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte rc = nsc_write(hndl, hndl->sb_pos, hndl->sb_len, 0);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_write_end, sv_dev_t *, svp);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Adjust FBA offset and requested (ie. remaining) length,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * loop if more data to transfer.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_freeb_start, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_freeb_end, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_freeb_start, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_freeb_end, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_rlse_start, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_dbg_rlse_end, sv_dev_t *, svp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!_sv_lyr_strategy: bp %p, bufh %p, bp->b_error %d\n",
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(sv_lyr_strategy_end, struct buf *, bp, int, bp->b_error);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If B_ASYNC was part of the DDI we could use it as a hint to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * not create a thread for synchronous i/o.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* not sv enabled - just pass through */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE1(sv_lyr_strategy_notsv, struct buf *, bp);
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana cmn_err(CE_CONT, "!sv_lyr_strategy: nthread %d nlive %d\n",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If there are only guard devices enabled there
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * won't be a threadset, so don't try and use it.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte tp = nst_create(sv_tset, sv_async_strategy, (blind_t)bp, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * out of threads, so fall back to synchronous io.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!sv_lyr_strategy: thread alloc failed\n");
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!sv_lyr_strategy: "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "new max nlive %d (nthread %d)\n",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * re-write the size of the current partition
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_fix_dkiocgvtoc(const intptr_t arg, const int mode, sv_dev_t *svp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ilp32 = (ddi_model_convert_from((mode & FMODELS)) == DDI_MODEL_ILP32);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc != 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!sv_gvtoc: unable to determine partition number "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc == 0) && ddi_copyout(&p_size, (void *)(arg + offset),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc == 0) && ddi_copyout(&p_size, (void *)(arg + offset),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * re-write the size of the current partition
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * arg is dk_efi_t.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * dk_efi_t->dki_data = (void *)(uintptr_t)efi.dki_data_64;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * dk_efi_t->dki_data --> efi_gpt_t (label header)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * dk_efi_t->dki_data + 1 --> efi_gpe_t[] (array of partitions)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * efi_gpt_t->efi_gpt_PartitionEntryArrayCRC32 --> CRC32 of array of parts
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * efi_gpt_t->efi_gpt_HeaderCRC32 --> CRC32 of header itself
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This assumes that sizeof (efi_gpt_t) is the same as the size of a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * logical block on the disk.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Everything is little endian (i.e. disk format).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_fix_dkiocgetefi(const intptr_t arg, const int mode, sv_dev_t *svp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte uint64_t p_size; /* virtual partition size from nsctl */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte int unparts; /* number of parts in user's array */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc != 0) {
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!sv_efi: unable to determine partition number for dev %lx",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ddi_copyin((void *)arg, &efi, sizeof (efi), mode)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte efi.dki_data = (void *)(uintptr_t)efi.dki_data_64;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (efi.dki_length < sizeof (gpt) + sizeof (gpe)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ddi_copyin((void *)efi.dki_data, &gpt, sizeof (gpt), mode)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((unparts = LE_32(gpt.efi_gpt_NumberOfPartitionEntries)) == 0)
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana "!sv_efi: partition# beyond end of user array (%d >= %d)",
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ddi_copyin((void *)(efi.dki_data + 1), gpe, sgpe, mode)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte LE_64(gpe[pnum].efi_gpe_StartingLBA) + p_size - 1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte gpt.efi_gpt_PartitionEntryArrayCRC32 = LE_32(~crc);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte CRC32(crc, &gpt, sizeof (gpt), -1U, sv_crc32_table);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc == 0) && ddi_copyout(&gpt, efi.dki_data, sizeof (gpt), mode)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((rc == 0) && ddi_copyout(gpe, efi.dki_data + 1, sgpe, mode)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Re-write the size of the partition specified by p_partno
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Note that if a DKIOCPARTITION is issued to an fd opened against a
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * non-sv'd device, but p_partno requests the size for a different
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * device that is sv'd, this function will *not* be called as sv is
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * not interposed on the original device (the fd).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * It would not be easy to change this as we cannot get the partition
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * number for the non-sv'd device, so cannot compute the dev_t of the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * (sv'd) p_partno device, and so cannot find out if it is sv'd or get
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * its size from nsctl.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * See also the "Bug 4755783" comment in sv_lyr_ioctl().
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_fix_dkiocpartition(const intptr_t arg, const int mode, sv_dev_t *svp)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (rc != 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (ddi_copyin((void *)arg, &p64, sizeof (p64), mode)) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* switch to requested partition, not the current one */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte nminor = getminor(svp->sv_dev) + (p64.p_partno - pnum);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ndev = makedevice(getmajor(svp->sv_dev), nminor);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* not sv device - just return */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (sv_reserve(svp->sv_fd, NSC_MULTI|NSC_PCATCH) == 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (void *)(arg + offsetof(struct partition64, p_size)),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#endif /* DKIOCPARTITION */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortesv_lyr_ioctl(const dev_t dev, const int cmd, const intptr_t arg,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * If sv_mod_status is 0 or SV_PREVENT_UNLOAD, then it will continue.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * else it means it previously was SV_PREVENT_UNLOAD, and now it's
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * SV_ALLOW_UNLOAD, expecting the driver to eventually unload.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * SV_ALLOW_UNLOAD is final state, so no need to grab sv_mutex.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * This is nskernd which always needs to see
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the underlying disk device accurately.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * So just pass the ioctl straight through
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * to the underlying driver as though the device
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * was not sv enabled.
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(sv_lyr_ioctl_nskernd, sv_dev_t *, svp,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * We now have a locked and enabled SV device, or a non-SV device.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * DKIOCGVTOC, DKIOCSVTOC, DKIOCPARTITION, DKIOCGETEFI
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * and DKIOCSETEFI are intercepted and faked up as some
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * i/o providers emulate volumes of a different size to
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * the underlying volume.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Setting the size by rewriting the vtoc is not permitted.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* not intercepted -- allow ioctl through */
3270659f55e0928d6edec3d26217cc29398a8149Srikanth, Ramana DTRACE_PROBE2(sv_lyr_ioctl_svtoc, dev_t, dev, int, EPERM);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Pass through the real ioctl command.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Bug 4755783
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Fix up the size of the current partition to allow
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * for the virtual volume to be a different size to the
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * physical volume (e.g. for II compact dependent shadows).
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * Note that this only attempts to fix up the current partition
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * - the one that the ioctl was issued against. There could be
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * other sv'd partitions in the same vtoc, but we cannot tell
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte * so we don't attempt to fix them up.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte#endif /* DKIOCPARTITION */