]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
megaraid_sas: complete outstanding IOCTLs before killing adapter
authorSumit.Saxena@avagotech.com <Sumit.Saxena@avagotech.com>
Mon, 5 Jan 2015 14:36:18 +0000 (20:06 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 6 Mar 2015 22:57:25 +0000 (14:57 -0800)
commit c8dd61eff2780c481fcf919c1572e16e397c714e upstream.

Driver calls megasas_complete_cmd() to call wake_up() for each MFI frame
that was issued through the ioctl() interface prior to the kill adapter.
This ensures userspace ioctl() system calls issued just before a kill
adapter don't get stuck in wait state and IOCTLs are returned to
the application.

Signed-off-by: Sumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: Chaitra Basappa <chaitra.basappa@avagotech.com>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/scsi/megaraid/megaraid_sas_base.c
drivers/scsi/megaraid/megaraid_sas_fusion.c

index 401ed67cf4c13700d6edaac5ef24adc89a9d7259..d63f04147a5952b3ffb257ee340ec9fba7f0bfcc 100644 (file)
@@ -1689,22 +1689,66 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
        return 0;
 }
 
+/*
+* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
+*                                       kill adapter
+* @instance:                           Adapter soft state
+*
+*/
+void megasas_complete_outstanding_ioctls(struct megasas_instance *instance)
+{
+       int i;
+       struct megasas_cmd *cmd_mfi;
+       struct megasas_cmd_fusion *cmd_fusion;
+       struct fusion_context *fusion = instance->ctrl_context;
+
+       /* Find all outstanding ioctls */
+       if (fusion) {
+               for (i = 0; i < instance->max_fw_cmds; i++) {
+                       cmd_fusion = fusion->cmd_list[i];
+                       if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) {
+                               cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
+                               if (cmd_mfi->sync_cmd &&
+                                       cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)
+                                       megasas_complete_cmd(instance,
+                                                            cmd_mfi, DID_OK);
+                       }
+               }
+       } else {
+               for (i = 0; i < instance->max_fw_cmds; i++) {
+                       cmd_mfi = instance->cmd_list[i];
+                       if (cmd_mfi->sync_cmd && cmd_mfi->frame->hdr.cmd !=
+                               MFI_CMD_ABORT)
+                               megasas_complete_cmd(instance, cmd_mfi, DID_OK);
+               }
+       }
+}
+
+
 void megaraid_sas_kill_hba(struct megasas_instance *instance)
 {
+       /* Set critical error to block I/O & ioctls in case caller didn't */
+       instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+       /* Wait 1 second to ensure IO or ioctls in build have posted */
+       msleep(1000);
        if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
-           (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
-           (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
-           (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
-           (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
-           (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
-               writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
+               (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+               writel(MFI_STOP_ADP,
+                       &instance->reg_set->doorbell);
                /* Flush */
                readl(&instance->reg_set->doorbell);
                if (instance->mpio && instance->requestorId)
                        memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
        } else {
-               writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
+               writel(MFI_STOP_ADP,
+                       &instance->reg_set->inbound_doorbell);
        }
+       /* Complete outstanding ioctls when adapter is killed */
+       megasas_complete_outstanding_ioctls(instance);
 }
 
  /**
@@ -3028,10 +3072,9 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance)
                                        "was tried multiple times during reset."
                                        "Shutting down the HBA\n",
                                        cmd, cmd->scmd, cmd->sync_cmd);
+                               instance->instancet->disable_intr(instance);
+                               atomic_set(&instance->fw_reset_no_pci_access, 1);
                                megaraid_sas_kill_hba(instance);
-
-                               instance->adprecovery =
-                                               MEGASAS_HW_CRITICAL_ERROR;
                                return;
                        }
                }
@@ -3165,8 +3208,8 @@ process_fw_state_change_wq(struct work_struct *work)
                if (megasas_transition_to_ready(instance, 1)) {
                        printk(KERN_NOTICE "megaraid_sas:adapter not ready\n");
 
+                       atomic_set(&instance->fw_reset_no_pci_access, 1);
                        megaraid_sas_kill_hba(instance);
-                       instance->adprecovery   = MEGASAS_HW_CRITICAL_ERROR;
                        return ;
                }
 
index 69249faf268c031f95731ab4886f4ba72ce84471..0764d20efb26525b18864da2a0f8a40a5d46df30 100644 (file)
@@ -2622,7 +2622,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
                                instance->host->host_no);
                        megaraid_sas_kill_hba(instance);
                        instance->skip_heartbeat_timer_del = 1;
-                       instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
                        retval = FAILED;
                        goto out;
                }
@@ -2818,8 +2817,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
                                dev_info(&instance->pdev->dev,
                                        "Failed from %s %d\n",
                                        __func__, __LINE__);
-                               instance->adprecovery =
-                                       MEGASAS_HW_CRITICAL_ERROR;
                                megaraid_sas_kill_hba(instance);
                                retval = FAILED;
                        }
@@ -2868,7 +2865,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
                       "adapter scsi%d.\n", instance->host->host_no);
                megaraid_sas_kill_hba(instance);
                instance->skip_heartbeat_timer_del = 1;
-               instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
                retval = FAILED;
        } else {
                /* For VF: Restart HB timer if we didn't OCR */