]> git.proxmox.com Git - mirror_ubuntu-disco-kernel.git/commitdiff
scsi: lpfc: Fix receive PRLI handling
authorJames Smart <jsmart2021@gmail.com>
Sat, 9 Dec 2017 01:18:05 +0000 (17:18 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 21 Dec 2017 02:11:45 +0000 (21:11 -0500)
Handling a rcv'ed PRLI incorrectly can cause the ndlp to end up in the
wrong state or the driver to ACC and PRLI when it should send LS_RJT.

The cause was due to the driver not properly looking at the PRLI type
and taking the multiple protocol support into consideration.

Resolved by adding checks in the various PRLI receive points to validate
PRLI type and reject if not valid for the enabled protocols and mode
(host vs target).

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

index 4a14f3c82a07747d56812f2c1808c21ee6a1101c..6ffd65a935c4c9e26f5a6c1995e2c222379d6037 100644 (file)
@@ -8063,13 +8063,6 @@ 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 b6957d944b9ac4d361be53c7654e02bc082867d7..df050b211e0bb7a7535dd56531c2229b7979d3a0 100644 (file)
@@ -727,6 +727,41 @@ out:
        return 0;
 }
 
+static uint32_t
+lpfc_rcv_prli_support_check(struct lpfc_vport *vport,
+                           struct lpfc_nodelist *ndlp,
+                           struct lpfc_iocbq *cmdiocb)
+{
+       struct ls_rjt stat;
+       uint32_t *payload;
+       uint32_t cmd;
+
+       payload = ((struct lpfc_dmabuf *)cmdiocb->context2)->virt;
+       cmd = *payload;
+       if (vport->phba->nvmet_support) {
+               /* Must be a NVME PRLI */
+               if (cmd ==  ELS_CMD_PRLI)
+                       goto out;
+       } else {
+               /* Initiator mode. */
+               if (!vport->nvmei_support && (cmd == ELS_CMD_NVMEPRLI))
+                       goto out;
+       }
+       return 1;
+out:
+       lpfc_printf_vlog(vport, KERN_WARNING, LOG_NVME_DISC,
+                        "6115 Rcv PRLI (%x) check failed: ndlp rpi %d "
+                        "state x%x flags x%x\n",
+                        cmd, ndlp->nlp_rpi, ndlp->nlp_state,
+                        ndlp->nlp_flag);
+       memset(&stat, 0, sizeof(struct ls_rjt));
+       stat.un.b.lsRjtRsnCode = LSRJT_CMD_UNSUPPORTED;
+       stat.un.b.lsRjtRsnCodeExp = LSEXP_REQ_UNSUPPORTED;
+       lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
+                           ndlp, NULL);
+       return 0;
+}
+
 static void
 lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
              struct lpfc_iocbq *cmdiocb)
@@ -1373,7 +1408,8 @@ lpfc_rcv_prli_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 {
        struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
-       lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
+       if (lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb))
+               lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
        return ndlp->nlp_state;
 }
 
@@ -1544,6 +1580,9 @@ lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
        struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
        struct ls_rjt     stat;
 
+       if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb)) {
+               return ndlp->nlp_state;
+       }
        if (vport->phba->nvmet_support) {
                /* NVME Target mode.  Handle and respond to the PRLI and
                 * transition to UNMAPPED provided the RPI has completed
@@ -1558,11 +1597,6 @@ lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
                         * to prevent an illegal state transition when the
                         * rpi registration does complete.
                         */
-                       lpfc_printf_vlog(vport, KERN_WARNING, LOG_NVME_DISC,
-                                        "6115 NVMET ndlp rpi %d state "
-                                        "unknown, state x%x flags x%08x\n",
-                                        ndlp->nlp_rpi, ndlp->nlp_state,
-                                        ndlp->nlp_flag);
                        memset(&stat, 0, sizeof(struct ls_rjt));
                        stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
                        stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS;
@@ -1573,7 +1607,6 @@ lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport,
                /* Initiator mode. */
                lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
        }
-
        return ndlp->nlp_state;
 }
 
@@ -1819,6 +1852,8 @@ lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 {
        struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
+       if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb))
+               return ndlp->nlp_state;
        lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
        return ndlp->nlp_state;
 }
@@ -2241,6 +2276,9 @@ lpfc_rcv_prli_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 {
        struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
+       if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb))
+               return ndlp->nlp_state;
+
        lpfc_rcv_prli(vport, ndlp, cmdiocb);
        lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
        return ndlp->nlp_state;
@@ -2310,6 +2348,8 @@ lpfc_rcv_prli_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 {
        struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg;
 
+       if (!lpfc_rcv_prli_support_check(vport, ndlp, cmdiocb))
+               return ndlp->nlp_state;
        lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp);
        return ndlp->nlp_state;
 }