diff options
| -rw-r--r-- | drivers/scsi/lpfc/lpfc.h | 4 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 346 | ||||
| -rw-r--r-- | drivers/scsi/lpfc/lpfc_hw.h | 41 |
3 files changed, 389 insertions, 2 deletions
diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index a50aa03b8ac1..cd4afcf749dd 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h | |||
| @@ -202,9 +202,12 @@ struct lpfc_stats { | |||
| 202 | uint32_t elsRcvPRLO; | 202 | uint32_t elsRcvPRLO; |
| 203 | uint32_t elsRcvPRLI; | 203 | uint32_t elsRcvPRLI; |
| 204 | uint32_t elsRcvLIRR; | 204 | uint32_t elsRcvLIRR; |
| 205 | uint32_t elsRcvRLS; | ||
| 205 | uint32_t elsRcvRPS; | 206 | uint32_t elsRcvRPS; |
| 206 | uint32_t elsRcvRPL; | 207 | uint32_t elsRcvRPL; |
| 207 | uint32_t elsRcvRRQ; | 208 | uint32_t elsRcvRRQ; |
| 209 | uint32_t elsRcvRTV; | ||
| 210 | uint32_t elsRcvECHO; | ||
| 208 | uint32_t elsXmitFLOGI; | 211 | uint32_t elsXmitFLOGI; |
| 209 | uint32_t elsXmitFDISC; | 212 | uint32_t elsXmitFDISC; |
| 210 | uint32_t elsXmitPLOGI; | 213 | uint32_t elsXmitPLOGI; |
| @@ -573,6 +576,7 @@ struct lpfc_hba { | |||
| 573 | /* These fields used to be binfo */ | 576 | /* These fields used to be binfo */ |
| 574 | uint32_t fc_pref_DID; /* preferred D_ID */ | 577 | uint32_t fc_pref_DID; /* preferred D_ID */ |
| 575 | uint8_t fc_pref_ALPA; /* preferred AL_PA */ | 578 | uint8_t fc_pref_ALPA; /* preferred AL_PA */ |
| 579 | uint32_t fc_edtovResol; /* E_D_TOV timer resolution */ | ||
| 576 | uint32_t fc_edtov; /* E_D_TOV timer value */ | 580 | uint32_t fc_edtov; /* E_D_TOV timer value */ |
| 577 | uint32_t fc_arbtov; /* ARB_TOV timer value */ | 581 | uint32_t fc_arbtov; /* ARB_TOV timer value */ |
| 578 | uint32_t fc_ratov; /* R_A_TOV timer value */ | 582 | uint32_t fc_ratov; /* R_A_TOV timer value */ |
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b16311d60c66..ea511d18f0ec 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c | |||
| @@ -517,6 +517,7 @@ 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 */ | 517 | if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ |
| 518 | phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000; | 518 | phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000; |
| 519 | 519 | ||
| 520 | phba->fc_edtovResol = sp->cmn.edtovResolution; | ||
| 520 | phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000; | 521 | phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000; |
| 521 | 522 | ||
| 522 | if (phba->fc_topology == TOPOLOGY_LOOP) { | 523 | if (phba->fc_topology == TOPOLOGY_LOOP) { |
| @@ -3928,6 +3929,64 @@ lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, | |||
| 3928 | } | 3929 | } |
| 3929 | 3930 | ||
| 3930 | /** | 3931 | /** |
| 3932 | * lpfc_els_rsp_echo_acc - Issue echo acc response | ||
| 3933 | * @vport: pointer to a virtual N_Port data structure. | ||
| 3934 | * @data: pointer to echo data to return in the accept. | ||
| 3935 | * @oldiocb: pointer to the original lpfc command iocb data structure. | ||
| 3936 | * @ndlp: pointer to a node-list data structure. | ||
| 3937 | * | ||
| 3938 | * Return code | ||
| 3939 | * 0 - Successfully issued acc echo response | ||
| 3940 | * 1 - Failed to issue acc echo response | ||
| 3941 | **/ | ||
| 3942 | static int | ||
| 3943 | lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, | ||
| 3944 | struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) | ||
| 3945 | { | ||
| 3946 | struct lpfc_hba *phba = vport->phba; | ||
| 3947 | struct lpfc_iocbq *elsiocb; | ||
| 3948 | struct lpfc_sli *psli; | ||
| 3949 | uint8_t *pcmd; | ||
| 3950 | uint16_t cmdsize; | ||
| 3951 | int rc; | ||
| 3952 | |||
| 3953 | psli = &phba->sli; | ||
| 3954 | cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len; | ||
| 3955 | |||
| 3956 | elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, | ||
| 3957 | ndlp->nlp_DID, ELS_CMD_ACC); | ||
| 3958 | if (!elsiocb) | ||
| 3959 | return 1; | ||
| 3960 | |||
| 3961 | elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext; /* Xri */ | ||
| 3962 | /* Xmit ECHO ACC response tag <ulpIoTag> */ | ||
| 3963 | lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, | ||
| 3964 | "2876 Xmit ECHO ACC response tag x%x xri x%x\n", | ||
| 3965 | elsiocb->iotag, elsiocb->iocb.ulpContext); | ||
| 3966 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
| 3967 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
| 3968 | pcmd += sizeof(uint32_t); | ||
| 3969 | memcpy(pcmd, data, cmdsize - sizeof(uint32_t)); | ||
| 3970 | |||
| 3971 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, | ||
| 3972 | "Issue ACC ECHO: did:x%x flg:x%x", | ||
| 3973 | ndlp->nlp_DID, ndlp->nlp_flag, 0); | ||
| 3974 | |||
| 3975 | phba->fc_stat.elsXmitACC++; | ||
| 3976 | elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; | ||
| 3977 | lpfc_nlp_put(ndlp); | ||
| 3978 | elsiocb->context1 = NULL; /* Don't need ndlp for cmpl, | ||
| 3979 | * it could be freed */ | ||
| 3980 | |||
| 3981 | rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); | ||
| 3982 | if (rc == IOCB_ERROR) { | ||
| 3983 | lpfc_els_free_iocb(phba, elsiocb); | ||
| 3984 | return 1; | ||
| 3985 | } | ||
| 3986 | return 0; | ||
| 3987 | } | ||
| 3988 | |||
| 3989 | /** | ||
| 3931 | * lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport | 3990 | * lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport |
| 3932 | * @vport: pointer to a host virtual N_Port data structure. | 3991 | * @vport: pointer to a host virtual N_Port data structure. |
| 3933 | * | 3992 | * |
| @@ -4686,6 +4745,30 @@ lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
| 4686 | } | 4745 | } |
| 4687 | 4746 | ||
| 4688 | /** | 4747 | /** |
| 4748 | * lpfc_els_rcv_echo - Process an unsolicited echo iocb | ||
| 4749 | * @vport: pointer to a host virtual N_Port data structure. | ||
| 4750 | * @cmdiocb: pointer to lpfc command iocb data structure. | ||
| 4751 | * @ndlp: pointer to a node-list data structure. | ||
| 4752 | * | ||
| 4753 | * Return code | ||
| 4754 | * 0 - Successfully processed echo iocb (currently always return 0) | ||
| 4755 | **/ | ||
| 4756 | static int | ||
| 4757 | lpfc_els_rcv_echo(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | ||
| 4758 | struct lpfc_nodelist *ndlp) | ||
| 4759 | { | ||
| 4760 | uint8_t *pcmd; | ||
| 4761 | |||
| 4762 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); | ||
| 4763 | |||
| 4764 | /* skip over first word of echo command to find echo data */ | ||
| 4765 | pcmd += sizeof(uint32_t); | ||
| 4766 | |||
| 4767 | lpfc_els_rsp_echo_acc(vport, pcmd, cmdiocb, ndlp); | ||
| 4768 | return 0; | ||
| 4769 | } | ||
| 4770 | |||
| 4771 | /** | ||
| 4689 | * lpfc_els_rcv_lirr - Process an unsolicited lirr iocb | 4772 | * lpfc_els_rcv_lirr - Process an unsolicited lirr iocb |
| 4690 | * @vport: pointer to a host virtual N_Port data structure. | 4773 | * @vport: pointer to a host virtual N_Port data structure. |
| 4691 | * @cmdiocb: pointer to lpfc command iocb data structure. | 4774 | * @cmdiocb: pointer to lpfc command iocb data structure. |
| @@ -4737,6 +4820,89 @@ lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
| 4737 | } | 4820 | } |
| 4738 | 4821 | ||
| 4739 | /** | 4822 | /** |
| 4823 | * lpfc_els_rsp_rls_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd | ||
| 4824 | * @phba: pointer to lpfc hba data structure. | ||
| 4825 | * @pmb: pointer to the driver internal queue element for mailbox command. | ||
| 4826 | * | ||
| 4827 | * This routine is the completion callback function for the MBX_READ_LNK_STAT | ||
| 4828 | * mailbox command. This callback function is to actually send the Accept | ||
| 4829 | * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It | ||
| 4830 | * collects the link statistics from the completion of the MBX_READ_LNK_STAT | ||
| 4831 | * mailbox command, constructs the RPS response with the link statistics | ||
| 4832 | * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC | ||
| 4833 | * response to the RPS. | ||
| 4834 | * | ||
| 4835 | * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp | ||
| 4836 | * will be incremented by 1 for holding the ndlp and the reference to ndlp | ||
| 4837 | * will be stored into the context1 field of the IOCB for the completion | ||
| 4838 | * callback function to the RPS Accept Response ELS IOCB command. | ||
| 4839 | * | ||
| 4840 | **/ | ||
| 4841 | static void | ||
| 4842 | lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | ||
| 4843 | { | ||
| 4844 | MAILBOX_t *mb; | ||
| 4845 | IOCB_t *icmd; | ||
| 4846 | struct RLS_RSP *rls_rsp; | ||
| 4847 | uint8_t *pcmd; | ||
| 4848 | struct lpfc_iocbq *elsiocb; | ||
| 4849 | struct lpfc_nodelist *ndlp; | ||
| 4850 | uint16_t xri; | ||
| 4851 | uint32_t cmdsize; | ||
| 4852 | |||
| 4853 | mb = &pmb->u.mb; | ||
| 4854 | |||
| 4855 | ndlp = (struct lpfc_nodelist *) pmb->context2; | ||
| 4856 | xri = (uint16_t) ((unsigned long)(pmb->context1)); | ||
| 4857 | pmb->context1 = NULL; | ||
| 4858 | pmb->context2 = NULL; | ||
| 4859 | |||
| 4860 | if (mb->mbxStatus) { | ||
| 4861 | mempool_free(pmb, phba->mbox_mem_pool); | ||
| 4862 | return; | ||
| 4863 | } | ||
| 4864 | |||
| 4865 | cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t); | ||
| 4866 | mempool_free(pmb, phba->mbox_mem_pool); | ||
| 4867 | elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, | ||
| 4868 | lpfc_max_els_tries, ndlp, | ||
| 4869 | ndlp->nlp_DID, ELS_CMD_ACC); | ||
| 4870 | |||
| 4871 | /* Decrement the ndlp reference count from previous mbox command */ | ||
| 4872 | lpfc_nlp_put(ndlp); | ||
| 4873 | |||
| 4874 | if (!elsiocb) | ||
| 4875 | return; | ||
| 4876 | |||
| 4877 | icmd = &elsiocb->iocb; | ||
| 4878 | icmd->ulpContext = xri; | ||
| 4879 | |||
| 4880 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
| 4881 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
| 4882 | pcmd += sizeof(uint32_t); /* Skip past command */ | ||
| 4883 | rls_rsp = (struct RLS_RSP *)pcmd; | ||
| 4884 | |||
| 4885 | rls_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); | ||
| 4886 | rls_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); | ||
| 4887 | rls_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); | ||
| 4888 | rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); | ||
| 4889 | rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); | ||
| 4890 | rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); | ||
| 4891 | |||
| 4892 | /* Xmit ELS RLS ACC response tag <ulpIoTag> */ | ||
| 4893 | lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, | ||
| 4894 | "2874 Xmit ELS RLS ACC response tag x%x xri x%x, " | ||
| 4895 | "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", | ||
| 4896 | elsiocb->iotag, elsiocb->iocb.ulpContext, | ||
| 4897 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, | ||
| 4898 | ndlp->nlp_rpi); | ||
| 4899 | elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; | ||
| 4900 | phba->fc_stat.elsXmitACC++; | ||
| 4901 | if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) | ||
| 4902 | lpfc_els_free_iocb(phba, elsiocb); | ||
| 4903 | } | ||
| 4904 | |||
| 4905 | /** | ||
| 4740 | * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd | 4906 | * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd |
| 4741 | * @phba: pointer to lpfc hba data structure. | 4907 | * @phba: pointer to lpfc hba data structure. |
| 4742 | * @pmb: pointer to the driver internal queue element for mailbox command. | 4908 | * @pmb: pointer to the driver internal queue element for mailbox command. |
| @@ -4829,7 +4995,155 @@ lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) | |||
| 4829 | } | 4995 | } |
| 4830 | 4996 | ||
| 4831 | /** | 4997 | /** |
| 4832 | * lpfc_els_rcv_rps - Process an unsolicited rps iocb | 4998 | * lpfc_els_rcv_rls - Process an unsolicited rls iocb |
| 4999 | * @vport: pointer to a host virtual N_Port data structure. | ||
| 5000 | * @cmdiocb: pointer to lpfc command iocb data structure. | ||
| 5001 | * @ndlp: pointer to a node-list data structure. | ||
| 5002 | * | ||
| 5003 | * This routine processes Read Port Status (RPL) IOCB received as an | ||
| 5004 | * ELS unsolicited event. It first checks the remote port state. If the | ||
| 5005 | * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE | ||
| 5006 | * state, it invokes the lpfc_els_rsl_reject() routine to send the reject | ||
| 5007 | * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command | ||
| 5008 | * for reading the HBA link statistics. It is for the callback function, | ||
| 5009 | * lpfc_els_rsp_rls_acc(), set to the MBX_READ_LNK_STAT mailbox command | ||
| 5010 | * to actually sending out RPL Accept (ACC) response. | ||
| 5011 | * | ||
| 5012 | * Return codes | ||
| 5013 | * 0 - Successfully processed rls iocb (currently always return 0) | ||
| 5014 | **/ | ||
| 5015 | static int | ||
| 5016 | lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | ||
| 5017 | struct lpfc_nodelist *ndlp) | ||
| 5018 | { | ||
| 5019 | struct lpfc_hba *phba = vport->phba; | ||
| 5020 | LPFC_MBOXQ_t *mbox; | ||
| 5021 | struct lpfc_dmabuf *pcmd; | ||
| 5022 | struct ls_rjt stat; | ||
| 5023 | |||
| 5024 | if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && | ||
| 5025 | (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) | ||
| 5026 | /* reject the unsolicited RPS request and done with it */ | ||
| 5027 | goto reject_out; | ||
| 5028 | |||
| 5029 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | ||
| 5030 | |||
| 5031 | mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); | ||
| 5032 | if (mbox) { | ||
| 5033 | lpfc_read_lnk_stat(phba, mbox); | ||
| 5034 | mbox->context1 = | ||
| 5035 | (void *)((unsigned long) cmdiocb->iocb.ulpContext); | ||
| 5036 | mbox->context2 = lpfc_nlp_get(ndlp); | ||
| 5037 | mbox->vport = vport; | ||
| 5038 | mbox->mbox_cmpl = lpfc_els_rsp_rls_acc; | ||
| 5039 | if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) | ||
| 5040 | != MBX_NOT_FINISHED) | ||
| 5041 | /* Mbox completion will send ELS Response */ | ||
| 5042 | return 0; | ||
| 5043 | /* Decrement reference count used for the failed mbox | ||
| 5044 | * command. | ||
| 5045 | */ | ||
| 5046 | lpfc_nlp_put(ndlp); | ||
| 5047 | mempool_free(mbox, phba->mbox_mem_pool); | ||
| 5048 | } | ||
| 5049 | reject_out: | ||
| 5050 | /* issue rejection response */ | ||
| 5051 | stat.un.b.lsRjtRsvd0 = 0; | ||
| 5052 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
| 5053 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; | ||
| 5054 | stat.un.b.vendorUnique = 0; | ||
| 5055 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); | ||
| 5056 | return 0; | ||
| 5057 | } | ||
| 5058 | |||
| 5059 | /** | ||
| 5060 | * lpfc_els_rcv_rtv - Process an unsolicited rtv iocb | ||
| 5061 | * @vport: pointer to a host virtual N_Port data structure. | ||
| 5062 | * @cmdiocb: pointer to lpfc command iocb data structure. | ||
| 5063 | * @ndlp: pointer to a node-list data structure. | ||
| 5064 | * | ||
| 5065 | * This routine processes Read Timout Value (RTV) IOCB received as an | ||
| 5066 | * ELS unsolicited event. It first checks the remote port state. If the | ||
| 5067 | * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE | ||
| 5068 | * state, it invokes the lpfc_els_rsl_reject() routine to send the reject | ||
| 5069 | * response. Otherwise, it sends the Accept(ACC) response to a Read Timeout | ||
| 5070 | * Value (RTV) unsolicited IOCB event. | ||
| 5071 | * | ||
| 5072 | * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp | ||
| 5073 | * will be incremented by 1 for holding the ndlp and the reference to ndlp | ||
| 5074 | * will be stored into the context1 field of the IOCB for the completion | ||
| 5075 | * callback function to the RPS Accept Response ELS IOCB command. | ||
| 5076 | * | ||
| 5077 | * Return codes | ||
| 5078 | * 0 - Successfully processed rtv iocb (currently always return 0) | ||
| 5079 | **/ | ||
| 5080 | static int | ||
| 5081 | lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | ||
| 5082 | struct lpfc_nodelist *ndlp) | ||
| 5083 | { | ||
| 5084 | struct lpfc_hba *phba = vport->phba; | ||
| 5085 | struct ls_rjt stat; | ||
| 5086 | struct RTV_RSP *rtv_rsp; | ||
| 5087 | uint8_t *pcmd; | ||
| 5088 | struct lpfc_iocbq *elsiocb; | ||
| 5089 | uint32_t cmdsize; | ||
| 5090 | |||
| 5091 | |||
| 5092 | if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && | ||
| 5093 | (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) | ||
| 5094 | /* reject the unsolicited RPS request and done with it */ | ||
| 5095 | goto reject_out; | ||
| 5096 | |||
| 5097 | cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t); | ||
| 5098 | elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, | ||
| 5099 | lpfc_max_els_tries, ndlp, | ||
| 5100 | ndlp->nlp_DID, ELS_CMD_ACC); | ||
| 5101 | |||
| 5102 | if (!elsiocb) | ||
| 5103 | return 1; | ||
| 5104 | |||
| 5105 | pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); | ||
| 5106 | *((uint32_t *) (pcmd)) = ELS_CMD_ACC; | ||
| 5107 | pcmd += sizeof(uint32_t); /* Skip past command */ | ||
| 5108 | |||
| 5109 | /* use the command's xri in the response */ | ||
| 5110 | elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext; | ||
| 5111 | |||
| 5112 | rtv_rsp = (struct RTV_RSP *)pcmd; | ||
| 5113 | |||
| 5114 | /* populate RTV payload */ | ||
| 5115 | rtv_rsp->ratov = cpu_to_be32(phba->fc_ratov * 1000); /* report msecs */ | ||
| 5116 | rtv_rsp->edtov = cpu_to_be32(phba->fc_edtov); | ||
| 5117 | bf_set(qtov_edtovres, rtv_rsp, phba->fc_edtovResol ? 1 : 0); | ||
| 5118 | bf_set(qtov_rttov, rtv_rsp, 0); /* Field is for FC ONLY */ | ||
| 5119 | rtv_rsp->qtov = cpu_to_be32(rtv_rsp->qtov); | ||
| 5120 | |||
| 5121 | /* Xmit ELS RLS ACC response tag <ulpIoTag> */ | ||
| 5122 | lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, | ||
| 5123 | "2875 Xmit ELS RTV ACC response tag x%x xri x%x, " | ||
| 5124 | "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x, " | ||
| 5125 | "Data: x%x x%x x%x\n", | ||
| 5126 | elsiocb->iotag, elsiocb->iocb.ulpContext, | ||
| 5127 | ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, | ||
| 5128 | ndlp->nlp_rpi, | ||
| 5129 | rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov); | ||
| 5130 | elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; | ||
| 5131 | phba->fc_stat.elsXmitACC++; | ||
| 5132 | if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) | ||
| 5133 | lpfc_els_free_iocb(phba, elsiocb); | ||
| 5134 | return 0; | ||
| 5135 | |||
| 5136 | reject_out: | ||
| 5137 | /* issue rejection response */ | ||
| 5138 | stat.un.b.lsRjtRsvd0 = 0; | ||
| 5139 | stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; | ||
| 5140 | stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; | ||
| 5141 | stat.un.b.vendorUnique = 0; | ||
| 5142 | lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); | ||
| 5143 | return 0; | ||
| 5144 | } | ||
| 5145 | |||
| 5146 | /* lpfc_els_rcv_rps - Process an unsolicited rps iocb | ||
| 4833 | * @vport: pointer to a host virtual N_Port data structure. | 5147 | * @vport: pointer to a host virtual N_Port data structure. |
| 4834 | * @cmdiocb: pointer to lpfc command iocb data structure. | 5148 | * @cmdiocb: pointer to lpfc command iocb data structure. |
| 4835 | * @ndlp: pointer to a node-list data structure. | 5149 | * @ndlp: pointer to a node-list data structure. |
| @@ -5019,7 +5333,6 @@ lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, | |||
| 5019 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; | 5333 | pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; |
| 5020 | lp = (uint32_t *) pcmd->virt; | 5334 | lp = (uint32_t *) pcmd->virt; |
| 5021 | rpl = (RPL *) (lp + 1); | 5335 | rpl = (RPL *) (lp + 1); |
| 5022 | |||
| 5023 | maxsize = be32_to_cpu(rpl->maxsize); | 5336 | maxsize = be32_to_cpu(rpl->maxsize); |
| 5024 | 5337 | ||
| 5025 | /* We support only one port */ | 5338 | /* We support only one port */ |
| @@ -5838,6 +6151,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
| 5838 | if (newnode) | 6151 | if (newnode) |
| 5839 | lpfc_nlp_put(ndlp); | 6152 | lpfc_nlp_put(ndlp); |
| 5840 | break; | 6153 | break; |
| 6154 | case ELS_CMD_RLS: | ||
| 6155 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | ||
| 6156 | "RCV RLS: did:x%x/ste:x%x flg:x%x", | ||
| 6157 | did, vport->port_state, ndlp->nlp_flag); | ||
| 6158 | |||
| 6159 | phba->fc_stat.elsRcvRLS++; | ||
| 6160 | lpfc_els_rcv_rls(vport, elsiocb, ndlp); | ||
| 6161 | if (newnode) | ||
| 6162 | lpfc_nlp_put(ndlp); | ||
| 6163 | break; | ||
| 5841 | case ELS_CMD_RPS: | 6164 | case ELS_CMD_RPS: |
| 5842 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | 6165 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, |
| 5843 | "RCV RPS: did:x%x/ste:x%x flg:x%x", | 6166 | "RCV RPS: did:x%x/ste:x%x flg:x%x", |
| @@ -5868,6 +6191,15 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
| 5868 | if (newnode) | 6191 | if (newnode) |
| 5869 | lpfc_nlp_put(ndlp); | 6192 | lpfc_nlp_put(ndlp); |
| 5870 | break; | 6193 | break; |
| 6194 | case ELS_CMD_RTV: | ||
| 6195 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | ||
| 6196 | "RCV RTV: did:x%x/ste:x%x flg:x%x", | ||
| 6197 | did, vport->port_state, ndlp->nlp_flag); | ||
| 6198 | phba->fc_stat.elsRcvRTV++; | ||
| 6199 | lpfc_els_rcv_rtv(vport, elsiocb, ndlp); | ||
| 6200 | if (newnode) | ||
| 6201 | lpfc_nlp_put(ndlp); | ||
| 6202 | break; | ||
| 5871 | case ELS_CMD_RRQ: | 6203 | case ELS_CMD_RRQ: |
| 5872 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | 6204 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, |
| 5873 | "RCV RRQ: did:x%x/ste:x%x flg:x%x", | 6205 | "RCV RRQ: did:x%x/ste:x%x flg:x%x", |
| @@ -5878,6 +6210,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, | |||
| 5878 | if (newnode) | 6210 | if (newnode) |
| 5879 | lpfc_nlp_put(ndlp); | 6211 | lpfc_nlp_put(ndlp); |
| 5880 | break; | 6212 | break; |
| 6213 | case ELS_CMD_ECHO: | ||
| 6214 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | ||
| 6215 | "RCV ECHO: did:x%x/ste:x%x flg:x%x", | ||
| 6216 | did, vport->port_state, ndlp->nlp_flag); | ||
| 6217 | |||
| 6218 | phba->fc_stat.elsRcvECHO++; | ||
| 6219 | lpfc_els_rcv_echo(vport, elsiocb, ndlp); | ||
| 6220 | if (newnode) | ||
| 6221 | lpfc_nlp_put(ndlp); | ||
| 6222 | break; | ||
| 5881 | default: | 6223 | default: |
| 5882 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, | 6224 | lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, |
| 5883 | "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", | 6225 | "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", |
diff --git a/drivers/scsi/lpfc/lpfc_hw.h b/drivers/scsi/lpfc/lpfc_hw.h index a631647051d9..9b8333456465 100644 --- a/drivers/scsi/lpfc/lpfc_hw.h +++ b/drivers/scsi/lpfc/lpfc_hw.h | |||
| @@ -861,6 +861,47 @@ typedef struct _RPS_RSP { /* Structure is in Big Endian format */ | |||
| 861 | uint32_t crcCnt; | 861 | uint32_t crcCnt; |
| 862 | } RPS_RSP; | 862 | } RPS_RSP; |
| 863 | 863 | ||
| 864 | struct RLS { /* Structure is in Big Endian format */ | ||
| 865 | uint32_t rls; | ||
| 866 | #define rls_rsvd_SHIFT 24 | ||
| 867 | #define rls_rsvd_MASK 0x000000ff | ||
| 868 | #define rls_rsvd_WORD rls | ||
| 869 | #define rls_did_SHIFT 0 | ||
| 870 | #define rls_did_MASK 0x00ffffff | ||
| 871 | #define rls_did_WORD rls | ||
| 872 | }; | ||
| 873 | |||
| 874 | struct RLS_RSP { /* Structure is in Big Endian format */ | ||
| 875 | uint32_t linkFailureCnt; | ||
| 876 | uint32_t lossSyncCnt; | ||
| 877 | uint32_t lossSignalCnt; | ||
| 878 | uint32_t primSeqErrCnt; | ||
| 879 | uint32_t invalidXmitWord; | ||
| 880 | uint32_t crcCnt; | ||
| 881 | }; | ||
| 882 | |||
| 883 | struct RTV_RSP { /* Structure is in Big Endian format */ | ||
| 884 | uint32_t ratov; | ||
| 885 | uint32_t edtov; | ||
| 886 | uint32_t qtov; | ||
| 887 | #define qtov_rsvd0_SHIFT 28 | ||
| 888 | #define qtov_rsvd0_MASK 0x0000000f | ||
| 889 | #define qtov_rsvd0_WORD qtov /* reserved */ | ||
| 890 | #define qtov_edtovres_SHIFT 27 | ||
| 891 | #define qtov_edtovres_MASK 0x00000001 | ||
| 892 | #define qtov_edtovres_WORD qtov /* E_D_TOV Resolution */ | ||
| 893 | #define qtov__rsvd1_SHIFT 19 | ||
| 894 | #define qtov_rsvd1_MASK 0x0000003f | ||
| 895 | #define qtov_rsvd1_WORD qtov /* reserved */ | ||
| 896 | #define qtov_rttov_SHIFT 18 | ||
| 897 | #define qtov_rttov_MASK 0x00000001 | ||
| 898 | #define qtov_rttov_WORD qtov /* R_T_TOV value */ | ||
| 899 | #define qtov_rsvd2_SHIFT 0 | ||
| 900 | #define qtov_rsvd2_MASK 0x0003ffff | ||
| 901 | #define qtov_rsvd2_WORD qtov /* reserved */ | ||
| 902 | }; | ||
| 903 | |||
| 904 | |||
| 864 | typedef struct _RPL { /* Structure is in Big Endian format */ | 905 | typedef struct _RPL { /* Structure is in Big Endian format */ |
| 865 | uint32_t maxsize; | 906 | uint32_t maxsize; |
| 866 | uint32_t index; | 907 | uint32_t index; |
