Merge branch 'mlx5-next' into rdma.git for-next
[linux-2.6-microblaze.git] / drivers / scsi / scsi_debug.c
index e27f4df..2740a90 100644 (file)
@@ -76,6 +76,7 @@ static const char *sdebug_version_date = "20190125";
 #define LBA_OUT_OF_RANGE 0x21
 #define INVALID_FIELD_IN_CDB 0x24
 #define INVALID_FIELD_IN_PARAM_LIST 0x26
+#define WRITE_PROTECTED 0x27
 #define UA_RESET_ASC 0x29
 #define UA_CHANGED_ASC 0x2a
 #define TARGET_CHANGED_ASC 0x3f
@@ -351,12 +352,11 @@ enum sdeb_opcode_index {
        SDEB_I_ATA_PT = 22,             /* 12, 16 */
        SDEB_I_SEND_DIAG = 23,
        SDEB_I_UNMAP = 24,
-       SDEB_I_XDWRITEREAD = 25,        /* 10 only */
-       SDEB_I_WRITE_BUFFER = 26,
-       SDEB_I_WRITE_SAME = 27,         /* 10, 16 */
-       SDEB_I_SYNC_CACHE = 28,         /* 10, 16 */
-       SDEB_I_COMP_WRITE = 29,
-       SDEB_I_LAST_ELEMENT = 30,       /* keep this last (previous + 1) */
+       SDEB_I_WRITE_BUFFER = 25,
+       SDEB_I_WRITE_SAME = 26,         /* 10, 16 */
+       SDEB_I_SYNC_CACHE = 27,         /* 10, 16 */
+       SDEB_I_COMP_WRITE = 28,
+       SDEB_I_LAST_ELEMENT = 29,       /* keep this last (previous + 1) */
 };
 
 
@@ -377,7 +377,7 @@ static const unsigned char opcode_ind_arr[256] = {
 /* 0x40; 0x40->0x5f: 10 byte cdbs */
        0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
-       0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
+       0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
            SDEB_I_RELEASE,
        0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
 /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
@@ -430,7 +430,6 @@ static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
-static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
 static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
@@ -600,9 +599,6 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
        {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
            {10,  0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
 /* 25 */
-       {0, 0x53, 0, F_D_IN | F_D_OUT | FF_MEDIA_IO, resp_xdwriteread_10,
-           NULL, {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
-                  0, 0, 0, 0, 0, 0} },         /* XDWRITEREAD(10) */
        {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
            {10,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
             0, 0, 0, 0} },                     /* WRITE_BUFFER */
@@ -618,7 +614,7 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
            {16,  0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
             0, 0xff, 0x3f, 0xc7} },            /* COMPARE AND WRITE */
 
-/* 30 */
+/* 29 */
        {0xff, 0, 0, 0, NULL, NULL,             /* terminating element */
            {0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
 };
@@ -673,6 +669,7 @@ static bool sdebug_verbose;
 static bool have_dif_prot;
 static bool write_since_sync;
 static bool sdebug_statistics = DEF_STATISTICS;
+static bool sdebug_wp;
 
 static unsigned int sdebug_store_sectors;
 static sector_t sdebug_capacity;       /* in sectors */
@@ -836,7 +833,8 @@ static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
        mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
 }
 
-static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
+static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
+                           void __user *arg)
 {
        if (sdebug_verbose) {
                if (0x1261 == cmd)
@@ -1010,16 +1008,16 @@ static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
                                int arr_len)
 {
        int act_len;
-       struct scsi_data_buffer *sdb = scsi_in(scp);
+       struct scsi_data_buffer *sdb = &scp->sdb;
 
        if (!sdb->length)
                return 0;
-       if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
+       if (scp->sc_data_direction != DMA_FROM_DEVICE)
                return DID_ERROR << 16;
 
        act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
                                      arr, arr_len);
-       sdb->resid = scsi_bufflen(scp) - act_len;
+       scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
 
        return 0;
 }
@@ -1033,20 +1031,21 @@ static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
                                  int arr_len, unsigned int off_dst)
 {
        int act_len, n;
-       struct scsi_data_buffer *sdb = scsi_in(scp);
+       struct scsi_data_buffer *sdb = &scp->sdb;
        off_t skip = off_dst;
 
        if (sdb->length <= off_dst)
                return 0;
-       if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE))
+       if (scp->sc_data_direction != DMA_FROM_DEVICE)
                return DID_ERROR << 16;
 
        act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
                                       arr, arr_len, skip);
        pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
-                __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid);
+                __func__, off_dst, scsi_bufflen(scp), act_len,
+                scsi_get_resid(scp));
        n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
-       sdb->resid = min(sdb->resid, n);
+       scsi_set_resid(scp, min(scsi_get_resid(scp), n));
        return 0;
 }
 
@@ -1058,7 +1057,7 @@ static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
 {
        if (!scsi_bufflen(scp))
                return 0;
-       if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE))
+       if (scp->sc_data_direction != DMA_TO_DEVICE)
                return -1;
 
        return scsi_sg_copy_to_buffer(scp, arr, arr_len);
@@ -2146,9 +2145,11 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
        target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
                        (devip->target * 1000) - 3;
        /* for disks set DPOFUA bit and clear write protect (WP) bit */
-       if (is_disk)
+       if (is_disk) {
                dev_spec = 0x10;        /* =0x90 if WP=1 implies read-only */
-       else
+               if (sdebug_wp)
+                       dev_spec |= 0x80;
+       } else
                dev_spec = 0x0;
        if (msense_6) {
                arr[2] = dev_spec;
@@ -2331,6 +2332,10 @@ static int resp_mode_select(struct scsi_cmnd *scp,
                if (ctrl_m_pg[1] == arr[off + 1]) {
                        memcpy(ctrl_m_pg + 2, arr + off + 2,
                               sizeof(ctrl_m_pg) - 2);
+                       if (ctrl_m_pg[4] & 0x8)
+                               sdebug_wp = true;
+                       else
+                               sdebug_wp = false;
                        sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
                        goto set_mode_changed_ua;
                }
@@ -2455,8 +2460,8 @@ static int resp_log_sense(struct scsi_cmnd *scp,
                    min(len, SDEBUG_MAX_INQ_ARR_SZ));
 }
 
-static int check_device_access_params(struct scsi_cmnd *scp,
-                                     unsigned long long lba, unsigned int num)
+static inline int check_device_access_params(struct scsi_cmnd *scp,
+       unsigned long long lba, unsigned int num, bool write)
 {
        if (lba + num > sdebug_capacity) {
                mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
@@ -2468,6 +2473,10 @@ static int check_device_access_params(struct scsi_cmnd *scp,
                mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
                return check_condition_result;
        }
+       if (write && unlikely(sdebug_wp)) {
+               mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
+               return check_condition_result;
+       }
        return 0;
 }
 
@@ -2477,21 +2486,19 @@ static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
 {
        int ret;
        u64 block, rest = 0;
-       struct scsi_data_buffer *sdb;
+       struct scsi_data_buffer *sdb = &scmd->sdb;
        enum dma_data_direction dir;
 
        if (do_write) {
-               sdb = scsi_out(scmd);
                dir = DMA_TO_DEVICE;
                write_since_sync = true;
        } else {
-               sdb = scsi_in(scmd);
                dir = DMA_FROM_DEVICE;
        }
 
        if (!sdb->length)
                return 0;
-       if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir))
+       if (scmd->sc_data_direction != dir)
                return -1;
 
        block = do_div(lba, sdebug_store_sectors);
@@ -2728,18 +2735,9 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        } else
                sqcp = NULL;
 
-       /* inline check_device_access_params() */
-       if (unlikely(lba + num > sdebug_capacity)) {
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
-               return check_condition_result;
-       }
-       /* transfer length excessive (tie in to block limits VPD page) */
-       if (unlikely(num > sdebug_store_sectors)) {
-               /* needs work to find which cdb byte 'num' comes from */
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
-               return check_condition_result;
-       }
-
+       ret = check_device_access_params(scp, lba, num, false);
+       if (ret)
+               return ret;
        if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
                     (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
                     ((lba + num) > sdebug_medium_error_start))) {
@@ -2774,7 +2772,7 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
        if (unlikely(ret == -1))
                return DID_ERROR << 16;
 
-       scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
+       scsi_set_resid(scp, scsi_bufflen(scp) - ret);
 
        if (unlikely(sqcp)) {
                if (sqcp->inj_recovered) {
@@ -3031,19 +3029,9 @@ static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                        sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
                                    "to DIF device\n");
        }
-
-       /* inline check_device_access_params() */
-       if (unlikely(lba + num > sdebug_capacity)) {
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
-               return check_condition_result;
-       }
-       /* transfer length excessive (tie in to block limits VPD page) */
-       if (unlikely(num > sdebug_store_sectors)) {
-               /* needs work to find which cdb byte 'num' comes from */
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
-               return check_condition_result;
-       }
-
+       ret = check_device_access_params(scp, lba, num, true);
+       if (ret)
+               return ret;
        write_lock_irqsave(&atomic_rw, iflags);
 
        /* DIX + T10 DIF */
@@ -3182,7 +3170,7 @@ static int resp_write_scat(struct scsi_cmnd *scp,
                                my_name, __func__, k, lba, num, sg_off);
                if (num == 0)
                        continue;
-               ret = check_device_access_params(scp, lba, num);
+               ret = check_device_access_params(scp, lba, num, true);
                if (ret)
                        goto err_out_unlock;
                num_by = num * lb_size;
@@ -3268,7 +3256,7 @@ static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
        u64 block, lbaa;
        u8 *fs1p;
 
-       ret = check_device_access_params(scp, lba, num);
+       ret = check_device_access_params(scp, lba, num, true);
        if (ret)
                return ret;
 
@@ -3440,18 +3428,9 @@ static int resp_comp_write(struct scsi_cmnd *scp,
            (cmd[1] & 0xe0) == 0)
                sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
                            "to DIF device\n");
-
-       /* inline check_device_access_params() */
-       if (lba + num > sdebug_capacity) {
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
-               return check_condition_result;
-       }
-       /* transfer length excessive (tie in to block limits VPD page) */
-       if (num > sdebug_store_sectors) {
-               /* needs work to find which cdb byte 'num' comes from */
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
-               return check_condition_result;
-       }
+       ret = check_device_access_params(scp, lba, num, false);
+       if (ret)
+               return ret;
        dnum = 2 * num;
        arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
        if (NULL == arr) {
@@ -3534,7 +3513,7 @@ static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
                unsigned long long lba = get_unaligned_be64(&desc[i].lba);
                unsigned int num = get_unaligned_be32(&desc[i].blocks);
 
-               ret = check_device_access_params(scp, lba, num);
+               ret = check_device_access_params(scp, lba, num, true);
                if (ret)
                        goto out;
 
@@ -3567,7 +3546,7 @@ static int resp_get_lba_status(struct scsi_cmnd *scp,
        if (alloc_len < 24)
                return 0;
 
-       ret = check_device_access_params(scp, lba, 1);
+       ret = check_device_access_params(scp, lba, 1, false);
        if (ret)
                return ret;
 
@@ -3719,68 +3698,6 @@ static int resp_report_luns(struct scsi_cmnd *scp,
        return res;
 }
 
-static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
-                           unsigned int num, struct sdebug_dev_info *devip)
-{
-       int j;
-       unsigned char *kaddr, *buf;
-       unsigned int offset;
-       struct scsi_data_buffer *sdb = scsi_in(scp);
-       struct sg_mapping_iter miter;
-
-       /* better not to use temporary buffer. */
-       buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
-       if (!buf) {
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
-                               INSUFF_RES_ASCQ);
-               return check_condition_result;
-       }
-
-       scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
-
-       offset = 0;
-       sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents,
-                       SG_MITER_ATOMIC | SG_MITER_TO_SG);
-
-       while (sg_miter_next(&miter)) {
-               kaddr = miter.addr;
-               for (j = 0; j < miter.length; j++)
-                       *(kaddr + j) ^= *(buf + offset + j);
-
-               offset += miter.length;
-       }
-       sg_miter_stop(&miter);
-       kfree(buf);
-
-       return 0;
-}
-
-static int resp_xdwriteread_10(struct scsi_cmnd *scp,
-                              struct sdebug_dev_info *devip)
-{
-       u8 *cmd = scp->cmnd;
-       u64 lba;
-       u32 num;
-       int errsts;
-
-       if (!scsi_bidi_cmnd(scp)) {
-               mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
-                               INSUFF_RES_ASCQ);
-               return check_condition_result;
-       }
-       errsts = resp_read_dt0(scp, devip);
-       if (errsts)
-               return errsts;
-       if (!(cmd[1] & 0x4)) {          /* DISABLE_WRITE is not set */
-               errsts = resp_write_dt0(scp, devip);
-               if (errsts)
-                       return errsts;
-       }
-       lba = get_unaligned_be32(cmd + 2);
-       num = get_unaligned_be16(cmd + 7);
-       return resp_xdwriteread(scp, lba, num, devip);
-}
-
 static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
 {
        u32 tag = blk_mq_unique_tag(cmnd->request);
@@ -3954,7 +3871,6 @@ static int scsi_debug_slave_alloc(struct scsi_device *sdp)
        if (sdebug_verbose)
                pr_info("slave_alloc <%u %u %u %llu>\n",
                       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
-       blk_queue_flag_set(QUEUE_FLAG_BIDI, sdp->request_queue);
        return 0;
 }
 
@@ -4554,6 +4470,7 @@ module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
 module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
 module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
                   S_IRUGO | S_IWUSR);
+module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
 module_param_named(write_same_length, sdebug_write_same_length, int,
                   S_IRUGO | S_IWUSR);
 
@@ -4613,6 +4530,7 @@ MODULE_PARM_DESC(uuid_ctl,
                 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
 MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
 MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
+MODULE_PARM_DESC(wp, "Write Protect (def=0)");
 MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
 
 #define SDEBUG_INFO_LEN 256