Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[sfrench/cifs-2.6.git] / drivers / scsi / lpfc / lpfc_nportdisc.c
index fc6e4546d738a59ab1be40271f406c520437dca2..ae435901384650ec7d3edf090a4a495c1b4d1c6a 100644 (file)
@@ -279,6 +279,55 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp)
        lpfc_cancel_retry_delay_tmo(phba->pport, ndlp);
 }
 
+/* lpfc_defer_pt2pt_acc - Complete SLI3 pt2pt processing on link up
+ * @phba: pointer to lpfc hba data structure.
+ * @link_mbox: pointer to CONFIG_LINK mailbox object
+ *
+ * This routine is only called if we are SLI3, direct connect pt2pt
+ * mode and the remote NPort issues the PLOGI after link up.
+ */
+static void
+lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox)
+{
+       LPFC_MBOXQ_t *login_mbox;
+       MAILBOX_t *mb = &link_mbox->u.mb;
+       struct lpfc_iocbq *save_iocb;
+       struct lpfc_nodelist *ndlp;
+       int rc;
+
+       ndlp = link_mbox->ctx_ndlp;
+       login_mbox = link_mbox->context3;
+       save_iocb = login_mbox->context3;
+       link_mbox->context3 = NULL;
+       login_mbox->context3 = NULL;
+
+       /* Check for CONFIG_LINK error */
+       if (mb->mbxStatus) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                               "4575 CONFIG_LINK fails pt2pt discovery: %x\n",
+                               mb->mbxStatus);
+               mempool_free(login_mbox, phba->mbox_mem_pool);
+               mempool_free(link_mbox, phba->mbox_mem_pool);
+               lpfc_sli_release_iocbq(phba, save_iocb);
+               return;
+       }
+
+       /* Now that CONFIG_LINK completed, and our SID is configured,
+        * we can now proceed with sending the PLOGI ACC.
+        */
+       rc = lpfc_els_rsp_acc(link_mbox->vport, ELS_CMD_PLOGI,
+                             save_iocb, ndlp, login_mbox);
+       if (rc) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                               "4576 PLOGI ACC fails pt2pt discovery: %x\n",
+                               rc);
+               mempool_free(login_mbox, phba->mbox_mem_pool);
+       }
+
+       mempool_free(link_mbox, phba->mbox_mem_pool);
+       lpfc_sli_release_iocbq(phba, save_iocb);
+}
+
 static int
 lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
               struct lpfc_iocbq *cmdiocb)
@@ -291,10 +340,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        IOCB_t *icmd;
        struct serv_parm *sp;
        uint32_t ed_tov;
-       LPFC_MBOXQ_t *mbox;
+       LPFC_MBOXQ_t *link_mbox;
+       LPFC_MBOXQ_t *login_mbox;
+       struct lpfc_iocbq *save_iocb;
        struct ls_rjt stat;
        uint32_t vid, flag;
-       int rc;
+       int rc, defer_acc;
 
        memset(&stat, 0, sizeof (struct ls_rjt));
        pcmd = (struct lpfc_dmabuf *) cmdiocb->context2;
@@ -343,6 +394,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        else
                ndlp->nlp_fcp_info |= CLASS3;
 
+       defer_acc = 0;
        ndlp->nlp_class_sup = 0;
        if (sp->cls1.classValid)
                ndlp->nlp_class_sup |= FC_COS_CLASS1;
@@ -354,7 +406,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                ndlp->nlp_class_sup |= FC_COS_CLASS4;
        ndlp->nlp_maxframe =
                ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb;
-
        /* if already logged in, do implicit logout */
        switch (ndlp->nlp_state) {
        case  NLP_STE_NPR_NODE:
@@ -396,6 +447,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE;
        ndlp->nlp_flag &= ~NLP_FIRSTBURST;
 
+       login_mbox = NULL;
+       link_mbox = NULL;
+       save_iocb = NULL;
+
        /* Check for Nport to NPort pt2pt protocol */
        if ((vport->fc_flag & FC_PT2PT) &&
            !(vport->fc_flag & FC_PT2PT_PLOGI)) {
@@ -423,17 +478,22 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                if (phba->sli_rev == LPFC_SLI_REV4)
                        lpfc_issue_reg_vfi(vport);
                else {
-                       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-                       if (mbox == NULL)
+                       defer_acc = 1;
+                       link_mbox = mempool_alloc(phba->mbox_mem_pool,
+                                                 GFP_KERNEL);
+                       if (!link_mbox)
                                goto out;
-                       lpfc_config_link(phba, mbox);
-                       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
-                       mbox->vport = vport;
-                       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
-                       if (rc == MBX_NOT_FINISHED) {
-                               mempool_free(mbox, phba->mbox_mem_pool);
+                       lpfc_config_link(phba, link_mbox);
+                       link_mbox->mbox_cmpl = lpfc_defer_pt2pt_acc;
+                       link_mbox->vport = vport;
+                       link_mbox->ctx_ndlp = ndlp;
+
+                       save_iocb = lpfc_sli_get_iocbq(phba);
+                       if (!save_iocb)
                                goto out;
-                       }
+                       /* Save info from cmd IOCB used in rsp */
+                       memcpy((uint8_t *)save_iocb, (uint8_t *)cmdiocb,
+                              sizeof(struct lpfc_iocbq));
                }
 
                lpfc_can_disctmo(vport);
@@ -448,8 +508,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        ndlp->nlp_flag |= NLP_SUPPRESS_RSP;
        }
 
-       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
-       if (!mbox)
+       login_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!login_mbox)
                goto out;
 
        /* Registering an existing RPI behaves differently for SLI3 vs SLI4 */
@@ -457,21 +517,19 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                lpfc_unreg_rpi(vport, ndlp);
 
        rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID,
-                           (uint8_t *) sp, mbox, ndlp->nlp_rpi);
-       if (rc) {
-               mempool_free(mbox, phba->mbox_mem_pool);
+                           (uint8_t *)sp, login_mbox, ndlp->nlp_rpi);
+       if (rc)
                goto out;
-       }
 
        /* ACC PLOGI rsp command needs to execute first,
-        * queue this mbox command to be processed later.
+        * queue this login_mbox command to be processed later.
         */
-       mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
+       login_mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login;
        /*
-        * mbox->ctx_ndlp = lpfc_nlp_get(ndlp) deferred until mailbox
+        * login_mbox->ctx_ndlp = lpfc_nlp_get(ndlp) deferred until mailbox
         * command issued in lpfc_cmpl_els_acc().
         */
-       mbox->vport = vport;
+       login_mbox->vport = vport;
        spin_lock_irq(shost->host_lock);
        ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI);
        spin_unlock_irq(shost->host_lock);
@@ -484,8 +542,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
         * single discovery thread, this will cause a huge delay in
         * discovery. Also this will cause multiple state machines
         * running in parallel for this node.
+        * This only applies to a fabric environment.
         */
-       if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) {
+       if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) &&
+           (vport->fc_flag & FC_FABRIC)) {
                /* software abort outstanding PLOGI */
                lpfc_els_abort(phba, ndlp);
        }
@@ -504,16 +564,47 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD;
                stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE;
                rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb,
-                       ndlp, mbox);
+                       ndlp, login_mbox);
                if (rc)
-                       mempool_free(mbox, phba->mbox_mem_pool);
+                       mempool_free(login_mbox, phba->mbox_mem_pool);
+               return 1;
+       }
+       if (defer_acc) {
+               /* So the order here should be:
+                * Issue CONFIG_LINK mbox
+                * CONFIG_LINK cmpl
+                * Issue PLOGI ACC
+                * PLOGI ACC cmpl
+                * Issue REG_LOGIN mbox
+                */
+
+               /* Save the REG_LOGIN mbox for and rcv IOCB copy later */
+               link_mbox->context3 = login_mbox;
+               login_mbox->context3 = save_iocb;
+
+               /* Start the ball rolling by issuing CONFIG_LINK here */
+               rc = lpfc_sli_issue_mbox(phba, link_mbox, MBX_NOWAIT);
+               if (rc == MBX_NOT_FINISHED)
+                       goto out;
                return 1;
        }
-       rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox);
+
+       rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, login_mbox);
        if (rc)
-               mempool_free(mbox, phba->mbox_mem_pool);
+               mempool_free(login_mbox, phba->mbox_mem_pool);
        return 1;
 out:
+       if (defer_acc)
+               lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY,
+                               "4577 pt2pt discovery failure: %p %p %p\n",
+                               save_iocb, link_mbox, login_mbox);
+       if (save_iocb)
+               lpfc_sli_release_iocbq(phba, save_iocb);
+       if (link_mbox)
+               mempool_free(link_mbox, phba->mbox_mem_pool);
+       if (login_mbox)
+               mempool_free(login_mbox, phba->mbox_mem_pool);
+
        stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC;
        stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE;
        lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL);
@@ -2030,7 +2121,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                if (bf_get_be32(prli_init, nvpr))
                        ndlp->nlp_type |= NLP_NVME_INITIATOR;
 
-               if (phba->nsler && bf_get_be32(prli_nsler, nvpr))
+               if (phba->nsler && bf_get_be32(prli_nsler, nvpr) &&
+                   bf_get_be32(prli_conf, nvpr))
+
                        ndlp->nlp_nvme_info |= NLP_NVME_NSLER;
                else
                        ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER;