[PATCH 5.17 0987/1126] scsi: qla2xxx: Fix laggy FC remote port session recovery

From: Greg Kroah-Hartman
Date: Tue Apr 05 2022 - 06:51:33 EST


From: Quinn Tran <qutran@xxxxxxxxxxx>

commit 713b415726f100f6644971e75ebfe1edbef1a390 upstream.

For session recovery, driver relies on the dpc thread to initiate certain
operations. The dpc thread runs exclusively without the Mailbox interface
being occupied. A recent code change for heartbeat check via mailbox cmd 0
is preventing the dpc thread from carrying out its operation. This patch
allows the higher priority error recovery to run first before running the
lower priority heartbeat check.

Link: https://lore.kernel.org/r/20220310092604.22950-9-njavali@xxxxxxxxxxx
Fixes: d94d8158e184 ("scsi: qla2xxx: Add heartbeat check")
Cc: stable@xxxxxxxxxxxxxxx
Reviewed-by: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx>
Signed-off-by: Quinn Tran <qutran@xxxxxxxxxxx>
Signed-off-by: Nilesh Javali <njavali@xxxxxxxxxxx>
Signed-off-by: Martin K. Petersen <martin.petersen@xxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
---
drivers/scsi/qla2xxx/qla_def.h | 1 +
drivers/scsi/qla2xxx/qla_os.c | 20 +++++++++++++++++---
2 files changed, 18 insertions(+), 3 deletions(-)

--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -4621,6 +4621,7 @@ struct qla_hw_data {
struct workqueue_struct *wq;
struct work_struct heartbeat_work;
struct qlfc_fw fw_buf;
+ unsigned long last_heartbeat_run_jiffies;

/* FCP_CMND priority support */
struct qla_fcp_prio_cfg *fcp_prio_cfg;
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -7209,7 +7209,7 @@ skip:
return do_heartbeat;
}

-static void qla_heart_beat(struct scsi_qla_host *vha)
+static void qla_heart_beat(struct scsi_qla_host *vha, u16 dpc_started)
{
struct qla_hw_data *ha = vha->hw;

@@ -7219,8 +7219,19 @@ static void qla_heart_beat(struct scsi_q
if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha))
return;

- if (qla_do_heartbeat(vha))
+ /*
+ * dpc thread cannot run if heartbeat is running at the same time.
+ * We also do not want to starve heartbeat task. Therefore, do
+ * heartbeat task at least once every 5 seconds.
+ */
+ if (dpc_started &&
+ time_before(jiffies, ha->last_heartbeat_run_jiffies + 5 * HZ))
+ return;
+
+ if (qla_do_heartbeat(vha)) {
+ ha->last_heartbeat_run_jiffies = jiffies;
queue_work(ha->wq, &ha->heartbeat_work);
+ }
}

/**************************************************************************
@@ -7411,6 +7422,8 @@ qla2x00_timer(struct timer_list *t)
start_dpc++;
}

+ /* borrowing w to signify dpc will run */
+ w = 0;
/* Schedule the DPC routine if needed */
if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) ||
test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) ||
@@ -7443,9 +7456,10 @@ qla2x00_timer(struct timer_list *t)
test_bit(RELOGIN_NEEDED, &vha->dpc_flags),
test_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags));
qla2xxx_wake_dpc(vha);
+ w = 1;
}

- qla_heart_beat(vha);
+ qla_heart_beat(vha, w);

qla2x00_restart_timer(vha, WATCH_INTERVAL);
}