scsi: qla2xxx: Wind down adapter after PCIe error
commit d3117c83ba316b3200d9f2fe900f2b9a5525a25c upstream. Put adapter into a wind down state if OS does not make any attempt to recover the adapter after PCIe error. Link: https://lore.kernel.org/r/20220616053508.27186-4-njavali@marvell.com Cc: stable@vger.kernel.org Signed-off-by: Quinn Tran <qutran@marvell.com> Signed-off-by: Nilesh Javali <njavali@marvell.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
c3a824d061
commit
dc07af0e7c
@ -2975,6 +2975,13 @@ qla24xx_bsg_timeout(struct bsg_job *bsg_job)
|
||||
|
||||
ql_log(ql_log_info, vha, 0x708b, "%s CMD timeout. bsg ptr %p.\n",
|
||||
__func__, bsg_job);
|
||||
|
||||
if (qla2x00_isp_reg_stat(ha)) {
|
||||
ql_log(ql_log_info, vha, 0x9007,
|
||||
"PCI/Register disconnect.\n");
|
||||
qla_pci_set_eeh_busy(vha);
|
||||
}
|
||||
|
||||
/* find the bsg job from the active list of commands */
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
for (que = 0; que < ha->max_req_queues; que++) {
|
||||
@ -2992,7 +2999,8 @@ qla24xx_bsg_timeout(struct bsg_job *bsg_job)
|
||||
sp->u.bsg_job == bsg_job) {
|
||||
req->outstanding_cmds[cnt] = NULL;
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
if (ha->isp_ops->abort_command(sp)) {
|
||||
|
||||
if (!ha->flags.eeh_busy && ha->isp_ops->abort_command(sp)) {
|
||||
ql_log(ql_log_warn, vha, 0x7089,
|
||||
"mbx abort_command failed.\n");
|
||||
bsg_reply->result = -EIO;
|
||||
|
@ -4048,6 +4048,9 @@ struct qla_hw_data {
|
||||
uint32_t n2n_fw_acc_sec:1;
|
||||
uint32_t plogi_template_valid:1;
|
||||
uint32_t port_isolated:1;
|
||||
uint32_t eeh_flush:2;
|
||||
#define EEH_FLUSH_RDY 1
|
||||
#define EEH_FLUSH_DONE 2
|
||||
} flags;
|
||||
|
||||
uint16_t max_exchg;
|
||||
@ -4082,6 +4085,7 @@ struct qla_hw_data {
|
||||
uint32_t rsp_que_len;
|
||||
uint32_t req_que_off;
|
||||
uint32_t rsp_que_off;
|
||||
unsigned long eeh_jif;
|
||||
|
||||
/* Multi queue data structs */
|
||||
device_reg_t *mqiobase;
|
||||
|
@ -47,6 +47,7 @@ qla2x00_sp_timeout(struct timer_list *t)
|
||||
{
|
||||
srb_t *sp = from_timer(sp, t, u.iocb_cmd.timer);
|
||||
struct srb_iocb *iocb;
|
||||
scsi_qla_host_t *vha = sp->vha;
|
||||
|
||||
WARN_ON(irqs_disabled());
|
||||
iocb = &sp->u.iocb_cmd;
|
||||
@ -54,6 +55,12 @@ qla2x00_sp_timeout(struct timer_list *t)
|
||||
|
||||
/* ref: TMR */
|
||||
kref_put(&sp->cmd_kref, qla2x00_sp_release);
|
||||
|
||||
if (vha && qla2x00_isp_reg_stat(vha->hw)) {
|
||||
ql_log(ql_log_info, vha, 0x9008,
|
||||
"PCI/Register disconnect.\n");
|
||||
qla_pci_set_eeh_busy(vha);
|
||||
}
|
||||
}
|
||||
|
||||
void qla2x00_sp_free(srb_t *sp)
|
||||
@ -9702,6 +9709,12 @@ int qla2xxx_disable_port(struct Scsi_Host *host)
|
||||
|
||||
vha->hw->flags.port_isolated = 1;
|
||||
|
||||
if (qla2x00_isp_reg_stat(vha->hw)) {
|
||||
ql_log(ql_log_info, vha, 0x9006,
|
||||
"PCI/Register disconnect, exiting.\n");
|
||||
qla_pci_set_eeh_busy(vha);
|
||||
return FAILED;
|
||||
}
|
||||
if (qla2x00_chip_is_down(vha))
|
||||
return 0;
|
||||
|
||||
@ -9717,6 +9730,13 @@ int qla2xxx_enable_port(struct Scsi_Host *host)
|
||||
{
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
|
||||
if (qla2x00_isp_reg_stat(vha->hw)) {
|
||||
ql_log(ql_log_info, vha, 0x9001,
|
||||
"PCI/Register disconnect, exiting.\n");
|
||||
qla_pci_set_eeh_busy(vha);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
vha->hw->flags.port_isolated = 0;
|
||||
/* Set the flag to 1, so that isp_abort can proceed */
|
||||
vha->flags.online = 1;
|
||||
|
@ -333,6 +333,11 @@ MODULE_PARM_DESC(ql2xabts_wait_nvme,
|
||||
"To wait for ABTS response on I/O timeouts for NVMe. (default: 1)");
|
||||
|
||||
|
||||
u32 ql2xdelay_before_pci_error_handling = 5;
|
||||
module_param(ql2xdelay_before_pci_error_handling, uint, 0644);
|
||||
MODULE_PARM_DESC(ql2xdelay_before_pci_error_handling,
|
||||
"Number of seconds delayed before qla begin PCI error self-handling (default: 5).\n");
|
||||
|
||||
static void qla2x00_clear_drv_active(struct qla_hw_data *);
|
||||
static void qla2x00_free_device(scsi_qla_host_t *);
|
||||
static int qla2xxx_map_queues(struct Scsi_Host *shost);
|
||||
@ -7257,6 +7262,44 @@ static void qla_heart_beat(struct scsi_qla_host *vha, u16 dpc_started)
|
||||
}
|
||||
}
|
||||
|
||||
static void qla_wind_down_chip(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!ha->flags.eeh_busy)
|
||||
return;
|
||||
if (ha->pci_error_state)
|
||||
/* system is trying to recover */
|
||||
return;
|
||||
|
||||
/*
|
||||
* Current system is not handling PCIE error. At this point, this is
|
||||
* best effort to wind down the adapter.
|
||||
*/
|
||||
if (time_after_eq(jiffies, ha->eeh_jif + ql2xdelay_before_pci_error_handling * HZ) &&
|
||||
!ha->flags.eeh_flush) {
|
||||
ql_log(ql_log_info, vha, 0x9009,
|
||||
"PCI Error detected, attempting to reset hardware.\n");
|
||||
|
||||
ha->isp_ops->reset_chip(vha);
|
||||
ha->isp_ops->disable_intrs(ha);
|
||||
|
||||
ha->flags.eeh_flush = EEH_FLUSH_RDY;
|
||||
ha->eeh_jif = jiffies;
|
||||
|
||||
} else if (ha->flags.eeh_flush == EEH_FLUSH_RDY &&
|
||||
time_after_eq(jiffies, ha->eeh_jif + 5 * HZ)) {
|
||||
pci_clear_master(ha->pdev);
|
||||
|
||||
/* flush all command */
|
||||
qla2x00_abort_isp_cleanup(vha);
|
||||
ha->flags.eeh_flush = EEH_FLUSH_DONE;
|
||||
|
||||
ql_log(ql_log_info, vha, 0x900a,
|
||||
"PCI Error handling complete, all IOs aborted.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* qla2x00_timer
|
||||
*
|
||||
@ -7280,6 +7323,8 @@ qla2x00_timer(struct timer_list *t)
|
||||
fc_port_t *fcport = NULL;
|
||||
|
||||
if (ha->flags.eeh_busy) {
|
||||
qla_wind_down_chip(vha);
|
||||
|
||||
ql_dbg(ql_dbg_timer, vha, 0x6000,
|
||||
"EEH = %d, restarting timer.\n",
|
||||
ha->flags.eeh_busy);
|
||||
@ -7860,6 +7905,9 @@ void qla_pci_set_eeh_busy(struct scsi_qla_host *vha)
|
||||
|
||||
spin_lock_irqsave(&base_vha->work_lock, flags);
|
||||
if (!ha->flags.eeh_busy) {
|
||||
ha->eeh_jif = jiffies;
|
||||
ha->flags.eeh_flush = 0;
|
||||
|
||||
ha->flags.eeh_busy = 1;
|
||||
do_cleanup = true;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user