diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 439 |
1 files changed, 382 insertions, 57 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index e6ca12f6c6cb..884f4d321799 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
@@ -177,15 +177,18 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, | |||
177 | (elscmd == ELS_CMD_LOGO))) | 177 | (elscmd == ELS_CMD_LOGO))) |
178 | switch (elscmd) { | 178 | switch (elscmd) { |
179 | case ELS_CMD_FLOGI: | 179 | case ELS_CMD_FLOGI: |
180 | elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT) | 180 | elsiocb->iocb_flag |= |
181 | ((LPFC_ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT) | ||
181 | & LPFC_FIP_ELS_ID_MASK); | 182 | & LPFC_FIP_ELS_ID_MASK); |
182 | break; | 183 | break; |
183 | case ELS_CMD_FDISC: | 184 | case ELS_CMD_FDISC: |
184 | elsiocb->iocb_flag |= ((ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT) | 185 | elsiocb->iocb_flag |= |
186 | ((LPFC_ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT) | ||
185 | & LPFC_FIP_ELS_ID_MASK); | 187 | & LPFC_FIP_ELS_ID_MASK); |
186 | break; | 188 | break; |
187 | case ELS_CMD_LOGO: | 189 | case ELS_CMD_LOGO: |
188 | elsiocb->iocb_flag |= ((ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT) | 190 | elsiocb->iocb_flag |= |
191 | ((LPFC_ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT) | ||
189 | & LPFC_FIP_ELS_ID_MASK); | 192 | & LPFC_FIP_ELS_ID_MASK); |
190 | break; | 193 | break; |
191 | } | 194 | } |
@@ -517,18 +520,13 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
517 | if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ | 520 | if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ |
518 | phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000; | 521 | phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000; |
519 | 522 | ||
523 | phba->fc_edtovResol = sp->cmn.edtovResolution; | ||
520 | phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000; | 524 | phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000; |
521 | 525 | ||
522 | if (phba->fc_topology == TOPOLOGY_LOOP) { | 526 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
523 | spin_lock_irq(shost->host_lock); | 527 | spin_lock_irq(shost->host_lock); |
524 | vport->fc_flag |= FC_PUBLIC_LOOP; | 528 | vport->fc_flag |= FC_PUBLIC_LOOP; |
525 | spin_unlock_irq(shost->host_lock); | 529 | spin_unlock_irq(shost->host_lock); |
526 | } else { | ||
527 | /* | ||
528 | * If we are a N-port connected to a Fabric, fixup sparam's so | ||
529 | * logins to devices on remote loops work. | ||
530 | */ | ||
531 | vport->fc_sparam.cmn.altBbCredit = 1; | ||
532 | } | 530 | } |
533 | 531 | ||
534 | vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; | 532 | vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; |
@@ -585,6 +583,10 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, | |||
585 | lpfc_unreg_rpi(vport, np); | 583 | lpfc_unreg_rpi(vport, np); |
586 | } | 584 | } |
587 | lpfc_cleanup_pending_mbox(vport); | 585 | lpfc_cleanup_pending_mbox(vport); |
586 | |||
587 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
588 | lpfc_sli4_unreg_all_rpis(vport); | ||
589 | |||
588 | if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { | 590 | if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { |
589 | lpfc_mbx_unreg_vpi(vport); | 591 | lpfc_mbx_unreg_vpi(vport); |
590 | spin_lock_irq(shost->host_lock); | 592 | spin_lock_irq(shost->host_lock); |
@@ -800,7 +802,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
800 | 802 | ||
801 | if (irsp->ulpStatus) { | 803 | if (irsp->ulpStatus) { |
802 | /* | 804 | /* |
803 | * In case of FIP mode, perform round robin FCF failover | 805 | * In case of FIP mode, perform roundrobin FCF failover |
804 | * due to new FCF discovery | 806 | * due to new FCF discovery |
805 | */ | 807 | */ |
806 | if ((phba->hba_flag & HBA_FIP_SUPPORT) && | 808 | if ((phba->hba_flag & HBA_FIP_SUPPORT) && |
@@ -808,48 +810,16 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
808 | (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) && | 810 | (irsp->ulpStatus != IOSTAT_LOCAL_REJECT) && |
809 | (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) { | 811 | (irsp->un.ulpWord[4] != IOERR_SLI_ABORTED)) { |
810 | lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, | 812 | lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, |
811 | "2611 FLOGI failed on registered " | 813 | "2611 FLOGI failed on FCF (x%x), " |
812 | "FCF record fcf_index(%d), status: " | 814 | "status:x%x/x%x, tmo:x%x, perform " |
813 | "x%x/x%x, tmo:x%x, trying to perform " | 815 | "roundrobin FCF failover\n", |
814 | "round robin failover\n", | ||
815 | phba->fcf.current_rec.fcf_indx, | 816 | phba->fcf.current_rec.fcf_indx, |
816 | irsp->ulpStatus, irsp->un.ulpWord[4], | 817 | irsp->ulpStatus, irsp->un.ulpWord[4], |
817 | irsp->ulpTimeout); | 818 | irsp->ulpTimeout); |
818 | fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba); | 819 | fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba); |
819 | if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) { | 820 | rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index); |
820 | /* | 821 | if (rc) |
821 | * Exhausted the eligible FCF record list, | 822 | goto out; |
822 | * fail through to retry FLOGI on current | ||
823 | * FCF record. | ||
824 | */ | ||
825 | lpfc_printf_log(phba, KERN_WARNING, | ||
826 | LOG_FIP | LOG_ELS, | ||
827 | "2760 Completed one round " | ||
828 | "of FLOGI FCF round robin " | ||
829 | "failover list, retry FLOGI " | ||
830 | "on currently registered " | ||
831 | "FCF index:%d\n", | ||
832 | phba->fcf.current_rec.fcf_indx); | ||
833 | } else { | ||
834 | lpfc_printf_log(phba, KERN_INFO, | ||
835 | LOG_FIP | LOG_ELS, | ||
836 | "2794 FLOGI FCF round robin " | ||
837 | "failover to FCF index x%x\n", | ||
838 | fcf_index); | ||
839 | rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba, | ||
840 | fcf_index); | ||
841 | if (rc) | ||
842 | lpfc_printf_log(phba, KERN_WARNING, | ||
843 | LOG_FIP | LOG_ELS, | ||
844 | "2761 FLOGI round " | ||
845 | "robin FCF failover " | ||
846 | "read FCF failed " | ||
847 | "rc:x%x, fcf_index:" | ||
848 | "%d\n", rc, | ||
849 | phba->fcf.current_rec.fcf_indx); | ||
850 | else | ||
851 | goto out; | ||
852 | } | ||
853 | } | 823 | } |
854 | 824 | ||
855 | /* FLOGI failure */ | 825 | /* FLOGI failure */ |
@@ -939,6 +909,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
939 | lpfc_nlp_put(ndlp); | 909 | lpfc_nlp_put(ndlp); |
940 | spin_lock_irq(&phba->hbalock); | 910 | spin_lock_irq(&phba->hbalock); |
941 | phba->fcf.fcf_flag &= ~FCF_DISCOVERY; | 911 | phba->fcf.fcf_flag &= ~FCF_DISCOVERY; |
912 | phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO); | ||
942 | spin_unlock_irq(&phba->hbalock); | 913 | spin_unlock_irq(&phba->hbalock); |
943 | goto out; | 914 | goto out; |
944 | } | 915 | } |
@@ -947,13 +918,12 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
947 | if (phba->hba_flag & HBA_FIP_SUPPORT) | 918 | if (phba->hba_flag & HBA_FIP_SUPPORT) |
948 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | | 919 | lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | |
949 | LOG_ELS, | 920 | LOG_ELS, |
950 | "2769 FLOGI successful on FCF " | 921 | "2769 FLOGI to FCF (x%x) " |
951 | "record: current_fcf_index:" | 922 | "completed successfully\n", |
952 | "x%x, terminate FCF round " | ||
953 | "robin failover process\n", | ||
954 | phba->fcf.current_rec.fcf_indx); | 923 | phba->fcf.current_rec.fcf_indx); |
955 | spin_lock_irq(&phba->hbalock); | 924 | spin_lock_irq(&phba->hbalock); |
956 | phba->fcf.fcf_flag &= ~FCF_DISCOVERY; | 925 | phba->fcf.fcf_flag &= ~FCF_DISCOVERY; |
926 | phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO); | ||
957 | spin_unlock_irq(&phba->hbalock); | 927 | spin_unlock_irq(&phba->hbalock); |
958 | goto out; | 928 | goto out; |
959 | } | 929 | } |
@@ -1175,12 +1145,13 @@ lpfc_initial_flogi(struct lpfc_vport *vport) | |||
1175 | return 0; | 1145 | return 0; |
1176 | } | 1146 | } |
1177 | 1147 | ||
1178 | if (lpfc_issue_els_flogi(vport, ndlp, 0)) | 1148 | if (lpfc_issue_els_flogi(vport, ndlp, 0)) { |
1179 | /* This decrement of reference count to node shall kick off | 1149 | /* This decrement of reference count to node shall kick off |
1180 | * the release of the node. | 1150 | * the release of the node. |
1181 | */ | 1151 | */ |
1182 | lpfc_nlp_put(ndlp); | 1152 | lpfc_nlp_put(ndlp); |
1183 | 1153 | return 0; | |
1154 | } | ||
1184 | return 1; | 1155 | return 1; |
1185 | } | 1156 | } |
1186 | 1157 | ||
@@ -1645,6 +1616,13 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) | |||
1645 | memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); | 1616 | memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); |
1646 | sp = (struct serv_parm *) pcmd; | 1617 | sp = (struct serv_parm *) pcmd; |
1647 | 1618 | ||
1619 | /* | ||
1620 | * If we are a N-port connected to a Fabric, fix-up paramm's so logins | ||
1621 | * to device on remote loops work. | ||
1622 | */ | ||
1623 | if ((vport->fc_flag & FC_FABRIC) && !(vport->fc_flag & FC_PUBLIC_LOOP)) | ||
1624 | sp->cmn.altBbCredit = 1; | ||
1625 | |||
1648 | if (sp->cmn.fcphLow < FC_PH_4_3) | 1626 | if (sp->cmn.fcphLow < FC_PH_4_3) |
1649 | sp->cmn.fcphLow = FC_PH_4_3; | 1627 | sp->cmn.fcphLow = FC_PH_4_3; |
1650 | 1628 | ||
@@ -3926,6 +3904,64 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, | |||
3926 | } | 3904 | } |
3927 | 3905 | ||
3928 | /** | 3906 | /** |
3907 | * lpfc_els_rsp_echo_acc - Issue echo acc response | ||
3908 | * @vport: pointer to a virtual N_Port data structure. | ||
3909 | * @data: pointer to echo data to return in the accept. | ||
3910 | * @oldiocb: pointer to the original lpfc command iocb data structure. | ||
3911 | * @ndlp: pointer to a node-list data structure. | ||
3912 | * | ||
3913 | * Return code | ||
3914 | * 0 - Successfully issued acc echo response | ||
3915 | * 1 - Failed to issue acc echo response | ||
3916 | **/ | ||
3917 | static int | ||
3918 | lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, | ||
3919 | struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) | ||
3920 | { | ||
3921 | struct lpfc_hba *phba = vport->phba; | ||
3922 | struct lpfc_iocbq *elsiocb; | ||
3923 | struct lpfc_sli *psli; | ||
3924 | uint8_t *pcmd; | ||
3925 | uint16_t cmdsize; | ||
3926 | int rc; | ||
3927 | |||
3928 | psli = &phba->sli; | ||
3929 | cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len; | ||
3930 | |||
3931 | elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, | ||
3932 | ndlp->nlp_DID, ELS_CMD_ACC); | ||
3933 | if (!elsiocb) | ||
3934 | return 1; | ||
3935 | |||
3936 | elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext; /* Xri */ | ||
3937 | /* Xmit ECHO ACC response tag <ulpIoTag> */ | ||
3938 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, | ||
3939 | "2876 Xmit ECHO ACC response tag x%x xri x%x\n", | ||
3940 | elsiocb->iotag, elsiocb->iocb.ulpContext); | ||
3941 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
3942 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
3943 | pcmd += sizeof(uint32_t); | ||
3944 | memcpy(pcmd, data, cmdsize - sizeof(uint32_t)); | ||
3945 | |||
3946 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, | ||
3947 | "Issue ACC ECHO: did:x%x flg:x%x", | ||
3948 | ndlp->nlp_DID, ndlp->nlp_flag, 0); | ||
3949 | |||
3950 | phba->fc_stat.elsXmitACC++; | ||
3951 | elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; | ||
3952 | lpfc_nlp_put(ndlp); | ||
3953 | elsiocb->context1 = NULL; /* Don't need ndlp for cmpl, | ||
3954 | * it could be freed */ | ||
3955 | |||
3956 | rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); | ||
3957 | if (rc == IOCB_ERROR) { | ||
3958 | lpfc_els_free_iocb(phba, elsiocb); | ||
3959 | return 1; | ||
3960 | } | ||
3961 | return 0; | ||
3962 | } | ||
3963 | |||
3964 | /** | ||
3929 | * lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport | 3965 | * lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport |
3930 | * @vport: pointer to a host virtual N_Port data structure. | 3966 | * @vport: pointer to a host virtual N_Port data structure. |
3931 | * | 3967 | * |
@@ -4684,6 +4720,30 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
4684 | } | 4720 | } |
4685 | 4721 | ||
4686 | /** | 4722 | /** |
4723 | * lpfc_els_rcv_echo - Process an unsolicited echo iocb | ||
4724 | * @vport: pointer to a host virtual N_Port data structure. | ||
4725 | * @cmdiocb: pointer to lpfc command iocb data structure. | ||
4726 | * @ndlp: pointer to a node-list data structure. | ||
4727 | * | ||
4728 | * Return code | ||
4729 | * 0 - Successfully processed echo iocb (currently always return 0) | ||
4730 | **/ | ||
4731 | static int | ||
4732 | lpfc_els_rcv_echo(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | ||
4733 | struct lpfc_nodelist *ndlp) | ||
4734 | { | ||
4735 | uint8_t *pcmd; | ||
4736 | |||
4737 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); | ||
4738 | |||
4739 | /* skip over first word of echo command to find echo data */ | ||
4740 | pcmd += sizeof(uint32_t); | ||
4741 | |||
4742 | lpfc_els_rsp_echo_acc(vport, pcmd, cmdiocb, ndlp); | ||
4743 | return 0; | ||
4744 | } | ||
4745 | |||
4746 | /** | ||
4687 | * lpfc_els_rcv_lirr - Process an unsolicited lirr iocb | 4747 | * lpfc_els_rcv_lirr - Process an unsolicited lirr iocb |
4688 | * @vport: pointer to a host virtual N_Port data structure. | 4748 | * @vport: pointer to a host virtual N_Port data structure. |
4689 | * @cmdiocb: pointer to lpfc command iocb data structure. | 4749 | * @cmdiocb: pointer to lpfc command iocb data structure. |
@@ -4735,6 +4795,89 @@ lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
4735 | } | 4795 | } |
4736 | 4796 | ||
4737 | /** | 4797 | /** |
4798 | * lpfc_els_rsp_rls_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd | ||
4799 | * @phba: pointer to lpfc hba data structure. | ||
4800 | * @pmb: pointer to the driver internal queue element for mailbox command. | ||
4801 | * | ||
4802 | * This routine is the completion callback function for the MBX_READ_LNK_STAT | ||
4803 | * mailbox command. This callback function is to actually send the Accept | ||
4804 | * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It | ||
4805 | * collects the link statistics from the completion of the MBX_READ_LNK_STAT | ||
4806 | * mailbox command, constructs the RPS response with the link statistics | ||
4807 | * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC | ||
4808 | * response to the RPS. | ||
4809 | * | ||
4810 | * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp | ||
4811 | * will be incremented by 1 for holding the ndlp and the reference to ndlp | ||
4812 | * will be stored into the context1 field of the IOCB for the completion | ||
4813 | * callback function to the RPS Accept Response ELS IOCB command. | ||
4814 | * | ||
4815 | **/ | ||
4816 | static void | ||
4817 | lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | ||
4818 | { | ||
4819 | MAILBOX_t *mb; | ||
4820 | IOCB_t *icmd; | ||
4821 | struct RLS_RSP *rls_rsp; | ||
4822 | uint8_t *pcmd; | ||
4823 | struct lpfc_iocbq *elsiocb; | ||
4824 | struct lpfc_nodelist *ndlp; | ||
4825 | uint16_t xri; | ||
4826 | uint32_t cmdsize; | ||
4827 | |||
4828 | mb = &pmb->u.mb; | ||
4829 | |||
4830 | ndlp = (struct lpfc_nodelist *) pmb->context2; | ||
4831 | xri = (uint16_t) ((unsigned long)(pmb->context1)); | ||
4832 | pmb->context1 = NULL; | ||
4833 | pmb->context2 = NULL; | ||
4834 | |||
4835 | if (mb->mbxStatus) { | ||
4836 | mempool_free(pmb, phba->mbox_mem_pool); | ||
4837 | return; | ||
4838 | } | ||
4839 | |||
4840 | cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t); | ||
4841 | mempool_free(pmb, phba->mbox_mem_pool); | ||
4842 | elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, | ||
4843 | lpfc_max_els_tries, ndlp, | ||
4844 | ndlp->nlp_DID, ELS_CMD_ACC); | ||
4845 | |||
4846 | /* Decrement the ndlp reference count from previous mbox command */ | ||
4847 | lpfc_nlp_put(ndlp); | ||
4848 | |||
4849 | if (!elsiocb) | ||
4850 | return; | ||
4851 | |||
4852 | icmd = &elsiocb->iocb; | ||
4853 | icmd->ulpContext = xri; | ||
4854 | |||
4855 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
4856 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
4857 | pcmd += sizeof(uint32_t); /* Skip past command */ | ||
4858 | rls_rsp = (struct RLS_RSP *)pcmd; | ||
4859 | |||
4860 | rls_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); | ||
4861 | rls_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); | ||
4862 | rls_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); | ||
4863 | rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); | ||
4864 | rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); | ||
4865 | rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); | ||
4866 | |||
4867 | /* Xmit ELS RLS ACC response tag <ulpIoTag> */ | ||
4868 | lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, | ||
4869 | "2874 Xmit ELS RLS ACC response tag x%x xri x%x, " | ||
4870 | "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", | ||
4871 | elsiocb->iotag, elsiocb->iocb.ulpContext, | ||
4872 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, | ||
4873 | ndlp->nlp_rpi); | ||
4874 | elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; | ||
4875 | phba->fc_stat.elsXmitACC++; | ||
4876 | if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) | ||
4877 | lpfc_els_free_iocb(phba, elsiocb); | ||
4878 | } | ||
4879 | |||
4880 | /** | ||
4738 | * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd | 4881 | * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd |
4739 | * @phba: pointer to lpfc hba data structure. | 4882 | * @phba: pointer to lpfc hba data structure. |
4740 | * @pmb: pointer to the driver internal queue element for mailbox command. | 4883 | * @pmb: pointer to the driver internal queue element for mailbox command. |
@@ -4827,7 +4970,155 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
4827 | } | 4970 | } |
4828 | 4971 | ||
4829 | /** | 4972 | /** |
4830 | * lpfc_els_rcv_rps - Process an unsolicited rps iocb | 4973 | * lpfc_els_rcv_rls - Process an unsolicited rls iocb |
4974 | * @vport: pointer to a host virtual N_Port data structure. | ||
4975 | * @cmdiocb: pointer to lpfc command iocb data structure. | ||
4976 | * @ndlp: pointer to a node-list data structure. | ||
4977 | * | ||
4978 | * This routine processes Read Port Status (RPL) IOCB received as an | ||
4979 | * ELS unsolicited event. It first checks the remote port state. If the | ||
4980 | * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE | ||
4981 | * state, it invokes the lpfc_els_rsl_reject() routine to send the reject | ||
4982 | * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command | ||
4983 | * for reading the HBA link statistics. It is for the callback function, | ||
4984 | * lpfc_els_rsp_rls_acc(), set to the MBX_READ_LNK_STAT mailbox command | ||
4985 | * to actually sending out RPL Accept (ACC) response. | ||
4986 | * | ||
4987 | * Return codes | ||
4988 | * 0 - Successfully processed rls iocb (currently always return 0) | ||
4989 | **/ | ||
4990 | static int | ||
4991 | lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | ||
4992 | struct lpfc_nodelist *ndlp) | ||
4993 | { | ||
4994 | struct lpfc_hba *phba = vport->phba; | ||
4995 | LPFC_MBOXQ_t *mbox; | ||
4996 | struct lpfc_dmabuf *pcmd; | ||
4997 | struct ls_rjt stat; | ||
4998 | |||
4999 | if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && | ||
5000 | (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) | ||
5001 | /* reject the unsolicited RPS request and done with it */ | ||
5002 | goto reject_out; | ||
5003 | |||
5004 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
5005 | |||
5006 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); | ||
5007 | if (mbox) { | ||
5008 | lpfc_read_lnk_stat(phba, mbox); | ||
5009 | mbox->context1 = | ||
5010 | (void *)((unsigned long) cmdiocb->iocb.ulpContext); | ||
5011 | mbox->context2 = lpfc_nlp_get(ndlp); | ||
5012 | mbox->vport = vport; | ||
5013 | mbox->mbox_cmpl = lpfc_els_rsp_rls_acc; | ||
5014 | if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) | ||
5015 | != MBX_NOT_FINISHED) | ||
5016 | /* Mbox completion will send ELS Response */ | ||
5017 | return 0; | ||
5018 | /* Decrement reference count used for the failed mbox | ||
5019 | * command. | ||
5020 | */ | ||
5021 | lpfc_nlp_put(ndlp); | ||
5022 | mempool_free(mbox, phba->mbox_mem_pool); | ||
5023 | } | ||
5024 | reject_out: | ||
5025 | /* issue rejection response */ | ||
5026 | stat.un.b.lsRjtRsvd0 = 0; | ||
5027 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
5028 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; | ||
5029 | stat.un.b.vendorUnique = 0; | ||
5030 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); | ||
5031 | return 0; | ||
5032 | } | ||
5033 | |||
5034 | /** | ||
5035 | * lpfc_els_rcv_rtv - Process an unsolicited rtv iocb | ||
5036 | * @vport: pointer to a host virtual N_Port data structure. | ||
5037 | * @cmdiocb: pointer to lpfc command iocb data structure. | ||
5038 | * @ndlp: pointer to a node-list data structure. | ||
5039 | * | ||
5040 | * This routine processes Read Timout Value (RTV) IOCB received as an | ||
5041 | * ELS unsolicited event. It first checks the remote port state. If the | ||
5042 | * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE | ||
5043 | * state, it invokes the lpfc_els_rsl_reject() routine to send the reject | ||
5044 | * response. Otherwise, it sends the Accept(ACC) response to a Read Timeout | ||
5045 | * Value (RTV) unsolicited IOCB event. | ||
5046 | * | ||
5047 | * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp | ||
5048 | * will be incremented by 1 for holding the ndlp and the reference to ndlp | ||
5049 | * will be stored into the context1 field of the IOCB for the completion | ||
5050 | * callback function to the RPS Accept Response ELS IOCB command. | ||
5051 | * | ||
5052 | * Return codes | ||
5053 | * 0 - Successfully processed rtv iocb (currently always return 0) | ||
5054 | **/ | ||
5055 | static int | ||
5056 | lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | ||
5057 | struct lpfc_nodelist *ndlp) | ||
5058 | { | ||
5059 | struct lpfc_hba *phba = vport->phba; | ||
5060 | struct ls_rjt stat; | ||
5061 | struct RTV_RSP *rtv_rsp; | ||
5062 | uint8_t *pcmd; | ||
5063 | struct lpfc_iocbq *elsiocb; | ||
5064 | uint32_t cmdsize; | ||
5065 | |||
5066 | |||
5067 | if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && | ||
5068 | (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) | ||
5069 | /* reject the unsolicited RPS request and done with it */ | ||
5070 | goto reject_out; | ||
5071 | |||
5072 | cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t); | ||
5073 | elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, | ||
5074 | lpfc_max_els_tries, ndlp, | ||
5075 | ndlp->nlp_DID, ELS_CMD_ACC); | ||
5076 | |||
5077 | if (!elsiocb) | ||
5078 | return 1; | ||
5079 | |||
5080 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
5081 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
5082 | pcmd += sizeof(uint32_t); /* Skip past command */ | ||
5083 | |||
5084 | /* use the command's xri in the response */ | ||
5085 | elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext; | ||
5086 | |||
5087 | rtv_rsp = (struct RTV_RSP *)pcmd; | ||
5088 | |||
5089 | /* populate RTV payload */ | ||
5090 | rtv_rsp->ratov = cpu_to_be32(phba->fc_ratov * 1000); /* report msecs */ | ||
5091 | rtv_rsp->edtov = cpu_to_be32(phba->fc_edtov); | ||
5092 | bf_set(qtov_edtovres, rtv_rsp, phba->fc_edtovResol ? 1 : 0); | ||
5093 | bf_set(qtov_rttov, rtv_rsp, 0); /* Field is for FC ONLY */ | ||
5094 | rtv_rsp->qtov = cpu_to_be32(rtv_rsp->qtov); | ||
5095 | |||
5096 | /* Xmit ELS RLS ACC response tag <ulpIoTag> */ | ||
5097 | lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, | ||
5098 | "2875 Xmit ELS RTV ACC response tag x%x xri x%x, " | ||
5099 | "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x, " | ||
5100 | "Data: x%x x%x x%x\n", | ||
5101 | elsiocb->iotag, elsiocb->iocb.ulpContext, | ||
5102 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, | ||
5103 | ndlp->nlp_rpi, | ||
5104 | rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov); | ||
5105 | elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; | ||
5106 | phba->fc_stat.elsXmitACC++; | ||
5107 | if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) | ||
5108 | lpfc_els_free_iocb(phba, elsiocb); | ||
5109 | return 0; | ||
5110 | |||
5111 | reject_out: | ||
5112 | /* issue rejection response */ | ||
5113 | stat.un.b.lsRjtRsvd0 = 0; | ||
5114 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
5115 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; | ||
5116 | stat.un.b.vendorUnique = 0; | ||
5117 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); | ||
5118 | return 0; | ||
5119 | } | ||
5120 | |||
5121 | /* lpfc_els_rcv_rps - Process an unsolicited rps iocb | ||
4831 | * @vport: pointer to a host virtual N_Port data structure. | 5122 | * @vport: pointer to a host virtual N_Port data structure. |
4832 | * @cmdiocb: pointer to lpfc command iocb data structure. | 5123 | * @cmdiocb: pointer to lpfc command iocb data structure. |
4833 | * @ndlp: pointer to a node-list data structure. | 5124 | * @ndlp: pointer to a node-list data structure. |
@@ -5017,7 +5308,6 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
5017 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | 5308 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; |
5018 | lp = (uint32_t *) pcmd->virt; | 5309 | lp = (uint32_t *) pcmd->virt; |
5019 | rpl = (RPL *) (lp + 1); | 5310 | rpl = (RPL *) (lp + 1); |
5020 | |||
5021 | maxsize = be32_to_cpu(rpl->maxsize); | 5311 | maxsize = be32_to_cpu(rpl->maxsize); |
5022 | 5312 | ||
5023 | /* We support only one port */ | 5313 | /* We support only one port */ |
@@ -5836,6 +6126,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
5836 | if (newnode) | 6126 | if (newnode) |
5837 | lpfc_nlp_put(ndlp); | 6127 | lpfc_nlp_put(ndlp); |
5838 | break; | 6128 | break; |
6129 | case ELS_CMD_RLS: | ||
6130 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | ||
6131 | "RCV RLS: did:x%x/ste:x%x flg:x%x", | ||
6132 | did, vport->port_state, ndlp->nlp_flag); | ||
6133 | |||
6134 | phba->fc_stat.elsRcvRLS++; | ||
6135 | lpfc_els_rcv_rls(vport, elsiocb, ndlp); | ||
6136 | if (newnode) | ||
6137 | lpfc_nlp_put(ndlp); | ||
6138 | break; | ||
5839 | case ELS_CMD_RPS: | 6139 | case ELS_CMD_RPS: |
5840 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | 6140 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, |
5841 | "RCV RPS: did:x%x/ste:x%x flg:x%x", | 6141 | "RCV RPS: did:x%x/ste:x%x flg:x%x", |
@@ -5866,6 +6166,15 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
5866 | if (newnode) | 6166 | if (newnode) |
5867 | lpfc_nlp_put(ndlp); | 6167 | lpfc_nlp_put(ndlp); |
5868 | break; | 6168 | break; |
6169 | case ELS_CMD_RTV: | ||
6170 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | ||
6171 | "RCV RTV: did:x%x/ste:x%x flg:x%x", | ||
6172 | did, vport->port_state, ndlp->nlp_flag); | ||
6173 | phba->fc_stat.elsRcvRTV++; | ||
6174 | lpfc_els_rcv_rtv(vport, elsiocb, ndlp); | ||
6175 | if (newnode) | ||
6176 | lpfc_nlp_put(ndlp); | ||
6177 | break; | ||
5869 | case ELS_CMD_RRQ: | 6178 | case ELS_CMD_RRQ: |
5870 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | 6179 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, |
5871 | "RCV RRQ: did:x%x/ste:x%x flg:x%x", | 6180 | "RCV RRQ: did:x%x/ste:x%x flg:x%x", |
@@ -5876,6 +6185,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
5876 | if (newnode) | 6185 | if (newnode) |
5877 | lpfc_nlp_put(ndlp); | 6186 | lpfc_nlp_put(ndlp); |
5878 | break; | 6187 | break; |
6188 | case ELS_CMD_ECHO: | ||
6189 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | ||
6190 | "RCV ECHO: did:x%x/ste:x%x flg:x%x", | ||
6191 | did, vport->port_state, ndlp->nlp_flag); | ||
6192 | |||
6193 | phba->fc_stat.elsRcvECHO++; | ||
6194 | lpfc_els_rcv_echo(vport, elsiocb, ndlp); | ||
6195 | if (newnode) | ||
6196 | lpfc_nlp_put(ndlp); | ||
6197 | break; | ||
5879 | default: | 6198 | default: |
5880 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | 6199 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, |
5881 | "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", | 6200 | "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", |
@@ -6170,6 +6489,8 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
6170 | 6489 | ||
6171 | default: | 6490 | default: |
6172 | /* Try to recover from this error */ | 6491 | /* Try to recover from this error */ |
6492 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
6493 | lpfc_sli4_unreg_all_rpis(vport); | ||
6173 | lpfc_mbx_unreg_vpi(vport); | 6494 | lpfc_mbx_unreg_vpi(vport); |
6174 | spin_lock_irq(shost->host_lock); | 6495 | spin_lock_irq(shost->host_lock); |
6175 | vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; | 6496 | vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; |
@@ -6437,6 +6758,10 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
6437 | lpfc_unreg_rpi(vport, np); | 6758 | lpfc_unreg_rpi(vport, np); |
6438 | } | 6759 | } |
6439 | lpfc_cleanup_pending_mbox(vport); | 6760 | lpfc_cleanup_pending_mbox(vport); |
6761 | |||
6762 | if (phba->sli_rev == LPFC_SLI_REV4) | ||
6763 | lpfc_sli4_unreg_all_rpis(vport); | ||
6764 | |||
6440 | lpfc_mbx_unreg_vpi(vport); | 6765 | lpfc_mbx_unreg_vpi(vport); |
6441 | spin_lock_irq(shost->host_lock); | 6766 | spin_lock_irq(shost->host_lock); |
6442 | vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; | 6767 | vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; |
@@ -6452,7 +6777,7 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, | |||
6452 | * to update the MAC address. | 6777 | * to update the MAC address. |
6453 | */ | 6778 | */ |
6454 | lpfc_register_new_vport(phba, vport, ndlp); | 6779 | lpfc_register_new_vport(phba, vport, ndlp); |
6455 | return ; | 6780 | goto out; |
6456 | } | 6781 | } |
6457 | 6782 | ||
6458 | if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) | 6783 | if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) |