Commit b63c64ac authored by Don Brace's avatar Don Brace Committed by Martin K. Petersen

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: default avatarScott Benesh <scott.benesh@microsemi.com>
Reviewed-by: default avatarScott Teel <scott.teel@microsemi.com>
Reviewed-by: default avatarKevin Barnett <kevin.barnett@microsemi.com>
Signed-off-by: default avatarDon Brace <don.brace@microsemi.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 3d38f00c
...@@ -4591,7 +4591,55 @@ static int hpsa_scatter_gather(struct ctlr_info *h, ...@@ -4591,7 +4591,55 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
return 0; 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) static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
{ {
int is_write = 0; int is_write = 0;
...@@ -4658,6 +4706,12 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h, ...@@ -4658,6 +4706,12 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX); 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)) { if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
atomic_dec(&phys_disk->ioaccel_cmds_out); atomic_dec(&phys_disk->ioaccel_cmds_out);
return IO_ACCEL_INELIGIBLE; return IO_ACCEL_INELIGIBLE;
...@@ -4822,6 +4876,12 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h, ...@@ -4822,6 +4876,12 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); 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)) { if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
atomic_dec(&phys_disk->ioaccel_cmds_out); atomic_dec(&phys_disk->ioaccel_cmds_out);
return IO_ACCEL_INELIGIBLE; return IO_ACCEL_INELIGIBLE;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment