Commit 79b82c2c authored by sumit.saxena@avagotech.com's avatar sumit.saxena@avagotech.com Committed by Martin K. Petersen

megaraid_sas: Chip reset if driver fails to get IOC ready

Fix the issue reported at:

	http://marc.info/?l=linux-scsi&m=143694494104544&w=2

Try to do chip reset at driver load time. If firmware fails to reach
ready state, try chip reset using adp_reset() callback. For Fusion
adapters the call back was previously void. Provide a suitable reset
function.
Signed-off-by: default avatarSumit Saxena <sumit.saxena@avagotech.com>
Signed-off-by: default avatarKashyap Desai <kashyap.desai@avagotech.com>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent bd5f9484
...@@ -2509,6 +2509,70 @@ static int ...@@ -2509,6 +2509,70 @@ static int
megasas_adp_reset_fusion(struct megasas_instance *instance, megasas_adp_reset_fusion(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs) struct megasas_register_set __iomem *regs)
{ {
u32 host_diag, abs_state, retry;
/* Now try to reset the chip */
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_1ST_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_2ND_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_3RD_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_4TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_5TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_6TH_KEY_VALUE, &instance->reg_set->fusion_seq_offset);
/* Check that the diag write enable (DRWE) bit is on */
host_diag = readl(&instance->reg_set->fusion_host_diag);
retry = 0;
while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
msleep(100);
host_diag = readl(&instance->reg_set->fusion_host_diag);
if (retry++ == 100) {
dev_warn(&instance->pdev->dev,
"Host diag unlock failed from %s %d\n",
__func__, __LINE__);
break;
}
}
if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
return -1;
/* Send chip reset command */
writel(host_diag | HOST_DIAG_RESET_ADAPTER,
&instance->reg_set->fusion_host_diag);
msleep(3000);
/* Make sure reset adapter bit is cleared */
host_diag = readl(&instance->reg_set->fusion_host_diag);
retry = 0;
while (host_diag & HOST_DIAG_RESET_ADAPTER) {
msleep(100);
host_diag = readl(&instance->reg_set->fusion_host_diag);
if (retry++ == 1000) {
dev_warn(&instance->pdev->dev,
"Diag reset adapter never cleared %s %d\n",
__func__, __LINE__);
break;
}
}
if (host_diag & HOST_DIAG_RESET_ADAPTER)
return -1;
abs_state = instance->instancet->read_fw_status_reg(instance->reg_set)
& MFI_STATE_MASK;
retry = 0;
while ((abs_state <= MFI_STATE_FW_INIT) && (retry++ < 1000)) {
msleep(100);
abs_state = instance->instancet->
read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
}
if (abs_state <= MFI_STATE_FW_INIT) {
dev_warn(&instance->pdev->dev,
"fw state < MFI_STATE_FW_INIT, state = 0x%x %s %d\n",
abs_state, __func__, __LINE__);
return -1;
}
return 0; return 0;
} }
...@@ -2674,11 +2738,11 @@ int megasas_check_mpio_paths(struct megasas_instance *instance, ...@@ -2674,11 +2738,11 @@ int megasas_check_mpio_paths(struct megasas_instance *instance,
/* Core fusion reset function */ /* Core fusion reset function */
int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
{ {
int retval = SUCCESS, i, retry = 0, convert = 0; int retval = SUCCESS, i, convert = 0;
struct megasas_instance *instance; struct megasas_instance *instance;
struct megasas_cmd_fusion *cmd_fusion; struct megasas_cmd_fusion *cmd_fusion;
struct fusion_context *fusion; struct fusion_context *fusion;
u32 host_diag, abs_state, status_reg, reset_adapter; u32 abs_state, status_reg, reset_adapter;
u32 io_timeout_in_crash_mode = 0; u32 io_timeout_in_crash_mode = 0;
struct scsi_cmnd *scmd_local = NULL; struct scsi_cmnd *scmd_local = NULL;
...@@ -2832,81 +2896,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) ...@@ -2832,81 +2896,10 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
/* Now try to reset the chip */ /* Now try to reset the chip */
for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) { for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) {
writel(MPI2_WRSEQ_FLUSH_KEY_VALUE,
&instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_1ST_KEY_VALUE,
&instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_2ND_KEY_VALUE,
&instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_3RD_KEY_VALUE,
&instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_4TH_KEY_VALUE,
&instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_5TH_KEY_VALUE,
&instance->reg_set->fusion_seq_offset);
writel(MPI2_WRSEQ_6TH_KEY_VALUE,
&instance->reg_set->fusion_seq_offset);
/* Check that the diag write enable (DRWE) bit is on */
host_diag = readl(&instance->reg_set->fusion_host_diag);
retry = 0;
while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) {
msleep(100);
host_diag =
readl(&instance->reg_set->fusion_host_diag);
if (retry++ == 100) {
dev_warn(&instance->pdev->dev,
"Host diag unlock failed! "
"for scsi%d\n",
instance->host->host_no);
break;
}
}
if (!(host_diag & HOST_DIAG_WRITE_ENABLE))
continue;
/* Send chip reset command */
writel(host_diag | HOST_DIAG_RESET_ADAPTER,
&instance->reg_set->fusion_host_diag);
msleep(3000);
/* Make sure reset adapter bit is cleared */
host_diag = readl(&instance->reg_set->fusion_host_diag);
retry = 0;
while (host_diag & HOST_DIAG_RESET_ADAPTER) {
msleep(100);
host_diag =
readl(&instance->reg_set->fusion_host_diag);
if (retry++ == 1000) {
dev_warn(&instance->pdev->dev,
"Diag reset adapter never "
"cleared for scsi%d!\n",
instance->host->host_no);
break;
}
}
if (host_diag & HOST_DIAG_RESET_ADAPTER)
continue;
abs_state = if (instance->instancet->adp_reset
instance->instancet->read_fw_status_reg( (instance, instance->reg_set))
instance->reg_set) & MFI_STATE_MASK;
retry = 0;
while ((abs_state <= MFI_STATE_FW_INIT) &&
(retry++ < 1000)) {
msleep(100);
abs_state =
instance->instancet->read_fw_status_reg(
instance->reg_set) & MFI_STATE_MASK;
}
if (abs_state <= MFI_STATE_FW_INIT) {
dev_warn(&instance->pdev->dev, "firmware "
"state < MFI_STATE_FW_INIT, state = "
"0x%x for scsi%d\n", abs_state,
instance->host->host_no);
continue; continue;
}
/* Wait for FW to become ready */ /* Wait for FW to become ready */
if (megasas_transition_to_ready(instance, 1)) { if (megasas_transition_to_ready(instance, 1)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment