diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 902b11b97999..990ee23d7bc2 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -2636,4 +2636,7 @@ void megasas_fusion_stop_watchdog(struct megasas_instance *instance); void megasas_set_dma_settings(struct megasas_instance *instance, struct megasas_dcmd_frame *dcmd, dma_addr_t dma_addr, u32 dma_len); +int megasas_adp_reset_wait_for_ready(struct megasas_instance *instance, + bool do_adp_reset, + int ocr_context); #endif /*LSI_MEGARAID_SAS_H */ diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 63b31082d985..34abd5194b0b 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5534,13 +5534,15 @@ static int megasas_init_fw(struct megasas_instance *instance) } if (megasas_transition_to_ready(instance, 0)) { + dev_info(&instance->pdev->dev, + "Failed to transition controller to ready from %s!\n", + __func__); if (instance->adapter_type != MFI_SERIES) { status_reg = instance->instancet->read_fw_status_reg( instance); if (status_reg & MFI_RESET_ADAPTER) { - instance->instancet->adp_reset - (instance, instance->reg_set); - if (megasas_transition_to_ready(instance, 0)) + if (megasas_adp_reset_wait_for_ready + (instance, true, 0) == FAILED) goto fail_ready_state; } else { goto fail_ready_state; @@ -5550,9 +5552,6 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->instancet->adp_reset (instance, instance->reg_set); atomic_set(&instance->fw_reset_no_pci_access, 0); - dev_info(&instance->pdev->dev, - "FW restarted successfully from %s!\n", - __func__); /*waiting for about 30 second before retry*/ ssleep(30); @@ -5560,6 +5559,10 @@ static int megasas_init_fw(struct megasas_instance *instance) if (megasas_transition_to_ready(instance, 0)) goto fail_ready_state; } + + dev_info(&instance->pdev->dev, + "FW restarted successfully from %s!\n", + __func__); } megasas_init_ctrl_params(instance); diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 7ef768dce944..5dc324ca4090 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -98,6 +98,62 @@ static void megasas_fusion_crash_dump(struct megasas_instance *instance); extern u32 megasas_readl(struct megasas_instance *instance, const volatile void __iomem *addr); +/** + * megasas_adp_reset_wait_for_ready - initiate chip reset and wait for + * controller to come to ready state + * @instance - adapter's soft state + * @do_adp_reset - If true, do a chip reset + * @ocr_context - If called from OCR context this will + * be set to 1, else 0 + * + * This function initates a chip reset followed by a wait for controller to + * transition to ready state. + * During this, driver will block all access to PCI config space from userspace + */ +int +megasas_adp_reset_wait_for_ready(struct megasas_instance *instance, + bool do_adp_reset, + int ocr_context) +{ + int ret = FAILED; + + /* + * Block access to PCI config space from userspace + * when diag reset is initiated from driver + */ + if (megasas_dbg_lvl & OCR_LOGS) + dev_info(&instance->pdev->dev, + "Block access to PCI config space %s %d\n", + __func__, __LINE__); + + pci_cfg_access_lock(instance->pdev); + + if (do_adp_reset) { + if (instance->instancet->adp_reset + (instance, instance->reg_set)) + goto out; + } + + /* Wait for FW to become ready */ + if (megasas_transition_to_ready(instance, ocr_context)) { + dev_warn(&instance->pdev->dev, + "Failed to transition controller to ready for scsi%d.\n", + instance->host->host_no); + goto out; + } + + ret = SUCCESS; +out: + if (megasas_dbg_lvl & OCR_LOGS) + dev_info(&instance->pdev->dev, + "Unlock access to PCI config space %s %d\n", + __func__, __LINE__); + + pci_cfg_access_unlock(instance->pdev); + + return ret; +} + /** * megasas_check_same_4gb_region - check if allocation * crosses same 4GB boundary or not @@ -4693,10 +4749,12 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int reason) /* Now try to reset the chip */ for (i = 0; i < max_reset_tries; i++) { - - if (do_adp_reset && - instance->instancet->adp_reset - (instance, instance->reg_set)) + /* + * Do adp reset and wait for + * controller to transition to ready + */ + if (megasas_adp_reset_wait_for_ready(instance, + do_adp_reset, 1) == FAILED) continue; /* Wait for FW to become ready */