Blob Blame History Raw
From: James Smart <jsmart2021@gmail.com>
Date: Wed, 14 Aug 2019 16:56:37 -0700
Subject: scsi: lpfc: Fix port relogin failure due to GID_FT interaction
Patch-mainline: v5.4-rc1
Git-commit: 57178b9275508e59d6daf89b874c03d597342776
References: jsc#SLE-8284 jsc#SLE-8654

In cases of remote-port-side cable pull/replug, there happens to be a
target that upon replug will send the port a PLOGI, a PRLI, and a LOGO.
When this sequence is received by the driver, the PLOGI accepted and a
GFT_ID is issued to find the protocol support for the remote port. While
the GFT_ID is outstanding, a LOGO is received. The driver logs the remote
port out and unregisters the RPI and schedules a new PLOGI transmission.
However, the GFT_ID was not terminated. When it completed, the driver
attempted to transition the remote port to PRLI transmission, which cancels
the PLOGI scheduling. The PRLI transmit attempt is rejected by the adapter
as the remote port is not logged in. No retry is attempted as it's expected
the logout is noted and the supposedly scheduled PLOGI should address the
state. As there is no PLOGI, the remote port does not get re-discovered.

Fix by aborting the outstanding GFT_ID if the related remote port is logged
out.

Ensure a PRLI transmit attempt only occurs if the remote port is logging
in. This avoids the incorrect attempt while logged out.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Acked-by: Daniel Wagner <dwagner@suse.de>
---
 drivers/scsi/lpfc/lpfc_ct.c        |   15 ++++++++++-----
 drivers/scsi/lpfc/lpfc_nportdisc.c |    8 ++++++++
 2 files changed, 18 insertions(+), 5 deletions(-)

--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -1210,13 +1210,18 @@ lpfc_cmpl_ct_cmd_gft_id(struct lpfc_hba
 				ndlp->nlp_fc4_type |= NLP_FC4_NVME;
 			lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
 					 "3064 Setting ndlp %p, DID x%06x with "
-					 "FC4 x%08x, Data: x%08x x%08x\n",
+					 "FC4 x%08x, Data: x%08x x%08x %d\n",
 					 ndlp, did, ndlp->nlp_fc4_type,
-					 FC_TYPE_FCP, FC_TYPE_NVME);
-			ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
+					 FC_TYPE_FCP, FC_TYPE_NVME,
+					 ndlp->nlp_state);
 
-			lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE);
-			lpfc_issue_els_prli(vport, ndlp, 0);
+			if (ndlp->nlp_state == NLP_STE_REG_LOGIN_ISSUE) {
+				ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE;
+
+				lpfc_nlp_set_state(vport, ndlp,
+						   NLP_STE_PRLI_ISSUE);
+				lpfc_issue_els_prli(vport, ndlp, 0);
+			}
 		}
 	} else
 		lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
@@ -1661,6 +1661,7 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc
 	LPFC_MBOXQ_t	  *mb;
 	LPFC_MBOXQ_t	  *nextmb;
 	struct lpfc_dmabuf *mp;
+	struct lpfc_nodelist *ns_ndlp;
 
 	cmdiocb = (struct lpfc_iocbq *) arg;
 
@@ -1693,6 +1694,13 @@ lpfc_rcv_logo_reglogin_issue(struct lpfc
 	}
 	spin_unlock_irq(&phba->hbalock);
 
+	/* software abort if any GID_FT is outstanding */
+	if (vport->cfg_enable_fc4_type != LPFC_ENABLE_FCP) {
+		ns_ndlp = lpfc_findnode_did(vport, NameServer_DID);
+		if (ns_ndlp && NLP_CHK_NODE_ACT(ns_ndlp))
+			lpfc_els_abort(phba, ns_ndlp);
+	}
+
 	lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO);
 	return ndlp->nlp_state;
 }