diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2014-11-25 02:18:02 +0100 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-11-25 15:42:56 +0100 |
commit | 817fd66beb779dbbe44c46dd11e64d8275efb593 (patch) | |
tree | e57cf120d2634f2c55ef42b039ae892aa5209b9e /drivers/scsi/scsi_debug.c | |
parent | scsi_debug: pinpoint invalid field in sense data (diff) | |
download | linux-817fd66beb779dbbe44c46dd11e64d8275efb593.tar.xz linux-817fd66beb779dbbe44c46dd11e64d8275efb593.zip |
scsi_debug: append inject error flags onto scsi_cmnd object
The way the existing scsi_debug command parser associated various
inject error flags to a command was difficult to replicate in the
table driven parser. This patch adds infrastructure to append those
flags to the end of a scsi_cmnd object with the cmd_size host
template option.
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index a1bca60ae83d..d337eaa128d0 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -209,6 +209,14 @@ static const char *scsi_debug_version_date = "20141022"; #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE" #endif +struct sdebug_scmd_extra_t { + bool inj_recovered; + bool inj_transport; + bool inj_dif; + bool inj_dix; + bool inj_short; +}; + static int scsi_debug_add_host = DEF_NUM_HOST; static int scsi_debug_ato = DEF_ATO; static int scsi_debug_delay = DEF_DELAY; @@ -248,6 +256,7 @@ static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH; static bool scsi_debug_removable = DEF_REMOVABLE; static bool scsi_debug_clustering; static bool scsi_debug_host_lock = DEF_HOST_LOCK; +static bool sdebug_any_injecting_opt; static atomic_t sdebug_cmnd_count; static atomic_t sdebug_completions; @@ -3416,6 +3425,16 @@ static ssize_t opts_store(struct device_driver *ddp, const char *buf, return -EINVAL; opts_done: scsi_debug_opts = opts; + if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) + sdebug_any_injecting_opt = true; + else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) + sdebug_any_injecting_opt = true; + else if (SCSI_DEBUG_OPT_DIF_ERR & opts) + sdebug_any_injecting_opt = true; + else if (SCSI_DEBUG_OPT_DIX_ERR & opts) + sdebug_any_injecting_opt = true; + else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) + sdebug_any_injecting_opt = true; atomic_set(&sdebug_cmnd_count, 0); atomic_set(&sdebug_a_tsf, 0); return count; @@ -4563,6 +4582,41 @@ sdebug_change_qtype(struct scsi_device *sdev, int qtype) return qtype; } +static int +check_inject(struct scsi_cmnd *scp) +{ + struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); + + memset(ep, 0, sizeof(struct sdebug_scmd_extra_t)); + + if (atomic_inc_return(&sdebug_cmnd_count) >= + abs(scsi_debug_every_nth)) { + atomic_set(&sdebug_cmnd_count, 0); + if (scsi_debug_every_nth < -1) + scsi_debug_every_nth = -1; + if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) + return 1; /* ignore command causing timeout */ + else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts && + scsi_medium_access_command(scp)) + return 1; /* time out reads and writes */ + if (sdebug_any_injecting_opt) { + int opts = scsi_debug_opts; + + if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) + ep->inj_recovered = true; + else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) + ep->inj_transport = true; + else if (SCSI_DEBUG_OPT_DIF_ERR & opts) + ep->inj_dif = true; + else if (SCSI_DEBUG_OPT_DIX_ERR & opts) + ep->inj_dix = true; + else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) + ep->inj_short = true; + } + } + return 0; +} + static struct scsi_host_template sdebug_driver_template = { .show_info = scsi_debug_show_info, .write_info = scsi_debug_write_info, @@ -4589,11 +4643,13 @@ static struct scsi_host_template sdebug_driver_template = { .use_clustering = DISABLE_CLUSTERING, .module = THIS_MODULE, .track_queue_depth = 1, + .cmd_size = sizeof(struct sdebug_scmd_extra_t), }; static int sdebug_driver_probe(struct device * dev) { int error = 0; + int opts; struct sdebug_host_info *sdbg_host; struct Scsi_Host *hpnt; int host_prot; @@ -4662,6 +4718,18 @@ static int sdebug_driver_probe(struct device * dev) else scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); + opts = scsi_debug_opts; + if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) + sdebug_any_injecting_opt = true; + else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) + sdebug_any_injecting_opt = true; + else if (SCSI_DEBUG_OPT_DIF_ERR & opts) + sdebug_any_injecting_opt = true; + else if (SCSI_DEBUG_OPT_DIX_ERR & opts) + sdebug_any_injecting_opt = true; + else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) + sdebug_any_injecting_opt = true; + error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); |