diff options
author | Deepak Ukey <deepak.ukey@microchip.com> | 2018-09-11 04:48:04 -0400 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2018-09-11 21:14:38 -0400 |
commit | 72349b62a571effd6faadd0600b8e657dd87afbf (patch) | |
tree | ebf719ebe39db294f399abefc2cc8272d5795c97 | |
parent | 76cb25b058034d37244be6aca97a2ad52a5fbcad (diff) |
scsi: pm80xx: Fixed system hang issue during kexec boot
When the firmware is not responding, execution of kexec boot causes a system
hang. When firmware assertion happened, driver get notified with interrupt
vector updated in MPI configuration table. Then, the driver will read
scratchpad register and set controller_fatal_error flag to true.
Signed-off-by: Deepak Ukey <deepak.ukey@microchip.com>
Signed-off-by: Viswas G <Viswas.G@microchip.com>
Acked-by: Jack Wang <jinpu.wang@profitbricks.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 6 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 7 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.h | 1 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.c | 80 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm80xx_hwi.h | 3 |
5 files changed, 91 insertions, 6 deletions
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index a14bf50a76d7..e37ab9789ba6 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c | |||
@@ -1479,6 +1479,12 @@ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, | |||
1479 | } else { | 1479 | } else { |
1480 | u32 producer_index; | 1480 | u32 producer_index; |
1481 | void *pi_virt = circularQ->pi_virt; | 1481 | void *pi_virt = circularQ->pi_virt; |
1482 | /* spurious interrupt during setup if | ||
1483 | * kexec-ing and driver doing a doorbell access | ||
1484 | * with the pre-kexec oq interrupt setup | ||
1485 | */ | ||
1486 | if (!pi_virt) | ||
1487 | break; | ||
1482 | /* Update the producer index from SPC */ | 1488 | /* Update the producer index from SPC */ |
1483 | producer_index = pm8001_read_32(pi_virt); | 1489 | producer_index = pm8001_read_32(pi_virt); |
1484 | circularQ->producer_index = cpu_to_le32(producer_index); | 1490 | circularQ->producer_index = cpu_to_le32(producer_index); |
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index e063faad66f5..b1e7d2699311 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c | |||
@@ -396,6 +396,13 @@ static int pm8001_task_exec(struct sas_task *task, | |||
396 | return 0; | 396 | return 0; |
397 | } | 397 | } |
398 | pm8001_ha = pm8001_find_ha_by_dev(task->dev); | 398 | pm8001_ha = pm8001_find_ha_by_dev(task->dev); |
399 | if (pm8001_ha->controller_fatal_error) { | ||
400 | struct task_status_struct *ts = &t->task_status; | ||
401 | |||
402 | ts->resp = SAS_TASK_UNDELIVERED; | ||
403 | t->task_done(t); | ||
404 | return 0; | ||
405 | } | ||
399 | PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n ")); | 406 | PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n ")); |
400 | spin_lock_irqsave(&pm8001_ha->lock, flags); | 407 | spin_lock_irqsave(&pm8001_ha->lock, flags); |
401 | do { | 408 | do { |
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 80b4dd6df0c2..1816e351071f 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h | |||
@@ -538,6 +538,7 @@ struct pm8001_hba_info { | |||
538 | u32 logging_level; | 538 | u32 logging_level; |
539 | u32 fw_status; | 539 | u32 fw_status; |
540 | u32 smp_exp_mode; | 540 | u32 smp_exp_mode; |
541 | bool controller_fatal_error; | ||
541 | const struct firmware *fw_image; | 542 | const struct firmware *fw_image; |
542 | struct isr_param irq_vector[PM8001_MAX_MSIX_VEC]; | 543 | struct isr_param irq_vector[PM8001_MAX_MSIX_VEC]; |
543 | u32 reset_in_progress; | 544 | u32 reset_in_progress; |
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 91ff6a44e9d9..b641875b8ad7 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c | |||
@@ -577,6 +577,9 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) | |||
577 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size); | 577 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_size); |
578 | pm8001_mw32(address, MAIN_PCS_EVENT_LOG_OPTION, | 578 | pm8001_mw32(address, MAIN_PCS_EVENT_LOG_OPTION, |
579 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity); | 579 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.pcs_event_log_severity); |
580 | /* Update Fatal error interrupt vector */ | ||
581 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt |= | ||
582 | ((pm8001_ha->number_of_intr - 1) << 8); | ||
580 | pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, | 583 | pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, |
581 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); | 584 | pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); |
582 | pm8001_mw32(address, MAIN_EVENT_CRC_CHECK, | 585 | pm8001_mw32(address, MAIN_EVENT_CRC_CHECK, |
@@ -1110,6 +1113,9 @@ static int pm80xx_chip_init(struct pm8001_hba_info *pm8001_ha) | |||
1110 | return -EBUSY; | 1113 | return -EBUSY; |
1111 | } | 1114 | } |
1112 | 1115 | ||
1116 | /* Initialize the controller fatal error flag */ | ||
1117 | pm8001_ha->controller_fatal_error = false; | ||
1118 | |||
1113 | /* Initialize pci space address eg: mpi offset */ | 1119 | /* Initialize pci space address eg: mpi offset */ |
1114 | init_pci_device_addresses(pm8001_ha); | 1120 | init_pci_device_addresses(pm8001_ha); |
1115 | init_default_table_values(pm8001_ha); | 1121 | init_default_table_values(pm8001_ha); |
@@ -1218,13 +1224,17 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) | |||
1218 | u32 bootloader_state; | 1224 | u32 bootloader_state; |
1219 | u32 ibutton0, ibutton1; | 1225 | u32 ibutton0, ibutton1; |
1220 | 1226 | ||
1221 | /* Check if MPI is in ready state to reset */ | 1227 | /* Process MPI table uninitialization only if FW is ready */ |
1222 | if (mpi_uninit_check(pm8001_ha) != 0) { | 1228 | if (!pm8001_ha->controller_fatal_error) { |
1223 | PM8001_FAIL_DBG(pm8001_ha, | 1229 | /* Check if MPI is in ready state to reset */ |
1224 | pm8001_printk("MPI state is not ready\n")); | 1230 | if (mpi_uninit_check(pm8001_ha) != 0) { |
1225 | return -1; | 1231 | regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); |
1232 | PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( | ||
1233 | "MPI state is not ready scratch1 :0x%x\n", | ||
1234 | regval)); | ||
1235 | return -1; | ||
1236 | } | ||
1226 | } | 1237 | } |
1227 | |||
1228 | /* checked for reset register normal state; 0x0 */ | 1238 | /* checked for reset register normal state; 0x0 */ |
1229 | regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); | 1239 | regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); |
1230 | PM8001_INIT_DBG(pm8001_ha, | 1240 | PM8001_INIT_DBG(pm8001_ha, |
@@ -3754,6 +3764,46 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) | |||
3754 | } | 3764 | } |
3755 | } | 3765 | } |
3756 | 3766 | ||
3767 | static void print_scratchpad_registers(struct pm8001_hba_info *pm8001_ha) | ||
3768 | { | ||
3769 | PM8001_FAIL_DBG(pm8001_ha, | ||
3770 | pm8001_printk("MSGU_SCRATCH_PAD_0: 0x%x\n", | ||
3771 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0))); | ||
3772 | PM8001_FAIL_DBG(pm8001_ha, | ||
3773 | pm8001_printk("MSGU_SCRATCH_PAD_1:0x%x\n", | ||
3774 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1))); | ||
3775 | PM8001_FAIL_DBG(pm8001_ha, | ||
3776 | pm8001_printk("MSGU_SCRATCH_PAD_2: 0x%x\n", | ||
3777 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2))); | ||
3778 | PM8001_FAIL_DBG(pm8001_ha, | ||
3779 | pm8001_printk("MSGU_SCRATCH_PAD_3: 0x%x\n", | ||
3780 | pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3))); | ||
3781 | PM8001_FAIL_DBG(pm8001_ha, | ||
3782 | pm8001_printk("MSGU_HOST_SCRATCH_PAD_0: 0x%x\n", | ||
3783 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0))); | ||
3784 | PM8001_FAIL_DBG(pm8001_ha, | ||
3785 | pm8001_printk("MSGU_HOST_SCRATCH_PAD_1: 0x%x\n", | ||
3786 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_1))); | ||
3787 | PM8001_FAIL_DBG(pm8001_ha, | ||
3788 | pm8001_printk("MSGU_HOST_SCRATCH_PAD_2: 0x%x\n", | ||
3789 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_2))); | ||
3790 | PM8001_FAIL_DBG(pm8001_ha, | ||
3791 | pm8001_printk("MSGU_HOST_SCRATCH_PAD_3: 0x%x\n", | ||
3792 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_3))); | ||
3793 | PM8001_FAIL_DBG(pm8001_ha, | ||
3794 | pm8001_printk("MSGU_HOST_SCRATCH_PAD_4: 0x%x\n", | ||
3795 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_4))); | ||
3796 | PM8001_FAIL_DBG(pm8001_ha, | ||
3797 | pm8001_printk("MSGU_HOST_SCRATCH_PAD_5: 0x%x\n", | ||
3798 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_5))); | ||
3799 | PM8001_FAIL_DBG(pm8001_ha, | ||
3800 | pm8001_printk("MSGU_RSVD_SCRATCH_PAD_0: 0x%x\n", | ||
3801 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_6))); | ||
3802 | PM8001_FAIL_DBG(pm8001_ha, | ||
3803 | pm8001_printk("MSGU_RSVD_SCRATCH_PAD_1: 0x%x\n", | ||
3804 | pm8001_cr32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_7))); | ||
3805 | } | ||
3806 | |||
3757 | static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) | 3807 | static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) |
3758 | { | 3808 | { |
3759 | struct outbound_queue_table *circularQ; | 3809 | struct outbound_queue_table *circularQ; |
@@ -3761,10 +3811,28 @@ static int process_oq(struct pm8001_hba_info *pm8001_ha, u8 vec) | |||
3761 | u8 uninitialized_var(bc); | 3811 | u8 uninitialized_var(bc); |
3762 | u32 ret = MPI_IO_STATUS_FAIL; | 3812 | u32 ret = MPI_IO_STATUS_FAIL; |
3763 | unsigned long flags; | 3813 | unsigned long flags; |
3814 | u32 regval; | ||
3764 | 3815 | ||
3816 | if (vec == (pm8001_ha->number_of_intr - 1)) { | ||
3817 | regval = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); | ||
3818 | if ((regval & SCRATCH_PAD_MIPSALL_READY) != | ||
3819 | SCRATCH_PAD_MIPSALL_READY) { | ||
3820 | pm8001_ha->controller_fatal_error = true; | ||
3821 | PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( | ||
3822 | "Firmware Fatal error! Regval:0x%x\n", regval)); | ||
3823 | print_scratchpad_registers(pm8001_ha); | ||
3824 | return ret; | ||
3825 | } | ||
3826 | } | ||
3765 | spin_lock_irqsave(&pm8001_ha->lock, flags); | 3827 | spin_lock_irqsave(&pm8001_ha->lock, flags); |
3766 | circularQ = &pm8001_ha->outbnd_q_tbl[vec]; | 3828 | circularQ = &pm8001_ha->outbnd_q_tbl[vec]; |
3767 | do { | 3829 | do { |
3830 | /* spurious interrupt during setup if kexec-ing and | ||
3831 | * driver doing a doorbell access w/ the pre-kexec oq | ||
3832 | * interrupt setup. | ||
3833 | */ | ||
3834 | if (!circularQ->pi_virt) | ||
3835 | break; | ||
3768 | ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); | 3836 | ret = pm8001_mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); |
3769 | if (MPI_IO_STATUS_SUCCESS == ret) { | 3837 | if (MPI_IO_STATUS_SUCCESS == ret) { |
3770 | /* process the outbound message */ | 3838 | /* process the outbound message */ |
diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index dead05a55aab..84d7426441bf 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h | |||
@@ -1386,6 +1386,9 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t; | |||
1386 | #define SCRATCH_PAD_BOOT_LOAD_SUCCESS 0x0 | 1386 | #define SCRATCH_PAD_BOOT_LOAD_SUCCESS 0x0 |
1387 | #define SCRATCH_PAD_IOP0_READY 0xC00 | 1387 | #define SCRATCH_PAD_IOP0_READY 0xC00 |
1388 | #define SCRATCH_PAD_IOP1_READY 0x3000 | 1388 | #define SCRATCH_PAD_IOP1_READY 0x3000 |
1389 | #define SCRATCH_PAD_MIPSALL_READY (SCRATCH_PAD_IOP1_READY | \ | ||
1390 | SCRATCH_PAD_IOP0_READY | \ | ||
1391 | SCRATCH_PAD_RAAE_READY) | ||
1389 | 1392 | ||
1390 | /* boot loader state */ | 1393 | /* boot loader state */ |
1391 | #define SCRATCH_PAD1_BOOTSTATE_MASK 0x70 /* Bit 4-6 */ | 1394 | #define SCRATCH_PAD1_BOOTSTATE_MASK 0x70 /* Bit 4-6 */ |