isci: Add decode for SMP request retry error condition

There are situations with slow expanders in which a first attempt
to execute an SMP request will fail with a timeout.  Immediate
subsequent retries will generally succeed.  This change makes sure
SMP I/O failures are immediately failed to libsas so that retries
happen with no discovery process timeout delay.

Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c
index 8bd1f7d..3a891d3 100644
--- a/drivers/scsi/isci/request.c
+++ b/drivers/scsi/isci/request.c
@@ -2508,9 +2508,16 @@
 		/* Task in the target is not done. */
 		*response_ptr = SAS_TASK_UNDELIVERED;
 		*status_ptr = SAM_STAT_TASK_ABORTED;
-		request->complete_in_target = false;
 
-		*complete_to_host_ptr = isci_perform_error_io_completion;
+		if (task->task_proto == SAS_PROTOCOL_SMP) {
+			request->complete_in_target = true;
+
+			*complete_to_host_ptr = isci_perform_normal_io_completion;
+		} else {
+			request->complete_in_target = false;
+
+			*complete_to_host_ptr = isci_perform_error_io_completion;
+		}
 		break;
 	}
 }
@@ -2882,6 +2889,21 @@
 			request->complete_in_target = false;
 			break;
 
+		case SCI_FAILURE_RETRY_REQUIRED:
+
+			/* Fail the I/O so it can be retried. */
+			response = SAS_TASK_UNDELIVERED;
+			if ((isci_device->status == isci_stopping) ||
+			    (isci_device->status == isci_stopped))
+				status = SAS_DEVICE_UNKNOWN;
+			else
+				status = SAS_ABORTED_TASK;
+
+			complete_to_host = isci_perform_normal_io_completion;
+			request->complete_in_target = true;
+			break;
+
+
 		default:
 			/* Catch any otherwise unhandled error codes here. */
 			dev_warn(&isci_host->pdev->dev,
@@ -2901,8 +2923,13 @@
 			else
 				status = SAS_ABORTED_TASK;
 
-			complete_to_host = isci_perform_error_io_completion;
-			request->complete_in_target = false;
+			if (SAS_PROTOCOL_SMP == task->task_proto) {
+				request->complete_in_target = true;
+				complete_to_host = isci_perform_normal_io_completion;
+			} else {
+				request->complete_in_target = false;
+				complete_to_host = isci_perform_error_io_completion;
+			}
 			break;
 		}
 		break;
diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h
index 432b81a..c8dd075 100644
--- a/drivers/scsi/isci/task.h
+++ b/drivers/scsi/isci/task.h
@@ -301,6 +301,27 @@
 	task->task_status.stat = status;
 
 	switch (task_notification_selection) {
+
+	case isci_perform_error_io_completion:
+
+		if (task->task_proto == SAS_PROTOCOL_SMP) {
+			/* There is no error escalation in the SMP case.
+			 * Convert to a normal completion to avoid the
+			 * timeout in the discovery path and to let the
+			 * next action take place quickly.
+			 */
+			task_notification_selection
+				= isci_perform_normal_io_completion;
+
+			/* Fall through to the normal case... */
+		} else {
+			/* Use sas_task_abort */
+			/* Leave SAS_TASK_STATE_DONE clear
+			 * Leave SAS_TASK_AT_INITIATOR set.
+			 */
+			break;
+		}
+
 	case isci_perform_aborted_io_completion:
 		/* This path can occur with task-managed requests as well as
 		 * requests terminated because of LUN or device resets.
@@ -313,12 +334,6 @@
 	default:
 		WARN_ONCE(1, "unknown task_notification_selection: %d\n",
 			 task_notification_selection);
-		/* Fall through to the error case... */
-	case isci_perform_error_io_completion:
-		/* Use sas_task_abort */
-		/* Leave SAS_TASK_STATE_DONE clear
-		 * Leave SAS_TASK_AT_INITIATOR set.
-		 */
 		break;
 	}