Johannes Thumshirn d1d42c
From: Dick Kennedy <dick.kennedy@broadcom.com>
Johannes Thumshirn d1d42c
Date: Wed, 23 Aug 2017 16:55:36 -0700
Johannes Thumshirn d1d42c
Subject: scsi: lpfc: Fix handling of FCP and NVME FC4 types in Pt2Pt topology
Johannes Thumshirn d1d42c
Patch-mainline: v4.14-rc1
Johannes Thumshirn d1d42c
Git-commit: 8db1c2b3e7fa1b1a75a8dddc77bf516acfc03e8a
Johannes Thumshirn d1d42c
References: bsc#1050239,FATE#322918
Johannes Thumshirn d1d42c
Johannes Thumshirn d1d42c
After link bounce in a NVME Pt2Pt config, the driver managed to map the
Johannes Thumshirn d1d42c
same nport twice, resulting in multiple device nodes for the same
Johannes Thumshirn d1d42c
namespace.
Johannes Thumshirn d1d42c
Johannes Thumshirn d1d42c
In Pt2Pt, the driver must send PRLI's for both (scsi) FCP and NVME
Johannes Thumshirn d1d42c
rather than using fabric aids. The driver was inconsistent on handling
Johannes Thumshirn d1d42c
various PRLI completions, especially rejects, which had reject codes
Johannes Thumshirn d1d42c
cross the different protocol PRLI completions.
Johannes Thumshirn d1d42c
Johannes Thumshirn d1d42c
Fixed to perform the following: if nvmet mode (fc port can only be a
Johannes Thumshirn d1d42c
nvme target) - rejects all unsolicitly FCP PRLI's. Never issues a FCP
Johannes Thumshirn d1d42c
PRLI.
Johannes Thumshirn d1d42c
Johannes Thumshirn d1d42c
The multiple protocol PRLI's are sent simultaneously. However, driver
Johannes Thumshirn d1d42c
will now only state transition after both PRLI's are complete. New flags
Johannes Thumshirn d1d42c
were added to aid tracking the responses from the different PRLI's.
Johannes Thumshirn d1d42c
Johannes Thumshirn d1d42c
Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Johannes Thumshirn d1d42c
Signed-off-by: James Smart <james.smart@broadcom.com>
Johannes Thumshirn d1d42c
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Johannes Thumshirn d1d42c
Acked-by: Johannes Thumshirn <jthumshirn@suse.de>
Johannes Thumshirn d1d42c
---
Johannes Thumshirn d1d42c
 drivers/scsi/lpfc/lpfc_disc.h      |    1 +
Johannes Thumshirn d1d42c
 drivers/scsi/lpfc/lpfc_els.c       |   28 ++++++++++++++++++++++++++++
Johannes Thumshirn d1d42c
 drivers/scsi/lpfc/lpfc_nportdisc.c |    9 +++++++++
Johannes Thumshirn d1d42c
 3 files changed, 38 insertions(+)
Johannes Thumshirn d1d42c
Johannes Thumshirn d1d42c
--- a/drivers/scsi/lpfc/lpfc_disc.h
Johannes Thumshirn d1d42c
+++ b/drivers/scsi/lpfc/lpfc_disc.h
Johannes Thumshirn d1d42c
@@ -159,6 +159,7 @@ struct lpfc_node_rrq {
Johannes Thumshirn d1d42c
 #define NLP_RNID_SND       0x00000400	/* sent RNID request for this entry */
Johannes Thumshirn d1d42c
 #define NLP_ELS_SND_MASK   0x000007e0	/* sent ELS request for this entry */
Johannes Thumshirn d1d42c
 #define NLP_NVMET_RECOV    0x00001000   /* NVMET auditing node for recovery. */
Johannes Thumshirn d1d42c
+#define NLP_FCP_PRLI_RJT   0x00002000   /* Rport does not support FCP PRLI. */
Johannes Thumshirn d1d42c
 #define NLP_DEFER_RM       0x00010000	/* Remove this ndlp if no longer used */
Johannes Thumshirn d1d42c
 #define NLP_DELAY_TMO      0x00020000	/* delay timeout is running for node */
Johannes Thumshirn d1d42c
 #define NLP_NPR_2B_DISC    0x00040000	/* node is included in num_disc_nodes */
Johannes Thumshirn d1d42c
--- a/drivers/scsi/lpfc/lpfc_els.c
Johannes Thumshirn d1d42c
+++ b/drivers/scsi/lpfc/lpfc_els.c
Johannes Thumshirn d1d42c
@@ -1966,6 +1966,7 @@ int
Johannes Thumshirn d1d42c
 lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
Johannes Thumshirn d1d42c
 {
Johannes Thumshirn d1d42c
 	struct lpfc_hba  *phba = vport->phba;
Johannes Thumshirn d1d42c
+	struct Scsi_Host *shost;
Johannes Thumshirn d1d42c
 	struct serv_parm *sp;
Johannes Thumshirn d1d42c
 	struct lpfc_nodelist *ndlp;
Johannes Thumshirn d1d42c
 	struct lpfc_iocbq *elsiocb;
Johannes Thumshirn d1d42c
@@ -1984,6 +1985,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *
Johannes Thumshirn d1d42c
 	if (!elsiocb)
Johannes Thumshirn d1d42c
 		return 1;
Johannes Thumshirn d1d42c
 
Johannes Thumshirn d1d42c
+	shost = lpfc_shost_from_vport(vport);
Johannes Thumshirn d1d42c
+	spin_lock_irq(shost->host_lock);
Johannes Thumshirn d1d42c
+	ndlp->nlp_flag &= ~NLP_FCP_PRLI_RJT;
Johannes Thumshirn d1d42c
+	spin_unlock_irq(shost->host_lock);
Johannes Thumshirn d1d42c
+
Johannes Thumshirn d1d42c
 	pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
Johannes Thumshirn d1d42c
 
Johannes Thumshirn d1d42c
 	/* For PLOGI request, remainder of payload is service parameters */
Johannes Thumshirn d1d42c
@@ -3442,6 +3448,21 @@ lpfc_els_retry(struct lpfc_hba *phba, st
Johannes Thumshirn d1d42c
 				goto out_retry;
Johannes Thumshirn d1d42c
 			}
Johannes Thumshirn d1d42c
 			break;
Johannes Thumshirn d1d42c
+		case LSRJT_CMD_UNSUPPORTED:
Johannes Thumshirn d1d42c
+			/* lpfc nvmet returns this type of LS_RJT when it
Johannes Thumshirn d1d42c
+			 * receives an FCP PRLI because lpfc nvmet only
Johannes Thumshirn d1d42c
+			 * support NVME.  ELS request is terminated for FCP4
Johannes Thumshirn d1d42c
+			 * on this rport.
Johannes Thumshirn d1d42c
+			 */
Johannes Thumshirn d1d42c
+			if (stat.un.b.lsRjtRsnCodeExp ==
Johannes Thumshirn d1d42c
+			    LSEXP_REQ_UNSUPPORTED && cmd == ELS_CMD_PRLI) {
Johannes Thumshirn d1d42c
+				spin_lock_irq(shost->host_lock);
Johannes Thumshirn d1d42c
+				ndlp->nlp_flag |= NLP_FCP_PRLI_RJT;
Johannes Thumshirn d1d42c
+				spin_unlock_irq(shost->host_lock);
Johannes Thumshirn d1d42c
+				retry = 0;
Johannes Thumshirn d1d42c
+				goto out_retry;
Johannes Thumshirn d1d42c
+			}
Johannes Thumshirn d1d42c
+			break;
Johannes Thumshirn d1d42c
 		}
Johannes Thumshirn d1d42c
 		break;
Johannes Thumshirn d1d42c
 
Johannes Thumshirn d1d42c
@@ -8007,6 +8028,13 @@ lpfc_els_unsol_buffer(struct lpfc_hba *p
Johannes Thumshirn d1d42c
 			rjt_exp = LSEXP_NOTHING_MORE;
Johannes Thumshirn d1d42c
 			break;
Johannes Thumshirn d1d42c
 		}
Johannes Thumshirn d1d42c
+
Johannes Thumshirn d1d42c
+		/* NVMET accepts NVME PRLI only.  Reject FCP PRLI */
Johannes Thumshirn d1d42c
+		if (cmd == ELS_CMD_PRLI && phba->nvmet_support) {
Johannes Thumshirn d1d42c
+			rjt_err = LSRJT_CMD_UNSUPPORTED;
Johannes Thumshirn d1d42c
+			rjt_exp = LSEXP_REQ_UNSUPPORTED;
Johannes Thumshirn d1d42c
+			break;
Johannes Thumshirn d1d42c
+		}
Johannes Thumshirn d1d42c
 		lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
Johannes Thumshirn d1d42c
 		break;
Johannes Thumshirn d1d42c
 	case ELS_CMD_LIRR:
Johannes Thumshirn d1d42c
--- a/drivers/scsi/lpfc/lpfc_nportdisc.c
Johannes Thumshirn d1d42c
+++ b/drivers/scsi/lpfc/lpfc_nportdisc.c
Johannes Thumshirn d1d42c
@@ -1895,6 +1895,15 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vp
Johannes Thumshirn d1d42c
 			goto out;
Johannes Thumshirn d1d42c
 		}
Johannes Thumshirn d1d42c
 
Johannes Thumshirn d1d42c
+		/* When the rport rejected the FCP PRLI as unsupported.
Johannes Thumshirn d1d42c
+		 * This should only happen in Pt2Pt so an NVME PRLI
Johannes Thumshirn d1d42c
+		 * should be outstanding still.
Johannes Thumshirn d1d42c
+		 */
Johannes Thumshirn d1d42c
+		if (npr && ndlp->nlp_flag & NLP_FCP_PRLI_RJT) {
Johannes Thumshirn d1d42c
+			ndlp->nlp_fc4_type &= ~NLP_FC4_FCP;
Johannes Thumshirn d1d42c
+			goto out_err;
Johannes Thumshirn d1d42c
+		}
Johannes Thumshirn d1d42c
+
Johannes Thumshirn d1d42c
 		/* The LS Req had some error.  Don't let this be a
Johannes Thumshirn d1d42c
 		 * target.
Johannes Thumshirn d1d42c
 		 */