scsi: megaraid_sas: Limit the number of retries for the IOCTLs causing firmware fault
authorAnand Lodnoor <anand.lodnoor@broadcom.com>
Tue, 14 Jan 2020 11:21:20 +0000 (16:51 +0530)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 16 Jan 2020 04:21:03 +0000 (23:21 -0500)
IOCTLs causing firmware fault may end up in failed controller resets and
finally killing the adapter.

This patch fixes this problem as stated below:

In OCR sequence, driver will attempt refiring pended IOCTLs upto two times.
If first two attempts fail, then in third attempt driver will return pended
IOCTLs with EBUSY status to application. These changes are done to ensure
if any of pended IOCTLs is causing firmware fault and resulting into OCR
failure, then in last attempt of OCR driver will refrain firing it to
firmware and saving adapter from being killed due to faulty IOCTL.

Link: https://lore.kernel.org/r/1579000882-20246-10-git-send-email-anand.lodnoor@broadcom.com
Signed-off-by: Sumit Saxena <sumit.saxena@broadcom.com>
Signed-off-by: Shivasharan S <shivasharan.srikanteshwara@broadcom.com>
Signed-off-by: Chandrakanth Patil <chandrakanth.patil@broadcom.com>
Signed-off-by: Anand Lodnoor <anand.lodnoor@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/megaraid/megaraid_sas_fusion.c

index 8b6cc1ba42093ac70fa1d9b1e884c63252bffc1f..0bdd47711941bebb96d5674401ff4fe60f2dda80 100644 (file)
@@ -4223,7 +4223,8 @@ void  megasas_reset_reply_desc(struct megasas_instance *instance)
  * megasas_refire_mgmt_cmd :   Re-fire management commands
  * @instance:                          Controller's soft instance
 */
-static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
+void megasas_refire_mgmt_cmd(struct megasas_instance *instance,
+                            bool return_ioctl)
 {
        int j;
        struct megasas_cmd_fusion *cmd_fusion;
@@ -4287,6 +4288,16 @@ static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
                        break;
                }
 
+               if (return_ioctl && cmd_mfi->sync_cmd &&
+                   cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT) {
+                       dev_err(&instance->pdev->dev,
+                               "return -EBUSY from %s %d cmd 0x%x opcode 0x%x\n",
+                               __func__, __LINE__, cmd_mfi->frame->hdr.cmd,
+                               le32_to_cpu(cmd_mfi->frame->dcmd.opcode));
+                       cmd_mfi->cmd_status_drv = DCMD_BUSY;
+                       result = COMPLETE_CMD;
+               }
+
                switch (result) {
                case REFIRE_CMD:
                        megasas_fire_cmd_fusion(instance, req_desc);
@@ -4301,6 +4312,37 @@ static void megasas_refire_mgmt_cmd(struct megasas_instance *instance)
        }
 }
 
+/*
+ * megasas_return_polled_cmds: Return polled mode commands back to the pool
+ *                            before initiating an OCR.
+ * @instance:                  Controller's soft instance
+ */
+static void
+megasas_return_polled_cmds(struct megasas_instance *instance)
+{
+       int i;
+       struct megasas_cmd_fusion *cmd_fusion;
+       struct fusion_context *fusion;
+       struct megasas_cmd *cmd_mfi;
+
+       fusion = instance->ctrl_context;
+
+       for (i = instance->max_scsi_cmds; i < instance->max_fw_cmds; i++) {
+               cmd_fusion = fusion->cmd_list[i];
+               cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
+
+               if (cmd_mfi->flags & DRV_DCMD_POLLED_MODE) {
+                       if (megasas_dbg_lvl & OCR_DEBUG)
+                               dev_info(&instance->pdev->dev,
+                                        "%s %d return cmd 0x%x opcode 0x%x\n",
+                                        __func__, __LINE__, cmd_mfi->frame->hdr.cmd,
+                                        le32_to_cpu(cmd_mfi->frame->dcmd.opcode));
+                       cmd_mfi->flags &= ~DRV_DCMD_POLLED_MODE;
+                       megasas_return_cmd(instance, cmd_mfi);
+               }
+       }
+}
+
 /*
  * megasas_track_scsiio : Track SCSI IOs outstanding to a SCSI device
  * @instance: per adapter struct
@@ -4956,7 +4998,9 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
                                goto kill_hba;
                        }
 
-                       megasas_refire_mgmt_cmd(instance);
+                       megasas_refire_mgmt_cmd(instance,
+                                               (i == (MEGASAS_FUSION_MAX_RESET_TRIES - 1)
+                                                       ? 1 : 0));
 
                        /* Reset load balance info */
                        if (fusion->load_balance_info)
@@ -4964,8 +5008,16 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason)
                                       (sizeof(struct LD_LOAD_BALANCE_INFO) *
                                       MAX_LOGICAL_DRIVES_EXT));
 
-                       if (!megasas_get_map_info(instance))
+                       if (!megasas_get_map_info(instance)) {
                                megasas_sync_map_info(instance);
+                       } else {
+                               /*
+                                * Return pending polled mode cmds before
+                                * retrying OCR
+                                */
+                               megasas_return_polled_cmds(instance);
+                               continue;
+                       }
 
                        megasas_setup_jbod_map(instance);