Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[sfrench/cifs-2.6.git] / drivers / scsi / scsi_debug.c
index 911cc72dd7acd3b626439284df461fe01ac171d4..c607755cce00d84897f17a8b3027b3309ae1810a 100644 (file)
@@ -7,7 +7,7 @@
  *  anything out of the ordinary is seen.
  * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  *
- * Copyright (C) 2001 - 2020 Douglas Gilbert
+ * Copyright (C) 2001 - 2021 Douglas Gilbert
  *
  *  For documentation see http://sg.danny.cz/sg/scsi_debug.html
  */
@@ -32,6 +32,7 @@
 #include <linux/blkdev.h>
 #include <linux/crc-t10dif.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/interrupt.h>
 #include <linux/atomic.h>
 #include <linux/hrtimer.h>
@@ -59,8 +60,8 @@
 #include "scsi_logging.h"
 
 /* make sure inq_product_rev string corresponds to this version */
-#define SDEBUG_VERSION "0190"  /* format to fit INQUIRY revision field */
-static const char *sdebug_version_date = "20200710";
+#define SDEBUG_VERSION "0191"  /* format to fit INQUIRY revision field */
+static const char *sdebug_version_date = "20210520";
 
 #define MY_NAME "scsi_debug"
 
@@ -82,6 +83,7 @@ static const char *sdebug_version_date = "20200710";
 #define INSUFF_RES_ASC 0x55
 #define INSUFF_RES_ASCQ 0x3
 #define POWER_ON_RESET_ASCQ 0x0
+#define POWER_ON_OCCURRED_ASCQ 0x1
 #define BUS_RESET_ASCQ 0x2     /* scsi bus reset occurred */
 #define MODE_CHANGED_ASCQ 0x1  /* mode parameters changed */
 #define CAPACITY_CHANGED_ASCQ 0x9
@@ -172,7 +174,7 @@ static const char *sdebug_version_date = "20200710";
 #define SDEBUG_OPT_MAC_TIMEOUT         128
 #define SDEBUG_OPT_SHORT_TRANSFER      0x100
 #define SDEBUG_OPT_Q_NOISE             0x200
-#define SDEBUG_OPT_ALL_TSF             0x400
+#define SDEBUG_OPT_ALL_TSF             0x400   /* ignore */
 #define SDEBUG_OPT_RARE_TSF            0x800
 #define SDEBUG_OPT_N_WCE               0x1000
 #define SDEBUG_OPT_RESET_NOISE         0x2000
@@ -195,13 +197,14 @@ static const char *sdebug_version_date = "20200710";
  * priority. The UA numbers should be a sequence starting from 0 with
  * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
 #define SDEBUG_UA_POR 0                /* Power on, reset, or bus device reset */
-#define SDEBUG_UA_BUS_RESET 1
-#define SDEBUG_UA_MODE_CHANGED 2
-#define SDEBUG_UA_CAPACITY_CHANGED 3
-#define SDEBUG_UA_LUNS_CHANGED 4
-#define SDEBUG_UA_MICROCODE_CHANGED 5  /* simulate firmware change */
-#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
-#define SDEBUG_NUM_UAS 7
+#define SDEBUG_UA_POOCCUR 1    /* Power on occurred */
+#define SDEBUG_UA_BUS_RESET 2
+#define SDEBUG_UA_MODE_CHANGED 3
+#define SDEBUG_UA_CAPACITY_CHANGED 4
+#define SDEBUG_UA_LUNS_CHANGED 5
+#define SDEBUG_UA_MICROCODE_CHANGED 6  /* simulate firmware change */
+#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7
+#define SDEBUG_NUM_UAS 8
 
 /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
  * sector on read commands: */
@@ -729,7 +732,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = {
            {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 };
 
-static int sdebug_num_hosts;
+static atomic_t sdebug_num_hosts;
+static DEFINE_MUTEX(add_host_mutex);
+
 static int sdebug_add_host = DEF_NUM_HOST;  /* in sysfs this is relative */
 static int sdebug_ato = DEF_ATO;
 static int sdebug_cdb_len = DEF_CDB_LEN;
@@ -776,10 +781,12 @@ static int sdebug_uuid_ctl = DEF_UUID_CTL;
 static bool sdebug_random = DEF_RANDOM;
 static bool sdebug_per_host_store = DEF_PER_HOST_STORE;
 static bool sdebug_removable = DEF_REMOVABLE;
+static bool sdebug_deflect_incoming;
 static bool sdebug_clustering;
 static bool sdebug_host_lock = DEF_HOST_LOCK;
 static bool sdebug_strict = DEF_STRICT;
 static bool sdebug_any_injecting_opt;
+static bool sdebug_no_rwlock;
 static bool sdebug_verbose;
 static bool have_dif_prot;
 static bool write_since_sync;
@@ -856,7 +863,7 @@ static const int illegal_condition_result =
        (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
 
 static const int device_qfull_result =
-       (DID_OK << 16) | SAM_STAT_TASK_SET_FULL;
+       (DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL;
 
 static const int condition_met_result = SAM_STAT_CONDITION_MET;
 
@@ -1081,6 +1088,12 @@ static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                        if (sdebug_verbose)
                                cp = "power on reset";
                        break;
+               case SDEBUG_UA_POOCCUR:
+                       mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
+                                       POWER_ON_OCCURRED_ASCQ);
+                       if (sdebug_verbose)
+                               cp = "power on occurred";
+                       break;
                case SDEBUG_UA_BUS_RESET:
                        mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
                                        BUS_RESET_ASCQ);
@@ -2580,6 +2593,18 @@ static int resp_ie_l_pg(unsigned char *arr)
        return sizeof(ie_l_pg);
 }
 
+static int resp_env_rep_l_spg(unsigned char *arr)
+{
+       unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8,
+                                        0x0, 40, 72, 0xff, 45, 18, 0, 0,
+                                        0x1, 0x0, 0x23, 0x8,
+                                        0x0, 55, 72, 35, 55, 45, 0, 0,
+               };
+
+       memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg));
+       return sizeof(env_rep_l_spg);
+}
+
 #define SDEBUG_MAX_LSENSE_SZ 512
 
 static int resp_log_sense(struct scsi_cmnd *scp,
@@ -2632,26 +2657,47 @@ static int resp_log_sense(struct scsi_cmnd *scp,
                        arr[n++] = 0xff;        /* this page */
                        arr[n++] = 0xd;
                        arr[n++] = 0x0;         /* Temperature */
+                       arr[n++] = 0xd;
+                       arr[n++] = 0x1;         /* Environment reporting */
+                       arr[n++] = 0xd;
+                       arr[n++] = 0xff;        /* all 0xd subpages */
                        arr[n++] = 0x2f;
                        arr[n++] = 0x0; /* Informational exceptions */
+                       arr[n++] = 0x2f;
+                       arr[n++] = 0xff;        /* all 0x2f subpages */
                        arr[3] = n - 4;
                        break;
                case 0xd:       /* Temperature subpages */
                        n = 4;
                        arr[n++] = 0xd;
                        arr[n++] = 0x0;         /* Temperature */
+                       arr[n++] = 0xd;
+                       arr[n++] = 0x1;         /* Environment reporting */
+                       arr[n++] = 0xd;
+                       arr[n++] = 0xff;        /* these subpages */
                        arr[3] = n - 4;
                        break;
                case 0x2f:      /* Informational exceptions subpages */
                        n = 4;
                        arr[n++] = 0x2f;
                        arr[n++] = 0x0;         /* Informational exceptions */
+                       arr[n++] = 0x2f;
+                       arr[n++] = 0xff;        /* these subpages */
                        arr[3] = n - 4;
                        break;
                default:
                        mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
                        return check_condition_result;
                }
+       } else if (subpcode > 0) {
+               arr[0] |= 0x40;
+               arr[1] = subpcode;
+               if (pcode == 0xd && subpcode == 1)
+                       arr[3] = resp_env_rep_l_spg(arr + 4);
+               else {
+                       mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
+                       return check_condition_result;
+               }
        } else {
                mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
                return check_condition_result;
@@ -3117,6 +3163,70 @@ static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec,
        return ret;
 }
 
+static inline void
+sdeb_read_lock(struct sdeb_store_info *sip)
+{
+       if (sdebug_no_rwlock) {
+               if (sip)
+                       __acquire(&sip->macc_lck);
+               else
+                       __acquire(&sdeb_fake_rw_lck);
+       } else {
+               if (sip)
+                       read_lock(&sip->macc_lck);
+               else
+                       read_lock(&sdeb_fake_rw_lck);
+       }
+}
+
+static inline void
+sdeb_read_unlock(struct sdeb_store_info *sip)
+{
+       if (sdebug_no_rwlock) {
+               if (sip)
+                       __release(&sip->macc_lck);
+               else
+                       __release(&sdeb_fake_rw_lck);
+       } else {
+               if (sip)
+                       read_unlock(&sip->macc_lck);
+               else
+                       read_unlock(&sdeb_fake_rw_lck);
+       }
+}
+
+static inline void
+sdeb_write_lock(struct sdeb_store_info *sip)
+{
+       if (sdebug_no_rwlock) {
+               if (sip)
+                       __acquire(&sip->macc_lck);
+               else
+                       __acquire(&sdeb_fake_rw_lck);
+       } else {
+               if (sip)
+                       write_lock(&sip->macc_lck);
+               else
+                       write_lock(&sdeb_fake_rw_lck);
+       }
+}
+
+static inline void
+sdeb_write_unlock(struct sdeb_store_info *sip)
+{
+       if (sdebug_no_rwlock) {
+               if (sip)
+                       __release(&sip->macc_lck);
+               else
+                       __release(&sdeb_fake_rw_lck);
+       } else {
+               if (sip)
+                       write_unlock(&sip->macc_lck);
+               else
+                       write_unlock(&sdeb_fake_rw_lck);
+       }
+}
+
 static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 {
        bool check_prot;
@@ -3125,7 +3235,6 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        int ret;
        u64 lba;
        struct sdeb_store_info *sip = devip2sip(devip, true);
-       rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
        u8 *cmd = scp->cmnd;
 
        switch (cmd[0]) {
@@ -3204,29 +3313,29 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                return check_condition_result;
        }
 
-       read_lock(macc_lckp);
+       sdeb_read_lock(sip);
 
        /* DIX + T10 DIF */
        if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
                switch (prot_verify_read(scp, lba, num, ei_lba)) {
                case 1: /* Guard tag error */
                        if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
-                               read_unlock(macc_lckp);
+                               sdeb_read_unlock(sip);
                                mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
                                return check_condition_result;
                        } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
-                               read_unlock(macc_lckp);
+                               sdeb_read_unlock(sip);
                                mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
                                return illegal_condition_result;
                        }
                        break;
                case 3: /* Reference tag error */
                        if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */
-                               read_unlock(macc_lckp);
+                               sdeb_read_unlock(sip);
                                mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
                                return check_condition_result;
                        } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
-                               read_unlock(macc_lckp);
+                               sdeb_read_unlock(sip);
                                mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
                                return illegal_condition_result;
                        }
@@ -3235,7 +3344,7 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        }
 
        ret = do_device_access(sip, scp, 0, lba, num, false);
-       read_unlock(macc_lckp);
+       sdeb_read_unlock(sip);
        if (unlikely(ret == -1))
                return DID_ERROR << 16;
 
@@ -3423,7 +3532,6 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        int ret;
        u64 lba;
        struct sdeb_store_info *sip = devip2sip(devip, true);
-       rwlock_t *macc_lckp = &sip->macc_lck;
        u8 *cmd = scp->cmnd;
 
        switch (cmd[0]) {
@@ -3478,10 +3586,10 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                                    "to DIF device\n");
        }
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
        ret = check_device_access_params(scp, lba, num, true);
        if (ret) {
-               write_unlock(macc_lckp);
+               sdeb_write_unlock(sip);
                return ret;
        }
 
@@ -3490,22 +3598,22 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                switch (prot_verify_write(scp, lba, num, ei_lba)) {
                case 1: /* Guard tag error */
                        if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) {
-                               write_unlock(macc_lckp);
+                               sdeb_write_unlock(sip);
                                mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
                                return illegal_condition_result;
                        } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
-                               write_unlock(macc_lckp);
+                               sdeb_write_unlock(sip);
                                mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
                                return check_condition_result;
                        }
                        break;
                case 3: /* Reference tag error */
                        if (scp->prot_flags & SCSI_PROT_REF_CHECK) {
-                               write_unlock(macc_lckp);
+                               sdeb_write_unlock(sip);
                                mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3);
                                return illegal_condition_result;
                        } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */
-                               write_unlock(macc_lckp);
+                               sdeb_write_unlock(sip);
                                mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3);
                                return check_condition_result;
                        }
@@ -3519,7 +3627,7 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        /* If ZBC zone then bump its write pointer */
        if (sdebug_dev_is_zoned(devip))
                zbc_inc_wp(devip, lba, num);
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
        if (unlikely(-1 == ret))
                return DID_ERROR << 16;
        else if (unlikely(sdebug_verbose &&
@@ -3559,7 +3667,6 @@ static int resp_write_scat(struct scsi_cmnd *scp,
        u8 *lrdp = NULL;
        u8 *up;
        struct sdeb_store_info *sip = devip2sip(devip, true);
-       rwlock_t *macc_lckp = &sip->macc_lck;
        u8 wrprotect;
        u16 lbdof, num_lrd, k;
        u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
@@ -3627,7 +3734,7 @@ static int resp_write_scat(struct scsi_cmnd *scp,
                goto err_out;
        }
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
        sg_off = lbdof_blen;
        /* Spec says Buffer xfer Length field in number of LBs in dout */
        cum_lb = 0;
@@ -3709,7 +3816,7 @@ static int resp_write_scat(struct scsi_cmnd *scp,
        }
        ret = 0;
 err_out_unlock:
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
 err_out:
        kfree(lrdp);
        return ret;
@@ -3726,15 +3833,14 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
        int ret;
        struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *)
                                                scp->device->hostdata, true);
-       rwlock_t *macc_lckp = &sip->macc_lck;
        u8 *fs1p;
        u8 *fsp;
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
 
        ret = check_device_access_params(scp, lba, num, true);
        if (ret) {
-               write_unlock(macc_lckp);
+               sdeb_write_unlock(sip);
                return ret;
        }
 
@@ -3754,7 +3860,7 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
                ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
 
        if (-1 == ret) {
-               write_unlock(&sip->macc_lck);
+               sdeb_write_unlock(sip);
                return DID_ERROR << 16;
        } else if (sdebug_verbose && !ndob && (ret < lb_size))
                sdev_printk(KERN_INFO, scp->device,
@@ -3773,7 +3879,7 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
        if (sdebug_dev_is_zoned(devip))
                zbc_inc_wp(devip, lba, num);
 out:
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
 
        return 0;
 }
@@ -3886,7 +3992,6 @@ static int resp_comp_write(struct scsi_cmnd *scp,
        u8 *cmd = scp->cmnd;
        u8 *arr;
        struct sdeb_store_info *sip = devip2sip(devip, true);
-       rwlock_t *macc_lckp = &sip->macc_lck;
        u64 lba;
        u32 dnum;
        u32 lb_size = sdebug_sector_size;
@@ -3919,7 +4024,7 @@ static int resp_comp_write(struct scsi_cmnd *scp,
                return check_condition_result;
        }
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
 
        ret = do_dout_fetch(scp, dnum, arr);
        if (ret == -1) {
@@ -3937,7 +4042,7 @@ static int resp_comp_write(struct scsi_cmnd *scp,
        if (scsi_debug_lbp())
                map_region(sip, lba, num);
 cleanup:
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
        kfree(arr);
        return retval;
 }
@@ -3953,7 +4058,6 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        unsigned char *buf;
        struct unmap_block_desc *desc;
        struct sdeb_store_info *sip = devip2sip(devip, true);
-       rwlock_t *macc_lckp = &sip->macc_lck;
        unsigned int i, payload_len, descriptors;
        int ret;
 
@@ -3982,7 +4086,7 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 
        desc = (void *)&buf[8];
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
 
        for (i = 0 ; i < descriptors ; i++) {
                unsigned long long lba = get_unaligned_be64(&desc[i].lba);
@@ -3998,7 +4102,7 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        ret = 0;
 
 out:
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
        kfree(buf);
 
        return ret;
@@ -4090,7 +4194,6 @@ static int resp_pre_fetch(struct scsi_cmnd *scp,
        u32 nblks;
        u8 *cmd = scp->cmnd;
        struct sdeb_store_info *sip = devip2sip(devip, true);
-       rwlock_t *macc_lckp = &sip->macc_lck;
        u8 *fsp = sip->storep;
 
        if (cmd[0] == PRE_FETCH) {      /* 10 byte cdb */
@@ -4112,12 +4215,12 @@ static int resp_pre_fetch(struct scsi_cmnd *scp,
                rest = block + nblks - sdebug_store_sectors;
 
        /* Try to bring the PRE-FETCH range into CPU's cache */
-       read_lock(macc_lckp);
+       sdeb_read_lock(sip);
        prefetch_range(fsp + (sdebug_sector_size * block),
                       (nblks - rest) * sdebug_sector_size);
        if (rest)
                prefetch_range(fsp, rest * sdebug_sector_size);
-       read_unlock(macc_lckp);
+       sdeb_read_unlock(sip);
 fini:
        if (cmd[1] & 0x2)
                res = SDEG_RES_IMMED_MASK;
@@ -4238,7 +4341,6 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        u8 *arr;
        u8 *cmd = scp->cmnd;
        struct sdeb_store_info *sip = devip2sip(devip, true);
-       rwlock_t *macc_lckp = &sip->macc_lck;
 
        bytchk = (cmd[1] >> 1) & 0x3;
        if (bytchk == 0) {
@@ -4277,7 +4379,7 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                return check_condition_result;
        }
        /* Not changing store, so only need read access */
-       read_lock(macc_lckp);
+       sdeb_read_lock(sip);
 
        ret = do_dout_fetch(scp, a_num, arr);
        if (ret == -1) {
@@ -4299,7 +4401,7 @@ static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                goto cleanup;
        }
 cleanup:
-       read_unlock(macc_lckp);
+       sdeb_read_unlock(sip);
        kfree(arr);
        return ret;
 }
@@ -4319,7 +4421,6 @@ static int resp_report_zones(struct scsi_cmnd *scp,
        u8 *cmd = scp->cmnd;
        struct sdeb_zone_state *zsp;
        struct sdeb_store_info *sip = devip2sip(devip, false);
-       rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
 
        if (!sdebug_dev_is_zoned(devip)) {
                mk_sense_invalid_opcode(scp);
@@ -4348,7 +4449,7 @@ static int resp_report_zones(struct scsi_cmnd *scp,
                return check_condition_result;
        }
 
-       read_lock(macc_lckp);
+       sdeb_read_lock(sip);
 
        desc = arr + 64;
        for (i = 0; i < max_zones; i++) {
@@ -4436,7 +4537,7 @@ static int resp_report_zones(struct scsi_cmnd *scp,
        ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len));
 
 fini:
-       read_unlock(macc_lckp);
+       sdeb_read_unlock(sip);
        kfree(arr);
        return ret;
 }
@@ -4462,14 +4563,13 @@ static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        struct sdeb_zone_state *zsp;
        bool all = cmd[14] & 0x01;
        struct sdeb_store_info *sip = devip2sip(devip, false);
-       rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
 
        if (!sdebug_dev_is_zoned(devip)) {
                mk_sense_invalid_opcode(scp);
                return check_condition_result;
        }
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
 
        if (all) {
                /* Check if all closed zones can be open */
@@ -4518,7 +4618,7 @@ static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 
        zbc_open_zone(devip, zsp, true);
 fini:
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
        return res;
 }
 
@@ -4539,14 +4639,13 @@ static int resp_close_zone(struct scsi_cmnd *scp,
        struct sdeb_zone_state *zsp;
        bool all = cmd[14] & 0x01;
        struct sdeb_store_info *sip = devip2sip(devip, false);
-       rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
 
        if (!sdebug_dev_is_zoned(devip)) {
                mk_sense_invalid_opcode(scp);
                return check_condition_result;
        }
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
 
        if (all) {
                zbc_close_all(devip);
@@ -4575,7 +4674,7 @@ static int resp_close_zone(struct scsi_cmnd *scp,
 
        zbc_close_zone(devip, zsp);
 fini:
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
        return res;
 }
 
@@ -4612,14 +4711,13 @@ static int resp_finish_zone(struct scsi_cmnd *scp,
        u8 *cmd = scp->cmnd;
        bool all = cmd[14] & 0x01;
        struct sdeb_store_info *sip = devip2sip(devip, false);
-       rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
 
        if (!sdebug_dev_is_zoned(devip)) {
                mk_sense_invalid_opcode(scp);
                return check_condition_result;
        }
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
 
        if (all) {
                zbc_finish_all(devip);
@@ -4648,7 +4746,7 @@ static int resp_finish_zone(struct scsi_cmnd *scp,
 
        zbc_finish_zone(devip, zsp, true);
 fini:
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
        return res;
 }
 
@@ -4693,14 +4791,13 @@ static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        u8 *cmd = scp->cmnd;
        bool all = cmd[14] & 0x01;
        struct sdeb_store_info *sip = devip2sip(devip, false);
-       rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck;
 
        if (!sdebug_dev_is_zoned(devip)) {
                mk_sense_invalid_opcode(scp);
                return check_condition_result;
        }
 
-       write_lock(macc_lckp);
+       sdeb_write_lock(sip);
 
        if (all) {
                zbc_rwp_all(devip);
@@ -4728,7 +4825,7 @@ static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
 
        zbc_rwp_zone(devip, zsp);
 fini:
-       write_unlock(macc_lckp);
+       sdeb_write_unlock(sip);
        return res;
 }
 
@@ -4777,7 +4874,7 @@ static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
                return;
        }
        spin_lock_irqsave(&sqp->qc_lock, iflags);
-       sd_dp->defer_t = SDEB_DEFER_NONE;
+       WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
        sqcp = &sqp->qc_arr[qc_idx];
        scp = sqcp->a_cmnd;
        if (unlikely(scp == NULL)) {
@@ -5002,7 +5099,7 @@ static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
        open_devip->lun = sdev->lun;
        open_devip->sdbg_host = sdbg_host;
        atomic_set(&open_devip->num_in_q, 0);
-       set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
+       set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm);
        open_devip->used = true;
        return open_devip;
 }
@@ -5025,6 +5122,10 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp)
                       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
        if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
                sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
+       if (smp_load_acquire(&sdebug_deflect_incoming)) {
+               pr_info("Exit early due to deflect_incoming\n");
+               return 1;
+       }
        if (devip == NULL) {
                devip = find_build_dev_info(sdp);
                if (devip == NULL)
@@ -5094,8 +5195,8 @@ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
                                sqcp->a_cmnd = NULL;
                                sd_dp = sqcp->sd_dp;
                                if (sd_dp) {
-                                       l_defer_t = sd_dp->defer_t;
-                                       sd_dp->defer_t = SDEB_DEFER_NONE;
+                                       l_defer_t = READ_ONCE(sd_dp->defer_t);
+                                       WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
                                } else
                                        l_defer_t = SDEB_DEFER_NONE;
                                spin_unlock_irqrestore(&sqp->qc_lock, iflags);
@@ -5110,7 +5211,7 @@ static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
 }
 
 /* Deletes (stops) timers or work queues of all queued commands */
-static void stop_all_queued(void)
+static void stop_all_queued(bool done_with_no_conn)
 {
        unsigned long iflags;
        int j, k;
@@ -5119,13 +5220,15 @@ static void stop_all_queued(void)
        struct sdebug_queued_cmd *sqcp;
        struct sdebug_dev_info *devip;
        struct sdebug_defer *sd_dp;
+       struct scsi_cmnd *scp;
 
        for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
                spin_lock_irqsave(&sqp->qc_lock, iflags);
                for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
                        if (test_bit(k, sqp->in_use_bm)) {
                                sqcp = &sqp->qc_arr[k];
-                               if (sqcp->a_cmnd == NULL)
+                               scp = sqcp->a_cmnd;
+                               if (!scp)
                                        continue;
                                devip = (struct sdebug_dev_info *)
                                        sqcp->a_cmnd->device->hostdata;
@@ -5134,12 +5237,16 @@ static void stop_all_queued(void)
                                sqcp->a_cmnd = NULL;
                                sd_dp = sqcp->sd_dp;
                                if (sd_dp) {
-                                       l_defer_t = sd_dp->defer_t;
-                                       sd_dp->defer_t = SDEB_DEFER_NONE;
+                                       l_defer_t = READ_ONCE(sd_dp->defer_t);
+                                       WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
                                } else
                                        l_defer_t = SDEB_DEFER_NONE;
                                spin_unlock_irqrestore(&sqp->qc_lock, iflags);
                                stop_qc_helper(sd_dp, l_defer_t);
+                               if (done_with_no_conn && l_defer_t != SDEB_DEFER_NONE) {
+                                       scp->result = DID_NO_CONNECT << 16;
+                                       scsi_done(scp);
+                               }
                                clear_bit(k, sqp->in_use_bm);
                                spin_lock_irqsave(&sqp->qc_lock, iflags);
                        }
@@ -5282,7 +5389,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
                }
        }
        spin_unlock(&sdebug_host_list_lock);
-       stop_all_queued();
+       stop_all_queued(false);
        if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
                sdev_printk(KERN_INFO, SCpnt->device,
                            "%s: %d device(s) found\n", __func__, k);
@@ -5342,13 +5449,50 @@ static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size)
        }
 }
 
-static void block_unblock_all_queues(bool block)
+static void sdeb_block_all_queues(void)
 {
        int j;
        struct sdebug_queue *sqp;
 
        for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
-               atomic_set(&sqp->blocked, (int)block);
+               atomic_set(&sqp->blocked, (int)true);
+}
+
+static void sdeb_unblock_all_queues(void)
+{
+       int j;
+       struct sdebug_queue *sqp;
+
+       for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
+               atomic_set(&sqp->blocked, (int)false);
+}
+
+static void
+sdeb_add_n_hosts(int num_hosts)
+{
+       if (num_hosts < 1)
+               return;
+       do {
+               bool found;
+               unsigned long idx;
+               struct sdeb_store_info *sip;
+               bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
+
+               found = false;
+               if (want_phs) {
+                       xa_for_each_marked(per_store_ap, idx, sip, SDEB_XA_NOT_IN_USE) {
+                               sdeb_most_recent_idx = (int)idx;
+                               found = true;
+                               break;
+                       }
+                       if (found)      /* re-use case */
+                               sdebug_add_host_helper((int)idx);
+                       else
+                               sdebug_do_add_host(true /* make new store */);
+               } else {
+                       sdebug_do_add_host(false);
+               }
+       } while (--num_hosts);
 }
 
 /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
@@ -5361,10 +5505,10 @@ static void tweak_cmnd_count(void)
        modulo = abs(sdebug_every_nth);
        if (modulo < 2)
                return;
-       block_unblock_all_queues(true);
+       sdeb_block_all_queues();
        count = atomic_read(&sdebug_cmnd_count);
        atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
-       block_unblock_all_queues(false);
+       sdeb_unblock_all_queues();
 }
 
 static void clear_queue_stats(void)
@@ -5382,6 +5526,15 @@ static bool inject_on_this_cmd(void)
        return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
 }
 
+static int process_deflect_incoming(struct scsi_cmnd *scp)
+{
+       u8 opcode = scp->cmnd[0];
+
+       if (opcode == SYNCHRONIZE_CACHE || opcode == SYNCHRONIZE_CACHE_16)
+               return 0;
+       return DID_NO_CONNECT << 16;
+}
+
 #define INCLUSIVE_TIMING_MAX_NS 1000000                /* 1 millisecond */
 
 /* Complete the processing of the thread that queued a SCSI command to this
@@ -5391,8 +5544,7 @@ static bool inject_on_this_cmd(void)
  */
 static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
                         int scsi_result,
-                        int (*pfp)(struct scsi_cmnd *,
-                                   struct sdebug_dev_info *),
+                        int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *),
                         int delta_jiff, int ndelay)
 {
        bool new_sd_dp;
@@ -5413,13 +5565,27 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
        }
        sdp = cmnd->device;
 
-       if (delta_jiff == 0)
+       if (delta_jiff == 0) {
+               sqp = get_queue(cmnd);
+               if (atomic_read(&sqp->blocked)) {
+                       if (smp_load_acquire(&sdebug_deflect_incoming))
+                               return process_deflect_incoming(cmnd);
+                       else
+                               return SCSI_MLQUEUE_HOST_BUSY;
+               }
                goto respond_in_thread;
+       }
 
        sqp = get_queue(cmnd);
        spin_lock_irqsave(&sqp->qc_lock, iflags);
        if (unlikely(atomic_read(&sqp->blocked))) {
                spin_unlock_irqrestore(&sqp->qc_lock, iflags);
+               if (smp_load_acquire(&sdebug_deflect_incoming)) {
+                       scsi_result = process_deflect_incoming(cmnd);
+                       goto respond_in_thread;
+               }
+               if (sdebug_verbose)
+                       pr_info("blocked --> SCSI_MLQUEUE_HOST_BUSY\n");
                return SCSI_MLQUEUE_HOST_BUSY;
        }
        num_in_q = atomic_read(&devip->num_in_q);
@@ -5447,18 +5613,11 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
                spin_unlock_irqrestore(&sqp->qc_lock, iflags);
                if (scsi_result)
                        goto respond_in_thread;
-               else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
-                       scsi_result = device_qfull_result;
+               scsi_result = device_qfull_result;
                if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
-                       sdev_printk(KERN_INFO, sdp,
-                                   "%s: max_queue=%d exceeded, %s\n",
-                                   __func__, sdebug_max_queue,
-                                   (scsi_result ?  "status: TASK SET FULL" :
-                                                   "report: host busy"));
-               if (scsi_result)
-                       goto respond_in_thread;
-               else
-                       return SCSI_MLQUEUE_HOST_BUSY;
+                       sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n",
+                                   __func__, sdebug_max_queue);
+               goto respond_in_thread;
        }
        set_bit(k, sqp->in_use_bm);
        atomic_inc(&devip->num_in_q);
@@ -5553,7 +5712,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
                                sd_dp->sqa_idx = sqp - sdebug_q_arr;
                                sd_dp->qc_idx = k;
                        }
-                       sd_dp->defer_t = SDEB_DEFER_POLL;
+                       WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
                        spin_unlock_irqrestore(&sqp->qc_lock, iflags);
                } else {
                        if (!sd_dp->init_hrt) {
@@ -5565,7 +5724,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
                                sd_dp->sqa_idx = sqp - sdebug_q_arr;
                                sd_dp->qc_idx = k;
                        }
-                       sd_dp->defer_t = SDEB_DEFER_HRT;
+                       WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT);
                        /* schedule the invocation of scsi_done() for a later time */
                        hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
                }
@@ -5584,7 +5743,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
                                sd_dp->sqa_idx = sqp - sdebug_q_arr;
                                sd_dp->qc_idx = k;
                        }
-                       sd_dp->defer_t = SDEB_DEFER_POLL;
+                       WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL);
                        spin_unlock_irqrestore(&sqp->qc_lock, iflags);
                } else {
                        if (!sd_dp->init_wq) {
@@ -5594,7 +5753,7 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
                                sd_dp->qc_idx = k;
                                INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
                        }
-                       sd_dp->defer_t = SDEB_DEFER_WQ;
+                       WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ);
                        schedule_work(&sd_dp->ew.work);
                }
                if (sdebug_statistics)
@@ -5615,8 +5774,12 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
 respond_in_thread:     /* call back to mid-layer using invocation thread */
        cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
        cmnd->result &= ~SDEG_RES_IMMED_MASK;
-       if (cmnd->result == 0 && scsi_result != 0)
+       if (cmnd->result == 0 && scsi_result != 0) {
                cmnd->result = scsi_result;
+               if (sdebug_verbose)
+                       pr_info("respond_in_thread: tag=0x%x, scp->result=0x%x\n",
+                               blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)), scsi_result);
+       }
        scsi_done(cmnd);
        return 0;
 }
@@ -5661,6 +5824,7 @@ module_param_named(medium_error_start, sdebug_medium_error_start, int,
                   S_IRUGO | S_IWUSR);
 module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
 module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
+module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR);
 module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
 module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
 module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
@@ -5733,6 +5897,7 @@ MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIU
 MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
 MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
 MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
+MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)");
 MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
 MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
 MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
@@ -5899,7 +6064,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf,
                        int j, k;
                        struct sdebug_queue *sqp;
 
-                       block_unblock_all_queues(true);
+                       sdeb_block_all_queues();
                        for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
                             ++j, ++sqp) {
                                k = find_first_bit(sqp->in_use_bm,
@@ -5913,7 +6078,7 @@ static ssize_t delay_store(struct device_driver *ddp, const char *buf,
                                sdebug_jdelay = jdelay;
                                sdebug_ndelay = 0;
                        }
-                       block_unblock_all_queues(false);
+                       sdeb_unblock_all_queues();
                }
                return res;
        }
@@ -5939,7 +6104,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
                        int j, k;
                        struct sdebug_queue *sqp;
 
-                       block_unblock_all_queues(true);
+                       sdeb_block_all_queues();
                        for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
                             ++j, ++sqp) {
                                k = find_first_bit(sqp->in_use_bm,
@@ -5954,7 +6119,7 @@ static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
                                sdebug_jdelay = ndelay  ? JDELAY_OVERRIDDEN
                                                        : DEF_JDELAY;
                        }
-                       block_unblock_all_queues(false);
+                       sdeb_unblock_all_queues();
                }
                return res;
        }
@@ -6268,7 +6433,7 @@ static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
        if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
            (n <= SDEBUG_CANQUEUE) &&
            (sdebug_host_max_queue == 0)) {
-               block_unblock_all_queues(true);
+               sdeb_block_all_queues();
                k = 0;
                for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
                     ++j, ++sqp) {
@@ -6283,7 +6448,7 @@ static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
                        atomic_set(&retired_max_queue, k + 1);
                else
                        atomic_set(&retired_max_queue, 0);
-               block_unblock_all_queues(false);
+               sdeb_unblock_all_queues();
                return count;
        }
        return -EINVAL;
@@ -6295,6 +6460,23 @@ static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf)
        return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue);
 }
 
+static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf)
+{
+       return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock);
+}
+
+static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count)
+{
+       bool v;
+
+       if (kstrtobool(buf, &v))
+               return -EINVAL;
+
+       sdebug_no_rwlock = v;
+       return count;
+}
+static DRIVER_ATTR_RW(no_rwlock);
+
 /*
  * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap
  * in range [0, sdebug_host_max_queue), we can't change it.
@@ -6355,43 +6537,48 @@ static DRIVER_ATTR_RW(virtual_gb);
 static ssize_t add_host_show(struct device_driver *ddp, char *buf)
 {
        /* absolute number of hosts currently active is what is shown */
-       return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts);
+       return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&sdebug_num_hosts));
 }
 
+/*
+ * Accept positive and negative values. Hex values (only positive) may be prefixed by '0x'.
+ * To remove all hosts use a large negative number (e.g. -9999). The value 0 does nothing.
+ * Returns -EBUSY if another add_host sysfs invocation is active.
+ */
 static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
                              size_t count)
 {
-       bool found;
-       unsigned long idx;
-       struct sdeb_store_info *sip;
-       bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store;
        int delta_hosts;
 
-       if (sscanf(buf, "%d", &delta_hosts) != 1)
+       if (count == 0 || kstrtoint(buf, 0, &delta_hosts))
                return -EINVAL;
+       if (sdebug_verbose)
+               pr_info("prior num_hosts=%d, num_to_add=%d\n",
+                       atomic_read(&sdebug_num_hosts), delta_hosts);
+       if (delta_hosts == 0)
+               return count;
+       if (mutex_trylock(&add_host_mutex) == 0)
+               return -EBUSY;
        if (delta_hosts > 0) {
-               do {
-                       found = false;
-                       if (want_phs) {
-                               xa_for_each_marked(per_store_ap, idx, sip,
-                                                  SDEB_XA_NOT_IN_USE) {
-                                       sdeb_most_recent_idx = (int)idx;
-                                       found = true;
-                                       break;
-                               }
-                               if (found)      /* re-use case */
-                                       sdebug_add_host_helper((int)idx);
-                               else
-                                       sdebug_do_add_host(true);
-                       } else {
-                               sdebug_do_add_host(false);
-                       }
-               } while (--delta_hosts);
+               sdeb_add_n_hosts(delta_hosts);
        } else if (delta_hosts < 0) {
+               smp_store_release(&sdebug_deflect_incoming, true);
+               sdeb_block_all_queues();
+               if (delta_hosts >= atomic_read(&sdebug_num_hosts))
+                       stop_all_queued(true);
                do {
+                       if (atomic_read(&sdebug_num_hosts) < 1) {
+                               free_all_queued();
+                               break;
+                       }
                        sdebug_do_remove_host(false);
                } while (++delta_hosts);
+               sdeb_unblock_all_queues();
+               smp_store_release(&sdebug_deflect_incoming, false);
        }
+       mutex_unlock(&add_host_mutex);
+       if (sdebug_verbose)
+               pr_info("post num_hosts=%d\n", atomic_read(&sdebug_num_hosts));
        return count;
 }
 static DRIVER_ATTR_RW(add_host);
@@ -6655,6 +6842,7 @@ static struct attribute *sdebug_drv_attrs[] = {
        &driver_attr_lun_format.attr,
        &driver_attr_max_luns.attr,
        &driver_attr_max_queue.attr,
+       &driver_attr_no_rwlock.attr,
        &driver_attr_no_uld.attr,
        &driver_attr_scsi_level.attr,
        &driver_attr_virtual_gb.attr,
@@ -6901,6 +7089,10 @@ static int __init scsi_debug_init(void)
        sdebug_add_host = 0;
 
        for (k = 0; k < hosts_to_add; k++) {
+               if (smp_load_acquire(&sdebug_deflect_incoming)) {
+                       pr_info("exit early as sdebug_deflect_incoming is set\n");
+                       return 0;
+               }
                if (want_store && k == 0) {
                        ret = sdebug_add_host_helper(idx);
                        if (ret < 0) {
@@ -6918,8 +7110,12 @@ static int __init scsi_debug_init(void)
                }
        }
        if (sdebug_verbose)
-               pr_info("built %d host(s)\n", sdebug_num_hosts);
+               pr_info("built %d host(s)\n", atomic_read(&sdebug_num_hosts));
 
+       /*
+        * Even though all the hosts have been established, due to async device (LU) scanning
+        * by the scsi mid-level, there may still be devices (LUs) being set up.
+        */
        return 0;
 
 bus_unreg:
@@ -6935,12 +7131,17 @@ free_q_arr:
 
 static void __exit scsi_debug_exit(void)
 {
-       int k = sdebug_num_hosts;
+       int k;
 
-       stop_all_queued();
-       for (; k; k--)
+       /* Possible race with LUs still being set up; stop them asap */
+       sdeb_block_all_queues();
+       smp_store_release(&sdebug_deflect_incoming, true);
+       stop_all_queued(false);
+       for (k = 0; atomic_read(&sdebug_num_hosts) > 0; k++)
                sdebug_do_remove_host(true);
        free_all_queued();
+       if (sdebug_verbose)
+               pr_info("removed %d hosts\n", k);
        driver_unregister(&sdebug_driverfs_driver);
        bus_unregister(&pseudo_lld_bus);
        root_device_unregister(pseudo_primary);
@@ -7110,13 +7311,13 @@ static int sdebug_add_host_helper(int per_host_idx)
        sdbg_host->dev.bus = &pseudo_lld_bus;
        sdbg_host->dev.parent = pseudo_primary;
        sdbg_host->dev.release = &sdebug_release_adapter;
-       dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts);
+       dev_set_name(&sdbg_host->dev, "adapter%d", atomic_read(&sdebug_num_hosts));
 
        error = device_register(&sdbg_host->dev);
        if (error)
                goto clean;
 
-       ++sdebug_num_hosts;
+       atomic_inc(&sdebug_num_hosts);
        return 0;
 
 clean:
@@ -7180,7 +7381,7 @@ static void sdebug_do_remove_host(bool the_end)
                return;
 
        device_unregister(&sdbg_host->dev);
-       --sdebug_num_hosts;
+       atomic_dec(&sdebug_num_hosts);
 }
 
 static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
@@ -7188,10 +7389,10 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
        int num_in_q = 0;
        struct sdebug_dev_info *devip;
 
-       block_unblock_all_queues(true);
+       sdeb_block_all_queues();
        devip = (struct sdebug_dev_info *)sdev->hostdata;
        if (NULL == devip) {
-               block_unblock_all_queues(false);
+               sdeb_unblock_all_queues();
                return  -ENODEV;
        }
        num_in_q = atomic_read(&devip->num_in_q);
@@ -7210,7 +7411,7 @@ static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
                sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
                            __func__, qdepth, num_in_q);
        }
-       block_unblock_all_queues(false);
+       sdeb_unblock_all_queues();
        return sdev->queue_depth;
 }
 
@@ -7318,16 +7519,21 @@ static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
        struct sdebug_defer *sd_dp;
 
        sqp = sdebug_q_arr + queue_num;
+       qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
+       if (qc_idx >= sdebug_max_queue)
+               return 0;
+
        spin_lock_irqsave(&sqp->qc_lock, iflags);
 
        for (first = true; first || qc_idx + 1 < sdebug_max_queue; )   {
                if (first) {
-                       qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
                        first = false;
+                       if (!test_bit(qc_idx, sqp->in_use_bm))
+                               continue;
                } else {
                        qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1);
                }
-               if (unlikely(qc_idx >= sdebug_max_queue))
+               if (qc_idx >= sdebug_max_queue)
                        break;
 
                sqcp = &sqp->qc_arr[qc_idx];
@@ -7340,7 +7546,7 @@ static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
                               queue_num, qc_idx, __func__);
                        break;
                }
-               if (sd_dp->defer_t == SDEB_DEFER_POLL) {
+               if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) {
                        if (kt_from_boot < sd_dp->cmpl_ts)
                                continue;
 
@@ -7374,13 +7580,17 @@ static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num)
                        else
                                atomic_set(&retired_max_queue, k + 1);
                }
-               sd_dp->defer_t = SDEB_DEFER_NONE;
+               WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE);
                spin_unlock_irqrestore(&sqp->qc_lock, iflags);
                scsi_done(scp); /* callback to mid level */
-               spin_lock_irqsave(&sqp->qc_lock, iflags);
                num_entries++;
+               spin_lock_irqsave(&sqp->qc_lock, iflags);
+               if (find_first_bit(sqp->in_use_bm, sdebug_max_queue) >= sdebug_max_queue)
+                       break;
        }
+
        spin_unlock_irqrestore(&sqp->qc_lock, iflags);
+
        if (num_entries > 0)
                atomic_add(num_entries, &sdeb_mq_poll_count);
        return num_entries;