From: Kevin Barnett <kevin.barnett@microsemi.com>
Date: Mon, 18 Jun 2018 13:22:48 -0500
Subject: [PATCH] scsi: smartpqi: improve error checking for sync requests
References: bsc#1086274
Git-commit: 26b390aba2a8f7b9dd5ce4e3ada9431de327da6d
Patch-mainline: v4.19-rc1

Detect rare error cases for synchronous requests down the RAID path.

Also retry INQUIRY of VPD page 0 sent to an HBA drive if the command failed
due to an abort.

Reviewed-by: Scott Benesh <scott.benesh@microsemi.com>
Reviewed-by: Scott Teel <scott.teel@microsemi.com>
Signed-off-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>
Signed-off-by: Hannes Reinecke <hare@suse.de>
---
 drivers/scsi/smartpqi/smartpqi.h      |  2 ++
 drivers/scsi/smartpqi/smartpqi_init.c | 54 ++++++++++++++++++++++++-----------
 2 files changed, 40 insertions(+), 16 deletions(-)

diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h
index dc3a0542a2e8..a8e7c4d48061 100644
--- a/drivers/scsi/smartpqi/smartpqi.h
+++ b/drivers/scsi/smartpqi/smartpqi.h
@@ -483,6 +483,8 @@ struct pqi_raid_error_info {
 #define CISS_CMD_STATUS_TMF			0xd
 #define CISS_CMD_STATUS_AIO_DISABLED		0xe
 
+#define PQI_CMD_STATUS_ABORTED	CISS_CMD_STATUS_ABORTED
+
 #define PQI_NUM_EVENT_QUEUE_ELEMENTS	32
 #define PQI_EVENT_OQ_ELEMENT_LENGTH	sizeof(struct pqi_event_response)
 
diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c
index d309438697a2..d3f1450e11a1 100644
--- a/drivers/scsi/smartpqi/smartpqi_init.c
+++ b/drivers/scsi/smartpqi/smartpqi_init.c
@@ -1197,20 +1197,30 @@ static void pqi_get_volume_status(struct pqi_ctrl_info *ctrl_info,
 	device->volume_offline = volume_offline;
 }
 
+#define PQI_INQUIRY_PAGE0_RETRIES	3
+
 static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info,
 	struct pqi_scsi_dev *device)
 {
 	int rc;
 	u8 *buffer;
+	unsigned int retries;
 
 	buffer = kmalloc(64, GFP_KERNEL);
 	if (!buffer)
 		return -ENOMEM;
 
 	/* Send an inquiry to the device to see what it is. */
-	rc = pqi_scsi_inquiry(ctrl_info, device->scsi3addr, 0, buffer, 64);
-	if (rc)
-		goto out;
+	for (retries = 0;;) {
+		rc = pqi_scsi_inquiry(ctrl_info, device->scsi3addr, 0,
+			buffer, 64);
+		if (rc == 0)
+			break;
+		if (pqi_is_logical_device(device) ||
+			rc != PQI_CMD_STATUS_ABORTED ||
+			++retries > PQI_INQUIRY_PAGE0_RETRIES)
+			goto out;
+	}
 
 	scsi_sanitize_inquiry_string(&buffer[8], 8);
 	scsi_sanitize_inquiry_string(&buffer[16], 16);
@@ -3621,6 +3631,29 @@ static void pqi_raid_synchronous_complete(struct pqi_io_request *io_request,
 	complete(waiting);
 }
 
+static int pqi_process_raid_io_error_synchronous(struct pqi_raid_error_info
+						*error_info)
+{
+	int rc = -EIO;
+
+	switch (error_info->data_out_result) {
+	case PQI_DATA_IN_OUT_GOOD:
+		if (error_info->status == SAM_STAT_GOOD)
+			rc = 0;
+		break;
+	case PQI_DATA_IN_OUT_UNDERFLOW:
+		if (error_info->status == SAM_STAT_GOOD ||
+			error_info->status == SAM_STAT_CHECK_CONDITION)
+			rc = 0;
+		break;
+	case PQI_DATA_IN_OUT_ABORTED:
+		rc = PQI_CMD_STATUS_ABORTED;
+		break;
+	}
+
+	return rc;
+}
+
 static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
 	struct pqi_iu_header *request, unsigned int flags,
 	struct pqi_raid_error_info *error_info, unsigned long timeout_msecs)
@@ -3710,19 +3743,8 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info,
 		else
 			memset(error_info, 0, sizeof(*error_info));
 	} else if (rc == 0 && io_request->error_info) {
-		u8 scsi_status;
-		struct pqi_raid_error_info *raid_error_info;
-
-		raid_error_info = io_request->error_info;
-		scsi_status = raid_error_info->status;
-
-		if (scsi_status == SAM_STAT_CHECK_CONDITION &&
-			raid_error_info->data_out_result ==
-			PQI_DATA_IN_OUT_UNDERFLOW)
-			scsi_status = SAM_STAT_GOOD;
-
-		if (scsi_status != SAM_STAT_GOOD)
-			rc = -EIO;
+		rc = pqi_process_raid_io_error_synchronous(
+			io_request->error_info);
 	}
 
 	pqi_free_io_request(io_request);
-- 
2.12.3

