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

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
Loading
Loading
Loading
Loading
+61 −1
Original line number Diff line number Diff line
@@ -4591,7 +4591,55 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
	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;