scsi: megaraid_sas: In probe context, retry IOC INIT once if firmware is in fault
authorChandrakanth Patil <chandrakanth.patil@broadcom.com>
Tue, 25 Jun 2019 11:04:24 +0000 (16:34 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 27 Jun 2019 04:07:35 +0000 (00:07 -0400)
Issue: Under certain conditions, controller goes in FAULT state after IOC
INIT fired to firmware. Such Fault can be recovered through controller
reset.

Fix: In driver probe context, if firmware fault is observed post IOC INIT,
driver would do controller reset followed by retry logic for IOC INIT
command.

Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/megaraid/megaraid_sas_fusion.c

index b8a5bbf45850adc6003f9e155345059077ec16a8..2e711b10ccc24b935df18752c4f8f5a12299c2b4 100644 (file)
@@ -1009,6 +1009,7 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
 {
        int i;
        struct megasas_header *frame_hdr = &cmd->frame->hdr;
+       u32 status_reg;
 
        u32 msecs = seconds * 1000;
 
@@ -1018,6 +1019,12 @@ wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
        for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) {
                rmb();
                msleep(20);
+               if (!(i % 5000)) {
+                       status_reg = instance->instancet->read_fw_status_reg(instance)
+                                       & MFI_STATE_MASK;
+                       if (status_reg == MFI_STATE_FAULT)
+                               break;
+               }
        }
 
        if (frame_hdr->cmd_status == MFI_STAT_INVALID_STATUS)
@@ -1720,6 +1727,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        struct fusion_context *fusion;
        u32 scratch_pad_1;
        int i = 0, count;
+       u32 status_reg;
 
        fusion = instance->ctrl_context;
 
@@ -1802,8 +1810,21 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
        if (megasas_alloc_cmds_fusion(instance))
                goto fail_alloc_cmds;
 
-       if (megasas_ioc_init_fusion(instance))
-               goto fail_ioc_init;
+       if (megasas_ioc_init_fusion(instance)) {
+               status_reg = instance->instancet->read_fw_status_reg(instance);
+               if (((status_reg & MFI_STATE_MASK) == MFI_STATE_FAULT) &&
+                   (status_reg & MFI_RESET_ADAPTER)) {
+                       /* Do a chip reset and then retry IOC INIT once */
+                       if (megasas_adp_reset_wait_for_ready
+                               (instance, true, 0) == FAILED)
+                               goto fail_ioc_init;
+
+                       if (megasas_ioc_init_fusion(instance))
+                               goto fail_ioc_init;
+               } else {
+                       goto fail_ioc_init;
+               }
+       }
 
        megasas_display_intel_branding(instance);
        if (megasas_get_ctrl_info(instance)) {