[PATCH 3.19 057/175] megaraid_sas: complete outstanding IOCTLs before killing adapter

Greg Kroah-Hartman
2015-03-04T06:20:49Z

From: "Sumit.Saxena@avagotech.com" <Sumit.Saxena@avagotech.com>

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 | 65 +++++++++++++++++++++++-----
drivers/scsi/megaraid/megaraid_sas_fusion.c | 4 -
2 files changed, 54 insertions(+), 15 deletions(-)

--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1689,22 +1689,66 @@ static int megasas_slave_alloc(struct sc
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
"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_s
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 ;
}

--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -2622,7 +2622,6 @@ int megasas_reset_fusion(struct Scsi_Hos
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_Hos
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_Hos
"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 */