[PATCH 08/10] qla2xxx: Move heart beat handling from dpc thread to workqueue
Himanshu Madhani
himanshu.madhani at oracle.com
Wed Sep 8 07:14:55 PDT 2021
> On Sep 8, 2021, at 2:28 AM, Nilesh Javali <njavali at marvell.com> wrote:
>
> From: Manish Rangankar <mrangankar at marvell.com>
>
> DPC thread gets restricted due to a no-op mailbox, which is a blocking call
> and has a high execution frequency. To free up the DPC thread we move no-op
> handling to the workqueue. Also, modified qla_do_hb to send no-op MBC if
> we don’t have any active interrupts, but there are still IOs outstanding
> with firmware.
>
> Fixes: d94d8158e184 ("scsi: qla2xxx: Add heartbeat check")
Cc: stable at vger.kernel.org
> Signed-off-by: Manish Rangankar <mrangankar at marvell.com>
> Signed-off-by: Nilesh Javali <njavali at marvell.com>
> ---
> drivers/scsi/qla2xxx/qla_def.h | 4 +-
> drivers/scsi/qla2xxx/qla_init.c | 2 +
> drivers/scsi/qla2xxx/qla_os.c | 74 +++++++++++++++------------------
> 3 files changed, 38 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
> index be2eb75ee1a3..d6e131bf1824 100644
> --- a/drivers/scsi/qla2xxx/qla_def.h
> +++ b/drivers/scsi/qla2xxx/qla_def.h
> @@ -3750,6 +3750,7 @@ struct qla_qpair {
> struct qla_fw_resources fwres ____cacheline_aligned;
> u32 cmd_cnt;
> u32 cmd_completion_cnt;
> + u32 prev_completion_cnt;
> };
>
> /* Place holder for FW buffer parameters */
> @@ -4607,6 +4608,7 @@ struct qla_hw_data {
> struct qla_chip_state_84xx *cs84xx;
> struct isp_operations *isp_ops;
> struct workqueue_struct *wq;
> + struct work_struct hb_work;
Use heartbeat_work (which is not awfully long and reads better.
> struct qlfc_fw fw_buf;
>
> /* FCP_CMND priority support */
> @@ -4708,7 +4710,6 @@ struct qla_hw_data {
>
> struct qla_hw_data_stat stat;
> pci_error_state_t pci_error_state;
> - u64 prev_cmd_cnt;
> struct dma_pool *purex_dma_pool;
> struct btree_head32 host_map;
>
> @@ -4854,7 +4855,6 @@ typedef struct scsi_qla_host {
> #define SET_ZIO_THRESHOLD_NEEDED 32
> #define ISP_ABORT_TO_ROM 33
> #define VPORT_DELETE 34
> -#define HEARTBEAT_CHK 38
>
> #define PROCESS_PUREX_IOCB 63
>
> diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
> index c6b3d0e7489e..a9a4243cb15a 100644
> --- a/drivers/scsi/qla2xxx/qla_init.c
> +++ b/drivers/scsi/qla2xxx/qla_init.c
> @@ -7025,12 +7025,14 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha)
> ha->chip_reset++;
> ha->base_qpair->chip_reset = ha->chip_reset;
> ha->base_qpair->cmd_cnt = ha->base_qpair->cmd_completion_cnt = 0;
> + ha->base_qpair->prev_completion_cnt = 0;
> for (i = 0; i < ha->max_qpairs; i++) {
> if (ha->queue_pair_map[i]) {
> ha->queue_pair_map[i]->chip_reset =
> ha->base_qpair->chip_reset;
> ha->queue_pair_map[i]->cmd_cnt =
> ha->queue_pair_map[i]->cmd_completion_cnt = 0;
> + ha->base_qpair->prev_completion_cnt = 0;
> }
> }
>
> diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
> index a1e861ecfc01..0454f79a8047 100644
> --- a/drivers/scsi/qla2xxx/qla_os.c
> +++ b/drivers/scsi/qla2xxx/qla_os.c
> @@ -2794,6 +2794,16 @@ qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time)
> return atomic_read(&vha->loop_state) == LOOP_READY;
> }
>
> +static void qla_hb_work_fn(struct work_struct *work)
^^^^^^^^^^^^^^
Use qla_heartbeat_work_fn for better readability
> +{
> + struct qla_hw_data *ha = container_of(work,
> + struct qla_hw_data, hb_work);
> + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
> +
> + if (!ha->flags.mbox_busy && base_vha->flags.init_done)
> + qla_no_op_mb(base_vha);
> +}
> +
> static void qla2x00_iocb_work_fn(struct work_struct *work)
> {
> struct scsi_qla_host *vha = container_of(work,
> @@ -3232,6 +3242,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
> host->transportt, sht->vendor_id);
>
> INIT_WORK(&base_vha->iocb_work, qla2x00_iocb_work_fn);
> + INIT_WORK(&ha->hb_work, qla_hb_work_fn);
>
> /* Set up the irqs */
> ret = qla2x00_request_irqs(ha, rsp);
> @@ -7118,17 +7129,6 @@ qla2x00_do_dpc(void *data)
> qla2x00_lip_reset(base_vha);
> }
>
> - if (test_bit(HEARTBEAT_CHK, &base_vha->dpc_flags)) {
> - /*
> - * if there is a mb in progress then that's
> - * enough of a check to see if fw is still ticking.
> - */
> - if (!ha->flags.mbox_busy && base_vha->flags.init_done)
> - qla_no_op_mb(base_vha);
> -
> - clear_bit(HEARTBEAT_CHK, &base_vha->dpc_flags);
> - }
> -
> ha->dpc_active = 0;
> end_loop:
> set_current_state(TASK_INTERRUPTIBLE);
> @@ -7187,57 +7187,51 @@ qla2x00_rst_aen(scsi_qla_host_t *vha)
>
> static bool qla_do_heartbeat(struct scsi_qla_host *vha)
> {
> - u64 cmd_cnt, prev_cmd_cnt;
> - bool do_hb = false;
> struct qla_hw_data *ha = vha->hw;
> - int i;
> + u32 cmpl_cnt;
> + u16 i;
> + bool do_hb = false;
>
use do_heartbeat which is self-explanatory and reads better
> - /* if cmds are still pending down in fw, then do hb */
> - if (ha->base_qpair->cmd_cnt != ha->base_qpair->cmd_completion_cnt) {
> + /*
> + * Allow do_hb only if we don’t have any active interrupts,
> + * but there are still IOs outstanding with firmware.
> + */
> + cmpl_cnt = ha->base_qpair->cmd_completion_cnt;
> + if (cmpl_cnt == ha->base_qpair->prev_completion_cnt &&
> + cmpl_cnt != ha->base_qpair->cmd_cnt) {
> do_hb = true;
> goto skip;
> }
> + ha->base_qpair->prev_completion_cnt = cmpl_cnt;
>
> for (i = 0; i < ha->max_qpairs; i++) {
> - if (ha->queue_pair_map[i] &&
> - ha->queue_pair_map[i]->cmd_cnt !=
> - ha->queue_pair_map[i]->cmd_completion_cnt) {
> - do_hb = true;
> - break;
> + if (ha->queue_pair_map[i]) {
> + cmpl_cnt = ha->queue_pair_map[i]->cmd_completion_cnt;
> + if (cmpl_cnt == ha->queue_pair_map[i]->prev_completion_cnt &&
> + cmpl_cnt != ha->queue_pair_map[i]->cmd_cnt) {
> + do_hb = true;
> + break;
> + }
> + ha->queue_pair_map[i]->prev_completion_cnt = cmpl_cnt;
> }
> }
>
> skip:
> - prev_cmd_cnt = ha->prev_cmd_cnt;
> - cmd_cnt = ha->base_qpair->cmd_cnt;
> - for (i = 0; i < ha->max_qpairs; i++) {
> - if (ha->queue_pair_map[i])
> - cmd_cnt += ha->queue_pair_map[i]->cmd_cnt;
> - }
> - ha->prev_cmd_cnt = cmd_cnt;
> -
> - if (!do_hb && ((cmd_cnt - prev_cmd_cnt) > 50))
> - /*
> - * IOs are completing before periodic hb check.
> - * IOs seems to be running, do hb for sanity check.
> - */
> - do_hb = true;
> -
> return do_hb;
> }
>
> static void qla_heart_beat(struct scsi_qla_host *vha)
> {
> + struct qla_hw_data *ha = vha->hw;
> +
> if (vha->vp_idx)
> return;
>
> if (vha->hw->flags.eeh_busy || qla2x00_chip_is_down(vha))
> return;
>
> - if (qla_do_heartbeat(vha)) {
> - set_bit(HEARTBEAT_CHK, &vha->dpc_flags);
> - qla2xxx_wake_dpc(vha);
> - }
> + if (qla_do_heartbeat(vha))
> + queue_work(ha->wq, &ha->hb_work);
> }
>
> /**************************************************************************
> --
> 2.19.0.rc0
>
--
Himanshu Madhani Oracle Linux Engineering
More information about the Linux-nvme
mailing list