diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 214 |
1 files changed, 124 insertions, 90 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 445826a4c98..7afc757338d 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -421,13 +421,13 @@ fail: * @vport: pointer to a host virtual N_Port data structure. * * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for - * the @vport. This mailbox command is necessary for FCoE only. + * the @vport. This mailbox command is necessary for SLI4 port only. * * Return code * 0 - successfully issued REG_VFI for @vport * A failure code otherwise. **/ -static int +int lpfc_issue_reg_vfi(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; @@ -438,10 +438,14 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) int rc = 0; sp = &phba->fc_fabparam; - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - rc = -ENODEV; - goto fail; + /* move forward in case of SLI4 FC port loopback test */ + if ((phba->sli_rev == LPFC_SLI_REV4) && + !(phba->link_flag & LS_LOOPBACK_MODE)) { + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + rc = -ENODEV; + goto fail; + } } dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); @@ -487,6 +491,54 @@ fail: } /** + * lpfc_issue_unreg_vfi - Unregister VFI for this vport's fabric login + * @vport: pointer to a host virtual N_Port data structure. + * + * This routine issues a UNREG_VFI mailbox with the vfi, vpi, fcfi triplet for + * the @vport. This mailbox command is necessary for SLI4 port only. + * + * Return code + * 0 - successfully issued REG_VFI for @vport + * A failure code otherwise. + **/ +int +lpfc_issue_unreg_vfi(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + struct Scsi_Host *shost; + LPFC_MBOXQ_t *mboxq; + int rc; + + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2556 UNREG_VFI mbox allocation failed" + "HBA state x%x\n", phba->pport->port_state); + return -ENOMEM; + } + + lpfc_unreg_vfi(mboxq, vport); + mboxq->vport = vport; + mboxq->mbox_cmpl = lpfc_unregister_vfi_cmpl; + + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, + "2557 UNREG_VFI issue mbox failed rc x%x " + "HBA state x%x\n", + rc, phba->pport->port_state); + mempool_free(mboxq, phba->mbox_mem_pool); + return -EIO; + } + + shost = lpfc_shost_from_vport(vport); + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VFI_REGISTERED; + spin_unlock_irq(shost->host_lock); + return 0; +} + +/** * lpfc_check_clean_addr_bit - Check whether assigned FCID is clean. * @vport: pointer to a host virtual N_Port data structure. * @sp: pointer to service parameter data structure. @@ -615,7 +667,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, "1816 FLOGI NPIV supported, " "response data 0x%x\n", sp->cmn.response_multiple_NPort); + spin_lock_irq(&phba->hbalock); phba->link_flag |= LS_NPIV_FAB_SUPPORTED; + spin_unlock_irq(&phba->hbalock); } else { /* Because we asked f/w for NPIV it still expects us to call reg_vnpid atleast for the physcial host */ @@ -623,7 +677,9 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, LOG_ELS | LOG_VPORT, "1817 Fabric does not support NPIV " "- configuring single port mode.\n"); + spin_lock_irq(&phba->hbalock); phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; + spin_unlock_irq(&phba->hbalock); } } @@ -686,11 +742,16 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_do_scr_ns_plogi(phba, vport); } else if (vport->fc_flag & FC_VFI_REGISTERED) lpfc_issue_init_vpi(vport); - else + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3135 Need register VFI: (x%x/%x)\n", + vport->fc_prevDID, vport->fc_myDID); lpfc_issue_reg_vfi(vport); + } } return 0; } + /** * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port * @vport: pointer to a host virtual N_Port data structure. @@ -907,17 +968,16 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no * alpa map would take too long otherwise. */ - if (phba->alpa_map[0] == 0) { + if (phba->alpa_map[0] == 0) vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS; - if ((phba->sli_rev == LPFC_SLI_REV4) && - (!(vport->fc_flag & FC_VFI_REGISTERED) || - (vport->fc_prevDID != vport->fc_myDID))) { - if (vport->fc_flag & FC_VFI_REGISTERED) - lpfc_sli4_unreg_all_rpis(vport); - lpfc_issue_reg_vfi(vport); - lpfc_nlp_put(ndlp); - goto out; - } + if ((phba->sli_rev == LPFC_SLI_REV4) && + (!(vport->fc_flag & FC_VFI_REGISTERED) || + (vport->fc_prevDID != vport->fc_myDID))) { + if (vport->fc_flag & FC_VFI_REGISTERED) + lpfc_sli4_unreg_all_rpis(vport); + lpfc_issue_reg_vfi(vport); + lpfc_nlp_put(ndlp); + goto out; } goto flogifail; } @@ -1075,6 +1135,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Setup CSPs accordingly for Fabric */ sp->cmn.e_d_tov = 0; sp->cmn.w2.r_a_tov = 0; + sp->cmn.virtual_fabric_support = 0; sp->cls1.classValid = 0; sp->cls2.seqDelivery = 1; sp->cls3.seqDelivery = 1; @@ -1163,8 +1224,7 @@ lpfc_els_abort_flogi(struct lpfc_hba *phba) spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { icmd = &iocb->iocb; - if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR && - icmd->un.elsreq64.bdl.ulpIoTag32) { + if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { ndlp = (struct lpfc_nodelist *)(iocb->context1); if (ndlp && NLP_CHK_NODE_ACT(ndlp) && (ndlp->nlp_DID == Fabric_DID)) @@ -3066,17 +3126,22 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (did == FDMI_DID) retry = 1; - if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) && + if ((cmd == ELS_CMD_FLOGI) && (phba->fc_topology != LPFC_TOPOLOGY_LOOP) && !lpfc_error_lost_link(irsp)) { /* FLOGI retry policy */ retry = 1; - /* retry forever */ + /* retry FLOGI forever */ maxretry = 0; if (cmdiocb->retry >= 100) delay = 5000; else if (cmdiocb->retry >= 32) delay = 1000; + } else if ((cmd == ELS_CMD_FDISC) && !lpfc_error_lost_link(irsp)) { + /* retry FDISCs every second up to devloss */ + retry = 1; + maxretry = vport->cfg_devloss_tmo; + delay = 1000; } cmdiocb->retry++; @@ -3389,11 +3454,17 @@ lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* * The driver received a LOGO from the rport and has ACK'd it. - * At this point, the driver is done so release the IOCB and - * remove the ndlp reference. + * At this point, the driver is done so release the IOCB */ lpfc_els_free_iocb(phba, cmdiocb); - lpfc_nlp_put(ndlp); + + /* + * Remove the ndlp reference if it's a fabric node that has + * sent us an unsolicted LOGO. + */ + if (ndlp->nlp_type & NLP_FABRIC) + lpfc_nlp_put(ndlp); + return; } @@ -4867,23 +4938,31 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, sizeof(struct lpfc_name)); if (!rc) { - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (phba->sli_rev < LPFC_SLI_REV4) { + mbox = mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!mbox) + return 1; + lpfc_linkdown(phba); + lpfc_init_link(phba, mbox, + phba->cfg_topology, + phba->cfg_link_speed); + mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, + MBX_NOWAIT); + lpfc_set_loopback_flag(phba); + if (rc == MBX_NOT_FINISHED) + mempool_free(mbox, phba->mbox_mem_pool); return 1; - - lpfc_linkdown(phba); - lpfc_init_link(phba, mbox, - phba->cfg_topology, - phba->cfg_link_speed); - mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - lpfc_set_loopback_flag(phba); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); + } else { + /* abort the flogi coming back to ourselves + * due to external loopback on the port. + */ + lpfc_els_abort_flogi(phba); + return 0; } - return 1; } else if (rc > 0) { /* greater than */ spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_PT2PT_PLOGI; @@ -5838,8 +5917,12 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, vport->fc_myDID = vport->fc_prevDID; if (phba->sli_rev < LPFC_SLI_REV4) lpfc_issue_fabric_reglogin(vport); - else + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3138 Need register VFI: (x%x/%x)\n", + vport->fc_prevDID, vport->fc_myDID); lpfc_issue_reg_vfi(vport); + } } } return 0; @@ -6596,56 +6679,6 @@ dropit: } /** - * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier - * @phba: pointer to lpfc hba data structure. - * @vpi: host virtual N_Port identifier. - * - * This routine finds a vport on a HBA (referred by @phba) through a - * @vpi. The function walks the HBA's vport list and returns the address - * of the vport with the matching @vpi. - * - * Return code - * NULL - No vport with the matching @vpi found - * Otherwise - Address to the vport with the matching @vpi. - **/ -struct lpfc_vport * -lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) -{ - struct lpfc_vport *vport; - unsigned long flags; - int i = 0; - - /* The physical ports are always vpi 0 - translate is unnecessary. */ - if (vpi > 0) { - /* - * Translate the physical vpi to the logical vpi. The - * vport stores the logical vpi. - */ - for (i = 0; i < phba->max_vpi; i++) { - if (vpi == phba->vpi_ids[i]) - break; - } - - if (i >= phba->max_vpi) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "2936 Could not find Vport mapped " - "to vpi %d\n", vpi); - return NULL; - } - } - - spin_lock_irqsave(&phba->hbalock, flags); - list_for_each_entry(vport, &phba->port_list, listentry) { - if (vport->vpi == i) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return vport; - } - } - spin_unlock_irqrestore(&phba->hbalock, flags); - return NULL; -} - -/** * lpfc_els_unsol_event - Process an unsolicited event from an els sli ring * @phba: pointer to lpfc hba data structure. * @pring: pointer to a SLI ring. @@ -7281,6 +7314,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* Setup CSPs accordingly for Fabric */ sp->cmn.e_d_tov = 0; sp->cmn.w2.r_a_tov = 0; + sp->cmn.virtual_fabric_support = 0; sp->cls1.classValid = 0; sp->cls2.seqDelivery = 1; sp->cls3.seqDelivery = 1; |