]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
Fix driver behavior when receiving an ADISC (CR 126654)
authorVaios Papadimitriou <vaios.papadimitriou@emulex.com>
Tue, 8 May 2012 22:01:24 +0000 (17:01 -0500)
committerMaxim Uvarov <maxim.uvarov@oracle.com>
Wed, 9 May 2012 00:01:24 +0000 (17:01 -0700)
ADISC gets ACC'ed if RPI is not present. RESUME_RPI does not get envoked when
receiving ADISC.

commit id: 6b5151fd7baec6812fece993ddd7a2cf9fd0125f

Signed-off-by: Maxim Uvarov <maxim.uvarov@oracle.com>
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_sli.c
drivers/scsi/lpfc/lpfc_sli4.h

index de002a2fe29baf04223edecccd301f950b399b7f..32b6d72cd98da8ac98355c9a7de1a526d12660de 100644 (file)
@@ -48,6 +48,10 @@ static int
 lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                 struct lpfc_name *nn, struct lpfc_name *pn)
 {
+       /* First, we MUST have a RPI registered */
+       if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED))
+               return 0;
+
        /* Compare the ADISC rsp WWNN / WWPN matches our internal node
         * table entry for that node.
         */
@@ -385,7 +389,9 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        if (!mbox)
                goto out;
 
-       lpfc_unreg_rpi(vport, ndlp);
+       /* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
+       if (phba->sli_rev == LPFC_SLI_REV4)
+               lpfc_unreg_rpi(vport, ndlp);
 
        rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
                            (uint8_t *) sp, mbox, ndlp->nlp_rpi);
@@ -447,11 +453,42 @@ out:
        return 0;
 }
 
+/**
+ * lpfc_mbx_cmpl_resume_rpi - Resume RPI completion routine
+ * @phba: pointer to lpfc hba data structure.
+ * @mboxq: pointer to mailbox object
+ *
+ * This routine is invoked to issue a completion to a rcv'ed
+ * ADISC or PDISC after the paused RPI has been resumed.
+ **/
+static void
+lpfc_mbx_cmpl_resume_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
+{
+       struct lpfc_vport *vport;
+       struct lpfc_iocbq *elsiocb;
+       struct lpfc_nodelist *ndlp;
+       uint32_t cmd;
+
+       elsiocb = (struct lpfc_iocbq *)mboxq->context1;
+       ndlp = (struct lpfc_nodelist *) mboxq->context2;
+       vport = mboxq->vport;
+       cmd = elsiocb->drvrTimeout;
+
+       if (cmd == ELS_CMD_ADISC) {
+               lpfc_els_rsp_adisc_acc(vport, elsiocb, ndlp);
+       } else {
+               lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, elsiocb,
+                       ndlp, NULL);
+       }
+       kfree(elsiocb);
+}
+
 static int
 lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                struct lpfc_iocbq *cmdiocb)
 {
        struct Scsi_Host   *shost = lpfc_shost_from_vport(vport);
+       struct lpfc_iocbq  *elsiocb;
        struct lpfc_dmabuf *pcmd;
        struct serv_parm   *sp;
        struct lpfc_name   *pnn, *ppn;
@@ -477,12 +514,43 @@ lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
 
        icmd = &cmdiocb->iocb;
        if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) {
+
+               /*
+                * As soon as  we send ACC, the remote NPort can
+                * start sending us data. Thus, for SLI4 we must
+                * resume the RPI before the ACC goes out.
+                */
+               if (vport->phba->sli_rev == LPFC_SLI_REV4) {
+                       elsiocb = kmalloc(sizeof(struct lpfc_iocbq),
+                               GFP_KERNEL);
+                       if (elsiocb) {
+
+                               /* Save info from cmd IOCB used in rsp */
+                               memcpy((uint8_t *)elsiocb, (uint8_t *)cmdiocb,
+                                       sizeof(struct lpfc_iocbq));
+
+                               /* Save the ELS cmd */
+                               elsiocb->drvrTimeout = cmd;
+
+                               lpfc_sli4_resume_rpi(ndlp,
+                                       lpfc_mbx_cmpl_resume_rpi, elsiocb);
+                               goto out;
+                       }
+               }
+
                if (cmd == ELS_CMD_ADISC) {
                        lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp);
                } else {
-                       lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp,
-                                        NULL);
+                       lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb,
+                               ndlp, NULL);
                }
+out:
+               /* If we are authenticated, move to the proper state */
+               if (ndlp->nlp_type & NLP_FCP_TARGET)
+                       lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE);
+               else
+                       lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE);
+
                return 1;
        }
        /* Reject this request because invalid parameters */
@@ -1231,7 +1299,7 @@ lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport,
        }
 
        if (phba->sli_rev == LPFC_SLI_REV4) {
-               rc = lpfc_sli4_resume_rpi(ndlp);
+               rc = lpfc_sli4_resume_rpi(ndlp, NULL, NULL);
                if (rc) {
                        /* Stay in state and retry. */
                        ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE;
index c35d1f19e551086a1551821e871e4a56c6102cc9..4e6ebb2adf895e49a18c2a7b90c59a0155a97397 100644 (file)
@@ -14749,7 +14749,8 @@ lpfc_sli4_remove_rpis(struct lpfc_hba *phba)
  * provided rpi via a bitmask.
  **/
 int
-lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp)
+lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp,
+       void (*cmpl)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *arg)
 {
        LPFC_MBOXQ_t *mboxq;
        struct lpfc_hba *phba = ndlp->phba;
@@ -14762,6 +14763,12 @@ lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp)
 
        /* Post all rpi memory regions to the port. */
        lpfc_resume_rpi(mboxq, ndlp);
+       if (cmpl) {
+               mboxq->mbox_cmpl = cmpl;
+               mboxq->context1 = arg;
+               mboxq->context2 = ndlp;
+       }
+       mboxq->vport = ndlp->vport;
        rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT);
        if (rc == MBX_NOT_FINISHED) {
                lpfc_printf_log(phba, KERN_ERR, LOG_SLI,
index 3f266e2c54e0d7f57131b91b4aa3bb1dd1dc9cf6..c19d139618b729ed7d7f5b8dfb99406e59e25236 100644 (file)
@@ -633,7 +633,8 @@ void lpfc_sli4_free_rpi(struct lpfc_hba *, int);
 void lpfc_sli4_remove_rpis(struct lpfc_hba *);
 void lpfc_sli4_async_event_proc(struct lpfc_hba *);
 void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *);
-int lpfc_sli4_resume_rpi(struct lpfc_nodelist *);
+int lpfc_sli4_resume_rpi(struct lpfc_nodelist *,
+                       void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *);
 void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *);
 void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *);
 void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *,