scsi: lpfc: Fix handling of FCP and NVME FC4 types in Pt2Pt topology
authorDick Kennedy <dick.kennedy@broadcom.com>
Wed, 23 Aug 2017 23:55:36 +0000 (16:55 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Fri, 25 Aug 2017 02:29:37 +0000 (22:29 -0400)
After link bounce in a NVME Pt2Pt config, the driver managed to map the
same nport twice, resulting in multiple device nodes for the same
namespace.

In Pt2Pt, the driver must send PRLI's for both (scsi) FCP and NVME
rather than using fabric aids. The driver was inconsistent on handling
various PRLI completions, especially rejects, which had reject codes
cross the different protocol PRLI completions.

Fixed to perform the following: if nvmet mode (fc port can only be a
nvme target) - rejects all unsolicitly FCP PRLI's. Never issues a FCP
PRLI.

The multiple protocol PRLI's are sent simultaneously. However, driver
will now only state transition after both PRLI's are complete. New flags
were added to aid tracking the responses from the different PRLI's.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <james.smart@broadcom.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_nportdisc.c

index 094c97b9e5f741faba5e0ef904f97faa3cc7a734..f9a566eaef0442258a2bd27a6093da76909ecfa4 100644 (file)
@@ -159,6 +159,7 @@ struct lpfc_node_rrq {
 #define NLP_RNID_SND       0x00000400  /* sent RNID request for this entry */
 #define NLP_ELS_SND_MASK   0x000007e0  /* sent ELS request for this entry */
 #define NLP_NVMET_RECOV    0x00001000   /* NVMET auditing node for recovery. */
+#define NLP_FCP_PRLI_RJT   0x00002000   /* Rport does not support FCP PRLI. */
 #define NLP_DEFER_RM       0x00010000  /* Remove this ndlp if no longer used */
 #define NLP_DELAY_TMO      0x00020000  /* delay timeout is running for node */
 #define NLP_NPR_2B_DISC    0x00040000  /* node is included in num_disc_nodes */
index 2dae501dc3234133bba8fd3bdb21fec2a65c523f..19af0e6e7667f104b030e006e270eae95b437aee 100644 (file)
@@ -1966,6 +1966,7 @@ int
 lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
 {
        struct lpfc_hba  *phba = vport->phba;
+       struct Scsi_Host *shost;
        struct serv_parm *sp;
        struct lpfc_nodelist *ndlp;
        struct lpfc_iocbq *elsiocb;
@@ -1984,6 +1985,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry)
        if (!elsiocb)
                return 1;
 
+       shost = lpfc_shost_from_vport(vport);
+       spin_lock_irq(shost->host_lock);
+       ndlp->nlp_flag &= ~NLP_FCP_PRLI_RJT;
+       spin_unlock_irq(shost->host_lock);
+
        pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt);
 
        /* For PLOGI request, remainder of payload is service parameters */
@@ -3442,6 +3448,21 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                                goto out_retry;
                        }
                        break;
+               case LSRJT_CMD_UNSUPPORTED:
+                       /* lpfc nvmet returns this type of LS_RJT when it
+                        * receives an FCP PRLI because lpfc nvmet only
+                        * support NVME.  ELS request is terminated for FCP4
+                        * on this rport.
+                        */
+                       if (stat.un.b.lsRjtRsnCodeExp ==
+                           LSEXP_REQ_UNSUPPORTED && cmd == ELS_CMD_PRLI) {
+                               spin_lock_irq(shost->host_lock);
+                               ndlp->nlp_flag |= NLP_FCP_PRLI_RJT;
+                               spin_unlock_irq(shost->host_lock);
+                               retry = 0;
+                               goto out_retry;
+                       }
+                       break;
                }
                break;
 
@@ -8007,6 +8028,13 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
                        rjt_exp = LSEXP_NOTHING_MORE;
                        break;
                }
+
+               /* NVMET accepts NVME PRLI only.  Reject FCP PRLI */
+               if (cmd == ELS_CMD_PRLI && phba->nvmet_support) {
+                       rjt_err = LSRJT_CMD_UNSUPPORTED;
+                       rjt_exp = LSEXP_REQ_UNSUPPORTED;
+                       break;
+               }
                lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI);
                break;
        case ELS_CMD_LIRR:
index a4488d6339c1d59b42e1179efd47419687accd5e..f3ad7cac355d3e96ffe99da8635dd643132ba5e8 100644 (file)
@@ -1895,6 +1895,15 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        goto out;
                }
 
+               /* When the rport rejected the FCP PRLI as unsupported.
+                * This should only happen in Pt2Pt so an NVME PRLI
+                * should be outstanding still.
+                */
+               if (npr && ndlp->nlp_flag & NLP_FCP_PRLI_RJT) {
+                       ndlp->nlp_fc4_type &= ~NLP_FC4_FCP;
+                       goto out_err;
+               }
+
                /* The LS Req had some error.  Don't let this be a
                 * target.
                 */