diff options
author | Don Brace <don.brace@microsemi.com> | 2017-05-04 17:51:42 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2017-06-12 20:48:01 -0400 |
commit | b63c64ac5a5ccb6ee56e0d906f2f5d2b7e54cbd9 (patch) | |
tree | ccb487f2d8b92bc7c062924d346ec63e2c591612 /drivers/scsi/hpsa.c | |
parent | 3d38f00c4107cc007056db9f4ab14ecb17ed193f (diff) | |
download | linux-b63c64ac5a5ccb6ee56e0d906f2f5d2b7e54cbd9.tar.bz2 |
scsi: hpsa: send ioaccel requests with 0 length down raid path
- Block I/O requests with 0 length transfers which go down the ioaccel
path. This causes lockup issues down in the basecode.
- These issues have been fixed, but there are customers who are
experiencing the issues when running older firmware.
Reviewed-by: Scott Benesh <scott.benesh@microsemi.com>
Reviewed-by: Scott Teel <scott.teel@microsemi.com>
Reviewed-by: Kevin Barnett <kevin.barnett@microsemi.com>
Signed-off-by: Don Brace <don.brace@microsemi.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/hpsa.c')
-rw-r--r-- | drivers/scsi/hpsa.c | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 2ec907993400..ea778cc453dc 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -4591,7 +4591,55 @@ sglist_finished: return 0; } -#define IO_ACCEL_INELIGIBLE (1) +#define BUFLEN 128 +static inline void warn_zero_length_transfer(struct ctlr_info *h, + u8 *cdb, int cdb_len, + const char *func) +{ + char buf[BUFLEN]; + int outlen; + int i; + + outlen = scnprintf(buf, BUFLEN, + "%s: Blocking zero-length request: CDB:", func); + for (i = 0; i < cdb_len; i++) + outlen += scnprintf(buf+outlen, BUFLEN - outlen, + "%02hhx", cdb[i]); + dev_warn(&h->pdev->dev, "%s\n", buf); +} + +#define IO_ACCEL_INELIGIBLE 1 +/* zero-length transfers trigger hardware errors. */ +static bool is_zero_length_transfer(u8 *cdb) +{ + u32 block_cnt; + + /* Block zero-length transfer sizes on certain commands. */ + switch (cdb[0]) { + case READ_10: + case WRITE_10: + case VERIFY: /* 0x2F */ + case WRITE_VERIFY: /* 0x2E */ + block_cnt = get_unaligned_be16(&cdb[7]); + break; + case READ_12: + case WRITE_12: + case VERIFY_12: /* 0xAF */ + case WRITE_VERIFY_12: /* 0xAE */ + block_cnt = get_unaligned_be32(&cdb[6]); + break; + case READ_16: + case WRITE_16: + case VERIFY_16: /* 0x8F */ + block_cnt = get_unaligned_be32(&cdb[10]); + break; + default: + return false; + } + + return block_cnt == 0; +} + static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len) { int is_write = 0; @@ -4658,6 +4706,12 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX); + if (is_zero_length_transfer(cdb)) { + warn_zero_length_transfer(h, cdb, cdb_len, __func__); + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } + if (fixup_ioaccel_cdb(cdb, &cdb_len)) { atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; @@ -4822,6 +4876,12 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); + if (is_zero_length_transfer(cdb)) { + warn_zero_length_transfer(h, cdb, cdb_len, __func__); + atomic_dec(&phys_disk->ioaccel_cmds_out); + return IO_ACCEL_INELIGIBLE; + } + if (fixup_ioaccel_cdb(cdb, &cdb_len)) { atomic_dec(&phys_disk->ioaccel_cmds_out); return IO_ACCEL_INELIGIBLE; |