diff options
author | James Smart <james.smart@avagotech.com> | 2015-12-16 18:11:53 -0500 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2015-12-21 21:51:56 -0500 |
commit | d6de08cc46269899988b4f40acc7337279693d4b (patch) | |
tree | c6bd9e48b696ef33b0570ea1576d926a01fbcde0 /drivers/scsi/lpfc/lpfc_els.c | |
parent | f5cb5304eb26d307c9b30269fb0e007e0b262b7d (diff) |
lpfc: Fix the FLOGI discovery logic to comply with T11 standards
Fix the FLOGI discovery logic to comply with T11 standards
We weren't properly setting fabric parameters, such as R_A_TOV and E_D_TOV,
when we registered the vfi object in default configs and pt2pt configs.
Revise to now pass service params with the values to the firmware and
ensure they are reset on link bounce. Required reworking the call sequence
in the discovery threads.
Signed-off-by: Dick Kennedy <dick.kennedy@avagotech.com>
Signed-off-by: James Smart <james.smart@avagotech.com>
Reviewed-by: Hannes Reinicke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 342 |
1 files changed, 156 insertions, 186 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b6fa257ea3e0..f6dd15b22383 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -455,9 +455,9 @@ int lpfc_issue_reg_vfi(struct lpfc_vport *vport) { struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mboxq; + LPFC_MBOXQ_t *mboxq = NULL; struct lpfc_nodelist *ndlp; - struct lpfc_dmabuf *dmabuf; + struct lpfc_dmabuf *dmabuf = NULL; int rc = 0; /* move forward in case of SLI4 FC port loopback test and pt2pt mode */ @@ -471,25 +471,33 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) } } - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!dmabuf) { + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { rc = -ENOMEM; goto fail; } - dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys); - if (!dmabuf->virt) { - rc = -ENOMEM; - goto fail_free_dmabuf; - } - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - rc = -ENOMEM; - goto fail_free_coherent; + /* Supply CSP's only if we are fabric connect or pt-to-pt connect */ + if ((vport->fc_flag & FC_FABRIC) || (vport->fc_flag & FC_PT2PT)) { + dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!dmabuf) { + rc = -ENOMEM; + goto fail; + } + dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys); + if (!dmabuf->virt) { + rc = -ENOMEM; + goto fail; + } + memcpy(dmabuf->virt, &phba->fc_fabparam, + sizeof(struct serv_parm)); } + vport->port_state = LPFC_FABRIC_CFG_LINK; - memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam)); - lpfc_reg_vfi(mboxq, vport, dmabuf->phys); + if (dmabuf) + lpfc_reg_vfi(mboxq, vport, dmabuf->phys); + else + lpfc_reg_vfi(mboxq, vport, 0); mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi; mboxq->vport = vport; @@ -497,17 +505,19 @@ lpfc_issue_reg_vfi(struct lpfc_vport *vport) rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); if (rc == MBX_NOT_FINISHED) { rc = -ENXIO; - goto fail_free_mbox; + goto fail; } return 0; -fail_free_mbox: - mempool_free(mboxq, phba->mbox_mem_pool); -fail_free_coherent: - lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); -fail_free_dmabuf: - kfree(dmabuf); fail: + if (mboxq) + mempool_free(mboxq, phba->mbox_mem_pool); + if (dmabuf) { + if (dmabuf->virt) + lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); + kfree(dmabuf); + } + lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "0289 Issue Register VFI failed: Err %d\n", rc); @@ -711,9 +721,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * For FC we need to do some special processing because of the SLI * Port's default settings of the Common Service Parameters. */ - if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) { + if ((phba->sli_rev == LPFC_SLI_REV4) && + (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC)) { /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */ - if ((phba->sli_rev == LPFC_SLI_REV4) && fabric_param_changed) + if (fabric_param_changed) lpfc_unregister_fcf_prep(phba); /* This should just update the VFI CSPs*/ @@ -824,13 +835,21 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_lock_irq(shost->host_lock); vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + vport->fc_flag |= FC_PT2PT; spin_unlock_irq(shost->host_lock); - phba->fc_edtov = FF_DEF_EDTOV; - phba->fc_ratov = FF_DEF_RATOV; + /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */ + if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) { + lpfc_unregister_fcf_prep(phba); + + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VFI_REGISTERED; + spin_unlock_irq(shost->host_lock); + phba->fc_topology_changed = 0; + } + rc = memcmp(&vport->fc_portname, &sp->portName, sizeof(vport->fc_portname)); - memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm)); if (rc >= 0) { /* This side will initiate the PLOGI */ @@ -839,38 +858,14 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, spin_unlock_irq(shost->host_lock); /* - * N_Port ID cannot be 0, set our to LocalID the other - * side will be RemoteID. + * N_Port ID cannot be 0, set our Id to LocalID + * the other side will be RemoteID. */ /* not equal */ if (rc) vport->fc_myDID = PT2PT_LocalID; - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - goto fail; - - 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); - goto fail; - } - - /* - * For SLI4, the VFI/VPI are registered AFTER the - * Nport with the higher WWPN sends the PLOGI with - * an assigned NPortId. - */ - - /* not equal */ - if ((phba->sli_rev == LPFC_SLI_REV4) && rc) - lpfc_issue_reg_vfi(vport); - /* Decrement ndlp reference count indicating that ndlp can be * safely released when other references to it are done. */ @@ -912,29 +907,20 @@ lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, /* If we are pt2pt with another NPort, force NPIV off! */ phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PT2PT; - spin_unlock_irq(shost->host_lock); - /* If physical FC port changed, unreg VFI and ALL VPIs / RPIs */ - if ((phba->sli_rev == LPFC_SLI_REV4) && phba->fc_topology_changed) { - lpfc_unregister_fcf_prep(phba); + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + goto fail; - /* The FC_VFI_REGISTERED flag will get clear in the cmpl - * handler for unreg_vfi, but if we don't force the - * FC_VFI_REGISTERED flag then the reg_vfi mailbox could be - * built with the update bit set instead of just the vp bit to - * change the Nport ID. We need to have the vp set and the - * Upd cleared on topology changes. - */ - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); - phba->fc_topology_changed = 0; - lpfc_issue_reg_vfi(vport); + lpfc_config_link(phba, mbox); + + mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mbox, phba->mbox_mem_pool); + goto fail; } - /* Start discovery - this should just do CLEAR_LA */ - lpfc_disc_start(vport); return 0; fail: return -ENXIO; @@ -1157,6 +1143,7 @@ flogifail: spin_lock_irq(&phba->hbalock); phba->fcf.fcf_flag &= ~FCF_DISCOVERY; spin_unlock_irq(&phba->hbalock); + lpfc_nlp_put(ndlp); if (!lpfc_error_lost_link(irsp)) { @@ -3898,6 +3885,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, IOCB_t *oldcmd; struct lpfc_iocbq *elsiocb; uint8_t *pcmd; + struct serv_parm *sp; uint16_t cmdsize; int rc; ELS_PKT *els_pkt_ptr; @@ -3927,6 +3915,7 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, "Issue ACC: did:x%x flg:x%x", ndlp->nlp_DID, ndlp->nlp_flag, 0); break; + case ELS_CMD_FLOGI: case ELS_CMD_PLOGI: cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t)); elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, @@ -3944,10 +3933,34 @@ lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, *((uint32_t *) (pcmd)) = ELS_CMD_ACC; pcmd += sizeof(uint32_t); - memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); + sp = (struct serv_parm *)pcmd; + + if (flag == ELS_CMD_FLOGI) { + /* Copy the received service parameters back */ + memcpy(sp, &phba->fc_fabparam, + sizeof(struct serv_parm)); + + /* Clear the F_Port bit */ + sp->cmn.fPort = 0; + + /* Mark all class service parameters as invalid */ + sp->cls1.classValid = 0; + sp->cls2.classValid = 0; + sp->cls3.classValid = 0; + sp->cls4.classValid = 0; + + /* Copy our worldwide names */ + memcpy(&sp->portName, &vport->fc_sparam.portName, + sizeof(struct lpfc_name)); + memcpy(&sp->nodeName, &vport->fc_sparam.nodeName, + sizeof(struct lpfc_name)); + } else { + memcpy(pcmd, &vport->fc_sparam, + sizeof(struct serv_parm)); + } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC PLOGI: did:x%x flg:x%x", + "Issue ACC FLOGI/PLOGI: did:x%x flg:x%x", ndlp->nlp_DID, ndlp->nlp_flag, 0); break; case ELS_CMD_PRLO: @@ -5739,7 +5752,6 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, IOCB_t *icmd = &cmdiocb->iocb; struct serv_parm *sp; LPFC_MBOXQ_t *mbox; - struct ls_rjt stat; uint32_t cmd, did; int rc; uint32_t fc_flag = 0; @@ -5765,135 +5777,92 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, return 1; } - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { - /* For a FLOGI we accept, then if our portname is greater - * then the remote portname we initiate Nport login. - */ + (void) lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1); - rc = memcmp(&vport->fc_portname, &sp->portName, - sizeof(struct lpfc_name)); - if (!rc) { - 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; - } else { - /* abort the flogi coming back to ourselves - * due to external loopback on the port. - */ - lpfc_els_abort_flogi(phba); - return 0; - } - } else if (rc > 0) { /* greater than */ - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PT2PT_PLOGI; - spin_unlock_irq(shost->host_lock); + /* + * If our portname is greater than the remote portname, + * then we initiate Nport login. + */ - /* If we have the high WWPN we can assign our own - * myDID; otherwise, we have to WAIT for a PLOGI - * from the remote NPort to find out what it - * will be. - */ - vport->fc_myDID = PT2PT_LocalID; - } else - vport->fc_myDID = PT2PT_RemoteID; + rc = memcmp(&vport->fc_portname, &sp->portName, + sizeof(struct lpfc_name)); - /* - * The vport state should go to LPFC_FLOGI only - * AFTER we issue a FLOGI, not receive one. + if (!rc) { + 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; + } + + /* abort the flogi coming back to ourselves + * due to external loopback on the port. */ + lpfc_els_abort_flogi(phba); + return 0; + + } else if (rc > 0) { /* greater than */ spin_lock_irq(shost->host_lock); - fc_flag = vport->fc_flag; - port_state = vport->port_state; - vport->fc_flag |= FC_PT2PT; - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + vport->fc_flag |= FC_PT2PT_PLOGI; spin_unlock_irq(shost->host_lock); - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3311 Rcv Flogi PS x%x new PS x%x " - "fc_flag x%x new fc_flag x%x\n", - port_state, vport->port_state, - fc_flag, vport->fc_flag); - /* - * We temporarily set fc_myDID to make it look like we are - * a Fabric. This is done just so we end up with the right - * did / sid on the FLOGI ACC rsp. + /* If we have the high WWPN we can assign our own + * myDID; otherwise, we have to WAIT for a PLOGI + * from the remote NPort to find out what it + * will be. */ - did = vport->fc_myDID; - vport->fc_myDID = Fabric_DID; - + vport->fc_myDID = PT2PT_LocalID; } else { - /* Reject this request because invalid parameters */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; - stat.un.b.vendorUnique = 0; - - /* - * We temporarily set fc_myDID to make it look like we are - * a Fabric. This is done just so we end up with the right - * did / sid on the FLOGI LS_RJT rsp. - */ - did = vport->fc_myDID; - vport->fc_myDID = Fabric_DID; - - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, - NULL); + vport->fc_myDID = PT2PT_RemoteID; + } - /* Now lets put fc_myDID back to what its supposed to be */ - vport->fc_myDID = did; + /* + * The vport state should go to LPFC_FLOGI only + * AFTER we issue a FLOGI, not receive one. + */ + spin_lock_irq(shost->host_lock); + fc_flag = vport->fc_flag; + port_state = vport->port_state; + vport->fc_flag |= FC_PT2PT; + vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + spin_unlock_irq(shost->host_lock); + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, + "3311 Rcv Flogi PS x%x new PS x%x " + "fc_flag x%x new fc_flag x%x\n", + port_state, vport->port_state, + fc_flag, vport->fc_flag); - return 1; - } + /* + * We temporarily set fc_myDID to make it look like we are + * a Fabric. This is done just so we end up with the right + * did / sid on the FLOGI ACC rsp. + */ + did = vport->fc_myDID; + vport->fc_myDID = Fabric_DID; - /* send our FLOGI first */ - if (vport->port_state < LPFC_FLOGI) { - vport->fc_myDID = 0; - lpfc_initial_flogi(vport); - vport->fc_myDID = Fabric_DID; - } + memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm)); /* Send back ACC */ - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); + lpfc_els_rsp_acc(vport, ELS_CMD_FLOGI, cmdiocb, ndlp, NULL); /* Now lets put fc_myDID back to what its supposed to be */ vport->fc_myDID = did; - if (!(vport->fc_flag & FC_PT2PT_PLOGI)) { - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - goto fail; - - 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); - goto fail; - } - } - return 0; -fail: - return 1; } /** @@ -7345,7 +7314,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, /* reject till our FLOGI completes */ if ((vport->port_state < LPFC_FABRIC_CFG_LINK) && - (cmd != ELS_CMD_FLOGI)) { + (cmd != ELS_CMD_FLOGI)) { rjt_err = LSRJT_UNABLE_TPC; rjt_exp = LSEXP_NOTHING_MORE; goto lsrjt; @@ -7381,6 +7350,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, rjt_exp = LSEXP_NOTHING_MORE; break; } + if (vport->port_state < LPFC_DISC_AUTH) { if (!(phba->pport->fc_flag & FC_PT2PT) || (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { |