Daniel Wagner e481f8
From: Quinn Tran <qutran@marvell.com>
Daniel Wagner e481f8
Date: Tue, 12 Jul 2022 22:20:40 -0700
Daniel Wagner e481f8
Subject: scsi: qla2xxx: edif: Fix dropped IKE message
Denis Kirjanov 718367
Patch-mainline: v5.20-rc1
Daniel Wagner e481f8
Git-commit: c019cd656e717349ff22d0c41d6fbfc773f48c52
Daniel Wagner e481f8
References: bsc#1201651
Daniel Wagner e481f8
Daniel Wagner e481f8
This patch fixes IKE message being dropped due to error in processing Purex
Daniel Wagner e481f8
IOCB and Continuation IOCBs.
Daniel Wagner e481f8
Daniel Wagner e481f8
Link: https://lore.kernel.org/r/20220713052045.10683-6-njavali@marvell.com
Daniel Wagner e481f8
Fixes: fac2807946c1 ("scsi: qla2xxx: edif: Add extraction of auth_els from the wire")
Daniel Wagner e481f8
Cc: stable@vger.kernel.org
Daniel Wagner e481f8
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Daniel Wagner e481f8
Signed-off-by: Quinn Tran <qutran@marvell.com>
Daniel Wagner e481f8
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Daniel Wagner e481f8
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Daniel Wagner e481f8
Acked-by: Daniel Wagner <dwagner@suse.de>
Daniel Wagner e481f8
---
Daniel Wagner e481f8
 drivers/scsi/qla2xxx/qla_isr.c |   54 ++++++++++++++++++-----------------------
Daniel Wagner e481f8
 1 file changed, 24 insertions(+), 30 deletions(-)
Daniel Wagner e481f8
Daniel Wagner e481f8
--- a/drivers/scsi/qla2xxx/qla_isr.c
Daniel Wagner e481f8
+++ b/drivers/scsi/qla2xxx/qla_isr.c
Daniel Wagner e481f8
@@ -3720,12 +3720,11 @@ void qla24xx_nvme_ls4_iocb(struct scsi_q
Daniel Wagner e481f8
  * Return: 0 all iocbs has arrived, xx- all iocbs have not arrived.
Daniel Wagner e481f8
  */
Daniel Wagner e481f8
 static int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha,
Daniel Wagner e481f8
-	struct rsp_que *rsp, response_t *pkt)
Daniel Wagner e481f8
+	struct rsp_que *rsp, response_t *pkt, u32 rsp_q_in)
Daniel Wagner e481f8
 {
Daniel Wagner e481f8
-	int start_pkt_ring_index, end_pkt_ring_index, n_ring_index;
Daniel Wagner e481f8
-	response_t *end_pkt;
Daniel Wagner e481f8
+	int start_pkt_ring_index;
Daniel Wagner e481f8
+	u32 iocb_cnt = 0;
Daniel Wagner e481f8
 	int rc = 0;
Daniel Wagner e481f8
-	u32 rsp_q_in;
Daniel Wagner e481f8
 
Daniel Wagner e481f8
 	if (pkt->entry_count == 1)
Daniel Wagner e481f8
 		return rc;
Daniel Wagner e481f8
@@ -3736,34 +3735,18 @@ static int qla_chk_cont_iocb_avail(struc
Daniel Wagner e481f8
 	else
Daniel Wagner e481f8
 		start_pkt_ring_index = rsp->ring_index - 1;
Daniel Wagner e481f8
 
Daniel Wagner e481f8
-	if ((start_pkt_ring_index + pkt->entry_count) >= rsp->length)
Daniel Wagner e481f8
-		end_pkt_ring_index = start_pkt_ring_index + pkt->entry_count -
Daniel Wagner e481f8
-			rsp->length - 1;
Daniel Wagner e481f8
+	if (rsp_q_in < start_pkt_ring_index)
Daniel Wagner e481f8
+		/* q in ptr is wrapped */
Daniel Wagner e481f8
+		iocb_cnt = rsp->length - start_pkt_ring_index + rsp_q_in;
Daniel Wagner e481f8
 	else
Daniel Wagner e481f8
-		end_pkt_ring_index = start_pkt_ring_index + pkt->entry_count - 1;
Daniel Wagner e481f8
+		iocb_cnt = rsp_q_in - start_pkt_ring_index;
Daniel Wagner e481f8
 
Daniel Wagner e481f8
-	end_pkt = rsp->ring + end_pkt_ring_index;
Daniel Wagner e481f8
-
Daniel Wagner e481f8
-	/*  next pkt = end_pkt + 1 */
Daniel Wagner e481f8
-	n_ring_index = end_pkt_ring_index + 1;
Daniel Wagner e481f8
-	if (n_ring_index >= rsp->length)
Daniel Wagner e481f8
-		n_ring_index = 0;
Daniel Wagner e481f8
-
Daniel Wagner e481f8
-	rsp_q_in = rsp->qpair->use_shadow_reg ? *rsp->in_ptr :
Daniel Wagner e481f8
-		rd_reg_dword(rsp->rsp_q_in);
Daniel Wagner e481f8
-
Daniel Wagner e481f8
-	/* rsp_q_in is either wrapped or pointing beyond endpkt */
Daniel Wagner e481f8
-	if ((rsp_q_in < start_pkt_ring_index && rsp_q_in < n_ring_index) ||
Daniel Wagner e481f8
-			rsp_q_in >= n_ring_index)
Daniel Wagner e481f8
-		/* all IOCBs arrived. */
Daniel Wagner e481f8
-		rc = 0;
Daniel Wagner e481f8
-	else
Daniel Wagner e481f8
+	if (iocb_cnt < pkt->entry_count)
Daniel Wagner e481f8
 		rc = -EIO;
Daniel Wagner e481f8
 
Daniel Wagner e481f8
-	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x5091,
Daniel Wagner e481f8
-	    "%s - ring %p pkt %p end pkt %p entry count %#x rsp_q_in %d rc %d\n",
Daniel Wagner e481f8
-	    __func__, rsp->ring, pkt, end_pkt, pkt->entry_count,
Daniel Wagner e481f8
-	    rsp_q_in, rc);
Daniel Wagner e481f8
+	ql_dbg(ql_dbg_init, vha, 0x5091,
Daniel Wagner e481f8
+	       "%s - ring %p pkt %p entry count %d iocb_cnt %d rsp_q_in %d rc %d\n",
Daniel Wagner e481f8
+	       __func__, rsp->ring, pkt, pkt->entry_count, iocb_cnt, rsp_q_in, rc);
Daniel Wagner e481f8
 
Daniel Wagner e481f8
 	return rc;
Daniel Wagner e481f8
 }
Daniel Wagner e481f8
@@ -3780,7 +3763,7 @@ void qla24xx_process_response_queue(stru
Daniel Wagner e481f8
 	struct qla_hw_data *ha = vha->hw;
Daniel Wagner e481f8
 	struct purex_entry_24xx *purex_entry;
Daniel Wagner e481f8
 	struct purex_item *pure_item;
Daniel Wagner e481f8
-	u16 rsp_in = 0;
Daniel Wagner e481f8
+	u16 rsp_in = 0, cur_ring_index;
Daniel Wagner e481f8
 	int follow_inptr, is_shadow_hba;
Daniel Wagner e481f8
 
Daniel Wagner e481f8
 	if (!ha->flags.fw_started)
Daniel Wagner e481f8
@@ -3811,6 +3794,7 @@ void qla24xx_process_response_queue(stru
Daniel Wagner e481f8
 		       (!follow_inptr &&
Daniel Wagner e481f8
 			rsp->ring_ptr->signature != RESPONSE_PROCESSED)) {
Daniel Wagner e481f8
 		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
Daniel Wagner e481f8
+		cur_ring_index = rsp->ring_index;
Daniel Wagner e481f8
 
Daniel Wagner e481f8
 		rsp->ring_index++;
Daniel Wagner e481f8
 		if (rsp->ring_index == rsp->length) {
Daniel Wagner e481f8
@@ -3931,7 +3915,17 @@ void qla24xx_process_response_queue(stru
Daniel Wagner e481f8
 				break;
Daniel Wagner e481f8
 
Daniel Wagner e481f8
 			case ELS_AUTH_ELS:
Daniel Wagner e481f8
-				if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt)) {
Daniel Wagner e481f8
+				if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) {
Daniel Wagner e481f8
+					/*
Daniel Wagner e481f8
+					 * ring_ptr and ring_index were
Daniel Wagner e481f8
+					 * pre-incremented above. Reset them
Daniel Wagner e481f8
+					 * back to current. Wait for next
Daniel Wagner e481f8
+					 * interrupt with all IOCBs to arrive
Daniel Wagner e481f8
+					 * and re-process.
Daniel Wagner e481f8
+					 */
Daniel Wagner e481f8
+					rsp->ring_ptr = (response_t *)pkt;
Daniel Wagner e481f8
+					rsp->ring_index = cur_ring_index;
Daniel Wagner e481f8
+
Daniel Wagner e481f8
 					ql_dbg(ql_dbg_init, vha, 0x5091,
Daniel Wagner e481f8
 					    "Defer processing ELS opcode %#x...\n",
Daniel Wagner e481f8
 					    purex_entry->els_frame_payload[3]);