scsi: qla2xxx: Fix laggy FC remote port session recovery
authorQuinn Tran <qutran@marvell.com>
Thu, 10 Mar 2022 09:25:59 +0000 (01:25 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 12 Jul 2022 14:34:59 +0000 (16:34 +0200)
[ Upstream commit 713b415726f100f6644971e75ebfe1edbef1a390 ]

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@marvell.com
Fixes: d94d8158e184 ("scsi: qla2xxx: Add heartbeat check")
Cc: stable@vger.kernel.org
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
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: Sasha Levin <sashal@kernel.org>
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_os.c

index 0589ab8..303ad60 100644 (file)
@@ -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;
index b224326..12958ae 100644 (file)
@@ -7205,7 +7205,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;
 
@@ -7215,8 +7215,19 @@ static void qla_heart_beat(struct scsi_qla_host *vha)
        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);
+       }
 }
 
 /**************************************************************************
@@ -7407,6 +7418,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) ||
@@ -7439,9 +7452,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);
 }