diff options
author | James Smart <james.smart@emulex.com> | 2010-10-22 11:05:53 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-10-25 17:36:18 -0400 |
commit | 12265f68ae925b9dee8099140b4213c28ef54f14 (patch) | |
tree | 5f9046cd9a03635955bea6f583585a047028933d | |
parent | 5ac6b303834aa74855ecc3db98b4b1d9cad0de2f (diff) |
[SCSI] lpfc 8.3.18: Add support of received ELS commands
Add support of received ELS commands
- Add support for received RLS ELS command
- Add support for received ECHO ELS command
- Add support for received RTV ELS command
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>
-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; |