Commit 1d0f9fea authored by Justin Tee's avatar Justin Tee Committed by Martin K. Petersen
Browse files

scsi: lpfc: Defer issuing new PLOGI if received RSCN before completing REG_LOGIN



When mapped to a target with multiple virtual ports, a link bounce
sometimes results in unsuccessful rediscovery of all of the target's
virtual ports.  This is because a succession of repeat RSCNs for the
virtual target ports leaves ndlps in the REG_LOGIN state with the
NLP_REG_LOGIN_SEND flag set.  With NLP_REG_LOGIN_SEND set, during the next
PLOGI, the driver will UNREG_RPI.  When UNREG_RPI is processed, the driver
can be in the middle of PRLI_ISSUE or MAPPED state resulting in an illegal
state transition by the discovery engine and stalling.

Fix by calling the discovery state machine with DEVICE_RECOVERY event
during RSCN processing.  This will set the NLP_IGNR_REG_CMPL bit and
prevent the old REG_LOGIN state from advancing.  Then for the new PLOGI
issue, add the check for the NLP_IGNR_REG_CMPL bit to delay issuing the new
PLOGI until the queued REG_LOGIN and UNREG_LOGIN have been processed.

Signed-off-by: default avatarJustin Tee <justin.tee@broadcom.com>
Link: https://lore.kernel.org/r/20230301231626.9621-6-justintee8345@gmail.com


Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 06578ac6
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -2208,14 +2208,15 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
	 * outstanding UNREG_RPI mbox command completes, unless we
	 * are going offline. This logic does not apply for Fabric DIDs
	 */
	if ((ndlp->nlp_flag & NLP_UNREG_INP) &&
	if ((ndlp->nlp_flag & (NLP_IGNR_REG_CMPL | NLP_UNREG_INP)) &&
	    ((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) &&
	    !(vport->fc_flag & FC_OFFLINE_MODE)) {
		lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY,
				 "4110 Issue PLOGI x%x deferred "
				 "on NPort x%x rpi x%x Data: x%px\n",
				 "on NPort x%x rpi x%x flg x%x Data:"
				 " x%px\n",
				 ndlp->nlp_defer_did, ndlp->nlp_DID,
				 ndlp->nlp_rpi, ndlp);
				 ndlp->nlp_rpi, ndlp->nlp_flag, ndlp);

		/* We can only defer 1st PLOGI */
		if (ndlp->nlp_defer_did == NLP_EVT_NOTHING_PENDING)
+2 −2
Original line number Diff line number Diff line
@@ -5755,8 +5755,8 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did)
			     (NLP_FCP_TARGET | NLP_NVME_TARGET)))
				return NULL;

			ndlp->nlp_prev_state = ndlp->nlp_state;
			lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE);
			lpfc_disc_state_machine(vport, ndlp, NULL,
						NLP_EVT_DEVICE_RECOVERY);

			spin_lock_irq(&ndlp->lock);
			ndlp->nlp_flag |= NLP_NPR_2B_DISC;