diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2020-07-23 22:48:19 +0300 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2020-07-29 07:00:01 +0300 |
commit | 84905d34f14987687ab1be64f15b453d11a41e55 (patch) | |
tree | 13cc4fc052baf3d1435ad6dc88e792b04f770a2b /drivers/scsi/scsi_debug.c | |
parent | 02e3e588f0e1176e89c46b7aa27aebb947ec4ccd (diff) | |
download | linux-84905d34f14987687ab1be64f15b453d11a41e55.tar.xz |
scsi: scsi_debug: Fix request sense
The SCSI REQUEST SENSE command emulation was found to be broken. It is a
quite complex command so try and make it do a subset of what it should
do. Remove the attempt to mimic SCSI-1 REQUEST SENSE (i.e. return the sense
data for the previous failed command). Add some reporting of "pollable"
sense data [see spc6r02: 5.12.2]. Keep the IEC mode page MRIE=6 TEST=1
predictive failure reporting.
Link: https://lore.kernel.org/r/20200723194819.545573-1-dgilbert@interlog.com
Signed-off-by: Douglas Gilbert <dgilbert@interlog.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/scsi_debug.c')
-rw-r--r-- | drivers/scsi/scsi_debug.c | 64 |
1 files changed, 29 insertions, 35 deletions
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index dff599b20bbd..f227359fd726 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1712,68 +1712,62 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return ret; } +/* See resp_iec_m_pg() for how this data is manipulated */ 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) { - unsigned char *sbuff; unsigned char *cmd = scp->cmnd; - unsigned char arr[SCSI_SENSE_BUFFERSIZE]; - bool dsense; + unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */ + bool dsense = !!(cmd[1] & 1); + int alloc_len = cmd[4]; int len = 18; + int stopped_state = atomic_read(&devip->stopped); memset(arr, 0, sizeof(arr)); - dsense = !!(cmd[1] & 1); - sbuff = scp->sense_buffer; - if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { + if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */ + if (dsense) { + arr[0] = 0x72; + arr[1] = NOT_READY; + arr[2] = LOGICAL_UNIT_NOT_READY; + arr[3] = (stopped_state == 2) ? 0x1 : 0x2; + len = 8; + } else { + arr[0] = 0x70; + arr[2] = NOT_READY; /* NO_SENSE in sense_key */ + arr[7] = 0xa; /* 18 byte sense buffer */ + arr[12] = LOGICAL_UNIT_NOT_READY; + arr[13] = (stopped_state == 2) ? 0x1 : 0x2; + } + } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { + /* Information exceptions control mode page: TEST=1, MRIE=6 */ if (dsense) { arr[0] = 0x72; arr[1] = 0x0; /* NO_SENSE in sense_key */ arr[2] = THRESHOLD_EXCEEDED; - arr[3] = 0xff; /* TEST set and MRIE==6 */ + arr[3] = 0xff; /* Failure prediction(false) */ len = 8; } else { arr[0] = 0x70; arr[2] = 0x0; /* NO_SENSE in sense_key */ arr[7] = 0xa; /* 18 byte sense buffer */ arr[12] = THRESHOLD_EXCEEDED; - arr[13] = 0xff; /* TEST set and MRIE==6 */ + arr[13] = 0xff; /* Failure prediction(false) */ } - } else { - memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); - if (arr[0] >= 0x70 && dsense == sdebug_dsense) - ; /* have sense and formats match */ - else if (arr[0] <= 0x70) { - if (dsense) { - memset(arr, 0, 8); - arr[0] = 0x72; - len = 8; - } else { - memset(arr, 0, 18); - arr[0] = 0x70; - arr[7] = 0xa; - } - } else if (dsense) { - memset(arr, 0, 8); - arr[0] = 0x72; - arr[1] = sbuff[2]; /* sense key */ - arr[2] = sbuff[12]; /* asc */ - arr[3] = sbuff[13]; /* ascq */ + } else { /* nothing to report */ + if (dsense) { len = 8; + memset(arr, 0, len); + arr[0] = 0x72; } else { - memset(arr, 0, 18); + memset(arr, 0, len); arr[0] = 0x70; - arr[2] = sbuff[1]; arr[7] = 0xa; - arr[12] = sbuff[1]; - arr[13] = sbuff[3]; } - } - mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); - return fill_from_dev_buffer(scp, arr, len); + return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len)); } static int resp_start_stop(struct scsi_cmnd *scp, |