Jiri Slaby ef7db2
From: Quinn Tran <qutran@marvell.com>
Jiri Slaby ef7db2
Date: Mon, 19 Dec 2022 03:07:42 -0800
Jiri Slaby ef7db2
Subject: [PATCH] scsi: qla2xxx: Fix exchange oversubscription for management
Jiri Slaby ef7db2
 commands
Jiri Slaby ef7db2
References: bsc#1012628
Jiri Slaby ef7db2
Patch-mainline: 6.2.3
Jiri Slaby ef7db2
Git-commit: 5f63a163ed2f12c34dd4ae9b2757962ec7bb86e5
Jiri Slaby ef7db2
Jiri Slaby ef7db2
[ Upstream commit 5f63a163ed2f12c34dd4ae9b2757962ec7bb86e5 ]
Jiri Slaby ef7db2
Jiri Slaby ef7db2
Add resource checking for management (non-I/O) commands.
Jiri Slaby ef7db2
Jiri Slaby ef7db2
Fixes: 89c72f4245a8 ("scsi: qla2xxx: Add IOCB resource tracking")
Jiri Slaby ef7db2
Signed-off-by: Quinn Tran <qutran@marvell.com>
Jiri Slaby ef7db2
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Jiri Slaby ef7db2
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Jiri Slaby ef7db2
Signed-off-by: Sasha Levin <sashal@kernel.org>
Jiri Slaby ef7db2
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
Jiri Slaby ef7db2
---
Jiri Slaby ef7db2
 drivers/scsi/qla2xxx/qla_dfs.c    | 10 ++++-
Jiri Slaby ef7db2
 drivers/scsi/qla2xxx/qla_inline.h |  5 ++-
Jiri Slaby ef7db2
 drivers/scsi/qla2xxx/qla_iocb.c   | 67 +++++++++++++++++++++++++++++++
Jiri Slaby ef7db2
 drivers/scsi/qla2xxx/qla_isr.c    |  1 +
Jiri Slaby ef7db2
 4 files changed, 80 insertions(+), 3 deletions(-)
Jiri Slaby ef7db2
Jiri Slaby ef7db2
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
Jiri Slaby ef7db2
index 777808af..1925cc68 100644
Jiri Slaby ef7db2
--- a/drivers/scsi/qla2xxx/qla_dfs.c
Jiri Slaby ef7db2
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
Jiri Slaby ef7db2
@@ -235,7 +235,7 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
Jiri Slaby ef7db2
 	uint16_t mb[MAX_IOCB_MB_REG];
Jiri Slaby ef7db2
 	int rc;
Jiri Slaby ef7db2
 	struct qla_hw_data *ha = vha->hw;
Jiri Slaby ef7db2
-	u16 iocbs_used, i;
Jiri Slaby ef7db2
+	u16 iocbs_used, i, exch_used;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 	rc = qla24xx_res_count_wait(vha, mb, SIZEOF_IOCB_MB_REG);
Jiri Slaby ef7db2
 	if (rc != QLA_SUCCESS) {
Jiri Slaby ef7db2
@@ -263,13 +263,19 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused)
Jiri Slaby ef7db2
 	if (ql2xenforce_iocb_limit) {
Jiri Slaby ef7db2
 		/* lock is not require. It's an estimate. */
Jiri Slaby ef7db2
 		iocbs_used = ha->base_qpair->fwres.iocbs_used;
Jiri Slaby ef7db2
+		exch_used = ha->base_qpair->fwres.exch_used;
Jiri Slaby ef7db2
 		for (i = 0; i < ha->max_qpairs; i++) {
Jiri Slaby ef7db2
-			if (ha->queue_pair_map[i])
Jiri Slaby ef7db2
+			if (ha->queue_pair_map[i]) {
Jiri Slaby ef7db2
 				iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used;
Jiri Slaby ef7db2
+				exch_used += ha->queue_pair_map[i]->fwres.exch_used;
Jiri Slaby ef7db2
+			}
Jiri Slaby ef7db2
 		}
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 		seq_printf(s, "Driver: estimate iocb used [%d] high water limit [%d]\n",
Jiri Slaby ef7db2
 			   iocbs_used, ha->base_qpair->fwres.iocbs_limit);
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+		seq_printf(s, "estimate exchange used[%d] high water limit [%d] n",
Jiri Slaby ef7db2
+			   exch_used, ha->base_qpair->fwres.exch_limit);
Jiri Slaby ef7db2
 	}
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 	return 0;
Jiri Slaby ef7db2
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
Jiri Slaby ef7db2
index 2d5a275d..b0ee307b 100644
Jiri Slaby ef7db2
--- a/drivers/scsi/qla2xxx/qla_inline.h
Jiri Slaby ef7db2
+++ b/drivers/scsi/qla2xxx/qla_inline.h
Jiri Slaby ef7db2
@@ -380,7 +380,7 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 enum {
Jiri Slaby ef7db2
 	RESOURCE_NONE,
Jiri Slaby ef7db2
-	RESOURCE_IOCB  = BIT_0,
Jiri Slaby ef7db2
+	RESOURCE_IOCB = BIT_0,
Jiri Slaby ef7db2
 	RESOURCE_EXCH = BIT_1,  /* exchange */
Jiri Slaby ef7db2
 	RESOURCE_FORCE = BIT_2,
Jiri Slaby ef7db2
 };
Jiri Slaby ef7db2
@@ -396,6 +396,8 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
Jiri Slaby ef7db2
 		iores->res_type = RESOURCE_NONE;
Jiri Slaby ef7db2
 		return 0;
Jiri Slaby ef7db2
 	}
Jiri Slaby ef7db2
+	if (iores->res_type & RESOURCE_FORCE)
Jiri Slaby ef7db2
+		goto force;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 	if ((iores->iocb_cnt + qp->fwres.iocbs_used) >= qp->fwres.iocbs_qp_limit) {
Jiri Slaby ef7db2
 		/* no need to acquire qpair lock. It's just rough calculation */
Jiri Slaby ef7db2
@@ -423,6 +425,7 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores)
Jiri Slaby ef7db2
 			return -ENOSPC;
Jiri Slaby ef7db2
 		}
Jiri Slaby ef7db2
 	}
Jiri Slaby ef7db2
+force:
Jiri Slaby ef7db2
 	qp->fwres.iocbs_used += iores->iocb_cnt;
Jiri Slaby ef7db2
 	qp->fwres.exch_used += iores->exch_cnt;
Jiri Slaby ef7db2
 	return 0;
Jiri Slaby ef7db2
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
Jiri Slaby ef7db2
index 399ec8da..4f48f098 100644
Jiri Slaby ef7db2
--- a/drivers/scsi/qla2xxx/qla_iocb.c
Jiri Slaby ef7db2
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
Jiri Slaby ef7db2
@@ -3817,6 +3817,65 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
Jiri Slaby ef7db2
 	logio->vp_index = sp->fcport->vha->vp_idx;
Jiri Slaby ef7db2
 }
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
+int qla_get_iocbs_resource(struct srb *sp)
Jiri Slaby ef7db2
+{
Jiri Slaby ef7db2
+	bool get_exch;
Jiri Slaby ef7db2
+	bool push_it_through = false;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	if (!ql2xenforce_iocb_limit) {
Jiri Slaby ef7db2
+		sp->iores.res_type = RESOURCE_NONE;
Jiri Slaby ef7db2
+		return 0;
Jiri Slaby ef7db2
+	}
Jiri Slaby ef7db2
+	sp->iores.res_type = RESOURCE_NONE;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	switch (sp->type) {
Jiri Slaby ef7db2
+	case SRB_TM_CMD:
Jiri Slaby ef7db2
+	case SRB_PRLI_CMD:
Jiri Slaby ef7db2
+	case SRB_ADISC_CMD:
Jiri Slaby ef7db2
+		push_it_through = true;
Jiri Slaby ef7db2
+		fallthrough;
Jiri Slaby ef7db2
+	case SRB_LOGIN_CMD:
Jiri Slaby ef7db2
+	case SRB_ELS_CMD_RPT:
Jiri Slaby ef7db2
+	case SRB_ELS_CMD_HST:
Jiri Slaby ef7db2
+	case SRB_ELS_CMD_HST_NOLOGIN:
Jiri Slaby ef7db2
+	case SRB_CT_CMD:
Jiri Slaby ef7db2
+	case SRB_NVME_LS:
Jiri Slaby ef7db2
+	case SRB_ELS_DCMD:
Jiri Slaby ef7db2
+		get_exch = true;
Jiri Slaby ef7db2
+		break;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	case SRB_FXIOCB_DCMD:
Jiri Slaby ef7db2
+	case SRB_FXIOCB_BCMD:
Jiri Slaby ef7db2
+		sp->iores.res_type = RESOURCE_NONE;
Jiri Slaby ef7db2
+		return 0;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	case SRB_SA_UPDATE:
Jiri Slaby ef7db2
+	case SRB_SA_REPLACE:
Jiri Slaby ef7db2
+	case SRB_MB_IOCB:
Jiri Slaby ef7db2
+	case SRB_ABT_CMD:
Jiri Slaby ef7db2
+	case SRB_NACK_PLOGI:
Jiri Slaby ef7db2
+	case SRB_NACK_PRLI:
Jiri Slaby ef7db2
+	case SRB_NACK_LOGO:
Jiri Slaby ef7db2
+	case SRB_LOGOUT_CMD:
Jiri Slaby ef7db2
+	case SRB_CTRL_VP:
Jiri Slaby ef7db2
+		push_it_through = true;
Jiri Slaby ef7db2
+		fallthrough;
Jiri Slaby ef7db2
+	default:
Jiri Slaby ef7db2
+		get_exch = false;
Jiri Slaby ef7db2
+	}
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	sp->iores.res_type |= RESOURCE_IOCB;
Jiri Slaby ef7db2
+	sp->iores.iocb_cnt = 1;
Jiri Slaby ef7db2
+	if (get_exch) {
Jiri Slaby ef7db2
+		sp->iores.res_type |= RESOURCE_EXCH;
Jiri Slaby ef7db2
+		sp->iores.exch_cnt = 1;
Jiri Slaby ef7db2
+	}
Jiri Slaby ef7db2
+	if (push_it_through)
Jiri Slaby ef7db2
+		sp->iores.res_type |= RESOURCE_FORCE;
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
+	return qla_get_fw_resources(sp->qpair, &sp->iores);
Jiri Slaby ef7db2
+}
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
 int
Jiri Slaby ef7db2
 qla2x00_start_sp(srb_t *sp)
Jiri Slaby ef7db2
 {
Jiri Slaby ef7db2
@@ -3831,6 +3890,12 @@ qla2x00_start_sp(srb_t *sp)
Jiri Slaby ef7db2
 		return -EIO;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
 	spin_lock_irqsave(qp->qp_lock_ptr, flags);
Jiri Slaby ef7db2
+	rval = qla_get_iocbs_resource(sp);
Jiri Slaby ef7db2
+	if (rval) {
Jiri Slaby ef7db2
+		spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
Jiri Slaby ef7db2
+		return -EAGAIN;
Jiri Slaby ef7db2
+	}
Jiri Slaby ef7db2
+
Jiri Slaby ef7db2
 	pkt = __qla2x00_alloc_iocbs(sp->qpair, sp);
Jiri Slaby ef7db2
 	if (!pkt) {
Jiri Slaby ef7db2
 		rval = EAGAIN;
Jiri Slaby ef7db2
@@ -3931,6 +3996,8 @@ qla2x00_start_sp(srb_t *sp)
Jiri Slaby ef7db2
 	wmb();
Jiri Slaby ef7db2
 	qla2x00_start_iocbs(vha, qp->req);
Jiri Slaby ef7db2
 done:
Jiri Slaby ef7db2
+	if (rval)
Jiri Slaby ef7db2
+		qla_put_fw_resources(sp->qpair, &sp->iores);
Jiri Slaby ef7db2
 	spin_unlock_irqrestore(qp->qp_lock_ptr, flags);
Jiri Slaby ef7db2
 	return rval;
Jiri Slaby ef7db2
 }
Jiri Slaby ef7db2
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
Jiri Slaby ef7db2
index 42d3d2de..759bea69 100644
Jiri Slaby ef7db2
--- a/drivers/scsi/qla2xxx/qla_isr.c
Jiri Slaby ef7db2
+++ b/drivers/scsi/qla2xxx/qla_isr.c
Jiri Slaby ef7db2
@@ -3112,6 +3112,7 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
Jiri Slaby ef7db2
 	}
Jiri Slaby ef7db2
 	bsg_reply->reply_payload_rcv_len = 0;
Jiri Slaby ef7db2
 
Jiri Slaby ef7db2
+	qla_put_fw_resources(sp->qpair, &sp->iores);
Jiri Slaby ef7db2
 done:
Jiri Slaby ef7db2
 	/* Return the vendor specific reply to API */
Jiri Slaby ef7db2
 	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
Jiri Slaby ef7db2
-- 
Jiri Slaby ef7db2
2.35.3
Jiri Slaby ef7db2