summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/lpfc/lpfc_els.c
diff options
context:
space:
mode:
authorJames Smart <jsmart2021@gmail.com>2018-11-30 01:09:30 +0100
committerMartin K. Petersen <martin.petersen@oracle.com>2018-12-08 04:35:32 +0100
commitdea16bdae2f1ab629702ca912dabe00f3dcdac25 (patch)
tree46a02b8f0ea6aef0ad70667e29b5868f8dffbb5b /drivers/scsi/lpfc/lpfc_els.c
parentscsi: lpfc: refactor mailbox structure context fields (diff)
downloadlinux-dea16bdae2f1ab629702ca912dabe00f3dcdac25.tar.xz
linux-dea16bdae2f1ab629702ca912dabe00f3dcdac25.zip
scsi: lpfc: Fix discovery failures during port failovers with lots of vports
The driver is getting hit with 100s of RSCNs during remote port address changes. Each of those RSCN's ends up generating UNREG_RPI and REG_PRI mailbox commands. The discovery engine within the driver doesn't wait for the mailbox command completions. Instead it sets state flags and moves forward. At some point, there's a massive backlog of mailbox commands which take time for the adapter to process. Additionally, it appears there were duplicate events from the switch so the driver generated duplicate mailbox commands for the same remote port. During this window, failures on PLOGI and PRLI ELS's are see as the adapter is rejecting them as they are for remote ports that still have pending mailbox commands. Streamline the discovery engine so that PLOGI log checks for outstanding UNREG_RPIs and defer the processing until the commands complete. This better synchronizes the ELS transmission vs the RPI registrations. Filter out multiple UNREG_RPIs being queued up for the same remote port. Beef up log messages in this area. 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>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c69
1 files changed, 58 insertions, 11 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index a2caa9e67890..902234a1fcfb 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -315,20 +315,20 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp,
/* Xmit ELS command <elsCmd> to remote NPORT <did> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0116 Xmit ELS command x%x to remote "
- "NPORT x%x I/O tag: x%x, port state:x%x"
- " fc_flag:x%x\n",
+ "NPORT x%x I/O tag: x%x, port state:x%x "
+ "rpi x%x fc_flag:x%x\n",
elscmd, did, elsiocb->iotag,
- vport->port_state,
+ vport->port_state, ndlp->nlp_rpi,
vport->fc_flag);
} else {
/* Xmit ELS response <elsCmd> to remote NPORT <did> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
"0117 Xmit ELS response x%x to remote "
"NPORT x%x I/O tag: x%x, size: x%x "
- "port_state x%x fc_flag x%x\n",
+ "port_state x%x rpi x%x fc_flag x%x\n",
elscmd, ndlp->nlp_DID, elsiocb->iotag,
cmdSize, vport->port_state,
- vport->fc_flag);
+ ndlp->nlp_rpi, vport->fc_flag);
}
return elsiocb;
@@ -1642,7 +1642,19 @@ lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp,
spin_lock_irq(shost->host_lock);
keep_nlp_flag = new_ndlp->nlp_flag;
new_ndlp->nlp_flag = ndlp->nlp_flag;
- ndlp->nlp_flag = keep_nlp_flag;
+
+ /* if new_ndlp had NLP_UNREG_INP set, keep it */
+ if (keep_nlp_flag & NLP_UNREG_INP)
+ new_ndlp->nlp_flag |= NLP_UNREG_INP;
+ else
+ new_ndlp->nlp_flag &= ~NLP_UNREG_INP;
+
+ /* if ndlp had NLP_UNREG_INP set, keep it */
+ if (ndlp->nlp_flag & NLP_UNREG_INP)
+ ndlp->nlp_flag = keep_nlp_flag | NLP_UNREG_INP;
+ else
+ ndlp->nlp_flag = keep_nlp_flag & ~NLP_UNREG_INP;
+
spin_unlock_irq(shost->host_lock);
/* Set nlp_states accordingly */
@@ -1919,7 +1931,7 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC);
ndlp->nlp_flag &= ~NLP_NPR_2B_DISC;
spin_unlock_irq(shost->host_lock);
- rc = 0;
+ rc = 0;
/* PLOGI completes to NPort <nlp_DID> */
lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS,
@@ -2026,8 +2038,29 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
int ret;
ndlp = lpfc_findnode_did(vport, did);
- if (ndlp && !NLP_CHK_NODE_ACT(ndlp))
- ndlp = NULL;
+
+ if (ndlp) {
+ /* Defer the processing of the issue PLOGI until after the
+ * 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) &&
+ ((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: %p\n",
+ ndlp->nlp_defer_did, ndlp->nlp_DID,
+ ndlp->nlp_rpi, ndlp);
+
+ /* We can only defer 1st PLOGI */
+ if (ndlp->nlp_defer_did == NLP_EVT_NOTHING_PENDING)
+ ndlp->nlp_defer_did = did;
+ return 0;
+ }
+ if (!NLP_CHK_NODE_ACT(ndlp))
+ ndlp = NULL;
+ }
/* If ndlp is not NULL, we will bump the reference count on it */
cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm));
@@ -2161,7 +2194,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
else
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_PRLI);
- } else
+ } else {
/* Good status, call state machine. However, if another
* PRLI is outstanding, don't call the state machine
* because final disposition to Mapped or Unmapped is
@@ -2169,6 +2202,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
*/
lpfc_disc_state_machine(vport, ndlp, cmdiocb,
NLP_EVT_CMPL_PRLI);
+ }
out:
lpfc_els_free_iocb(phba, cmdiocb);
@@ -2227,7 +2261,7 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
ndlp->nlp_type &= ~(NLP_NVME_TARGET | NLP_NVME_INITIATOR);
ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
- ndlp->nlp_flag &= ~NLP_FIRSTBURST;
+ ndlp->nlp_flag &= ~(NLP_FIRSTBURST | NLP_NPR_2B_DISC);
ndlp->nvme_fb_size = 0;
send_next_prli:
@@ -6112,6 +6146,19 @@ lpfc_rscn_recovery_check(struct lpfc_vport *vport)
if (vport->phba->nvmet_support)
continue;
+ /* If we are in the process of doing discovery on this
+ * NPort, let it continue on its own.
+ */
+ switch (ndlp->nlp_state) {
+ case NLP_STE_PLOGI_ISSUE:
+ case NLP_STE_ADISC_ISSUE:
+ case NLP_STE_REG_LOGIN_ISSUE:
+ case NLP_STE_PRLI_ISSUE:
+ case NLP_STE_LOGO_ISSUE:
+ continue;
+ }
+
+
lpfc_disc_state_machine(vport, ndlp, NULL,
NLP_EVT_DEVICE_RECOVERY);
lpfc_cancel_retry_delay_tmo(vport, ndlp);