Commit 0d8af096 authored by James Smart's avatar James Smart Committed by Martin K. Petersen

scsi: lpfc: Add NVMe sequence level error recovery support

FC-NVMe-2 added support for sequence level error recovery in the FC-NVME
protocol. This allows for the detection of errors and lost frames and
immediate retransmission of data to avoid exchange termination, which
escalates into NVMeoFC connection and association failures. A significant
RAS improvement.

The driver is modified to indicate support for SLER in the NVMe PRLI is
issues and to check for support in the PRLI response.  When both sides
support it, the driver will set a bit in the WQE to enable the recovery
behavior on the exchange. The adapter will take care of all detection and
retransmission.
Signed-off-by: default avatarDick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: default avatarJames Smart <jsmart2021@gmail.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent d79c9e9d
...@@ -797,6 +797,7 @@ struct lpfc_hba { ...@@ -797,6 +797,7 @@ struct lpfc_hba {
uint8_t mds_diags_support; uint8_t mds_diags_support;
uint8_t bbcredit_support; uint8_t bbcredit_support;
uint8_t enab_exp_wqcq_pages; uint8_t enab_exp_wqcq_pages;
u8 nsler; /* Firmware supports FC-NVMe-2 SLER */
/* HBA Config Parameters */ /* HBA Config Parameters */
uint32_t cfg_ack0; uint32_t cfg_ack0;
......
...@@ -112,6 +112,8 @@ struct lpfc_nodelist { ...@@ -112,6 +112,8 @@ struct lpfc_nodelist {
uint8_t nlp_retry; /* used for ELS retries */ uint8_t nlp_retry; /* used for ELS retries */
uint8_t nlp_fcp_info; /* class info, bits 0-3 */ uint8_t nlp_fcp_info; /* class info, bits 0-3 */
#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ #define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */
u8 nlp_nvme_info; /* NVME NSLER Support */
#define NLP_NVME_NSLER 0x1 /* NVME NSLER device */
uint16_t nlp_usg_map; /* ndlp management usage bitmap */ uint16_t nlp_usg_map; /* ndlp management usage bitmap */
#define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */ #define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */
......
...@@ -2435,6 +2435,10 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -2435,6 +2435,10 @@ lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
npr_nvme = (struct lpfc_nvme_prli *)pcmd; npr_nvme = (struct lpfc_nvme_prli *)pcmd;
bf_set(prli_type_code, npr_nvme, PRLI_NVME_TYPE); bf_set(prli_type_code, npr_nvme, PRLI_NVME_TYPE);
bf_set(prli_estabImagePair, npr_nvme, 0); /* Should be 0 */ bf_set(prli_estabImagePair, npr_nvme, 0); /* Should be 0 */
if (phba->nsler) {
bf_set(prli_nsler, npr_nvme, 1);
bf_set(prli_conf, npr_nvme, 1);
}
/* Only initiators request first burst. */ /* Only initiators request first burst. */
if ((phba->cfg_nvme_enable_fb) && if ((phba->cfg_nvme_enable_fb) &&
......
...@@ -3480,6 +3480,10 @@ struct lpfc_sli4_parameters { ...@@ -3480,6 +3480,10 @@ struct lpfc_sli4_parameters {
#define cfg_bv1s_MASK 0x00000001 #define cfg_bv1s_MASK 0x00000001
#define cfg_bv1s_WORD word19 #define cfg_bv1s_WORD word19
#define cfg_nsler_SHIFT 12
#define cfg_nsler_MASK 0x00000001
#define cfg_nsler_WORD word19
uint32_t word20; uint32_t word20;
#define cfg_max_tow_xri_SHIFT 0 #define cfg_max_tow_xri_SHIFT 0
#define cfg_max_tow_xri_MASK 0x0000ffff #define cfg_max_tow_xri_MASK 0x0000ffff
...@@ -4621,6 +4625,7 @@ struct lpfc_nvme_prli { ...@@ -4621,6 +4625,7 @@ struct lpfc_nvme_prli {
#define prli_type_code_WORD word1 #define prli_type_code_WORD word1
uint32_t word_rsvd2; uint32_t word_rsvd2;
uint32_t word_rsvd3; uint32_t word_rsvd3;
uint32_t word4; uint32_t word4;
#define prli_fba_SHIFT 0 #define prli_fba_SHIFT 0
#define prli_fba_MASK 0x00000001 #define prli_fba_MASK 0x00000001
...@@ -4637,6 +4642,9 @@ struct lpfc_nvme_prli { ...@@ -4637,6 +4642,9 @@ struct lpfc_nvme_prli {
#define prli_conf_SHIFT 7 #define prli_conf_SHIFT 7
#define prli_conf_MASK 0x00000001 #define prli_conf_MASK 0x00000001
#define prli_conf_WORD word4 #define prli_conf_WORD word4
#define prli_nsler_SHIFT 8
#define prli_nsler_MASK 0x00000001
#define prli_nsler_WORD word4
uint32_t word5; uint32_t word5;
#define prli_fb_sz_SHIFT 0 #define prli_fb_sz_SHIFT 0
#define prli_fb_sz_MASK 0x0000ffff #define prli_fb_sz_MASK 0x0000ffff
......
...@@ -11846,6 +11846,14 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) ...@@ -11846,6 +11846,14 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
else else
phba->mds_diags_support = 0; phba->mds_diags_support = 0;
/*
* Check if the SLI port supports NSLER
*/
if (bf_get(cfg_nsler, mbx_sli4_parameters))
phba->nsler = 1;
else
phba->nsler = 0;
return 0; return 0;
} }
......
...@@ -799,9 +799,15 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -799,9 +799,15 @@ lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (npr->writeXferRdyDis) if (npr->writeXferRdyDis)
ndlp->nlp_flag |= NLP_FIRSTBURST; ndlp->nlp_flag |= NLP_FIRSTBURST;
} }
if (npr->Retry) if (npr->Retry && ndlp->nlp_type &
(NLP_FCP_INITIATOR | NLP_FCP_TARGET))
ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE;
if (npr->Retry && phba->nsler &&
ndlp->nlp_type & (NLP_NVME_INITIATOR | NLP_NVME_TARGET))
ndlp->nlp_nvme_info |= NLP_NVME_NSLER;
/* If this driver is in nvme target mode, set the ndlp's fc4 /* If this driver is in nvme target mode, set the ndlp's fc4
* type to NVME provided the PRLI response claims NVME FC4 * type to NVME provided the PRLI response claims NVME FC4
* type. Target mode does not issue gft_id so doesn't get * type. Target mode does not issue gft_id so doesn't get
...@@ -2024,6 +2030,11 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ...@@ -2024,6 +2030,11 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp,
if (bf_get_be32(prli_init, nvpr)) if (bf_get_be32(prli_init, nvpr))
ndlp->nlp_type |= NLP_NVME_INITIATOR; ndlp->nlp_type |= NLP_NVME_INITIATOR;
if (phba->nsler && bf_get_be32(prli_nsler, nvpr))
ndlp->nlp_nvme_info |= NLP_NVME_NSLER;
else
ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER;
/* Target driver cannot solicit NVME FB. */ /* Target driver cannot solicit NVME FB. */
if (bf_get_be32(prli_tgt, nvpr)) { if (bf_get_be32(prli_tgt, nvpr)) {
/* Complete the nvme target roles. The transport /* Complete the nvme target roles. The transport
......
...@@ -1255,6 +1255,9 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport, ...@@ -1255,6 +1255,9 @@ lpfc_nvme_prep_io_cmd(struct lpfc_vport *vport,
sizeof(uint32_t) * 8); sizeof(uint32_t) * 8);
cstat->control_requests++; cstat->control_requests++;
} }
if (pnode->nlp_nvme_info & NLP_NVME_NSLER)
bf_set(wqe_erp, &wqe->generic.wqe_com, 1);
/* /*
* Finish initializing those WQE fields that are independent * Finish initializing those WQE fields that are independent
* of the nvme_cmnd request_buffer * of the nvme_cmnd request_buffer
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment