]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
hpsa: send ioaccel requests with 0 length trasfer down raid path
authorDon Brace <don.brace@microsemi.com>
Sat, 25 Feb 2017 00:08:03 +0000 (16:08 -0800)
committerChuck Anderson <chuck.anderson@oracle.com>
Mon, 6 Mar 2017 20:17:59 +0000 (12:17 -0800)
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.

Signed-off-by: Don Brace <don.brace@microsemi.com>
Orabug: 25605941
Signed-off-by: Jack Vogel <jack.vogel@oracle.com>
drivers/scsi/hpsa.c

index abb392e5c1f1e891fd685c0535fa6cd09379d340..eefff89fa4f51b81c888873366688245a2284d50 100644 (file)
@@ -4450,7 +4450,50 @@ sglist_finished:
        return 0;
 }
 
-#define IO_ACCEL_INELIGIBLE (1)
+static inline void warn_zero_length_transfer(struct ctlr_info *h,
+                                               u8 *cdb, const char *func)
+{
+       dev_warn(&h->pdev->dev,
+                       "%s: Blocking zero-length request: CDB:%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
+                       func,
+                       cdb[0], cdb[1], cdb[2], cdb[3],
+                       cdb[4], cdb[5], cdb[6], cdb[7],
+                       cdb[8], cdb[9], cdb[10], cdb[11],
+                       cdb[12], cdb[13], cdb[14], cdb[15]);
+}
+
+#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;
@@ -4517,6 +4560,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, __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;
@@ -4681,6 +4730,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, __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;