aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_debug.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-04-05 15:05:53 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2018-04-05 15:05:53 -0700
commit052c220da392c4dcbc628852d04970447a315683 (patch)
treeb251b5c977152c1c63c51ed625ee1b31a8741851 /drivers/scsi/scsi_debug.c
parentMerge tag 'for-4.17/block-20180402' of git://git.kernel.dk/linux-block (diff)
parentMerge branch 'fixes' into misc (diff)
downloadlinux-dev-052c220da392c4dcbc628852d04970447a315683.tar.xz
linux-dev-052c220da392c4dcbc628852d04970447a315683.zip
Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley: "This is mostly updates of the usual drivers: arcmsr, qla2xx, lpfc, ufs, mpt3sas, hisi_sas. In addition we have removed several really old drivers: sym53c416, NCR53c406a, fdomain, fdomain_cs and removed the old scsi_module.c initialization from all remaining drivers. Plus an assortment of bug fixes, initialization errors and other minor fixes" * tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (168 commits) scsi: ufs: Add support for Auto-Hibernate Idle Timer scsi: ufs: sysfs: reworking of the rpm_lvl and spm_lvl entries scsi: qla2xxx: fx00 copypaste typo scsi: qla2xxx: fix error message on <qla2400 scsi: smartpqi: update driver version scsi: smartpqi: workaround fw bug for oq deletion scsi: arcmsr: Change driver version to v1.40.00.05-20180309 scsi: arcmsr: Sleep to avoid CPU stuck too long for waiting adapter ready scsi: arcmsr: Handle adapter removed due to thunderbolt cable disconnection. scsi: arcmsr: Rename ACB_F_BUS_HANG_ON to ACB_F_ADAPTER_REMOVED for adapter hot-plug scsi: qla2xxx: Update driver version to 10.00.00.06-k scsi: qla2xxx: Fix Async GPN_FT for FCP and FC-NVMe scan scsi: qla2xxx: Cleanup code to improve FC-NVMe error handling scsi: qla2xxx: Fix FC-NVMe IO abort during driver reset scsi: qla2xxx: Fix retry for PRLI RJT with reason of BUSY scsi: qla2xxx: Remove nvme_done_list scsi: qla2xxx: Return busy if rport going away scsi: qla2xxx: Fix n2n_ae flag to prevent dev_loss on PDB change scsi: qla2xxx: Add FC-NVMe abort processing scsi: qla2xxx: Add changes for devloss timeout in driver ...
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r--drivers/scsi/scsi_debug.c241
1 files changed, 152 insertions, 89 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 1cb353f18d08..9ef5e3b810f6 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -6,7 +6,7 @@
* anything out of the ordinary is seen.
* ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
- * Copyright (C) 2001 - 2017 Douglas Gilbert
+ * Copyright (C) 2001 - 2018 Douglas Gilbert
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -61,8 +61,8 @@
#include "scsi_logging.h"
/* make sure inq_product_rev string corresponds to this version */
-#define SDEBUG_VERSION "0187" /* format to fit INQUIRY revision field */
-static const char *sdebug_version_date = "20171202";
+#define SDEBUG_VERSION "0188" /* format to fit INQUIRY revision field */
+static const char *sdebug_version_date = "20180128";
#define MY_NAME "scsi_debug"
@@ -234,6 +234,7 @@ static const char *sdebug_version_date = "20171202";
#define F_INV_OP 0x200
#define F_FAKE_RW 0x400
#define F_M_ACCESS 0x800 /* media access */
+#define F_LONG_DELAY 0x1000
#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
@@ -349,7 +350,7 @@ enum sdeb_opcode_index {
SDEB_I_XDWRITEREAD = 25, /* 10 only */
SDEB_I_WRITE_BUFFER = 26,
SDEB_I_WRITE_SAME = 27, /* 10, 16 */
- SDEB_I_SYNC_CACHE = 28, /* 10 only */
+ SDEB_I_SYNC_CACHE = 28, /* 10, 16 */
SDEB_I_COMP_WRITE = 29,
SDEB_I_LAST_ELEMENT = 30, /* keep this last (previous + 1) */
};
@@ -382,7 +383,7 @@ static const unsigned char opcode_ind_arr[256] = {
/* 0x80; 0x80->0x9f: 16 byte cdbs */
0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
- 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
+ 0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
@@ -398,6 +399,14 @@ static const unsigned char opcode_ind_arr[256] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
+/*
+ * The following "response" functions return the SCSI mid-level's 4 byte
+ * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
+ * command completion, they can mask their return value with
+ * SDEG_RES_IMMED_MASK .
+ */
+#define SDEG_RES_IMMED_MASK 0x40000000
+
static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
@@ -420,6 +429,7 @@ 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 *);
/*
* The following are overflow arrays for cdbs that "hit" the same index in
@@ -499,6 +509,12 @@ static const struct opcode_info_t release_iarr[] = {
{6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
};
+static const struct opcode_info_t sync_cache_iarr[] = {
+ {0, 0x91, 0, F_LONG_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
+ {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */
+};
+
/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
* plus the terminating elements for logic that scans this table such as
@@ -536,8 +552,8 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
{ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
resp_write_dt0, write_iarr, /* WRITE(16) */
{16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* WRITE(16) */
- {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
+ {0, 0x1b, 0, F_LONG_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
{6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
{ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
@@ -590,9 +606,10 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
{10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
0, 0, 0, 0, 0} },
- {0, 0x35, 0, F_DELAY_OVERR | FF_MEDIA_IO, NULL, NULL, /* SYNC_CACHE */
+ {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_LONG_DELAY | F_M_ACCESS,
+ resp_sync_cache, sync_cache_iarr,
{10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
- 0, 0, 0, 0} },
+ 0, 0, 0, 0} }, /* SYNC_CACHE (10) */
{0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
{16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
@@ -616,6 +633,8 @@ static unsigned int sdebug_guard = DEF_GUARD;
static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
static int sdebug_max_luns = DEF_MAX_LUNS;
static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
+static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
+static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
static int sdebug_no_lun_0 = DEF_NO_LUN_0;
@@ -649,7 +668,6 @@ static bool sdebug_any_injecting_opt;
static bool sdebug_verbose;
static bool have_dif_prot;
static bool sdebug_statistics = DEF_STATISTICS;
-static bool sdebug_mq_active;
static unsigned int sdebug_store_sectors;
static sector_t sdebug_capacity; /* in sectors */
@@ -1155,8 +1173,8 @@ static int inquiry_vpd_84(unsigned char *arr)
static int inquiry_vpd_85(unsigned char *arr)
{
int num = 0;
- const char * na1 = "https://www.kernel.org/config";
- const char * na2 = "http://www.kernel.org/log";
+ const char *na1 = "https://www.kernel.org/config";
+ const char *na2 = "http://www.kernel.org/log";
int plen, olen;
arr[num++] = 0x1; /* lu, storage config */
@@ -1372,7 +1390,7 @@ static int inquiry_vpd_b2(unsigned char *arr)
static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
unsigned char pq_pdt;
- unsigned char * arr;
+ unsigned char *arr;
unsigned char *cmd = scp->cmnd;
int alloc_len, n, ret;
bool have_wlun, is_disk;
@@ -1523,10 +1541,10 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
0, 0, 0x0, 0x0};
-static int resp_requests(struct scsi_cmnd * scp,
- struct sdebug_dev_info * devip)
+static int resp_requests(struct scsi_cmnd *scp,
+ struct sdebug_dev_info *devip)
{
- unsigned char * sbuff;
+ unsigned char *sbuff;
unsigned char *cmd = scp->cmnd;
unsigned char arr[SCSI_SENSE_BUFFERSIZE];
bool dsense;
@@ -1584,8 +1602,8 @@ static int resp_requests(struct scsi_cmnd * scp,
return fill_from_dev_buffer(scp, arr, len);
}
-static int resp_start_stop(struct scsi_cmnd * scp,
- struct sdebug_dev_info * devip)
+static int resp_start_stop(struct scsi_cmnd *scp,
+ struct sdebug_dev_info *devip)
{
unsigned char *cmd = scp->cmnd;
int power_cond, stop;
@@ -1597,7 +1615,7 @@ static int resp_start_stop(struct scsi_cmnd * scp,
}
stop = !(cmd[4] & 1);
atomic_xchg(&devip->stopped, stop);
- return 0;
+ return (cmd[1] & 0x1) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
}
static sector_t get_sdebug_capacity(void)
@@ -1612,8 +1630,8 @@ static sector_t get_sdebug_capacity(void)
}
#define SDEBUG_READCAP_ARR_SZ 8
-static int resp_readcap(struct scsi_cmnd * scp,
- struct sdebug_dev_info * devip)
+static int resp_readcap(struct scsi_cmnd *scp,
+ struct sdebug_dev_info *devip)
{
unsigned char arr[SDEBUG_READCAP_ARR_SZ];
unsigned int capac;
@@ -1631,8 +1649,8 @@ static int resp_readcap(struct scsi_cmnd * scp,
}
#define SDEBUG_READCAP16_ARR_SZ 32
-static int resp_readcap16(struct scsi_cmnd * scp,
- struct sdebug_dev_info * devip)
+static int resp_readcap16(struct scsi_cmnd *scp,
+ struct sdebug_dev_info *devip)
{
unsigned char *cmd = scp->cmnd;
unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
@@ -1670,11 +1688,11 @@ static int resp_readcap16(struct scsi_cmnd * scp,
#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
-static int resp_report_tgtpgs(struct scsi_cmnd * scp,
- struct sdebug_dev_info * devip)
+static int resp_report_tgtpgs(struct scsi_cmnd *scp,
+ struct sdebug_dev_info *devip)
{
unsigned char *cmd = scp->cmnd;
- unsigned char * arr;
+ unsigned char *arr;
int host_no = devip->sdbg_host->shost->host_no;
int n, ret, alen, rlen;
int port_group_a, port_group_b, port_a, port_b;
@@ -1926,7 +1944,7 @@ static int resp_rsup_tmfs(struct scsi_cmnd *scp,
/* <<Following mode page info copied from ST318451LW>> */
-static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
+static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
{ /* Read-Write Error Recovery page for mode_sense */
unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
5, 0, 0xff, 0xff};
@@ -1937,7 +1955,7 @@ static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
return sizeof(err_recov_pg);
}
-static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
+static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
{ /* Disconnect-Reconnect page for mode_sense */
unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0};
@@ -1948,7 +1966,7 @@ static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
return sizeof(disconnect_pg);
}
-static int resp_format_pg(unsigned char * p, int pcontrol, int target)
+static int resp_format_pg(unsigned char *p, int pcontrol, int target)
{ /* Format device page for mode_sense */
unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -1968,7 +1986,7 @@ static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
0, 0, 0, 0};
-static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
+static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
{ /* Caching page for mode_sense */
unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
@@ -1988,7 +2006,7 @@ static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
0, 0, 0x2, 0x4b};
-static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
{ /* Control mode page for mode_sense */
unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
0, 0, 0, 0};
@@ -2012,7 +2030,7 @@ static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
}
-static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
{ /* Informational Exceptions control mode page for mode_sense */
unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
0, 0, 0x0, 0x0};
@@ -2027,7 +2045,7 @@ static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
return sizeof(iec_m_pg);
}
-static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
+static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
{ /* SAS SSP mode page - short format for mode_sense */
unsigned char sas_sf_m_pg[] = {0x19, 0x6,
0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
@@ -2039,7 +2057,7 @@ static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target)
}
-static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
+static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
int target_dev_id)
{ /* SAS phy control and discover mode page for mode_sense */
unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
@@ -2072,7 +2090,7 @@ static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target,
return sizeof(sas_pcd_m_pg);
}
-static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
+static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
{ /* SAS SSP shared protocol specific port mode subpage */
unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -2093,7 +2111,7 @@ static int resp_mode_sense(struct scsi_cmnd *scp,
unsigned char dev_spec;
int alloc_len, offset, len, target_dev_id;
int target = scp->device->id;
- unsigned char * ap;
+ unsigned char *ap;
unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
unsigned char *cmd = scp->cmnd;
bool dbd, llbaa, msense_6, is_disk, bad_pcode;
@@ -2324,7 +2342,7 @@ set_mode_changed_ua:
return 0;
}
-static int resp_temp_l_pg(unsigned char * arr)
+static int resp_temp_l_pg(unsigned char *arr)
{
unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
0x0, 0x1, 0x3, 0x2, 0x0, 65,
@@ -2334,7 +2352,7 @@ static int resp_temp_l_pg(unsigned char * arr)
return sizeof(temp_l_pg);
}
-static int resp_ie_l_pg(unsigned char * arr)
+static int resp_ie_l_pg(unsigned char *arr)
{
unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
};
@@ -2712,8 +2730,8 @@ static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
}
if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
- (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
- ((lba + num) > OPT_MEDIUM_ERR_ADDR))) {
+ (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
+ ((lba + num) > sdebug_medium_error_start))) {
/* claim unrecoverable read error */
mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
/* set info field and valid bit for fixed descriptor */
@@ -3562,6 +3580,27 @@ static int resp_get_lba_status(struct scsi_cmnd *scp,
return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
}
+static int resp_sync_cache(struct scsi_cmnd *scp,
+ struct sdebug_dev_info *devip)
+{
+ u64 lba;
+ u32 num_blocks;
+ u8 *cmd = scp->cmnd;
+
+ if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
+ lba = get_unaligned_be32(cmd + 2);
+ num_blocks = get_unaligned_be16(cmd + 7);
+ } else { /* SYNCHRONIZE_CACHE(16) */
+ lba = get_unaligned_be64(cmd + 2);
+ num_blocks = get_unaligned_be32(cmd + 10);
+ }
+ if (lba + num_blocks > sdebug_capacity) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
+ return check_condition_result;
+ }
+ return (cmd[1] & 0x2) ? SDEG_RES_IMMED_MASK : 0; /* check IMMED bit */
+}
+
#define RL_BUCKET_ELEMS 8
/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
@@ -3727,20 +3766,13 @@ static int resp_xdwriteread_10(struct scsi_cmnd *scp,
static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
{
- struct sdebug_queue *sqp = sdebug_q_arr;
+ u32 tag = blk_mq_unique_tag(cmnd->request);
+ u16 hwq = blk_mq_unique_tag_to_hwq(tag);
- if (sdebug_mq_active) {
- u32 tag = blk_mq_unique_tag(cmnd->request);
- u16 hwq = blk_mq_unique_tag_to_hwq(tag);
-
- if (unlikely(hwq >= submit_queues)) {
- pr_warn("Unexpected hwq=%d, apply modulo\n", hwq);
- hwq %= submit_queues;
- }
- pr_debug("tag=%u, hwq=%d\n", tag, hwq);
- return sqp + hwq;
- } else
- return sqp;
+ pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
+ if (WARN_ON_ONCE(hwq >= submit_queues))
+ hwq = 0;
+ return sdebug_q_arr + hwq;
}
/* Queued (deferred) command completions converge here. */
@@ -4066,7 +4098,7 @@ static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
return SUCCESS;
}
-static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
+static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
{
++num_dev_resets;
if (SCpnt && SCpnt->device) {
@@ -4118,7 +4150,7 @@ lie:
return SUCCESS;
}
-static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
+static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
{
struct sdebug_host_info *sdbg_host;
struct sdebug_dev_info *devip;
@@ -4151,9 +4183,9 @@ lie:
return SUCCESS;
}
-static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
+static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
{
- struct sdebug_host_info * sdbg_host;
+ struct sdebug_host_info *sdbg_host;
struct sdebug_dev_info *devip;
int k = 0;
@@ -4179,7 +4211,7 @@ static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
static void __init sdebug_build_parts(unsigned char *ramp,
unsigned long store_size)
{
- struct partition * pp;
+ struct partition *pp;
int starts[SDEBUG_MAX_PARTS + 2];
int sectors_per_part, num_sectors, k;
int heads_by_sects, start_sec, end_sec;
@@ -4262,8 +4294,13 @@ static void clear_queue_stats(void)
static void setup_inject(struct sdebug_queue *sqp,
struct sdebug_queued_cmd *sqcp)
{
- if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0)
+ if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
+ if (sdebug_every_nth > 0)
+ sqcp->inj_recovered = sqcp->inj_transport
+ = sqcp->inj_dif
+ = sqcp->inj_dix = sqcp->inj_short = 0;
return;
+ }
sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
@@ -4278,7 +4315,10 @@ static void setup_inject(struct sdebug_queue *sqp,
* SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
*/
static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
- int scsi_result, int delta_jiff, int ndelay)
+ int scsi_result,
+ int (*pfp)(struct scsi_cmnd *,
+ struct sdebug_dev_info *),
+ int delta_jiff, int ndelay)
{
unsigned long iflags;
int k, num_in_q, qdepth, inject;
@@ -4294,9 +4334,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
}
sdp = cmnd->device;
- if (unlikely(sdebug_verbose && scsi_result))
- sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
- __func__, scsi_result);
if (delta_jiff == 0)
goto respond_in_thread;
@@ -4351,7 +4388,6 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
sqcp = &sqp->qc_arr[k];
sqcp->a_cmnd = cmnd;
cmnd->host_scribble = (unsigned char *)sqcp;
- cmnd->result = scsi_result;
sd_dp = sqcp->sd_dp;
spin_unlock_irqrestore(&sqp->qc_lock, iflags);
if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
@@ -4361,6 +4397,22 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
if (sd_dp == NULL)
return SCSI_MLQUEUE_HOST_BUSY;
}
+
+ cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
+ if (cmnd->result & SDEG_RES_IMMED_MASK) {
+ /*
+ * This is the F_DELAY_OVERR case. No delay.
+ */
+ cmnd->result &= ~SDEG_RES_IMMED_MASK;
+ delta_jiff = ndelay = 0;
+ }
+ if (cmnd->result == 0 && scsi_result != 0)
+ cmnd->result = scsi_result;
+
+ if (unlikely(sdebug_verbose && cmnd->result))
+ sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
+ __func__, cmnd->result);
+
if (delta_jiff > 0 || ndelay > 0) {
ktime_t kt;
@@ -4403,7 +4455,10 @@ static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
return 0;
respond_in_thread: /* call back to mid-layer using invocation thread */
- cmnd->result = scsi_result;
+ cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
+ cmnd->result &= ~SDEG_RES_IMMED_MASK;
+ if (cmnd->result == 0 && scsi_result != 0)
+ cmnd->result = scsi_result;
cmnd->scsi_done(cmnd);
return 0;
}
@@ -4440,6 +4495,8 @@ module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
+module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
+module_param_named(medium_error_count, sdebug_medium_error_count, 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_uld, sdebug_no_uld, int, S_IRUGO);
@@ -4497,6 +4554,8 @@ MODULE_PARM_DESC(lbprz,
MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
+MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
+MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on 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_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
@@ -4526,7 +4585,7 @@ MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xff
#define SDEBUG_INFO_LEN 256
static char sdebug_info[SDEBUG_INFO_LEN];
-static const char * scsi_debug_info(struct Scsi_Host * shp)
+static const char *scsi_debug_info(struct Scsi_Host *shp)
{
int k;
@@ -4587,9 +4646,8 @@ static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
num_host_resets);
seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
dix_reads, dix_writes, dif_errors);
- seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n",
- TICK_NSEC / 1000, "statistics", sdebug_statistics,
- sdebug_mq_active);
+ seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
+ sdebug_statistics);
seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
atomic_read(&sdebug_cmnd_count),
atomic_read(&sdebug_completions),
@@ -5450,7 +5508,7 @@ static void __exit scsi_debug_exit(void)
device_initcall(scsi_debug_init);
module_exit(scsi_debug_exit);
-static void sdebug_release_adapter(struct device * dev)
+static void sdebug_release_adapter(struct device *dev)
{
struct sdebug_host_info *sdbg_host;
@@ -5588,6 +5646,7 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
struct sdebug_dev_info *devip;
u8 *cmd = scp->cmnd;
int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
+ int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
int k, na;
int errsts = 0;
u32 flags;
@@ -5612,13 +5671,8 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
n += scnprintf(b + n, sb - n, "%02x ",
(u32)cmd[k]);
}
- if (sdebug_mq_active)
- sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n",
- my_name, blk_mq_unique_tag(scp->request),
- b);
- else
- sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name,
- b);
+ sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
+ blk_mq_unique_tag(scp->request), b);
}
if (fake_host_busy(scp))
return SCSI_MLQUEUE_HOST_BUSY;
@@ -5714,20 +5768,30 @@ static int scsi_debug_queuecommand(struct Scsi_Host *shost,
return 0; /* ignore command: make trouble */
}
if (likely(oip->pfp))
- errsts = oip->pfp(scp, devip); /* calls a resp_* function */
- else if (r_pfp) /* if leaf function ptr NULL, try the root's */
- errsts = r_pfp(scp, devip);
+ pfp = oip->pfp; /* calls a resp_* function */
+ else
+ pfp = r_pfp; /* if leaf function ptr NULL, try the root's */
fini:
if (F_DELAY_OVERR & flags)
- return schedule_resp(scp, devip, errsts, 0, 0);
- else
- return schedule_resp(scp, devip, errsts, sdebug_jdelay,
+ return schedule_resp(scp, devip, errsts, pfp, 0, 0);
+ else if ((sdebug_jdelay || sdebug_ndelay) && (flags & F_LONG_DELAY)) {
+ /*
+ * If any delay is active, want F_LONG_DELAY to be at least 1
+ * second and if sdebug_jdelay>0 want a long delay of that
+ * many seconds.
+ */
+ int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
+
+ jdelay = mult_frac(USER_HZ * jdelay, HZ, USER_HZ);
+ return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
+ } else
+ return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
sdebug_ndelay);
check_cond:
- return schedule_resp(scp, devip, check_condition_result, 0, 0);
+ return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
err_out:
- return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0, 0);
+ return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
}
static struct scsi_host_template sdebug_driver_template = {
@@ -5757,7 +5821,7 @@ static struct scsi_host_template sdebug_driver_template = {
.track_queue_depth = 1,
};
-static int sdebug_driver_probe(struct device * dev)
+static int sdebug_driver_probe(struct device *dev)
{
int error = 0;
struct sdebug_host_info *sdbg_host;
@@ -5782,8 +5846,7 @@ static int sdebug_driver_probe(struct device * dev)
}
/* Decide whether to tell scsi subsystem that we want mq */
/* Following should give the same answer for each host */
- sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1);
- if (sdebug_mq_active)
+ if (shost_use_blk_mq(hpnt))
hpnt->nr_hw_queues = submit_queues;
sdbg_host->shost = hpnt;
@@ -5855,7 +5918,7 @@ static int sdebug_driver_probe(struct device * dev)
return error;
}
-static int sdebug_driver_remove(struct device * dev)
+static int sdebug_driver_remove(struct device *dev)
{
struct sdebug_host_info *sdbg_host;
struct sdebug_dev_info *sdbg_devinfo, *tmp;