isci: implement error isr

Add basic support for handling/reporting error interrupts.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
diff --git a/drivers/scsi/isci/core/scic_sds_controller.c b/drivers/scsi/isci/core/scic_sds_controller.c
index cd8017f..7ea3662 100644
--- a/drivers/scsi/isci/core/scic_sds_controller.c
+++ b/drivers/scsi/isci/core/scic_sds_controller.c
@@ -1937,18 +1937,12 @@
 	SMU_IMR_WRITE(scic, 0x00000000);
 }
 
-/**
- * This is the method provided to handle the error MSIX message interrupt.
- *    This is the normal operating mode for the hardware if MSIX is enabled.
- *
- * bool true if an interrupt is processed false if no interrupt was processed
- */
-static bool scic_sds_controller_error_vector_interrupt_handler(
-	struct scic_sds_controller *scic)
+bool scic_sds_controller_error_isr(struct scic_sds_controller *scic)
 {
 	u32 interrupt_status;
 
 	interrupt_status = SMU_ISR_READ(scic);
+
 	interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND);
 
 	if (interrupt_status != 0) {
@@ -1970,12 +1964,7 @@
 	return false;
 }
 
-/**
- * This is the method provided to handle the error completions when the
- *    hardware is using two MSIX messages.
- */
-static void scic_sds_controller_error_vector_completion_handler(
-	struct scic_sds_controller *scic)
+void scic_sds_controller_error_handler(struct scic_sds_controller *scic)
 {
 	u32 interrupt_status;
 
@@ -1988,10 +1977,7 @@
 		SMU_ISR_WRITE(scic, SMU_ISR_QUEUE_SUSPEND);
 
 	} else {
-		dev_err(scic_to_dev(scic),
-			"%s: SCIC Controller reports CRC error on completion "
-			"ISR %x\n",
-			__func__,
+		dev_err(scic_to_dev(scic), "%s: status: %#x\n", __func__,
 			interrupt_status);
 
 		sci_base_state_machine_change_state(
@@ -2585,9 +2571,9 @@
 				= scic_sds_controller_completion_handler;
 
 			handler_methods[1].interrupt_handler
-				= scic_sds_controller_error_vector_interrupt_handler;
+				= scic_sds_controller_error_isr;
 			handler_methods[1].completion_handler
-				= scic_sds_controller_error_vector_completion_handler;
+				= scic_sds_controller_error_handler;
 
 			status = SCI_SUCCESS;
 		}
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c
index 7f351a3..cb2e3f9 100644
--- a/drivers/scsi/isci/host.c
+++ b/drivers/scsi/isci/host.c
@@ -85,11 +85,27 @@
 		if (scic_sds_controller_isr(scic)) {
 			tasklet_schedule(&ihost->completion_tasklet);
 			ret = IRQ_HANDLED;
+		} else if (scic_sds_controller_error_isr(scic)) {
+			spin_lock(&ihost->scic_lock);
+			scic_sds_controller_error_handler(scic);
+			spin_unlock(&ihost->scic_lock);
+			ret = IRQ_HANDLED;
 		}
 	}
+
 	return ret;
 }
 
+irqreturn_t isci_error_isr(int vec, void *data)
+{
+	struct isci_host *ihost = data;
+	struct scic_sds_controller *scic = ihost->core_controller;
+
+	if (scic_sds_controller_error_isr(scic))
+		scic_sds_controller_error_handler(scic);
+
+	return IRQ_HANDLED;
+}
 
 /**
  * isci_host_start_complete() - This function is called by the core library,
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index f2bd92b..4d6decb 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -330,11 +330,17 @@
 		int id = i / SCI_NUM_MSI_X_INT;
 		struct msix_entry *msix = &pci_info->msix_entries[i];
 		struct isci_host *isci_host = isci_host_by_id(pdev, id);
+		irq_handler_t isr;
+
+		/* odd numbered vectors are error interrupts */
+		if (i & 1)
+			isr = isci_error_isr;
+		else
+			isr = isci_msix_isr;
 
 		BUG_ON(!isci_host);
 
-		/* @todo: need to handle error case. */
-		err = devm_request_irq(&pdev->dev, msix->vector, isci_msix_isr, 0,
+		err = devm_request_irq(&pdev->dev, msix->vector, isr, 0,
 				       DRV_NAME"-msix", isci_host);
 		if (!err)
 			continue;
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h
index 3dc0f6c..39efd5f2 100644
--- a/drivers/scsi/isci/isci.h
+++ b/drivers/scsi/isci/isci.h
@@ -115,9 +115,12 @@
 
 irqreturn_t isci_msix_isr(int vec, void *data);
 irqreturn_t isci_intx_isr(int vec, void *data);
+irqreturn_t isci_error_isr(int vec, void *data);
 
 bool scic_sds_controller_isr(struct scic_sds_controller *scic);
 void scic_sds_controller_completion_handler(struct scic_sds_controller *scic);
+bool scic_sds_controller_error_isr(struct scic_sds_controller *scic);
+void scic_sds_controller_error_handler(struct scic_sds_controller *scic);
 
 enum sci_status isci_parse_oem_parameters(
 	union scic_oem_parameters *oem_params,