[SCSI] lpfc 8.3.12: Fix discovery issues
James Smart [Tue, 6 Apr 2010 19:06:30 +0000 (15:06 -0400)]
- Add code to prevent unreg_vpi mailbox command from failing.
- Add code to reset the HBA if unreg_vpi mailbox fails with busy status.
- Remove code that was clearing the nlp_type stored during rport discovery.

Signed-off-by: Alex Iannicelli <alex.iannicelli@emulex.com>
Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>

drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_disc.h
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_nportdisc.c
drivers/scsi/lpfc/lpfc_sli.c

index 5087c42..fbc9bae 100644 (file)
@@ -65,6 +65,7 @@ void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *);
 void lpfc_retry_pport_discovery(struct lpfc_hba *);
+void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t);
 
 void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
 void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *);
index 2851d75..36257a6 100644 (file)
@@ -38,6 +38,7 @@ enum lpfc_work_type {
        LPFC_EVT_ELS_RETRY,
        LPFC_EVT_DEV_LOSS,
        LPFC_EVT_FASTPATH_MGMT_EVT,
+       LPFC_EVT_RESET_HBA,
 };
 
 /* structure used to queue event to the discovery tasklet */
index 1de60ce..c4c7f0a 100644 (file)
@@ -584,6 +584,7 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                        spin_unlock_irq(shost->host_lock);
                        lpfc_unreg_rpi(vport, np);
                }
+               lpfc_cleanup_pending_mbox(vport);
                if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) {
                        lpfc_mbx_unreg_vpi(vport);
                        spin_lock_irq(shost->host_lock);
@@ -6316,6 +6317,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        spin_unlock_irq(shost->host_lock);
                        lpfc_unreg_rpi(vport, np);
                }
+               lpfc_cleanup_pending_mbox(vport);
                lpfc_mbx_unreg_vpi(vport);
                spin_lock_irq(shost->host_lock);
                vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
index d2b55f0..1f87b4f 100644 (file)
@@ -475,6 +475,10 @@ lpfc_work_list_done(struct lpfc_hba *phba)
                        lpfc_send_fastpath_evt(phba, evtp);
                        free_evt = 0;
                        break;
+               case LPFC_EVT_RESET_HBA:
+                       if (!(phba->pport->load_flag & FC_UNLOADING))
+                               lpfc_reset_hba(phba);
+                       break;
                }
                if (free_evt)
                        kfree(evtp);
@@ -2737,11 +2741,18 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        switch (mb->mbxStatus) {
        case 0x0011:
        case 0x0020:
-       case 0x9700:
                lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE,
                                 "0911 cmpl_unreg_vpi, mb status = 0x%x\n",
                                 mb->mbxStatus);
                break;
+       /* If VPI is busy, reset the HBA */
+       case 0x9700:
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE,
+                       "2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n",
+                       vport->vpi, mb->mbxStatus);
+               if (!(phba->pport->load_flag & FC_UNLOADING))
+                       lpfc_workq_post_event(phba, NULL, NULL,
+                               LPFC_EVT_RESET_HBA);
        }
        spin_lock_irq(shost->host_lock);
        vport->vpi_state &= ~LPFC_VPI_REGISTERED;
@@ -3233,7 +3244,6 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
        struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
        if (new_state == NLP_STE_UNMAPPED_NODE) {
-               ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR);
                ndlp->nlp_flag &= ~NLP_NODEV_REMOVE;
                ndlp->nlp_type |= NLP_FC_NODE;
        }
@@ -4991,6 +5001,7 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
                        ndlp = lpfc_findnode_did(vports[i], Fabric_DID);
                        if (ndlp)
                                lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
+                       lpfc_cleanup_pending_mbox(vports[i]);
                        lpfc_mbx_unreg_vpi(vports[i]);
                        shost = lpfc_shost_from_vport(vports[i]);
                        spin_lock_irq(shost->host_lock);
index 0368101..cd9697e 100644 (file)
@@ -3227,12 +3227,26 @@ lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport)
 
        if (!vport)
                return NULL;
-       ndlp = lpfc_findnode_did(vport, Fabric_DID);
-       if (!ndlp)
-               return NULL;
        phba = vport->phba;
        if (!phba)
                return NULL;
+       ndlp = lpfc_findnode_did(vport, Fabric_DID);
+       if (!ndlp) {
+               /* Cannot find existing Fabric ndlp, so allocate a new one */
+               ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL);
+               if (!ndlp)
+                       return 0;
+               lpfc_nlp_init(vport, ndlp, Fabric_DID);
+               /* Set the node type */
+               ndlp->nlp_type |= NLP_FABRIC;
+               /* Put ndlp onto node list */
+               lpfc_enqueue_node(vport, ndlp);
+       } else if (!NLP_CHK_NODE_ACT(ndlp)) {
+               /* re-setup ndlp without removing from node list */
+               ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE);
+               if (!ndlp)
+                       return 0;
+       }
        if (phba->pport->port_state <= LPFC_FLOGI)
                return NULL;
        /* If virtual link is not yet instantiated ignore CVL */
index e1086da..b90820a 100644 (file)
@@ -637,11 +637,55 @@ lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp)
        lpfc_unreg_rpi(vport, ndlp);
        return 0;
 }
+/**
+ * lpfc_release_rpi - Release a RPI by issueing unreg_login mailbox cmd.
+ * @phba : Pointer to lpfc_hba structure.
+ * @vport: Pointer to lpfc_vport structure.
+ * @rpi  : rpi to be release.
+ *
+ * This function will send a unreg_login mailbox command to the firmware
+ * to release a rpi.
+ **/
+void
+lpfc_release_rpi(struct lpfc_hba *phba,
+               struct lpfc_vport *vport,
+               uint16_t rpi)
+{
+       LPFC_MBOXQ_t *pmb;
+       int rc;
+
+       pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool,
+                       GFP_KERNEL);
+       if (!pmb)
+               lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
+                       "2796 mailbox memory allocation failed \n");
+       else {
+               lpfc_unreg_login(phba, vport->vpi, rpi, pmb);
+               pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+               if (rc == MBX_NOT_FINISHED)
+                       mempool_free(pmb, phba->mbox_mem_pool);
+       }
+}
 
 static uint32_t
 lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
                  void *arg, uint32_t evt)
 {
+       struct lpfc_hba *phba;
+       LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+       MAILBOX_t *mb;
+       uint16_t rpi;
+
+       phba = vport->phba;
+       /* Release the RPI if reglogin completing */
+       if (!(phba->pport->load_flag & FC_UNLOADING) &&
+               (evt == NLP_EVT_CMPL_REG_LOGIN) &&
+               (!pmb->u.mb.mbxStatus)) {
+               mb = &pmb->u.mb;
+               rpi = pmb->u.mb.un.varWords[0];
+               lpfc_release_rpi(phba, vport, rpi);
+       }
        lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY,
                         "0271 Illegal State Transition: node x%x "
                         "event x%x, state x%x Data: x%x x%x\n",
@@ -977,6 +1021,18 @@ static uint32_t
 lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport,
        struct lpfc_nodelist *ndlp, void *arg, uint32_t evt)
 {
+       struct lpfc_hba *phba;
+       LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg;
+       MAILBOX_t *mb = &pmb->u.mb;
+       uint16_t rpi;
+
+       phba = vport->phba;
+       /* Release the RPI */
+       if (!(phba->pport->load_flag & FC_UNLOADING) &&
+               !mb->mbxStatus) {
+               rpi = pmb->u.mb.un.varWords[0];
+               lpfc_release_rpi(phba, vport, rpi);
+       }
        return ndlp->nlp_state;
 }
 
index 1ab7937..7a61455 100644 (file)
@@ -12661,6 +12661,7 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
        struct lpfc_hba *phba = vport->phba;
        LPFC_MBOXQ_t *mb, *nextmb;
        struct lpfc_dmabuf *mp;
+       struct lpfc_nodelist *ndlp;
 
        spin_lock_irq(&phba->hbalock);
        list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) {
@@ -12677,6 +12678,11 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
                                __lpfc_mbuf_free(phba, mp->virt, mp->phys);
                                kfree(mp);
                        }
+                       ndlp = (struct lpfc_nodelist *) mb->context2;
+                       if (ndlp) {
+                               lpfc_nlp_put(ndlp);
+                               mb->context2 = NULL;
+                       }
                }
                list_del(&mb->list);
                mempool_free(mb, phba->mbox_mem_pool);
@@ -12686,6 +12692,15 @@ lpfc_cleanup_pending_mbox(struct lpfc_vport *vport)
                if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) ||
                        (mb->u.mb.mbxCommand == MBX_REG_VPI))
                        mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+               if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) {
+                       ndlp = (struct lpfc_nodelist *) mb->context2;
+                       if (ndlp) {
+                               lpfc_nlp_put(ndlp);
+                               mb->context2 = NULL;
+                       }
+                       /* Unregister the RPI when mailbox complete */
+                       mb->mbox_flag |= LPFC_MBX_IMED_UNREG;
+               }
        }
        spin_unlock_irq(&phba->hbalock);
 }