From 6fe700bf0b4451a462c5aa0c0187a72d071c2a07 Mon Sep 17 00:00:00 2001 From: Michal Kubecek Date: Apr 15 2020 11:58:40 +0000 Subject: Merge branch 'users/hare/SLE15-SP2/for-next' into SLE15-SP2 Pull nvme backport from Hannes Reinecke. --- diff --git a/config/arm64/default b/config/arm64/default index 40f93b8..4f7f7a7 100644 --- a/config/arm64/default +++ b/config/arm64/default @@ -2371,6 +2371,7 @@ CONFIG_BLK_DEV_RBD=m CONFIG_NVME_CORE=m CONFIG_BLK_DEV_NVME=m CONFIG_NVME_MULTIPATH=y +CONFIG_NVME_HWMON=y CONFIG_NVME_FABRICS=m CONFIG_NVME_RDMA=m CONFIG_NVME_FC=m diff --git a/config/ppc64le/default b/config/ppc64le/default index 33052ee..0b1f7ab 100644 --- a/config/ppc64le/default +++ b/config/ppc64le/default @@ -1942,6 +1942,7 @@ CONFIG_BLK_DEV_RBD=m CONFIG_NVME_CORE=m CONFIG_BLK_DEV_NVME=m CONFIG_NVME_MULTIPATH=y +CONFIG_NVME_HWMON=y CONFIG_NVME_FABRICS=m CONFIG_NVME_RDMA=m CONFIG_NVME_FC=m diff --git a/config/s390x/default b/config/s390x/default index 077481f..82b94b2 100644 --- a/config/s390x/default +++ b/config/s390x/default @@ -1575,6 +1575,7 @@ CONFIG_BLK_DEV_RBD=m CONFIG_NVME_CORE=m CONFIG_BLK_DEV_NVME=m CONFIG_NVME_MULTIPATH=y +# CONFIG_NVME_HWMON is not set CONFIG_NVME_FABRICS=m CONFIG_NVME_RDMA=m CONFIG_NVME_FC=m diff --git a/config/x86_64/default b/config/x86_64/default index ae8b82c..ce5e986 100644 --- a/config/x86_64/default +++ b/config/x86_64/default @@ -2309,6 +2309,7 @@ CONFIG_BLK_DEV_RBD=m CONFIG_NVME_CORE=m CONFIG_BLK_DEV_NVME=m CONFIG_NVME_MULTIPATH=y +CONFIG_NVME_HWMON=y CONFIG_NVME_FABRICS=m CONFIG_NVME_RDMA=m CONFIG_NVME_FC=m diff --git a/patches.suse/lpfc-Commonize-lpfc_async_xchg_ctx-state-and-flag-de.patch b/patches.suse/lpfc-Commonize-lpfc_async_xchg_ctx-state-and-flag-de.patch new file mode 100644 index 0000000..5639cde --- /dev/null +++ b/patches.suse/lpfc-Commonize-lpfc_async_xchg_ctx-state-and-flag-de.patch @@ -0,0 +1,667 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:04 -0700 +Subject: [PATCH] lpfc: Commonize lpfc_async_xchg_ctx state and flag +Git-commit: 80b6438fe05ee43a71f54c44b6cc7d0f66c6fd22 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + definitions + +The last step of commonization is to remove the 'T' suffix from +state and flag field definitions. This is minor, but removes the +mental association that it solely applies to nvmet use. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_init.c | 2 +- + drivers/scsi/lpfc/lpfc_nvme.h | 37 +++++----- + drivers/scsi/lpfc/lpfc_nvmet.c | 158 ++++++++++++++++++++--------------------- + 3 files changed, 100 insertions(+), 97 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index 14964e8300d4..9cf6d9b6847c 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -1105,7 +1105,7 @@ lpfc_hba_down_post_s4(struct lpfc_hba *phba) + &nvmet_aborts); + spin_unlock_irq(&phba->sli4_hba.abts_nvmet_buf_list_lock); + list_for_each_entry_safe(ctxp, ctxp_next, &nvmet_aborts, list) { +- ctxp->flag &= ~(LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP); ++ ctxp->flag &= ~(LPFC_NVME_XBUSY | LPFC_NVME_ABORT_OP); + lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); + } + } +diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h +index be7d262f8cf3..220b51af43da 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.h ++++ b/drivers/scsi/lpfc/lpfc_nvme.h +@@ -162,6 +162,26 @@ struct lpfc_nvmet_ctx_info { + #define lpfc_get_ctx_list(phba, cpu, mrq) \ + (phba->sli4_hba.nvmet_ctx_info + ((cpu * phba->cfg_nvmet_mrq) + mrq)) + ++/* Values for state field of struct lpfc_async_xchg_ctx */ ++#define LPFC_NVME_STE_LS_RCV 1 ++#define LPFC_NVME_STE_LS_ABORT 2 ++#define LPFC_NVME_STE_LS_RSP 3 ++#define LPFC_NVME_STE_RCV 4 ++#define LPFC_NVME_STE_DATA 5 ++#define LPFC_NVME_STE_ABORT 6 ++#define LPFC_NVME_STE_DONE 7 ++#define LPFC_NVME_STE_FREE 0xff ++ ++/* Values for flag field of struct lpfc_async_xchg_ctx */ ++#define LPFC_NVME_IO_INP 0x1 /* IO is in progress on exchange */ ++#define LPFC_NVME_ABORT_OP 0x2 /* Abort WQE issued on exchange */ ++#define LPFC_NVME_XBUSY 0x4 /* XB bit set on IO cmpl */ ++#define LPFC_NVME_CTX_RLS 0x8 /* ctx free requested */ ++#define LPFC_NVME_ABTS_RCV 0x10 /* ABTS received on exchange */ ++#define LPFC_NVME_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */ ++#define LPFC_NVME_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ ++#define LPFC_NVME_TNOTIFY 0x80 /* notify transport of abts */ ++ + struct lpfc_async_xchg_ctx { + union { + struct nvmefc_tgt_fcp_req fcp_req; +@@ -181,24 +201,7 @@ struct lpfc_async_xchg_ctx { + uint16_t cpu; + uint16_t idx; + uint16_t state; +- /* States */ +-#define LPFC_NVMET_STE_LS_RCV 1 +-#define LPFC_NVMET_STE_LS_ABORT 2 +-#define LPFC_NVMET_STE_LS_RSP 3 +-#define LPFC_NVMET_STE_RCV 4 +-#define LPFC_NVMET_STE_DATA 5 +-#define LPFC_NVMET_STE_ABORT 6 +-#define LPFC_NVMET_STE_DONE 7 +-#define LPFC_NVMET_STE_FREE 0xff + uint16_t flag; +-#define LPFC_NVMET_IO_INP 0x1 /* IO is in progress on exchange */ +-#define LPFC_NVMET_ABORT_OP 0x2 /* Abort WQE issued on exchange */ +-#define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */ +-#define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */ +-#define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ +-#define LPFC_NVMET_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */ +-#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ +-#define LPFC_NVMET_TNOTIFY 0x80 /* notify transport of abts */ + struct rqb_dmabuf *rqb_buffer; + struct lpfc_nvmet_ctxbuf *ctxbuf; + struct lpfc_sli4_hdw_queue *hdwq; +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c +index ded7f973cad4..28db056cf5af 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.c ++++ b/drivers/scsi/lpfc/lpfc_nvmet.c +@@ -271,10 +271,10 @@ lpfc_nvmet_defer_release(struct lpfc_hba *phba, + "6313 NVMET Defer ctx release oxid x%x flg x%x\n", + ctxp->oxid, ctxp->flag); + +- if (ctxp->flag & LPFC_NVMET_CTX_RLS) ++ if (ctxp->flag & LPFC_NVME_CTX_RLS) + return; + +- ctxp->flag |= LPFC_NVMET_CTX_RLS; ++ ctxp->flag |= LPFC_NVME_CTX_RLS; + spin_lock(&phba->sli4_hba.t_active_list_lock); + list_del(&ctxp->list); + spin_unlock(&phba->sli4_hba.t_active_list_lock); +@@ -306,7 +306,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + result = wcqe->parameter; + ctxp = cmdwqe->context2; + +- if (ctxp->state != LPFC_NVMET_STE_LS_RSP || ctxp->entry_cnt != 2) { ++ if (ctxp->state != LPFC_NVME_STE_LS_RSP || ctxp->entry_cnt != 2) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6410 NVMET LS cmpl state mismatch IO x%x: " + "%d %d\n", +@@ -374,7 +374,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) + int cpu; + unsigned long iflag; + +- if (ctxp->state == LPFC_NVMET_STE_FREE) { ++ if (ctxp->state == LPFC_NVME_STE_FREE) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6411 NVMET free, already free IO x%x: %d %d\n", + ctxp->oxid, ctxp->state, ctxp->entry_cnt); +@@ -386,8 +386,8 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) + /* check if freed in another path whilst acquiring lock */ + if (nvmebuf) { + ctxp->rqb_buffer = NULL; +- if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { +- ctxp->flag &= ~LPFC_NVMET_CTX_REUSE_WQ; ++ if (ctxp->flag & LPFC_NVME_CTX_REUSE_WQ) { ++ ctxp->flag &= ~LPFC_NVME_CTX_REUSE_WQ; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + nvmebuf->hrq->rqbp->rqb_free_buffer(phba, + nvmebuf); +@@ -400,7 +400,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + } + } +- ctxp->state = LPFC_NVMET_STE_FREE; ++ ctxp->state = LPFC_NVME_STE_FREE; + + spin_lock_irqsave(&phba->sli4_hba.nvmet_io_wait_lock, iflag); + if (phba->sli4_hba.nvmet_io_wait_cnt) { +@@ -424,7 +424,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) + ctxp->size = size; + ctxp->oxid = oxid; + ctxp->sid = sid; +- ctxp->state = LPFC_NVMET_STE_RCV; ++ ctxp->state = LPFC_NVME_STE_RCV; + ctxp->entry_cnt = 1; + ctxp->flag = 0; + ctxp->ctxbuf = ctx_buf; +@@ -449,7 +449,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) + + /* Indicate that a replacement buffer has been posted */ + spin_lock_irqsave(&ctxp->ctxlock, iflag); +- ctxp->flag |= LPFC_NVMET_CTX_REUSE_WQ; ++ ctxp->flag |= LPFC_NVME_CTX_REUSE_WQ; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + if (!queue_work(phba->wq, &ctx_buf->defer_work)) { +@@ -707,7 +707,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + #endif + + ctxp = cmdwqe->context2; +- ctxp->flag &= ~LPFC_NVMET_IO_INP; ++ ctxp->flag &= ~LPFC_NVME_IO_INP; + + rsp = &ctxp->hdlrctx.fcp_req; + op = rsp->op; +@@ -736,13 +736,13 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + + /* pick up SLI4 exhange busy condition */ + if (bf_get(lpfc_wcqe_c_xb, wcqe)) { +- ctxp->flag |= LPFC_NVMET_XBUSY; ++ ctxp->flag |= LPFC_NVME_XBUSY; + logerr |= LOG_NVME_ABTS; + if (tgtp) + atomic_inc(&tgtp->xmt_fcp_rsp_xb_set); + + } else { +- ctxp->flag &= ~LPFC_NVMET_XBUSY; ++ ctxp->flag &= ~LPFC_NVME_XBUSY; + } + + lpfc_printf_log(phba, KERN_INFO, logerr, +@@ -764,7 +764,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + if ((op == NVMET_FCOP_READDATA_RSP) || + (op == NVMET_FCOP_RSP)) { + /* Sanity check */ +- ctxp->state = LPFC_NVMET_STE_DONE; ++ ctxp->state = LPFC_NVME_STE_DONE; + ctxp->entry_cnt++; + + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS +@@ -848,14 +848,14 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, + "6023 NVMET LS rsp oxid x%x\n", ctxp->oxid); + +- if ((ctxp->state != LPFC_NVMET_STE_LS_RCV) || ++ if ((ctxp->state != LPFC_NVME_STE_LS_RCV) || + (ctxp->entry_cnt != 1)) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6412 NVMET LS rsp state mismatch " + "oxid x%x: %d %d\n", + ctxp->oxid, ctxp->state, ctxp->entry_cnt); + } +- ctxp->state = LPFC_NVMET_STE_LS_RSP; ++ ctxp->state = LPFC_NVME_STE_LS_RSP; + ctxp->entry_cnt++; + + nvmewqeq = lpfc_nvmet_prep_ls_wqe(phba, ctxp, rsp->rspdma, +@@ -965,8 +965,8 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, + #endif + + /* Sanity check */ +- if ((ctxp->flag & LPFC_NVMET_ABTS_RCV) || +- (ctxp->state == LPFC_NVMET_STE_ABORT)) { ++ if ((ctxp->flag & LPFC_NVME_ABTS_RCV) || ++ (ctxp->state == LPFC_NVME_STE_ABORT)) { + atomic_inc(&lpfc_nvmep->xmt_fcp_drop); + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6102 IO oxid x%x aborted\n", +@@ -994,7 +994,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, + lpfc_nvmeio_data(phba, "NVMET FCP CMND: xri x%x op x%x len x%x\n", + ctxp->oxid, rsp->op, rsp->rsplen); + +- ctxp->flag |= LPFC_NVMET_IO_INP; ++ ctxp->flag |= LPFC_NVME_IO_INP; + rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq); + if (rc == WQE_SUCCESS) { + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS +@@ -1013,7 +1013,7 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, + * WQ was full, so queue nvmewqeq to be sent after + * WQE release CQE + */ +- ctxp->flag |= LPFC_NVMET_DEFER_WQFULL; ++ ctxp->flag |= LPFC_NVME_DEFER_WQFULL; + wq = ctxp->hdwq->io_wq; + pring = wq->pring; + spin_lock_irqsave(&pring->ring_lock, iflags); +@@ -1082,13 +1082,13 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, + /* Since iaab/iaar are NOT set, we need to check + * if the firmware is in process of aborting IO + */ +- if (ctxp->flag & (LPFC_NVMET_XBUSY | LPFC_NVMET_ABORT_OP)) { ++ if (ctxp->flag & (LPFC_NVME_XBUSY | LPFC_NVME_ABORT_OP)) { + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + return; + } +- ctxp->flag |= LPFC_NVMET_ABORT_OP; ++ ctxp->flag |= LPFC_NVME_ABORT_OP; + +- if (ctxp->flag & LPFC_NVMET_DEFER_WQFULL) { ++ if (ctxp->flag & LPFC_NVME_DEFER_WQFULL) { + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, + ctxp->oxid); +@@ -1098,11 +1098,11 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, + } + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + +- /* An state of LPFC_NVMET_STE_RCV means we have just received ++ /* A state of LPFC_NVME_STE_RCV means we have just received + * the NVME command and have not started processing it. + * (by issuing any IO WQEs on this exchange yet) + */ +- if (ctxp->state == LPFC_NVMET_STE_RCV) ++ if (ctxp->state == LPFC_NVME_STE_RCV) + lpfc_nvmet_unsol_fcp_issue_abort(phba, ctxp, ctxp->sid, + ctxp->oxid); + else +@@ -1122,19 +1122,19 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, + bool aborting = false; + + spin_lock_irqsave(&ctxp->ctxlock, flags); +- if (ctxp->flag & LPFC_NVMET_XBUSY) ++ if (ctxp->flag & LPFC_NVME_XBUSY) + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_IOERR, + "6027 NVMET release with XBUSY flag x%x" + " oxid x%x\n", + ctxp->flag, ctxp->oxid); +- else if (ctxp->state != LPFC_NVMET_STE_DONE && +- ctxp->state != LPFC_NVMET_STE_ABORT) ++ else if (ctxp->state != LPFC_NVME_STE_DONE && ++ ctxp->state != LPFC_NVME_STE_ABORT) + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6413 NVMET release bad state %d %d oxid x%x\n", + ctxp->state, ctxp->entry_cnt, ctxp->oxid); + +- if ((ctxp->flag & LPFC_NVMET_ABORT_OP) || +- (ctxp->flag & LPFC_NVMET_XBUSY)) { ++ if ((ctxp->flag & LPFC_NVME_ABORT_OP) || ++ (ctxp->flag & LPFC_NVME_XBUSY)) { + aborting = true; + /* let the abort path do the real release */ + lpfc_nvmet_defer_release(phba, ctxp); +@@ -1145,7 +1145,7 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, + ctxp->state, aborting); + + atomic_inc(&lpfc_nvmep->xmt_fcp_release); +- ctxp->flag &= ~LPFC_NVMET_TNOTIFY; ++ ctxp->flag &= ~LPFC_NVME_TNOTIFY; + + if (aborting) + return; +@@ -1365,7 +1365,7 @@ lpfc_nvmet_setup_io_context(struct lpfc_hba *phba) + return -ENOMEM; + } + ctx_buf->context->ctxbuf = ctx_buf; +- ctx_buf->context->state = LPFC_NVMET_STE_FREE; ++ ctx_buf->context->state = LPFC_NVME_STE_FREE; + + ctx_buf->iocbq = lpfc_sli_get_iocbq(phba); + if (!ctx_buf->iocbq) { +@@ -1596,12 +1596,12 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, + /* Check if we already received a free context call + * and we have completed processing an abort situation. + */ +- if (ctxp->flag & LPFC_NVMET_CTX_RLS && +- !(ctxp->flag & LPFC_NVMET_ABORT_OP)) { ++ if (ctxp->flag & LPFC_NVME_CTX_RLS && ++ !(ctxp->flag & LPFC_NVME_ABORT_OP)) { + list_del_init(&ctxp->list); + released = true; + } +- ctxp->flag &= ~LPFC_NVMET_XBUSY; ++ ctxp->flag &= ~LPFC_NVME_XBUSY; + spin_unlock(&ctxp->ctxlock); + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + +@@ -1643,8 +1643,8 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, + rxid); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); +- ctxp->flag |= LPFC_NVMET_ABTS_RCV; +- ctxp->state = LPFC_NVMET_STE_ABORT; ++ ctxp->flag |= LPFC_NVME_ABTS_RCV; ++ ctxp->state = LPFC_NVME_STE_ABORT; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, +@@ -1687,7 +1687,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, + spin_unlock_irqrestore(&phba->hbalock, iflag); + + spin_lock_irqsave(&ctxp->ctxlock, iflag); +- ctxp->flag |= LPFC_NVMET_ABTS_RCV; ++ ctxp->flag |= LPFC_NVME_ABTS_RCV; + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, +@@ -1756,7 +1756,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, + xri = ctxp->ctxbuf->sglq->sli4_xritag; + + spin_lock_irqsave(&ctxp->ctxlock, iflag); +- ctxp->flag |= (LPFC_NVMET_ABTS_RCV | LPFC_NVMET_ABORT_OP); ++ ctxp->flag |= (LPFC_NVME_ABTS_RCV | LPFC_NVME_ABORT_OP); + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + + lpfc_nvmeio_data(phba, +@@ -1768,7 +1768,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, + "flag x%x state x%x\n", + ctxp->oxid, xri, ctxp->flag, ctxp->state); + +- if (ctxp->flag & LPFC_NVMET_TNOTIFY) { ++ if (ctxp->flag & LPFC_NVME_TNOTIFY) { + /* Notify the transport */ + nvmet_fc_rcv_fcp_abort(phba->targetport, + &ctxp->hdlrctx.fcp_req); +@@ -1983,7 +1983,7 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + ctxp->oxid = oxid; + ctxp->sid = sid; + ctxp->wqeq = NULL; +- ctxp->state = LPFC_NVMET_STE_LS_RCV; ++ ctxp->state = LPFC_NVME_STE_LS_RCV; + ctxp->entry_cnt = 1; + ctxp->rqb_buffer = (void *)nvmebuf; + ctxp->hdwq = &phba->sli4_hba.hdwq[0]; +@@ -2051,7 +2051,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) + return; + } + +- if (ctxp->flag & LPFC_NVMET_ABTS_RCV) { ++ if (ctxp->flag & LPFC_NVME_ABTS_RCV) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6324 IO oxid x%x aborted\n", + ctxp->oxid); +@@ -2060,7 +2060,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) + + payload = (uint32_t *)(nvmebuf->dbuf.virt); + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; +- ctxp->flag |= LPFC_NVMET_TNOTIFY; ++ ctxp->flag |= LPFC_NVME_TNOTIFY; + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (ctxp->ts_isr_cmd) + ctxp->ts_cmd_nvme = ktime_get_ns(); +@@ -2080,7 +2080,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) + if (rc == 0) { + atomic_inc(&tgtp->rcv_fcp_cmd_out); + spin_lock_irqsave(&ctxp->ctxlock, iflags); +- if ((ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) || ++ if ((ctxp->flag & LPFC_NVME_CTX_REUSE_WQ) || + (nvmebuf != ctxp->rqb_buffer)) { + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + return; +@@ -2099,7 +2099,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) + atomic_inc(&tgtp->rcv_fcp_cmd_out); + atomic_inc(&tgtp->defer_fod); + spin_lock_irqsave(&ctxp->ctxlock, iflags); +- if (ctxp->flag & LPFC_NVMET_CTX_REUSE_WQ) { ++ if (ctxp->flag & LPFC_NVME_CTX_REUSE_WQ) { + spin_unlock_irqrestore(&ctxp->ctxlock, iflags); + return; + } +@@ -2114,7 +2114,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) + phba->sli4_hba.nvmet_mrq_data[qno], 1, qno); + return; + } +- ctxp->flag &= ~LPFC_NVMET_TNOTIFY; ++ ctxp->flag &= ~LPFC_NVME_TNOTIFY; + atomic_inc(&tgtp->rcv_fcp_cmd_drop); + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "2582 FCP Drop IO x%x: err x%x: x%x x%x x%x\n", +@@ -2309,7 +2309,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list); + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); +- if (ctxp->state != LPFC_NVMET_STE_FREE) { ++ if (ctxp->state != LPFC_NVME_STE_FREE) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6414 NVMET Context corrupt %d %d oxid x%x\n", + ctxp->state, ctxp->entry_cnt, ctxp->oxid); +@@ -2321,7 +2321,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, + ctxp->oxid = oxid; + ctxp->sid = sid; + ctxp->idx = idx; +- ctxp->state = LPFC_NVMET_STE_RCV; ++ ctxp->state = LPFC_NVME_STE_RCV; + ctxp->entry_cnt = 1; + ctxp->flag = 0; + ctxp->ctxbuf = ctx_buf; +@@ -2645,9 +2645,9 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, + } + + /* Sanity check */ +- if (((ctxp->state == LPFC_NVMET_STE_RCV) && ++ if (((ctxp->state == LPFC_NVME_STE_RCV) && + (ctxp->entry_cnt == 1)) || +- (ctxp->state == LPFC_NVMET_STE_DATA)) { ++ (ctxp->state == LPFC_NVME_STE_DATA)) { + wqe = &nvmewqe->wqe; + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +@@ -2910,7 +2910,7 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, + sgl++; + ctxp->offset += cnt; + } +- ctxp->state = LPFC_NVMET_STE_DATA; ++ ctxp->state = LPFC_NVME_STE_DATA; + ctxp->entry_cnt++; + return nvmewqe; + } +@@ -2939,23 +2939,23 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + result = wcqe->parameter; + + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; +- if (ctxp->flag & LPFC_NVMET_ABORT_OP) ++ if (ctxp->flag & LPFC_NVME_ABORT_OP) + atomic_inc(&tgtp->xmt_fcp_abort_cmpl); + + spin_lock_irqsave(&ctxp->ctxlock, flags); +- ctxp->state = LPFC_NVMET_STE_DONE; ++ ctxp->state = LPFC_NVME_STE_DONE; + + /* Check if we already received a free context call + * and we have completed processing an abort situation. + */ +- if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && +- !(ctxp->flag & LPFC_NVMET_XBUSY)) { ++ if ((ctxp->flag & LPFC_NVME_CTX_RLS) && ++ !(ctxp->flag & LPFC_NVME_XBUSY)) { + spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + list_del_init(&ctxp->list); + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + released = true; + } +- ctxp->flag &= ~LPFC_NVMET_ABORT_OP; ++ ctxp->flag &= ~LPFC_NVME_ABORT_OP; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + atomic_inc(&tgtp->xmt_abort_rsp); + +@@ -2979,7 +2979,7 @@ lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + lpfc_sli_release_iocbq(phba, cmdwqe); + + /* Since iaab/iaar are NOT set, there is no work left. +- * For LPFC_NVMET_XBUSY, lpfc_sli4_nvmet_xri_aborted ++ * For LPFC_NVME_XBUSY, lpfc_sli4_nvmet_xri_aborted + * should have been called already. + */ + } +@@ -3018,11 +3018,11 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + spin_lock_irqsave(&ctxp->ctxlock, flags); +- if (ctxp->flag & LPFC_NVMET_ABORT_OP) ++ if (ctxp->flag & LPFC_NVME_ABORT_OP) + atomic_inc(&tgtp->xmt_fcp_abort_cmpl); + + /* Sanity check */ +- if (ctxp->state != LPFC_NVMET_STE_ABORT) { ++ if (ctxp->state != LPFC_NVME_STE_ABORT) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, + "6112 ABTS Wrong state:%d oxid x%x\n", + ctxp->state, ctxp->oxid); +@@ -3031,15 +3031,15 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + /* Check if we already received a free context call + * and we have completed processing an abort situation. + */ +- ctxp->state = LPFC_NVMET_STE_DONE; +- if ((ctxp->flag & LPFC_NVMET_CTX_RLS) && +- !(ctxp->flag & LPFC_NVMET_XBUSY)) { ++ ctxp->state = LPFC_NVME_STE_DONE; ++ if ((ctxp->flag & LPFC_NVME_CTX_RLS) && ++ !(ctxp->flag & LPFC_NVME_XBUSY)) { + spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + list_del_init(&ctxp->list); + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + released = true; + } +- ctxp->flag &= ~LPFC_NVMET_ABORT_OP; ++ ctxp->flag &= ~LPFC_NVME_ABORT_OP; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + atomic_inc(&tgtp->xmt_abort_rsp); + +@@ -3060,7 +3060,7 @@ lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + lpfc_nvmet_ctxbuf_post(phba, ctxp->ctxbuf); + + /* Since iaab/iaar are NOT set, there is no work left. +- * For LPFC_NVMET_XBUSY, lpfc_sli4_nvmet_xri_aborted ++ * For LPFC_NVME_XBUSY, lpfc_sli4_nvmet_xri_aborted + * should have been called already. + */ + } +@@ -3105,7 +3105,7 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + return; + } + +- if (ctxp->state != LPFC_NVMET_STE_LS_ABORT) { ++ if (ctxp->state != LPFC_NVME_STE_LS_ABORT) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6416 NVMET LS abort cmpl state mismatch: " + "oxid x%x: %d %d\n", +@@ -3242,7 +3242,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, + + /* No failure to an ABTS request. */ + spin_lock_irqsave(&ctxp->ctxlock, flags); +- ctxp->flag &= ~LPFC_NVMET_ABORT_OP; ++ ctxp->flag &= ~LPFC_NVME_ABORT_OP; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + return 0; + } +@@ -3256,13 +3256,13 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, + "6161 ABORT failed: No wqeqs: " + "xri: x%x\n", ctxp->oxid); + /* No failure to an ABTS request. */ +- ctxp->flag &= ~LPFC_NVMET_ABORT_OP; ++ ctxp->flag &= ~LPFC_NVME_ABORT_OP; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + return 0; + } + abts_wqeq = ctxp->abort_wqeq; +- ctxp->state = LPFC_NVMET_STE_ABORT; +- opt = (ctxp->flag & LPFC_NVMET_ABTS_RCV) ? INHIBIT_ABORT : 0; ++ ctxp->state = LPFC_NVME_STE_ABORT; ++ opt = (ctxp->flag & LPFC_NVME_ABTS_RCV) ? INHIBIT_ABORT : 0; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + + /* Announce entry to new IO submit field. */ +@@ -3285,7 +3285,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, + phba->hba_flag, ctxp->oxid); + lpfc_sli_release_iocbq(phba, abts_wqeq); + spin_lock_irqsave(&ctxp->ctxlock, flags); +- ctxp->flag &= ~LPFC_NVMET_ABORT_OP; ++ ctxp->flag &= ~LPFC_NVME_ABORT_OP; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + return 0; + } +@@ -3300,7 +3300,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, + ctxp->oxid); + lpfc_sli_release_iocbq(phba, abts_wqeq); + spin_lock_irqsave(&ctxp->ctxlock, flags); +- ctxp->flag &= ~LPFC_NVMET_ABORT_OP; ++ ctxp->flag &= ~LPFC_NVME_ABORT_OP; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + return 0; + } +@@ -3329,7 +3329,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, + + atomic_inc(&tgtp->xmt_abort_rsp_error); + spin_lock_irqsave(&ctxp->ctxlock, flags); +- ctxp->flag &= ~LPFC_NVMET_ABORT_OP; ++ ctxp->flag &= ~LPFC_NVME_ABORT_OP; + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + lpfc_sli_release_iocbq(phba, abts_wqeq); + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_ABTS, +@@ -3356,14 +3356,14 @@ lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, + ctxp->wqeq->hba_wqidx = 0; + } + +- if (ctxp->state == LPFC_NVMET_STE_FREE) { ++ if (ctxp->state == LPFC_NVME_STE_FREE) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6417 NVMET ABORT ctx freed %d %d oxid x%x\n", + ctxp->state, ctxp->entry_cnt, ctxp->oxid); + rc = WQE_BUSY; + goto aerr; + } +- ctxp->state = LPFC_NVMET_STE_ABORT; ++ ctxp->state = LPFC_NVME_STE_ABORT; + ctxp->entry_cnt++; + rc = lpfc_nvmet_unsol_issue_abort(phba, ctxp, sid, xri); + if (rc == 0) +@@ -3385,13 +3385,13 @@ lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, + + aerr: + spin_lock_irqsave(&ctxp->ctxlock, flags); +- if (ctxp->flag & LPFC_NVMET_CTX_RLS) { ++ if (ctxp->flag & LPFC_NVME_CTX_RLS) { + spin_lock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + list_del_init(&ctxp->list); + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + released = true; + } +- ctxp->flag &= ~(LPFC_NVMET_ABORT_OP | LPFC_NVMET_CTX_RLS); ++ ctxp->flag &= ~(LPFC_NVME_ABORT_OP | LPFC_NVME_CTX_RLS); + spin_unlock_irqrestore(&ctxp->ctxlock, flags); + + atomic_inc(&tgtp->xmt_abort_rsp_error); +@@ -3414,16 +3414,16 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, + unsigned long flags; + int rc; + +- if ((ctxp->state == LPFC_NVMET_STE_LS_RCV && ctxp->entry_cnt == 1) || +- (ctxp->state == LPFC_NVMET_STE_LS_RSP && ctxp->entry_cnt == 2)) { +- ctxp->state = LPFC_NVMET_STE_LS_ABORT; ++ if ((ctxp->state == LPFC_NVME_STE_LS_RCV && ctxp->entry_cnt == 1) || ++ (ctxp->state == LPFC_NVME_STE_LS_RSP && ctxp->entry_cnt == 2)) { ++ ctxp->state = LPFC_NVME_STE_LS_ABORT; + ctxp->entry_cnt++; + } else { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "6418 NVMET LS abort state mismatch " + "IO x%x: %d %d\n", + ctxp->oxid, ctxp->state, ctxp->entry_cnt); +- ctxp->state = LPFC_NVMET_STE_LS_ABORT; ++ ctxp->state = LPFC_NVME_STE_LS_ABORT; + } + + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; +-- +2.16.4 + diff --git a/patches.suse/lpfc-Refactor-NVME-LS-receive-handling.patch b/patches.suse/lpfc-Refactor-NVME-LS-receive-handling.patch new file mode 100644 index 0000000..7f814f0 --- /dev/null +++ b/patches.suse/lpfc-Refactor-NVME-LS-receive-handling.patch @@ -0,0 +1,483 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:05 -0700 +Subject: [PATCH] lpfc: Refactor NVME LS receive handling +Git-commit: 8dabf6050c994570c0ac1a5eaf4d1e127dce6bb0 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +In preparation for supporting both intiator mode and target mode +receiving NVME LS's, commonize the existing NVME LS request receive +handling found in the base driver and in the nvmet side. + +Using the original lpfc_nvmet_unsol_ls_event() and +lpfc_nvme_unsol_ls_buffer() routines as a templates, commonize the +reception of an NVME LS request. The common routine will validate the LS +request, that it was received from a logged-in node, and allocate a +lpfc_async_xchg_ctx that is used to manage the LS request. The role of +the port is then inspected to determine which handler is to receive the +LS - nvme or nvmet. As such, the nvmet handler is tied back in. A handler +is created in nvme and is stubbed out. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_crtn.h | 6 +- + drivers/scsi/lpfc/lpfc_nvme.c | 19 +++++ + drivers/scsi/lpfc/lpfc_nvme.h | 5 ++ + drivers/scsi/lpfc/lpfc_nvmet.c | 163 ++++++++++------------------------------- + drivers/scsi/lpfc/lpfc_sli.c | 121 +++++++++++++++++++++++++++++- + 5 files changed, 184 insertions(+), 130 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h +index dc76729f8864..51b0f01c6206 100644 +--- a/drivers/scsi/lpfc/lpfc_crtn.h ++++ b/drivers/scsi/lpfc/lpfc_crtn.h +@@ -564,8 +564,10 @@ void lpfc_nvme_update_localport(struct lpfc_vport *vport); + int lpfc_nvmet_create_targetport(struct lpfc_hba *phba); + int lpfc_nvmet_update_targetport(struct lpfc_hba *phba); + void lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba); +-void lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, +- struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb); ++int lpfc_nvme_handle_lsreq(struct lpfc_hba *phba, ++ struct lpfc_async_xchg_ctx *axchg); ++int lpfc_nvmet_handle_lsreq(struct lpfc_hba *phba, ++ struct lpfc_async_xchg_ctx *axchg); + void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx, + struct rqb_dmabuf *nvmebuf, uint64_t isr_ts, + uint8_t cqflag); +diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c +index 12223a50be38..7eb6e89f7f62 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.c ++++ b/drivers/scsi/lpfc/lpfc_nvme.c +@@ -391,6 +391,25 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) + return; + } + ++/** ++ * lpfc_nvme_handle_lsreq - Process an unsolicited NVME LS request ++ * @phba: pointer to lpfc hba data structure. ++ * @axchg: pointer to exchange context for the NVME LS request ++ * ++ * This routine is used for processing an asychronously received NVME LS ++ * request. Any remaining validation is done and the LS is then forwarded ++ * to the nvme-fc transport via nvme_fc_rcv_ls_req(). ++ * ++ * Returns 0 if LS was handled and delivered to the transport ++ * Returns 1 if LS failed to be handled and should be dropped ++ */ ++int ++lpfc_nvme_handle_lsreq(struct lpfc_hba *phba, ++ struct lpfc_async_xchg_ctx *axchg) ++{ ++ return 1; ++} ++ + static void + lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + struct lpfc_wcqe_complete *wcqe) +diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h +index 220b51af43da..10e8d868608e 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.h ++++ b/drivers/scsi/lpfc/lpfc_nvme.h +@@ -188,6 +188,7 @@ struct lpfc_async_xchg_ctx { + } hdlrctx; + struct list_head list; + struct lpfc_hba *phba; ++ struct lpfc_nodelist *ndlp; + struct nvmefc_ls_req *ls_req; + struct nvmefc_ls_rsp ls_rsp; + struct lpfc_iocbq *wqeq; +@@ -202,6 +203,7 @@ struct lpfc_async_xchg_ctx { + uint16_t idx; + uint16_t state; + uint16_t flag; ++ void *payload; + struct rqb_dmabuf *rqb_buffer; + struct lpfc_nvmet_ctxbuf *ctxbuf; + struct lpfc_sli4_hdw_queue *hdwq; +@@ -224,3 +226,6 @@ struct lpfc_async_xchg_ctx { + /* routines found in lpfc_nvme.c */ + + /* routines found in lpfc_nvmet.c */ ++int lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba, ++ struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, ++ uint16_t xri); +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c +index 28db056cf5af..e6895c719683 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.c ++++ b/drivers/scsi/lpfc/lpfc_nvmet.c +@@ -63,9 +63,6 @@ static int lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *, + static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *, + struct lpfc_async_xchg_ctx *, + uint32_t, uint16_t); +-static int lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *, +- struct lpfc_async_xchg_ctx *, +- uint32_t, uint16_t); + static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *, struct lpfc_queue *, + struct lpfc_async_xchg_ctx *); + static void lpfc_nvmet_fcp_rqst_defer_work(struct work_struct *); +@@ -867,7 +864,7 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, + ctxp->oxid); + lpfc_in_buf_free(phba, &nvmebuf->dbuf); + atomic_inc(&nvmep->xmt_ls_abort); +- lpfc_nvmet_unsol_ls_issue_abort(phba, ctxp, ++ lpfc_nvme_unsol_ls_issue_abort(phba, ctxp, + ctxp->sid, ctxp->oxid); + return -ENOMEM; + } +@@ -910,7 +907,7 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, + + lpfc_in_buf_free(phba, &nvmebuf->dbuf); + atomic_inc(&nvmep->xmt_ls_abort); +- lpfc_nvmet_unsol_ls_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); ++ lpfc_nvme_unsol_ls_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); + return -ENXIO; + } + +@@ -1923,107 +1920,49 @@ lpfc_nvmet_destroy_targetport(struct lpfc_hba *phba) + } + + /** +- * lpfc_nvmet_unsol_ls_buffer - Process an unsolicited event data buffer ++ * lpfc_nvmet_handle_lsreq - Process an NVME LS request + * @phba: pointer to lpfc hba data structure. +- * @pring: pointer to a SLI ring. +- * @nvmebuf: pointer to lpfc nvme command HBQ data structure. ++ * @axchg: pointer to exchange context for the NVME LS request + * +- * This routine is used for processing the WQE associated with a unsolicited +- * event. It first determines whether there is an existing ndlp that matches +- * the DID from the unsolicited WQE. If not, it will create a new one with +- * the DID from the unsolicited WQE. The ELS command from the unsolicited +- * WQE is then used to invoke the proper routine and to set up proper state +- * of the discovery state machine. +- **/ +-static void +-lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, +- struct hbq_dmabuf *nvmebuf) ++ * This routine is used for processing an asychronously received NVME LS ++ * request. Any remaining validation is done and the LS is then forwarded ++ * to the nvmet-fc transport via nvmet_fc_rcv_ls_req(). ++ * ++ * The calling sequence should be: nvmet_fc_rcv_ls_req() -> (processing) ++ * -> lpfc_nvmet_xmt_ls_rsp/cmp -> req->done. ++ * lpfc_nvme_xmt_ls_rsp_cmp should free the allocated axchg. ++ * ++ * Returns 0 if LS was handled and delivered to the transport ++ * Returns 1 if LS failed to be handled and should be dropped ++ */ ++int ++lpfc_nvmet_handle_lsreq(struct lpfc_hba *phba, ++ struct lpfc_async_xchg_ctx *axchg) + { + #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +- struct lpfc_nvmet_tgtport *tgtp; +- struct fc_frame_header *fc_hdr; +- struct lpfc_async_xchg_ctx *ctxp; +- uint32_t *payload; +- uint32_t size, oxid, sid, rc; +- +- +- if (!nvmebuf || !phba->targetport) { +- lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +- "6154 LS Drop IO\n"); +- oxid = 0; +- size = 0; +- sid = 0; +- ctxp = NULL; +- goto dropit; +- } +- +- fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt); +- oxid = be16_to_cpu(fc_hdr->fh_ox_id); +- +- tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; +- payload = (uint32_t *)(nvmebuf->dbuf.virt); +- size = bf_get(lpfc_rcqe_length, &nvmebuf->cq_event.cqe.rcqe_cmpl); +- sid = sli4_sid_from_fc_hdr(fc_hdr); +- +- ctxp = kzalloc(sizeof(struct lpfc_async_xchg_ctx), GFP_ATOMIC); +- if (ctxp == NULL) { +- atomic_inc(&tgtp->rcv_ls_req_drop); +- lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +- "6155 LS Drop IO x%x: Alloc\n", +- oxid); +-dropit: +- lpfc_nvmeio_data(phba, "NVMET LS DROP: " +- "xri x%x sz %d from %06x\n", +- oxid, size, sid); +- lpfc_in_buf_free(phba, &nvmebuf->dbuf); +- return; +- } +- ctxp->phba = phba; +- ctxp->size = size; +- ctxp->oxid = oxid; +- ctxp->sid = sid; +- ctxp->wqeq = NULL; +- ctxp->state = LPFC_NVME_STE_LS_RCV; +- ctxp->entry_cnt = 1; +- ctxp->rqb_buffer = (void *)nvmebuf; +- ctxp->hdwq = &phba->sli4_hba.hdwq[0]; ++ struct lpfc_nvmet_tgtport *tgtp = phba->targetport->private; ++ uint32_t *payload = axchg->payload; ++ int rc; + +- lpfc_nvmeio_data(phba, "NVMET LS RCV: xri x%x sz %d from %06x\n", +- oxid, size, sid); +- /* +- * The calling sequence should be: +- * nvmet_fc_rcv_ls_req -> lpfc_nvmet_xmt_ls_rsp/cmp ->_req->done +- * lpfc_nvmet_xmt_ls_rsp_cmp should free the allocated ctxp. +- */ + atomic_inc(&tgtp->rcv_ls_req_in); +- rc = nvmet_fc_rcv_ls_req(phba->targetport, NULL, &ctxp->ls_rsp, +- payload, size); ++ ++ rc = nvmet_fc_rcv_ls_req(phba->targetport, NULL, &axchg->ls_rsp, ++ axchg->payload, axchg->size); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, + "6037 NVMET Unsol rcv: sz %d rc %d: %08x %08x %08x " +- "%08x %08x %08x\n", size, rc, ++ "%08x %08x %08x\n", axchg->size, rc, + *payload, *(payload+1), *(payload+2), + *(payload+3), *(payload+4), *(payload+5)); + +- if (rc == 0) { ++ if (!rc) { + atomic_inc(&tgtp->rcv_ls_req_out); +- return; ++ return 0; + } + +- lpfc_nvmeio_data(phba, "NVMET LS DROP: xri x%x sz %d from %06x\n", +- oxid, size, sid); +- + atomic_inc(&tgtp->rcv_ls_req_drop); +- lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +- "6156 LS Drop IO x%x: nvmet_fc_rcv_ls_req %d\n", +- ctxp->oxid, rc); +- +- /* We assume a rcv'ed cmd ALWAYs fits into 1 buffer */ +- lpfc_in_buf_free(phba, &nvmebuf->dbuf); +- +- atomic_inc(&tgtp->xmt_ls_abort); +- lpfc_nvmet_unsol_ls_issue_abort(phba, ctxp, sid, oxid); + #endif ++ return 1; + } + + static void +@@ -2367,40 +2306,6 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, + } + } + +-/** +- * lpfc_nvmet_unsol_ls_event - Process an unsolicited event from an nvme nport +- * @phba: pointer to lpfc hba data structure. +- * @pring: pointer to a SLI ring. +- * @nvmebuf: pointer to received nvme data structure. +- * +- * This routine is used to process an unsolicited event received from a SLI +- * (Service Level Interface) ring. The actual processing of the data buffer +- * associated with the unsolicited event is done by invoking the routine +- * lpfc_nvmet_unsol_ls_buffer() after properly set up the buffer from the +- * SLI RQ on which the unsolicited event was received. +- **/ +-void +-lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, +- struct lpfc_iocbq *piocb) +-{ +- struct lpfc_dmabuf *d_buf; +- struct hbq_dmabuf *nvmebuf; +- +- d_buf = piocb->context2; +- nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf); +- +- if (!nvmebuf) { +- lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +- "3015 LS Drop IO\n"); +- return; +- } +- if (phba->nvmet_support == 0) { +- lpfc_in_buf_free(phba, &nvmebuf->dbuf); +- return; +- } +- lpfc_nvmet_unsol_ls_buffer(phba, pring, nvmebuf); +-} +- + /** + * lpfc_nvmet_unsol_fcp_event - Process an unsolicited event from an nvme nport + * @phba: pointer to lpfc hba data structure. +@@ -3404,8 +3309,16 @@ lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, + return 1; + } + +-static int +-lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, ++/** ++ * lpfc_nvme_unsol_ls_issue_abort - issue ABTS on an exchange received ++ * via async frame receive where the frame is not handled. ++ * @phba: pointer to adapter structure ++ * @ctxp: pointer to the asynchronously received received sequence ++ * @sid: address of the remote port to send the ABTS to ++ * @xri: oxid value to for the ABTS (other side's exchange id). ++ **/ ++int ++lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba, + struct lpfc_async_xchg_ctx *ctxp, + uint32_t sid, uint16_t xri) + { +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index 730a8ea4ad94..96fc6aefa4b3 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -2799,6 +2799,121 @@ lpfc_sli_get_buff(struct lpfc_hba *phba, + return &hbq_entry->dbuf; + } + ++/** ++ * lpfc_nvme_unsol_ls_handler - Process an unsolicited event data buffer ++ * containing a NVME LS request. ++ * @phba: pointer to lpfc hba data structure. ++ * @piocb: pointer to the iocbq struct representing the sequence starting ++ * frame. ++ * ++ * This routine initially validates the NVME LS, validates there is a login ++ * with the port that sent the LS, and then calls the appropriate nvme host ++ * or target LS request handler. ++ **/ ++static void ++lpfc_nvme_unsol_ls_handler(struct lpfc_hba *phba, struct lpfc_iocbq *piocb) ++{ ++ struct lpfc_nodelist *ndlp; ++ struct lpfc_dmabuf *d_buf; ++ struct hbq_dmabuf *nvmebuf; ++ struct fc_frame_header *fc_hdr; ++ struct lpfc_async_xchg_ctx *axchg = NULL; ++ char *failwhy = NULL; ++ uint32_t oxid, sid, did, fctl, size; ++ int ret; ++ ++ d_buf = piocb->context2; ++ ++ nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf); ++ fc_hdr = nvmebuf->hbuf.virt; ++ oxid = be16_to_cpu(fc_hdr->fh_ox_id); ++ sid = sli4_sid_from_fc_hdr(fc_hdr); ++ did = sli4_did_from_fc_hdr(fc_hdr); ++ fctl = (fc_hdr->fh_f_ctl[0] << 16 | ++ fc_hdr->fh_f_ctl[1] << 8 | ++ fc_hdr->fh_f_ctl[2]); ++ size = bf_get(lpfc_rcqe_length, &nvmebuf->cq_event.cqe.rcqe_cmpl); ++ ++ lpfc_nvmeio_data(phba, "NVME LS RCV: xri x%x sz %d from %06x\n", ++ oxid, size, sid); ++ ++ if (phba->pport->load_flag & FC_UNLOADING) { ++ failwhy = "Driver Unloading"; ++ } else if (!(phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) { ++ failwhy = "NVME FC4 Disabled"; ++ } else if (!phba->nvmet_support && !phba->pport->localport) { ++ failwhy = "No Localport"; ++ } else if (phba->nvmet_support && !phba->targetport) { ++ failwhy = "No Targetport"; ++ } else if (unlikely(fc_hdr->fh_r_ctl != FC_RCTL_ELS4_REQ)) { ++ failwhy = "Bad NVME LS R_CTL"; ++ } else if (unlikely((fctl & 0x00FF0000) != ++ (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT))) { ++ failwhy = "Bad NVME LS F_CTL"; ++ } else { ++ axchg = kzalloc(sizeof(*axchg), GFP_ATOMIC); ++ if (!axchg) ++ failwhy = "No CTX memory"; ++ } ++ ++ if (unlikely(failwhy)) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC | LOG_NVME_IOERR, ++ "6154 Drop NVME LS: SID %06X OXID x%X: %s\n", ++ sid, oxid, failwhy); ++ goto out_fail; ++ } ++ ++ /* validate the source of the LS is logged in */ ++ ndlp = lpfc_findnode_did(phba->pport, sid); ++ if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ++ ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && ++ (ndlp->nlp_state != NLP_STE_MAPPED_NODE))) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, ++ "6216 NVME Unsol rcv: No ndlp: " ++ "NPort_ID x%x oxid x%x\n", ++ sid, oxid); ++ goto out_fail; ++ } ++ ++ axchg->phba = phba; ++ axchg->ndlp = ndlp; ++ axchg->size = size; ++ axchg->oxid = oxid; ++ axchg->sid = sid; ++ axchg->wqeq = NULL; ++ axchg->state = LPFC_NVME_STE_LS_RCV; ++ axchg->entry_cnt = 1; ++ axchg->rqb_buffer = (void *)nvmebuf; ++ axchg->hdwq = &phba->sli4_hba.hdwq[0]; ++ axchg->payload = nvmebuf->dbuf.virt; ++ INIT_LIST_HEAD(&axchg->list); ++ ++ if (phba->nvmet_support) ++ ret = lpfc_nvmet_handle_lsreq(phba, axchg); ++ else ++ ret = lpfc_nvme_handle_lsreq(phba, axchg); ++ ++ /* if zero, LS was successfully handled. If non-zero, LS not handled */ ++ if (!ret) ++ return; ++ ++ lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC | LOG_NVME_IOERR, ++ "6155 Drop NVME LS from DID %06X: SID %06X OXID x%X " ++ "NVMe%s handler failed %d\n", ++ did, sid, oxid, ++ (phba->nvmet_support) ? "T" : "I", ret); ++ ++out_fail: ++ kfree(axchg); ++ ++ /* recycle receive buffer */ ++ lpfc_in_buf_free(phba, &nvmebuf->dbuf); ++ ++ /* If start of new exchange, abort it */ ++ if (fctl & FC_FC_FIRST_SEQ && !(fctl & FC_FC_EX_CTX)) ++ lpfc_nvme_unsol_ls_issue_abort(phba, axchg, sid, oxid); ++} ++ + /** + * lpfc_complete_unsol_iocb - Complete an unsolicited sequence + * @phba: Pointer to HBA context object. +@@ -2820,7 +2935,7 @@ lpfc_complete_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + + switch (fch_type) { + case FC_TYPE_NVME: +- lpfc_nvmet_unsol_ls_event(phba, pring, saveq); ++ lpfc_nvme_unsol_ls_handler(phba, saveq); + return 1; + default: + break; +@@ -14005,8 +14120,8 @@ lpfc_sli4_nvmet_handle_rcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, + + /* Just some basic sanity checks on FCP Command frame */ + fctl = (fc_hdr->fh_f_ctl[0] << 16 | +- fc_hdr->fh_f_ctl[1] << 8 | +- fc_hdr->fh_f_ctl[2]); ++ fc_hdr->fh_f_ctl[1] << 8 | ++ fc_hdr->fh_f_ctl[2]); + if (((fctl & + (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)) != + (FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT)) || +-- +2.16.4 + diff --git a/patches.suse/lpfc-Refactor-Send-LS-Abort-support.patch b/patches.suse/lpfc-Refactor-Send-LS-Abort-support.patch new file mode 100644 index 0000000..831b50a --- /dev/null +++ b/patches.suse/lpfc-Refactor-Send-LS-Abort-support.patch @@ -0,0 +1,208 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:07 -0700 +Subject: [PATCH] lpfc: Refactor Send LS Abort support +Git-commit: 2cd0363b234f8557d0ec3fa9a099854ce7940aa3 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Send LS Abort support is needed when Send LS Request is supported. + +Currently, the ability to abort an NVME LS request is limited to the nvme +(host) side of the driver. In preparation of both the nvme and nvmet sides +supporting Send LS Abort, rework the existing ls_req abort routines such +that there is common code that can be used by both sides. + +While refactoring it was seen the logic in the abort routine was incorrect. +It attempted to abort all NVME LS's on the indicated port. As such, the +routine was reworked to abort only the NVME LS request that was specified. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_nvme.c | 125 +++++++++++++++++++++++++----------------- + drivers/scsi/lpfc/lpfc_nvme.h | 2 + + 2 files changed, 77 insertions(+), 50 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c +index 2fa48d0049bd..776ee547740a 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.c ++++ b/drivers/scsi/lpfc/lpfc_nvme.c +@@ -790,83 +790,108 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, + } + + /** +- * lpfc_nvme_ls_abort - Issue an Link Service request +- * @lpfc_pnvme: Pointer to the driver's nvme instance data +- * @lpfc_nvme_lport: Pointer to the driver's local port data +- * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq ++ * __lpfc_nvme_ls_abort - Generic service routine to abort a prior ++ * NVME LS request ++ * @vport: The local port that issued the LS ++ * @ndlp: The remote port the LS was sent to ++ * @pnvme_lsreq: Pointer to LS request structure from the transport + * +- * Driver registers this routine to handle any link service request +- * from the nvme_fc transport to a remote nvme-aware port. ++ * The driver validates the ndlp, looks for the LS, and aborts the ++ * LS if found. + * +- * Return value : +- * 0 - Success +- * TODO: What are the failure codes. ++ * Returns: ++ * 0 : if LS found and aborted ++ * non-zero: various error conditions in form -Exxx + **/ +-static void +-lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, +- struct nvme_fc_remote_port *pnvme_rport, +- struct nvmefc_ls_req *pnvme_lsreq) ++int ++__lpfc_nvme_ls_abort(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ++ struct nvmefc_ls_req *pnvme_lsreq) + { +- struct lpfc_nvme_lport *lport; +- struct lpfc_vport *vport; +- struct lpfc_hba *phba; +- struct lpfc_nodelist *ndlp; +- LIST_HEAD(abort_list); ++ struct lpfc_hba *phba = vport->phba; + struct lpfc_sli_ring *pring; + struct lpfc_iocbq *wqe, *next_wqe; ++ bool foundit = false; + +- lport = (struct lpfc_nvme_lport *)pnvme_lport->private; +- if (unlikely(!lport)) +- return; +- vport = lport->vport; +- phba = vport->phba; +- +- if (vport->load_flag & FC_UNLOADING) +- return; +- +- ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); + if (!ndlp) { +- lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_ABTS, +- "6049 Could not find node for DID %x\n", +- pnvme_rport->port_id); +- return; ++ lpfc_printf_log(phba, KERN_ERR, ++ LOG_NVME_DISC | LOG_NODE | ++ LOG_NVME_IOERR | LOG_NVME_ABTS, ++ "6049 NVMEx LS REQ Abort: Bad NDLP x%px DID " ++ "x%06x, Failing LS Req\n", ++ ndlp, ndlp ? ndlp->nlp_DID : 0); ++ return -EINVAL; + } + +- /* Expand print to include key fields. */ +- lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_ABTS, +- "6040 ENTER. lport x%px, rport x%px lsreq x%px rqstlen:%d " +- "rsplen:%d %pad %pad\n", +- pnvme_lport, pnvme_rport, ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_NVME_ABTS, ++ "6040 NVMEx LS REQ Abort: Issue LS_ABORT for lsreq " ++ "x%p rqstlen:%d rsplen:%d %pad %pad\n", + pnvme_lsreq, pnvme_lsreq->rqstlen, + pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma, + &pnvme_lsreq->rspdma); + + /* +- * Lock the ELS ring txcmplq and build a local list of all ELS IOs +- * that need an ABTS. The IOs need to stay on the txcmplq so that +- * the abort operation completes them successfully. ++ * Lock the ELS ring txcmplq and look for the wqe that matches ++ * this ELS. If found, issue an abort on the wqe. + */ + pring = phba->sli4_hba.nvmels_wq->pring; + spin_lock_irq(&phba->hbalock); + spin_lock(&pring->ring_lock); + list_for_each_entry_safe(wqe, next_wqe, &pring->txcmplq, list) { +- /* Add to abort_list on on NDLP match. */ +- if (lpfc_check_sli_ndlp(phba, pring, wqe, ndlp)) { ++ if (wqe->context2 == pnvme_lsreq) { + wqe->iocb_flag |= LPFC_DRIVER_ABORTED; +- list_add_tail(&wqe->dlist, &abort_list); ++ foundit = true; ++ break; + } + } + spin_unlock(&pring->ring_lock); ++ ++ if (foundit) ++ lpfc_sli_issue_abort_iotag(phba, pring, wqe); + spin_unlock_irq(&phba->hbalock); + +- /* Abort the targeted IOs and remove them from the abort list. */ +- list_for_each_entry_safe(wqe, next_wqe, &abort_list, dlist) { ++ if (foundit) ++ return 0; ++ ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_NVME_ABTS, ++ "6213 NVMEx LS REQ Abort: Unable to locate req x%p\n", ++ pnvme_lsreq); ++ return 1; ++} ++ ++/** ++ * lpfc_nvme_ls_abort - Abort a prior NVME LS request ++ * @lpfc_nvme_lport: Transport localport that LS is to be issued from. ++ * @lpfc_nvme_rport: Transport remoteport that LS is to be sent to. ++ * @pnvme_lsreq - the transport nvme_ls_req structure for the LS ++ * ++ * Driver registers this routine to abort a NVME LS request that is ++ * in progress (from the transports perspective). ++ **/ ++static void ++lpfc_nvme_ls_abort(struct nvme_fc_local_port *pnvme_lport, ++ struct nvme_fc_remote_port *pnvme_rport, ++ struct nvmefc_ls_req *pnvme_lsreq) ++{ ++ struct lpfc_nvme_lport *lport; ++ struct lpfc_vport *vport; ++ struct lpfc_hba *phba; ++ struct lpfc_nodelist *ndlp; ++ int ret; ++ ++ lport = (struct lpfc_nvme_lport *)pnvme_lport->private; ++ if (unlikely(!lport)) ++ return; ++ vport = lport->vport; ++ phba = vport->phba; ++ ++ if (vport->load_flag & FC_UNLOADING) ++ return; ++ ++ ndlp = lpfc_findnode_did(vport, pnvme_rport->port_id); ++ ++ ret = __lpfc_nvme_ls_abort(vport, ndlp, pnvme_lsreq); ++ if (!ret) + atomic_inc(&lport->xmt_ls_abort); +- spin_lock_irq(&phba->hbalock); +- list_del_init(&wqe->dlist); +- lpfc_sli_issue_abort_iotag(phba, pring, wqe); +- spin_unlock_irq(&phba->hbalock); +- } + } + + /* Fix up the existing sgls for NVME IO. */ +diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h +index 6f8d44aa47b2..a9ad81d0c182 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.h ++++ b/drivers/scsi/lpfc/lpfc_nvme.h +@@ -237,6 +237,8 @@ int __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + struct lpfc_wcqe_complete *wcqe)); + void __lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport, + struct lpfc_iocbq *cmdwqe, struct lpfc_wcqe_complete *wcqe); ++int __lpfc_nvme_ls_abort(struct lpfc_vport *vport, ++ struct lpfc_nodelist *ndlp, struct nvmefc_ls_req *pnvme_lsreq); + + /* routines found in lpfc_nvmet.c */ + int lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba, +-- +2.16.4 + diff --git a/patches.suse/lpfc-Refactor-Send-LS-Request-support.patch b/patches.suse/lpfc-Refactor-Send-LS-Request-support.patch new file mode 100644 index 0000000..2c61a0b --- /dev/null +++ b/patches.suse/lpfc-Refactor-Send-LS-Request-support.patch @@ -0,0 +1,450 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:06 -0700 +Subject: [PATCH] lpfc: Refactor Send LS Request support +Git-commit: 237c60bd5f6465d5303e76f04a9e526704ccdd15 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Currently, the ability to send an NVME LS request is limited to the nvme +(host) side of the driver. In preparation of both the nvme and nvmet sides +support Send LS Request, rework the existing send ls_req and ls_req +completion routines such that there is common code that can be used by +both sides. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_nvme.c | 289 +++++++++++++++++++++++++----------------- + drivers/scsi/lpfc/lpfc_nvme.h | 13 ++ + 2 files changed, 184 insertions(+), 118 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c +index 7eb6e89f7f62..2fa48d0049bd 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.c ++++ b/drivers/scsi/lpfc/lpfc_nvme.c +@@ -410,43 +410,43 @@ lpfc_nvme_handle_lsreq(struct lpfc_hba *phba, + return 1; + } + +-static void +-lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, +- struct lpfc_wcqe_complete *wcqe) ++/** ++ * __lpfc_nvme_ls_req_cmp - Generic completion handler for a NVME ++ * LS request. ++ * @phba: Pointer to HBA context object ++ * @vport: The local port that issued the LS ++ * @cmdwqe: Pointer to driver command WQE object. ++ * @wcqe: Pointer to driver response CQE object. ++ * ++ * This function is the generic completion handler for NVME LS requests. ++ * The function updates any states and statistics, calls the transport ++ * ls_req done() routine, then tears down the command and buffers used ++ * for the LS request. ++ **/ ++void ++__lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport, ++ struct lpfc_iocbq *cmdwqe, ++ struct lpfc_wcqe_complete *wcqe) + { +- struct lpfc_vport *vport = cmdwqe->vport; +- struct lpfc_nvme_lport *lport; +- uint32_t status; + struct nvmefc_ls_req *pnvme_lsreq; + struct lpfc_dmabuf *buf_ptr; + struct lpfc_nodelist *ndlp; ++ uint32_t status; + + pnvme_lsreq = (struct nvmefc_ls_req *)cmdwqe->context2; ++ ndlp = (struct lpfc_nodelist *)cmdwqe->context1; + status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; + +- if (vport->localport) { +- lport = (struct lpfc_nvme_lport *)vport->localport->private; +- if (lport) { +- atomic_inc(&lport->fc4NvmeLsCmpls); +- if (status) { +- if (bf_get(lpfc_wcqe_c_xb, wcqe)) +- atomic_inc(&lport->cmpl_ls_xb); +- atomic_inc(&lport->cmpl_ls_err); +- } +- } +- } +- +- ndlp = (struct lpfc_nodelist *)cmdwqe->context1; + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, +- "6047 nvme cmpl Enter " +- "Data %px DID %x Xri: %x status %x reason x%x " +- "cmd:x%px lsreg:x%px bmp:x%px ndlp:x%px\n", ++ "6047 NVMEx LS REQ %px cmpl DID %x Xri: %x " ++ "status %x reason x%x cmd:x%px lsreg:x%px bmp:x%px " ++ "ndlp:x%px\n", + pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0, + cmdwqe->sli4_xritag, status, + (wcqe->parameter & 0xffff), + cmdwqe, pnvme_lsreq, cmdwqe->context3, ndlp); + +- lpfc_nvmeio_data(phba, "NVME LS CMPL: xri x%x stat x%x parm x%x\n", ++ lpfc_nvmeio_data(phba, "NVMEx LS CMPL: xri x%x stat x%x parm x%x\n", + cmdwqe->sli4_xritag, status, wcqe->parameter); + + if (cmdwqe->context3) { +@@ -459,7 +459,7 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + pnvme_lsreq->done(pnvme_lsreq, status); + else + lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, +- "6046 nvme cmpl without done call back? " ++ "6046 NVMEx cmpl without done call back? " + "Data %px DID %x Xri: %x status %x\n", + pnvme_lsreq, ndlp ? ndlp->nlp_DID : 0, + cmdwqe->sli4_xritag, status); +@@ -470,6 +470,31 @@ lpfc_nvme_cmpl_gen_req(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + lpfc_sli_release_iocbq(phba, cmdwqe); + } + ++static void ++lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, ++ struct lpfc_wcqe_complete *wcqe) ++{ ++ struct lpfc_vport *vport = cmdwqe->vport; ++ struct lpfc_nvme_lport *lport; ++ uint32_t status; ++ ++ status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; ++ ++ if (vport->localport) { ++ lport = (struct lpfc_nvme_lport *)vport->localport->private; ++ if (lport) { ++ atomic_inc(&lport->fc4NvmeLsCmpls); ++ if (status) { ++ if (bf_get(lpfc_wcqe_c_xb, wcqe)) ++ atomic_inc(&lport->cmpl_ls_xb); ++ atomic_inc(&lport->cmpl_ls_err); ++ } ++ } ++ } ++ ++ __lpfc_nvme_ls_req_cmp(phba, vport, cmdwqe, wcqe); ++} ++ + static int + lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, + struct lpfc_dmabuf *inp, +@@ -571,13 +596,6 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, + + + /* Issue GEN REQ WQE for NPORT */ +- lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, +- "6050 Issue GEN REQ WQE to NPORT x%x " +- "Data: x%x x%x wq:x%px lsreq:x%px bmp:x%px " +- "xmit:%d 1st:%d\n", +- ndlp->nlp_DID, genwqe->iotag, +- vport->port_state, +- genwqe, pnvme_lsreq, bmp, xmit_len, first_len); + genwqe->wqe_cmpl = cmpl; + genwqe->iocb_cmpl = NULL; + genwqe->drvrTimeout = tmo + LPFC_DRVR_TIMEOUT; +@@ -589,105 +607,108 @@ lpfc_nvme_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, + + rc = lpfc_sli4_issue_wqe(phba, &phba->sli4_hba.hdwq[0], genwqe); + if (rc) { +- lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, ++ lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC | LOG_ELS, + "6045 Issue GEN REQ WQE to NPORT x%x " +- "Data: x%x x%x\n", ++ "Data: x%x x%x rc x%x\n", + ndlp->nlp_DID, genwqe->iotag, +- vport->port_state); ++ vport->port_state, rc); + lpfc_sli_release_iocbq(phba, genwqe); + return 1; + } ++ ++ lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC | LOG_ELS, ++ "6050 Issue GEN REQ WQE to NPORT x%x " ++ "Data: oxid: x%x state: x%x wq:x%px lsreq:x%px " ++ "bmp:x%px xmit:%d 1st:%d\n", ++ ndlp->nlp_DID, genwqe->sli4_xritag, ++ vport->port_state, ++ genwqe, pnvme_lsreq, bmp, xmit_len, first_len); + return 0; + } + ++ + /** +- * lpfc_nvme_ls_req - Issue an Link Service request +- * @lpfc_pnvme: Pointer to the driver's nvme instance data +- * @lpfc_nvme_lport: Pointer to the driver's local port data +- * @lpfc_nvme_rport: Pointer to the rport getting the @lpfc_nvme_ereq ++ * __lpfc_nvme_ls_req - Generic service routine to issue an NVME LS request ++ * @vport: The local port issuing the LS ++ * @ndlp: The remote port to send the LS to ++ * @pnvme_lsreq: Pointer to LS request structure from the transport + * +- * Driver registers this routine to handle any link service request +- * from the nvme_fc transport to a remote nvme-aware port. ++ * Routine validates the ndlp, builds buffers and sends a GEN_REQUEST ++ * WQE to perform the LS operation. + * + * Return value : + * 0 - Success +- * TODO: What are the failure codes. ++ * non-zero: various error codes, in form of -Exxx + **/ +-static int +-lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, +- struct nvme_fc_remote_port *pnvme_rport, +- struct nvmefc_ls_req *pnvme_lsreq) ++int ++__lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ++ struct nvmefc_ls_req *pnvme_lsreq, ++ void (*gen_req_cmp)(struct lpfc_hba *phba, ++ struct lpfc_iocbq *cmdwqe, ++ struct lpfc_wcqe_complete *wcqe)) + { +- int ret = 0; +- struct lpfc_nvme_lport *lport; +- struct lpfc_nvme_rport *rport; +- struct lpfc_vport *vport; +- struct lpfc_nodelist *ndlp; +- struct ulp_bde64 *bpl; + struct lpfc_dmabuf *bmp; ++ struct ulp_bde64 *bpl; ++ int ret; + uint16_t ntype, nstate; + +- /* there are two dma buf in the request, actually there is one and +- * the second one is just the start address + cmd size. +- * Before calling lpfc_nvme_gen_req these buffers need to be wrapped +- * in a lpfc_dmabuf struct. When freeing we just free the wrapper +- * because the nvem layer owns the data bufs. +- * We do not have to break these packets open, we don't care what is in +- * them. And we do not have to look at the resonse data, we only care +- * that we got a response. All of the caring is going to happen in the +- * nvme-fc layer. +- */ +- +- lport = (struct lpfc_nvme_lport *)pnvme_lport->private; +- rport = (struct lpfc_nvme_rport *)pnvme_rport->private; +- if (unlikely(!lport) || unlikely(!rport)) +- return -EINVAL; +- +- vport = lport->vport; +- +- if (vport->load_flag & FC_UNLOADING) +- return -ENODEV; +- +- /* Need the ndlp. It is stored in the driver's rport. */ +- ndlp = rport->ndlp; + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { +- lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, +- "6051 Remoteport x%px, rport has invalid ndlp. " +- "Failing LS Req\n", pnvme_rport); ++ lpfc_printf_vlog(vport, KERN_ERR, ++ LOG_NVME_DISC | LOG_NODE | LOG_NVME_IOERR, ++ "6051 NVMEx LS REQ: Bad NDLP x%px, Failing " ++ "LS Req\n", ++ ndlp); + return -ENODEV; + } + +- /* The remote node has to be a mapped nvme target or an +- * unmapped nvme initiator or it's an error. +- */ + ntype = ndlp->nlp_type; + nstate = ndlp->nlp_state; + if ((ntype & NLP_NVME_TARGET && nstate != NLP_STE_MAPPED_NODE) || + (ntype & NLP_NVME_INITIATOR && nstate != NLP_STE_UNMAPPED_NODE)) { +- lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE | LOG_NVME_IOERR, +- "6088 DID x%06x not ready for " +- "IO. State x%x, Type x%x\n", +- pnvme_rport->port_id, +- ndlp->nlp_state, ndlp->nlp_type); ++ lpfc_printf_vlog(vport, KERN_ERR, ++ LOG_NVME_DISC | LOG_NODE | LOG_NVME_IOERR, ++ "6088 NVMEx LS REQ: Fail DID x%06x not " ++ "ready for IO. Type x%x, State x%x\n", ++ ndlp->nlp_DID, ntype, nstate); + return -ENODEV; + } +- bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); ++ ++ /* ++ * there are two dma buf in the request, actually there is one and ++ * the second one is just the start address + cmd size. ++ * Before calling lpfc_nvme_gen_req these buffers need to be wrapped ++ * in a lpfc_dmabuf struct. When freeing we just free the wrapper ++ * because the nvem layer owns the data bufs. ++ * We do not have to break these packets open, we don't care what is ++ * in them. And we do not have to look at the resonse data, we only ++ * care that we got a response. All of the caring is going to happen ++ * in the nvme-fc layer. ++ */ ++ ++ bmp = kmalloc(sizeof(*bmp), GFP_KERNEL); + if (!bmp) { + +- lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, +- "6044 Could not find node for DID %x\n", +- pnvme_rport->port_id); +- return 2; ++ lpfc_printf_vlog(vport, KERN_ERR, ++ LOG_NVME_DISC | LOG_NVME_IOERR, ++ "6044 NVMEx LS REQ: Could not alloc LS buf " ++ "for DID %x\n", ++ ndlp->nlp_DID); ++ return -ENOMEM; + } +- INIT_LIST_HEAD(&bmp->list); ++ + bmp->virt = lpfc_mbuf_alloc(vport->phba, MEM_PRI, &(bmp->phys)); + if (!bmp->virt) { +- lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, +- "6042 Could not find node for DID %x\n", +- pnvme_rport->port_id); ++ lpfc_printf_vlog(vport, KERN_ERR, ++ LOG_NVME_DISC | LOG_NVME_IOERR, ++ "6042 NVMEx LS REQ: Could not alloc mbuf " ++ "for DID %x\n", ++ ndlp->nlp_DID); + kfree(bmp); +- return 3; ++ return -ENOMEM; + } ++ ++ INIT_LIST_HEAD(&bmp->list); ++ + bpl = (struct ulp_bde64 *)bmp->virt; + bpl->addrHigh = le32_to_cpu(putPaddrHigh(pnvme_lsreq->rqstdma)); + bpl->addrLow = le32_to_cpu(putPaddrLow(pnvme_lsreq->rqstdma)); +@@ -702,37 +723,69 @@ lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, + bpl->tus.f.bdeSize = pnvme_lsreq->rsplen; + bpl->tus.w = le32_to_cpu(bpl->tus.w); + +- /* Expand print to include key fields. */ + lpfc_printf_vlog(vport, KERN_INFO, LOG_NVME_DISC, +- "6149 Issue LS Req to DID 0x%06x lport x%px, " +- "rport x%px lsreq x%px rqstlen:%d rsplen:%d " +- "%pad %pad\n", +- ndlp->nlp_DID, pnvme_lport, pnvme_rport, +- pnvme_lsreq, pnvme_lsreq->rqstlen, +- pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma, +- &pnvme_lsreq->rspdma); +- +- atomic_inc(&lport->fc4NvmeLsRequests); ++ "6149 NVMEx LS REQ: Issue to DID 0x%06x lsreq x%px, " ++ "rqstlen:%d rsplen:%d %pad %pad\n", ++ ndlp->nlp_DID, pnvme_lsreq, pnvme_lsreq->rqstlen, ++ pnvme_lsreq->rsplen, &pnvme_lsreq->rqstdma, ++ &pnvme_lsreq->rspdma); + +- /* Hardcode the wait to 30 seconds. Connections are failing otherwise. +- * This code allows it all to work. +- */ + ret = lpfc_nvme_gen_req(vport, bmp, pnvme_lsreq->rqstaddr, +- pnvme_lsreq, lpfc_nvme_cmpl_gen_req, +- ndlp, 2, 30, 0); ++ pnvme_lsreq, gen_req_cmp, ndlp, 2, ++ LPFC_NVME_LS_TIMEOUT, 0); + if (ret != WQE_SUCCESS) { +- atomic_inc(&lport->xmt_ls_err); +- lpfc_printf_vlog(vport, KERN_ERR, LOG_NVME_DISC, +- "6052 EXIT. issue ls wqe failed lport x%px, " +- "rport x%px lsreq x%px Status %x DID %x\n", +- pnvme_lport, pnvme_rport, pnvme_lsreq, +- ret, ndlp->nlp_DID); ++ lpfc_printf_vlog(vport, KERN_ERR, ++ LOG_NVME_DISC | LOG_NVME_IOERR, ++ "6052 NVMEx REQ: EXIT. issue ls wqe failed " ++ "lsreq x%px Status %x DID %x\n", ++ pnvme_lsreq, ret, ndlp->nlp_DID); + lpfc_mbuf_free(vport->phba, bmp->virt, bmp->phys); + kfree(bmp); +- return ret; ++ return -EIO; + } + +- /* Stub in routine and return 0 for now. */ ++ return 0; ++} ++ ++/** ++ * lpfc_nvme_ls_req - Issue an NVME Link Service request ++ * @lpfc_nvme_lport: Transport localport that LS is to be issued from. ++ * @lpfc_nvme_rport: Transport remoteport that LS is to be sent to. ++ * @pnvme_lsreq - the transport nvme_ls_req structure for the LS ++ * ++ * Driver registers this routine to handle any link service request ++ * from the nvme_fc transport to a remote nvme-aware port. ++ * ++ * Return value : ++ * 0 - Success ++ * non-zero: various error codes, in form of -Exxx ++ **/ ++static int ++lpfc_nvme_ls_req(struct nvme_fc_local_port *pnvme_lport, ++ struct nvme_fc_remote_port *pnvme_rport, ++ struct nvmefc_ls_req *pnvme_lsreq) ++{ ++ struct lpfc_nvme_lport *lport; ++ struct lpfc_nvme_rport *rport; ++ struct lpfc_vport *vport; ++ int ret; ++ ++ lport = (struct lpfc_nvme_lport *)pnvme_lport->private; ++ rport = (struct lpfc_nvme_rport *)pnvme_rport->private; ++ if (unlikely(!lport) || unlikely(!rport)) ++ return -EINVAL; ++ ++ vport = lport->vport; ++ if (vport->load_flag & FC_UNLOADING) ++ return -ENODEV; ++ ++ atomic_inc(&lport->fc4NvmeLsRequests); ++ ++ ret = __lpfc_nvme_ls_req(vport, rport->ndlp, pnvme_lsreq, ++ lpfc_nvme_ls_req_cmp); ++ if (ret) ++ atomic_inc(&lport->xmt_ls_err); ++ + return ret; + } + +diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h +index 10e8d868608e..6f8d44aa47b2 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.h ++++ b/drivers/scsi/lpfc/lpfc_nvme.h +@@ -79,6 +79,12 @@ struct lpfc_nvme_fcpreq_priv { + struct lpfc_io_buf *nvme_buf; + }; + ++/* ++ * set NVME LS request timeouts to 30s. It is larger than the 2*R_A_TOV ++ * set by the spec, which appears to have issues with some devices. ++ */ ++#define LPFC_NVME_LS_TIMEOUT 30 ++ + + #define LPFC_NVMET_DEFAULT_SEGS (64 + 1) /* 256K IOs */ + #define LPFC_NVMET_RQE_MIN_POST 128 +@@ -224,6 +230,13 @@ struct lpfc_async_xchg_ctx { + + + /* routines found in lpfc_nvme.c */ ++int __lpfc_nvme_ls_req(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ++ struct nvmefc_ls_req *pnvme_lsreq, ++ void (*gen_req_cmp)(struct lpfc_hba *phba, ++ struct lpfc_iocbq *cmdwqe, ++ struct lpfc_wcqe_complete *wcqe)); ++void __lpfc_nvme_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_vport *vport, ++ struct lpfc_iocbq *cmdwqe, struct lpfc_wcqe_complete *wcqe); + + /* routines found in lpfc_nvmet.c */ + int lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba, +-- +2.16.4 + diff --git a/patches.suse/lpfc-Refactor-Send-LS-Response-support.patch b/patches.suse/lpfc-Refactor-Send-LS-Response-support.patch new file mode 100644 index 0000000..1b07134 --- /dev/null +++ b/patches.suse/lpfc-Refactor-Send-LS-Response-support.patch @@ -0,0 +1,380 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:08 -0700 +Subject: [PATCH] lpfc: Refactor Send LS Response support +Git-commit: d17bb8a5d9b171706fb145039ea38fccc2d47728 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Currently, the ability to send an NVME LS response is limited to the nvmet +(controller/target) side of the driver. In preparation of both the nvme +and nvmet sides supporting Send LS Response, rework the existing send +ls_rsp and ls_rsp completion routines such that there is common code that +can be used by both sides. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_nvme.h | 7 ++ + drivers/scsi/lpfc/lpfc_nvmet.c | 255 ++++++++++++++++++++++++++++------------- + 2 files changed, 184 insertions(+), 78 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h +index a9ad81d0c182..f28a6789e252 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.h ++++ b/drivers/scsi/lpfc/lpfc_nvme.h +@@ -244,3 +244,10 @@ int __lpfc_nvme_ls_abort(struct lpfc_vport *vport, + int lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba, + struct lpfc_async_xchg_ctx *ctxp, uint32_t sid, + uint16_t xri); ++int __lpfc_nvme_xmt_ls_rsp(struct lpfc_async_xchg_ctx *axchg, ++ struct nvmefc_ls_rsp *ls_rsp, ++ void (*xmt_ls_rsp_cmp)(struct lpfc_hba *phba, ++ struct lpfc_iocbq *cmdwqe, ++ struct lpfc_wcqe_complete *wcqe)); ++void __lpfc_nvme_xmt_ls_rsp_cmp(struct lpfc_hba *phba, ++ struct lpfc_iocbq *cmdwqe, struct lpfc_wcqe_complete *wcqe); +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c +index e6895c719683..edec7c3ffab1 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.c ++++ b/drivers/scsi/lpfc/lpfc_nvmet.c +@@ -280,6 +280,53 @@ lpfc_nvmet_defer_release(struct lpfc_hba *phba, + spin_unlock(&phba->sli4_hba.abts_nvmet_buf_list_lock); + } + ++/** ++ * __lpfc_nvme_xmt_ls_rsp_cmp - Generic completion handler for the ++ * transmission of an NVME LS response. ++ * @phba: Pointer to HBA context object. ++ * @cmdwqe: Pointer to driver command WQE object. ++ * @wcqe: Pointer to driver response CQE object. ++ * ++ * The function is called from SLI ring event handler with no ++ * lock held. The function frees memory resources used for the command ++ * used to send the NVME LS RSP. ++ **/ ++void ++__lpfc_nvme_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, ++ struct lpfc_wcqe_complete *wcqe) ++{ ++ struct lpfc_async_xchg_ctx *axchg = cmdwqe->context2; ++ struct nvmefc_ls_rsp *ls_rsp = &axchg->ls_rsp; ++ uint32_t status, result; ++ ++ status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; ++ result = wcqe->parameter; ++ ++ if (axchg->state != LPFC_NVME_STE_LS_RSP || axchg->entry_cnt != 2) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC | LOG_NVME_IOERR, ++ "6410 NVMEx LS cmpl state mismatch IO x%x: " ++ "%d %d\n", ++ axchg->oxid, axchg->state, axchg->entry_cnt); ++ } ++ ++ lpfc_nvmeio_data(phba, "NVMEx LS CMPL: xri x%x stat x%x result x%x\n", ++ axchg->oxid, status, result); ++ ++ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, ++ "6038 NVMEx LS rsp cmpl: %d %d oxid x%x\n", ++ status, result, axchg->oxid); ++ ++ lpfc_nlp_put(cmdwqe->context1); ++ cmdwqe->context2 = NULL; ++ cmdwqe->context3 = NULL; ++ lpfc_sli_release_iocbq(phba, cmdwqe); ++ ls_rsp->done(ls_rsp); ++ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, ++ "6200 NVMEx LS rsp cmpl done status %d oxid x%x\n", ++ status, axchg->oxid); ++ kfree(axchg); ++} ++ + /** + * lpfc_nvmet_xmt_ls_rsp_cmp - Completion handler for LS Response + * @phba: Pointer to HBA context object. +@@ -288,33 +335,23 @@ lpfc_nvmet_defer_release(struct lpfc_hba *phba, + * + * The function is called from SLI ring event handler with no + * lock held. This function is the completion handler for NVME LS commands +- * The function frees memory resources used for the NVME commands. ++ * The function updates any states and statistics, then calls the ++ * generic completion handler to free resources. + **/ + static void + lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + struct lpfc_wcqe_complete *wcqe) + { + struct lpfc_nvmet_tgtport *tgtp; +- struct nvmefc_ls_rsp *rsp; +- struct lpfc_async_xchg_ctx *ctxp; + uint32_t status, result; + +- status = bf_get(lpfc_wcqe_c_status, wcqe); +- result = wcqe->parameter; +- ctxp = cmdwqe->context2; +- +- if (ctxp->state != LPFC_NVME_STE_LS_RSP || ctxp->entry_cnt != 2) { +- lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +- "6410 NVMET LS cmpl state mismatch IO x%x: " +- "%d %d\n", +- ctxp->oxid, ctxp->state, ctxp->entry_cnt); +- } +- + if (!phba->targetport) +- goto out; ++ goto finish; + +- tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; ++ status = bf_get(lpfc_wcqe_c_status, wcqe) & LPFC_IOCB_STATUS_MASK; ++ result = wcqe->parameter; + ++ tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; + if (tgtp) { + if (status) { + atomic_inc(&tgtp->xmt_ls_rsp_error); +@@ -327,22 +364,8 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + } + } + +-out: +- rsp = &ctxp->ls_rsp; +- +- lpfc_nvmeio_data(phba, "NVMET LS CMPL: xri x%x stat x%x result x%x\n", +- ctxp->oxid, status, result); +- +- lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, +- "6038 NVMET LS rsp cmpl: %d %d oxid x%x\n", +- status, result, ctxp->oxid); +- +- lpfc_nlp_put(cmdwqe->context1); +- cmdwqe->context2 = NULL; +- cmdwqe->context3 = NULL; +- lpfc_sli_release_iocbq(phba, cmdwqe); +- rsp->done(rsp); +- kfree(ctxp); ++finish: ++ __lpfc_nvme_xmt_ls_rsp_cmp(phba, cmdwqe, wcqe); + } + + /** +@@ -821,52 +844,61 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + #endif + } + +-static int +-lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, +- struct nvmefc_ls_rsp *rsp) ++/** ++ * __lpfc_nvme_xmt_ls_rsp - Generic service routine to issue transmit ++ * an NVME LS rsp for a prior NVME LS request that was received. ++ * @axchg: pointer to exchange context for the NVME LS request the response ++ * is for. ++ * @ls_rsp: pointer to the transport LS RSP that is to be sent ++ * @xmt_ls_rsp_cmp: completion routine to call upon RSP transmit done ++ * ++ * This routine is used to format and send a WQE to transmit a NVME LS ++ * Response. The response is for a prior NVME LS request that was ++ * received and posted to the transport. ++ * ++ * Returns: ++ * 0 : if response successfully transmit ++ * non-zero : if response failed to transmit, of the form -Exxx. ++ **/ ++int ++__lpfc_nvme_xmt_ls_rsp(struct lpfc_async_xchg_ctx *axchg, ++ struct nvmefc_ls_rsp *ls_rsp, ++ void (*xmt_ls_rsp_cmp)(struct lpfc_hba *phba, ++ struct lpfc_iocbq *cmdwqe, ++ struct lpfc_wcqe_complete *wcqe)) + { +- struct lpfc_async_xchg_ctx *ctxp = +- container_of(rsp, struct lpfc_async_xchg_ctx, ls_rsp); +- struct lpfc_hba *phba = ctxp->phba; +- struct hbq_dmabuf *nvmebuf = +- (struct hbq_dmabuf *)ctxp->rqb_buffer; ++ struct lpfc_hba *phba = axchg->phba; ++ struct hbq_dmabuf *nvmebuf = (struct hbq_dmabuf *)axchg->rqb_buffer; + struct lpfc_iocbq *nvmewqeq; +- struct lpfc_nvmet_tgtport *nvmep = tgtport->private; + struct lpfc_dmabuf dmabuf; + struct ulp_bde64 bpl; + int rc; + +- if (phba->pport->load_flag & FC_UNLOADING) +- return -ENODEV; +- + if (phba->pport->load_flag & FC_UNLOADING) + return -ENODEV; + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, +- "6023 NVMET LS rsp oxid x%x\n", ctxp->oxid); ++ "6023 NVMEx LS rsp oxid x%x\n", axchg->oxid); + +- if ((ctxp->state != LPFC_NVME_STE_LS_RCV) || +- (ctxp->entry_cnt != 1)) { +- lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +- "6412 NVMET LS rsp state mismatch " ++ if (axchg->state != LPFC_NVME_STE_LS_RCV || axchg->entry_cnt != 1) { ++ lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC | LOG_NVME_IOERR, ++ "6412 NVMEx LS rsp state mismatch " + "oxid x%x: %d %d\n", +- ctxp->oxid, ctxp->state, ctxp->entry_cnt); ++ axchg->oxid, axchg->state, axchg->entry_cnt); ++ return -EALREADY; + } +- ctxp->state = LPFC_NVME_STE_LS_RSP; +- ctxp->entry_cnt++; ++ axchg->state = LPFC_NVME_STE_LS_RSP; ++ axchg->entry_cnt++; + +- nvmewqeq = lpfc_nvmet_prep_ls_wqe(phba, ctxp, rsp->rspdma, +- rsp->rsplen); ++ nvmewqeq = lpfc_nvmet_prep_ls_wqe(phba, axchg, ls_rsp->rspdma, ++ ls_rsp->rsplen); + if (nvmewqeq == NULL) { +- atomic_inc(&nvmep->xmt_ls_drop); +- lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +- "6150 LS Drop IO x%x: Prep\n", +- ctxp->oxid); +- lpfc_in_buf_free(phba, &nvmebuf->dbuf); +- atomic_inc(&nvmep->xmt_ls_abort); +- lpfc_nvme_unsol_ls_issue_abort(phba, ctxp, +- ctxp->sid, ctxp->oxid); +- return -ENOMEM; ++ lpfc_printf_log(phba, KERN_ERR, ++ LOG_NVME_DISC | LOG_NVME_IOERR | LOG_NVME_ABTS, ++ "6150 NVMEx LS Drop Rsp x%x: Prep\n", ++ axchg->oxid); ++ rc = -ENOMEM; ++ goto out_free_buf; + } + + /* Save numBdes for bpl2sgl */ +@@ -876,39 +908,106 @@ lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, + dmabuf.virt = &bpl; + bpl.addrLow = nvmewqeq->wqe.xmit_sequence.bde.addrLow; + bpl.addrHigh = nvmewqeq->wqe.xmit_sequence.bde.addrHigh; +- bpl.tus.f.bdeSize = rsp->rsplen; ++ bpl.tus.f.bdeSize = ls_rsp->rsplen; + bpl.tus.f.bdeFlags = 0; + bpl.tus.w = le32_to_cpu(bpl.tus.w); ++ /* ++ * Note: although we're using stack space for the dmabuf, the ++ * call to lpfc_sli4_issue_wqe is synchronous, so it will not ++ * be referenced after it returns back to this routine. ++ */ + +- nvmewqeq->wqe_cmpl = lpfc_nvmet_xmt_ls_rsp_cmp; ++ nvmewqeq->wqe_cmpl = xmt_ls_rsp_cmp; + nvmewqeq->iocb_cmpl = NULL; +- nvmewqeq->context2 = ctxp; ++ nvmewqeq->context2 = axchg; + +- lpfc_nvmeio_data(phba, "NVMET LS RESP: xri x%x wqidx x%x len x%x\n", +- ctxp->oxid, nvmewqeq->hba_wqidx, rsp->rsplen); ++ lpfc_nvmeio_data(phba, "NVMEx LS RSP: xri x%x wqidx x%x len x%x\n", ++ axchg->oxid, nvmewqeq->hba_wqidx, ls_rsp->rsplen); ++ ++ rc = lpfc_sli4_issue_wqe(phba, axchg->hdwq, nvmewqeq); ++ ++ /* clear to be sure there's no reference */ ++ nvmewqeq->context3 = NULL; + +- rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq); + if (rc == WQE_SUCCESS) { + /* + * Okay to repost buffer here, but wait till cmpl + * before freeing ctxp and iocbq. + */ + lpfc_in_buf_free(phba, &nvmebuf->dbuf); +- atomic_inc(&nvmep->xmt_ls_rsp); + return 0; + } +- /* Give back resources */ +- atomic_inc(&nvmep->xmt_ls_drop); +- lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +- "6151 LS Drop IO x%x: Issue %d\n", +- ctxp->oxid, rc); ++ ++ lpfc_printf_log(phba, KERN_ERR, ++ LOG_NVME_DISC | LOG_NVME_IOERR | LOG_NVME_ABTS, ++ "6151 NVMEx LS RSP x%x: failed to transmit %d\n", ++ axchg->oxid, rc); ++ ++ rc = -ENXIO; + + lpfc_nlp_put(nvmewqeq->context1); + ++out_free_buf: ++ /* Give back resources */ + lpfc_in_buf_free(phba, &nvmebuf->dbuf); +- atomic_inc(&nvmep->xmt_ls_abort); +- lpfc_nvme_unsol_ls_issue_abort(phba, ctxp, ctxp->sid, ctxp->oxid); +- return -ENXIO; ++ ++ /* ++ * As transport doesn't track completions of responses, if the rsp ++ * fails to send, the transport will effectively ignore the rsp ++ * and consider the LS done. However, the driver has an active ++ * exchange open for the LS - so be sure to abort the exchange ++ * if the response isn't sent. ++ */ ++ lpfc_nvme_unsol_ls_issue_abort(phba, axchg, axchg->sid, axchg->oxid); ++ return rc; ++} ++ ++/** ++ * lpfc_nvmet_xmt_ls_rsp - Transmit NVME LS response ++ * @tgtport: pointer to target port that NVME LS is to be transmit from. ++ * @ls_rsp: pointer to the transport LS RSP that is to be sent ++ * ++ * Driver registers this routine to transmit responses for received NVME ++ * LS requests. ++ * ++ * This routine is used to format and send a WQE to transmit a NVME LS ++ * Response. The ls_rsp is used to reverse-map the LS to the original ++ * NVME LS request sequence, which provides addressing information for ++ * the remote port the LS to be sent to, as well as the exchange id ++ * that is the LS is bound to. ++ * ++ * Returns: ++ * 0 : if response successfully transmit ++ * non-zero : if response failed to transmit, of the form -Exxx. ++ **/ ++static int ++lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, ++ struct nvmefc_ls_rsp *ls_rsp) ++{ ++ struct lpfc_async_xchg_ctx *axchg = ++ container_of(ls_rsp, struct lpfc_async_xchg_ctx, ls_rsp); ++ struct lpfc_nvmet_tgtport *nvmep = tgtport->private; ++ int rc; ++ ++ if (axchg->phba->pport->load_flag & FC_UNLOADING) ++ return -ENODEV; ++ ++ rc = __lpfc_nvme_xmt_ls_rsp(axchg, ls_rsp, lpfc_nvmet_xmt_ls_rsp_cmp); ++ ++ if (rc) { ++ atomic_inc(&nvmep->xmt_ls_drop); ++ /* ++ * unless the failure is due to having already sent ++ * the response, an abort will be generated for the ++ * exchange if the rsp can't be sent. ++ */ ++ if (rc != -EALREADY) ++ atomic_inc(&nvmep->xmt_ls_abort); ++ return rc; ++ } ++ ++ atomic_inc(&nvmep->xmt_ls_rsp); ++ return 0; + } + + static int +-- +2.16.4 + diff --git a/patches.suse/lpfc-Refactor-lpfc-nvme-headers.patch b/patches.suse/lpfc-Refactor-lpfc-nvme-headers.patch new file mode 100644 index 0000000..2112e68 --- /dev/null +++ b/patches.suse/lpfc-Refactor-lpfc-nvme-headers.patch @@ -0,0 +1,553 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:02 -0700 +Subject: [PATCH] lpfc: Refactor lpfc nvme headers +Git-commit: 9de977c42511150081661faad89e840c5b6bf2d8 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +A lot of files in lpfc include nvme headers, building up relationships that +require a file to change for its headers when there is no other change +necessary. It would be better to localize the nvme headers. + +There is also no need for separate nvme (initiator) and nvmet (tgt) +header files. + +Refactor the inclusion of nvme headers so that all nvme items are +included by lpfc_nvme.h + +Merge lpfc_nvmet.h into lpfc_nvme.h so that there is a single header used +by both the nvme and nvmet sides. This prepares for structure sharing +between the two roles. Prep to add shared function prototypes for upcoming +shared routines. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_attr.c | 3 - + drivers/scsi/lpfc/lpfc_ct.c | 1 - + drivers/scsi/lpfc/lpfc_debugfs.c | 3 - + drivers/scsi/lpfc/lpfc_hbadisc.c | 2 - + drivers/scsi/lpfc/lpfc_init.c | 3 - + drivers/scsi/lpfc/lpfc_mem.c | 4 - + drivers/scsi/lpfc/lpfc_nportdisc.c | 2 - + drivers/scsi/lpfc/lpfc_nvme.c | 3 - + drivers/scsi/lpfc/lpfc_nvme.h | 146 ++++++++++++++++++++++++++++++++++ + drivers/scsi/lpfc/lpfc_nvmet.c | 5 -- + drivers/scsi/lpfc/lpfc_nvmet.h | 158 ------------------------------------- + drivers/scsi/lpfc/lpfc_sli.c | 3 - + 12 files changed, 146 insertions(+), 187 deletions(-) + delete mode 100644 drivers/scsi/lpfc/lpfc_nvmet.h + +diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c +index 46f56f30f77e..ed59b12b3705 100644 +--- a/drivers/scsi/lpfc/lpfc_attr.c ++++ b/drivers/scsi/lpfc/lpfc_attr.c +@@ -37,8 +37,6 @@ + #include + #include + +-#include +- + #include "lpfc_hw4.h" + #include "lpfc_hw.h" + #include "lpfc_sli.h" +@@ -48,7 +46,6 @@ + #include "lpfc.h" + #include "lpfc_scsi.h" + #include "lpfc_nvme.h" +-#include "lpfc_nvmet.h" + #include "lpfc_logmsg.h" + #include "lpfc_version.h" + #include "lpfc_compat.h" +diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c +index 58b35a1442c1..dc48edb409b1 100644 +--- a/drivers/scsi/lpfc/lpfc_ct.c ++++ b/drivers/scsi/lpfc/lpfc_ct.c +@@ -44,7 +44,6 @@ + #include "lpfc_disc.h" + #include "lpfc.h" + #include "lpfc_scsi.h" +-#include "lpfc_nvme.h" + #include "lpfc_logmsg.h" + #include "lpfc_crtn.h" + #include "lpfc_version.h" +diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c +index 819335b16c2e..02420588ddd1 100644 +--- a/drivers/scsi/lpfc/lpfc_debugfs.c ++++ b/drivers/scsi/lpfc/lpfc_debugfs.c +@@ -39,8 +39,6 @@ + #include + #include + +-#include +- + #include "lpfc_hw4.h" + #include "lpfc_hw.h" + #include "lpfc_sli.h" +@@ -50,7 +48,6 @@ + #include "lpfc.h" + #include "lpfc_scsi.h" + #include "lpfc_nvme.h" +-#include "lpfc_nvmet.h" + #include "lpfc_logmsg.h" + #include "lpfc_crtn.h" + #include "lpfc_vport.h" +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index dcc8999c6a68..000a26d46f54 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -36,8 +36,6 @@ + #include + #include + +-#include +- + #include "lpfc_hw4.h" + #include "lpfc_hw.h" + #include "lpfc_nl.h" +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index 5a605773dd0a..994af5547ab3 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -50,8 +50,6 @@ + #include + #include + +-#include +- + #include "lpfc_hw4.h" + #include "lpfc_hw.h" + #include "lpfc_sli.h" +@@ -61,7 +59,6 @@ + #include "lpfc.h" + #include "lpfc_scsi.h" + #include "lpfc_nvme.h" +-#include "lpfc_nvmet.h" + #include "lpfc_logmsg.h" + #include "lpfc_crtn.h" + #include "lpfc_vport.h" +diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c +index 7082279e4c01..726f6619230f 100644 +--- a/drivers/scsi/lpfc/lpfc_mem.c ++++ b/drivers/scsi/lpfc/lpfc_mem.c +@@ -31,8 +31,6 @@ + #include + #include + +-#include +- + #include "lpfc_hw4.h" + #include "lpfc_hw.h" + #include "lpfc_sli.h" +@@ -41,8 +39,6 @@ + #include "lpfc_disc.h" + #include "lpfc.h" + #include "lpfc_scsi.h" +-#include "lpfc_nvme.h" +-#include "lpfc_nvmet.h" + #include "lpfc_crtn.h" + #include "lpfc_logmsg.h" + +diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c +index a024e5a3918f..81f4ba1c24b4 100644 +--- a/drivers/scsi/lpfc/lpfc_nportdisc.c ++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c +@@ -32,8 +32,6 @@ + #include + #include + +-#include +- + #include "lpfc_hw4.h" + #include "lpfc_hw.h" + #include "lpfc_sli.h" +diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c +index db4a04a207ec..12223a50be38 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.c ++++ b/drivers/scsi/lpfc/lpfc_nvme.c +@@ -36,9 +36,6 @@ + #include + #include + +-#include +-#include +-#include + #include "lpfc_version.h" + #include "lpfc_hw4.h" + #include "lpfc_hw.h" +diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h +index 593c48ff634e..e59dc1f5c18a 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.h ++++ b/drivers/scsi/lpfc/lpfc_nvme.h +@@ -21,6 +21,10 @@ + * included with this package. * + ********************************************************************/ + ++#include ++#include ++#include ++ + #define LPFC_NVME_DEFAULT_SEGS (64 + 1) /* 256K IOs */ + + #define LPFC_NVME_ERSP_LEN 0x20 +@@ -74,3 +78,145 @@ struct lpfc_nvme_rport { + struct lpfc_nvme_fcpreq_priv { + struct lpfc_io_buf *nvme_buf; + }; ++ ++ ++#define LPFC_NVMET_DEFAULT_SEGS (64 + 1) /* 256K IOs */ ++#define LPFC_NVMET_RQE_MIN_POST 128 ++#define LPFC_NVMET_RQE_DEF_POST 512 ++#define LPFC_NVMET_RQE_DEF_COUNT 2048 ++#define LPFC_NVMET_SUCCESS_LEN 12 ++ ++#define LPFC_NVMET_MRQ_AUTO 0 ++#define LPFC_NVMET_MRQ_MAX 16 ++ ++#define LPFC_NVMET_WAIT_TMO (5 * MSEC_PER_SEC) ++ ++/* Used for NVME Target */ ++struct lpfc_nvmet_tgtport { ++ struct lpfc_hba *phba; ++ struct completion *tport_unreg_cmp; ++ ++ /* Stats counters - lpfc_nvmet_unsol_ls_buffer */ ++ atomic_t rcv_ls_req_in; ++ atomic_t rcv_ls_req_out; ++ atomic_t rcv_ls_req_drop; ++ atomic_t xmt_ls_abort; ++ atomic_t xmt_ls_abort_cmpl; ++ ++ /* Stats counters - lpfc_nvmet_xmt_ls_rsp */ ++ atomic_t xmt_ls_rsp; ++ atomic_t xmt_ls_drop; ++ ++ /* Stats counters - lpfc_nvmet_xmt_ls_rsp_cmp */ ++ atomic_t xmt_ls_rsp_error; ++ atomic_t xmt_ls_rsp_aborted; ++ atomic_t xmt_ls_rsp_xb_set; ++ atomic_t xmt_ls_rsp_cmpl; ++ ++ /* Stats counters - lpfc_nvmet_unsol_fcp_buffer */ ++ atomic_t rcv_fcp_cmd_in; ++ atomic_t rcv_fcp_cmd_out; ++ atomic_t rcv_fcp_cmd_drop; ++ atomic_t rcv_fcp_cmd_defer; ++ atomic_t xmt_fcp_release; ++ ++ /* Stats counters - lpfc_nvmet_xmt_fcp_op */ ++ atomic_t xmt_fcp_drop; ++ atomic_t xmt_fcp_read_rsp; ++ atomic_t xmt_fcp_read; ++ atomic_t xmt_fcp_write; ++ atomic_t xmt_fcp_rsp; ++ ++ /* Stats counters - lpfc_nvmet_xmt_fcp_op_cmp */ ++ atomic_t xmt_fcp_rsp_xb_set; ++ atomic_t xmt_fcp_rsp_cmpl; ++ atomic_t xmt_fcp_rsp_error; ++ atomic_t xmt_fcp_rsp_aborted; ++ atomic_t xmt_fcp_rsp_drop; ++ ++ /* Stats counters - lpfc_nvmet_xmt_fcp_abort */ ++ atomic_t xmt_fcp_xri_abort_cqe; ++ atomic_t xmt_fcp_abort; ++ atomic_t xmt_fcp_abort_cmpl; ++ atomic_t xmt_abort_sol; ++ atomic_t xmt_abort_unsol; ++ atomic_t xmt_abort_rsp; ++ atomic_t xmt_abort_rsp_error; ++ ++ /* Stats counters - defer IO */ ++ atomic_t defer_ctx; ++ atomic_t defer_fod; ++ atomic_t defer_wqfull; ++}; ++ ++struct lpfc_nvmet_ctx_info { ++ struct list_head nvmet_ctx_list; ++ spinlock_t nvmet_ctx_list_lock; /* lock per CPU */ ++ struct lpfc_nvmet_ctx_info *nvmet_ctx_next_cpu; ++ struct lpfc_nvmet_ctx_info *nvmet_ctx_start_cpu; ++ uint16_t nvmet_ctx_list_cnt; ++ char pad[16]; /* pad to a cache-line */ ++}; ++ ++/* This retrieves the context info associated with the specified cpu / mrq */ ++#define lpfc_get_ctx_list(phba, cpu, mrq) \ ++ (phba->sli4_hba.nvmet_ctx_info + ((cpu * phba->cfg_nvmet_mrq) + mrq)) ++ ++struct lpfc_nvmet_rcv_ctx { ++ union { ++ struct nvmefc_ls_rsp ls_rsp; ++ struct nvmefc_tgt_fcp_req fcp_req; ++ } ctx; ++ struct list_head list; ++ struct lpfc_hba *phba; ++ struct lpfc_iocbq *wqeq; ++ struct lpfc_iocbq *abort_wqeq; ++ spinlock_t ctxlock; /* protect flag access */ ++ uint32_t sid; ++ uint32_t offset; ++ uint16_t oxid; ++ uint16_t size; ++ uint16_t entry_cnt; ++ uint16_t cpu; ++ uint16_t idx; ++ uint16_t state; ++ /* States */ ++#define LPFC_NVMET_STE_LS_RCV 1 ++#define LPFC_NVMET_STE_LS_ABORT 2 ++#define LPFC_NVMET_STE_LS_RSP 3 ++#define LPFC_NVMET_STE_RCV 4 ++#define LPFC_NVMET_STE_DATA 5 ++#define LPFC_NVMET_STE_ABORT 6 ++#define LPFC_NVMET_STE_DONE 7 ++#define LPFC_NVMET_STE_FREE 0xff ++ uint16_t flag; ++#define LPFC_NVMET_IO_INP 0x1 /* IO is in progress on exchange */ ++#define LPFC_NVMET_ABORT_OP 0x2 /* Abort WQE issued on exchange */ ++#define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */ ++#define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */ ++#define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ ++#define LPFC_NVMET_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */ ++#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ ++#define LPFC_NVMET_TNOTIFY 0x80 /* notify transport of abts */ ++ struct rqb_dmabuf *rqb_buffer; ++ struct lpfc_nvmet_ctxbuf *ctxbuf; ++ struct lpfc_sli4_hdw_queue *hdwq; ++ ++#ifdef CONFIG_SCSI_LPFC_DEBUG_FS ++ uint64_t ts_isr_cmd; ++ uint64_t ts_cmd_nvme; ++ uint64_t ts_nvme_data; ++ uint64_t ts_data_wqput; ++ uint64_t ts_isr_data; ++ uint64_t ts_data_nvme; ++ uint64_t ts_nvme_status; ++ uint64_t ts_status_wqput; ++ uint64_t ts_isr_status; ++ uint64_t ts_status_nvme; ++#endif ++}; ++ ++ ++/* routines found in lpfc_nvme.c */ ++ ++/* routines found in lpfc_nvmet.c */ +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c +index 47b983eddbb2..8d991466970f 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.c ++++ b/drivers/scsi/lpfc/lpfc_nvmet.c +@@ -36,10 +36,6 @@ + #include + #include + +-#include +-#include +-#include +- + #include "lpfc_version.h" + #include "lpfc_hw4.h" + #include "lpfc_hw.h" +@@ -50,7 +46,6 @@ + #include "lpfc.h" + #include "lpfc_scsi.h" + #include "lpfc_nvme.h" +-#include "lpfc_nvmet.h" + #include "lpfc_logmsg.h" + #include "lpfc_crtn.h" + #include "lpfc_vport.h" +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h +deleted file mode 100644 +index f0196f3ef90d..000000000000 +--- a/drivers/scsi/lpfc/lpfc_nvmet.h ++++ /dev/null +@@ -1,158 +0,0 @@ +-/******************************************************************* +- * This file is part of the Emulex Linux Device Driver for * +- * Fibre Channel Host Bus Adapters. * +- * Copyright (C) 2017-2019 Broadcom. All Rights Reserved. The term * +- * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * +- * Copyright (C) 2004-2016 Emulex. All rights reserved. * +- * EMULEX and SLI are trademarks of Emulex. * +- * www.broadcom.com * +- * Portions Copyright (C) 2004-2005 Christoph Hellwig * +- * * +- * This program is free software; you can redistribute it and/or * +- * modify it under the terms of version 2 of the GNU General * +- * Public License as published by the Free Software Foundation. * +- * This program is distributed in the hope that it will be useful. * +- * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * +- * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * +- * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * +- * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * +- * TO BE LEGALLY INVALID. See the GNU General Public License for * +- * more details, a copy of which can be found in the file COPYING * +- * included with this package. * +- ********************************************************************/ +- +-#define LPFC_NVMET_DEFAULT_SEGS (64 + 1) /* 256K IOs */ +-#define LPFC_NVMET_RQE_MIN_POST 128 +-#define LPFC_NVMET_RQE_DEF_POST 512 +-#define LPFC_NVMET_RQE_DEF_COUNT 2048 +-#define LPFC_NVMET_SUCCESS_LEN 12 +- +-#define LPFC_NVMET_MRQ_AUTO 0 +-#define LPFC_NVMET_MRQ_MAX 16 +- +-#define LPFC_NVMET_WAIT_TMO (5 * MSEC_PER_SEC) +- +-/* Used for NVME Target */ +-struct lpfc_nvmet_tgtport { +- struct lpfc_hba *phba; +- struct completion *tport_unreg_cmp; +- +- /* Stats counters - lpfc_nvmet_unsol_ls_buffer */ +- atomic_t rcv_ls_req_in; +- atomic_t rcv_ls_req_out; +- atomic_t rcv_ls_req_drop; +- atomic_t xmt_ls_abort; +- atomic_t xmt_ls_abort_cmpl; +- +- /* Stats counters - lpfc_nvmet_xmt_ls_rsp */ +- atomic_t xmt_ls_rsp; +- atomic_t xmt_ls_drop; +- +- /* Stats counters - lpfc_nvmet_xmt_ls_rsp_cmp */ +- atomic_t xmt_ls_rsp_error; +- atomic_t xmt_ls_rsp_aborted; +- atomic_t xmt_ls_rsp_xb_set; +- atomic_t xmt_ls_rsp_cmpl; +- +- /* Stats counters - lpfc_nvmet_unsol_fcp_buffer */ +- atomic_t rcv_fcp_cmd_in; +- atomic_t rcv_fcp_cmd_out; +- atomic_t rcv_fcp_cmd_drop; +- atomic_t rcv_fcp_cmd_defer; +- atomic_t xmt_fcp_release; +- +- /* Stats counters - lpfc_nvmet_xmt_fcp_op */ +- atomic_t xmt_fcp_drop; +- atomic_t xmt_fcp_read_rsp; +- atomic_t xmt_fcp_read; +- atomic_t xmt_fcp_write; +- atomic_t xmt_fcp_rsp; +- +- /* Stats counters - lpfc_nvmet_xmt_fcp_op_cmp */ +- atomic_t xmt_fcp_rsp_xb_set; +- atomic_t xmt_fcp_rsp_cmpl; +- atomic_t xmt_fcp_rsp_error; +- atomic_t xmt_fcp_rsp_aborted; +- atomic_t xmt_fcp_rsp_drop; +- +- /* Stats counters - lpfc_nvmet_xmt_fcp_abort */ +- atomic_t xmt_fcp_xri_abort_cqe; +- atomic_t xmt_fcp_abort; +- atomic_t xmt_fcp_abort_cmpl; +- atomic_t xmt_abort_sol; +- atomic_t xmt_abort_unsol; +- atomic_t xmt_abort_rsp; +- atomic_t xmt_abort_rsp_error; +- +- /* Stats counters - defer IO */ +- atomic_t defer_ctx; +- atomic_t defer_fod; +- atomic_t defer_wqfull; +-}; +- +-struct lpfc_nvmet_ctx_info { +- struct list_head nvmet_ctx_list; +- spinlock_t nvmet_ctx_list_lock; /* lock per CPU */ +- struct lpfc_nvmet_ctx_info *nvmet_ctx_next_cpu; +- struct lpfc_nvmet_ctx_info *nvmet_ctx_start_cpu; +- uint16_t nvmet_ctx_list_cnt; +- char pad[16]; /* pad to a cache-line */ +-}; +- +-/* This retrieves the context info associated with the specified cpu / mrq */ +-#define lpfc_get_ctx_list(phba, cpu, mrq) \ +- (phba->sli4_hba.nvmet_ctx_info + ((cpu * phba->cfg_nvmet_mrq) + mrq)) +- +-struct lpfc_nvmet_rcv_ctx { +- union { +- struct nvmefc_ls_rsp ls_rsp; +- struct nvmefc_tgt_fcp_req fcp_req; +- } ctx; +- struct list_head list; +- struct lpfc_hba *phba; +- struct lpfc_iocbq *wqeq; +- struct lpfc_iocbq *abort_wqeq; +- spinlock_t ctxlock; /* protect flag access */ +- uint32_t sid; +- uint32_t offset; +- uint16_t oxid; +- uint16_t size; +- uint16_t entry_cnt; +- uint16_t cpu; +- uint16_t idx; +- uint16_t state; +- /* States */ +-#define LPFC_NVMET_STE_LS_RCV 1 +-#define LPFC_NVMET_STE_LS_ABORT 2 +-#define LPFC_NVMET_STE_LS_RSP 3 +-#define LPFC_NVMET_STE_RCV 4 +-#define LPFC_NVMET_STE_DATA 5 +-#define LPFC_NVMET_STE_ABORT 6 +-#define LPFC_NVMET_STE_DONE 7 +-#define LPFC_NVMET_STE_FREE 0xff +- uint16_t flag; +-#define LPFC_NVMET_IO_INP 0x1 /* IO is in progress on exchange */ +-#define LPFC_NVMET_ABORT_OP 0x2 /* Abort WQE issued on exchange */ +-#define LPFC_NVMET_XBUSY 0x4 /* XB bit set on IO cmpl */ +-#define LPFC_NVMET_CTX_RLS 0x8 /* ctx free requested */ +-#define LPFC_NVMET_ABTS_RCV 0x10 /* ABTS received on exchange */ +-#define LPFC_NVMET_CTX_REUSE_WQ 0x20 /* ctx reused via WQ */ +-#define LPFC_NVMET_DEFER_WQFULL 0x40 /* Waiting on a free WQE */ +-#define LPFC_NVMET_TNOTIFY 0x80 /* notify transport of abts */ +- struct rqb_dmabuf *rqb_buffer; +- struct lpfc_nvmet_ctxbuf *ctxbuf; +- struct lpfc_sli4_hdw_queue *hdwq; +- +-#ifdef CONFIG_SCSI_LPFC_DEBUG_FS +- uint64_t ts_isr_cmd; +- uint64_t ts_cmd_nvme; +- uint64_t ts_nvme_data; +- uint64_t ts_data_wqput; +- uint64_t ts_isr_data; +- uint64_t ts_data_nvme; +- uint64_t ts_nvme_status; +- uint64_t ts_status_wqput; +- uint64_t ts_isr_status; +- uint64_t ts_status_nvme; +-#endif +-}; +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index 64002b0cb02d..b232be81bbd2 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -39,8 +39,6 @@ + #include + #endif + +-#include +- + #include "lpfc_hw4.h" + #include "lpfc_hw.h" + #include "lpfc_sli.h" +@@ -50,7 +48,6 @@ + #include "lpfc.h" + #include "lpfc_scsi.h" + #include "lpfc_nvme.h" +-#include "lpfc_nvmet.h" + #include "lpfc_crtn.h" + #include "lpfc_logmsg.h" + #include "lpfc_compat.h" +-- +2.16.4 + diff --git a/patches.suse/lpfc-Refactor-nvmet_rcv_ctx-to-create-lpfc_async_xch.patch b/patches.suse/lpfc-Refactor-nvmet_rcv_ctx-to-create-lpfc_async_xch.patch new file mode 100644 index 0000000..229e4b5 --- /dev/null +++ b/patches.suse/lpfc-Refactor-nvmet_rcv_ctx-to-create-lpfc_async_xch.patch @@ -0,0 +1,533 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:03 -0700 +Subject: [PATCH] lpfc: Refactor nvmet_rcv_ctx to create lpfc_async_xchg_ctx +Git-commit: d02f78f85f316a8bc492132bfab92def1cb4f1a6 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +To support FC-NVME-2 support (actually FC-NVME (rev 1) with Ammendment 1), +both the nvme (host) and nvmet (controller/target) sides will need to be +able to receive LS requests. Currently, this support is in the nvmet side +only. To prepare for both sides supporting LS receive, rename +lpfc_nvmet_rcv_ctx to lpfc_async_xchg_ctx and commonize the definition. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc.h | 2 +- + drivers/scsi/lpfc/lpfc_crtn.h | 1 - + drivers/scsi/lpfc/lpfc_debugfs.c | 2 +- + drivers/scsi/lpfc/lpfc_init.c | 2 +- + drivers/scsi/lpfc/lpfc_nvme.h | 7 +-- + drivers/scsi/lpfc/lpfc_nvmet.c | 109 ++++++++++++++++++++------------------- + drivers/scsi/lpfc/lpfc_sli.c | 2 +- + 7 files changed, 63 insertions(+), 62 deletions(-) + +diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h +index 04d73e2be373..8b0d8f390034 100644 +--- a/drivers/scsi/lpfc/lpfc.h ++++ b/drivers/scsi/lpfc/lpfc.h +@@ -143,7 +143,7 @@ struct lpfc_dmabuf { + + struct lpfc_nvmet_ctxbuf { + struct list_head list; +- struct lpfc_nvmet_rcv_ctx *context; ++ struct lpfc_async_xchg_ctx *context; + struct lpfc_iocbq *iocbq; + struct lpfc_sglq *sglq; + struct work_struct defer_work; +diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h +index 25d3dd39bc05..dc76729f8864 100644 +--- a/drivers/scsi/lpfc/lpfc_crtn.h ++++ b/drivers/scsi/lpfc/lpfc_crtn.h +@@ -24,7 +24,6 @@ typedef int (*node_filter)(struct lpfc_nodelist *, void *); + + struct fc_rport; + struct fc_frame_header; +-struct lpfc_nvmet_rcv_ctx; + void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *); + void lpfc_sli_read_link_ste(struct lpfc_hba *); + void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t); +diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c +index 02420588ddd1..9e87b8ccc8e6 100644 +--- a/drivers/scsi/lpfc/lpfc_debugfs.c ++++ b/drivers/scsi/lpfc/lpfc_debugfs.c +@@ -1032,7 +1032,7 @@ lpfc_debugfs_nvmestat_data(struct lpfc_vport *vport, char *buf, int size) + { + struct lpfc_hba *phba = vport->phba; + struct lpfc_nvmet_tgtport *tgtp; +- struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; ++ struct lpfc_async_xchg_ctx *ctxp, *next_ctxp; + struct nvme_fc_local_port *localport; + struct lpfc_fc4_ctrl_stat *cstat; + struct lpfc_nvme_lport *lport; +diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c +index 994af5547ab3..14964e8300d4 100644 +--- a/drivers/scsi/lpfc/lpfc_init.c ++++ b/drivers/scsi/lpfc/lpfc_init.c +@@ -1038,7 +1038,7 @@ static int + lpfc_hba_down_post_s4(struct lpfc_hba *phba) + { + struct lpfc_io_buf *psb, *psb_next; +- struct lpfc_nvmet_rcv_ctx *ctxp, *ctxp_next; ++ struct lpfc_async_xchg_ctx *ctxp, *ctxp_next; + struct lpfc_sli4_hdw_queue *qp; + LIST_HEAD(aborts); + LIST_HEAD(nvme_aborts); +diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h +index e59dc1f5c18a..be7d262f8cf3 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.h ++++ b/drivers/scsi/lpfc/lpfc_nvme.h +@@ -162,13 +162,14 @@ struct lpfc_nvmet_ctx_info { + #define lpfc_get_ctx_list(phba, cpu, mrq) \ + (phba->sli4_hba.nvmet_ctx_info + ((cpu * phba->cfg_nvmet_mrq) + mrq)) + +-struct lpfc_nvmet_rcv_ctx { ++struct lpfc_async_xchg_ctx { + union { +- struct nvmefc_ls_rsp ls_rsp; + struct nvmefc_tgt_fcp_req fcp_req; +- } ctx; ++ } hdlrctx; + struct list_head list; + struct lpfc_hba *phba; ++ struct nvmefc_ls_req *ls_req; ++ struct nvmefc_ls_rsp ls_rsp; + struct lpfc_iocbq *wqeq; + struct lpfc_iocbq *abort_wqeq; + spinlock_t ctxlock; /* protect flag access */ +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c +index 8d991466970f..ded7f973cad4 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.c ++++ b/drivers/scsi/lpfc/lpfc_nvmet.c +@@ -52,22 +52,22 @@ + #include "lpfc_debugfs.h" + + static struct lpfc_iocbq *lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *, +- struct lpfc_nvmet_rcv_ctx *, ++ struct lpfc_async_xchg_ctx *, + dma_addr_t rspbuf, + uint16_t rspsize); + static struct lpfc_iocbq *lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *, +- struct lpfc_nvmet_rcv_ctx *); ++ struct lpfc_async_xchg_ctx *); + static int lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *, +- struct lpfc_nvmet_rcv_ctx *, ++ struct lpfc_async_xchg_ctx *, + uint32_t, uint16_t); + static int lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *, +- struct lpfc_nvmet_rcv_ctx *, ++ struct lpfc_async_xchg_ctx *, + uint32_t, uint16_t); + static int lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *, +- struct lpfc_nvmet_rcv_ctx *, ++ struct lpfc_async_xchg_ctx *, + uint32_t, uint16_t); + static void lpfc_nvmet_wqfull_flush(struct lpfc_hba *, struct lpfc_queue *, +- struct lpfc_nvmet_rcv_ctx *); ++ struct lpfc_async_xchg_ctx *); + static void lpfc_nvmet_fcp_rqst_defer_work(struct work_struct *); + + static void lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf); +@@ -216,10 +216,10 @@ lpfc_nvmet_cmd_template(void) + } + + #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +-static struct lpfc_nvmet_rcv_ctx * ++static struct lpfc_async_xchg_ctx * + lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) + { +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + unsigned long iflag; + bool found = false; + +@@ -238,10 +238,10 @@ lpfc_nvmet_get_ctx_for_xri(struct lpfc_hba *phba, u16 xri) + return NULL; + } + +-static struct lpfc_nvmet_rcv_ctx * ++static struct lpfc_async_xchg_ctx * + lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid) + { +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + unsigned long iflag; + bool found = false; + +@@ -262,7 +262,8 @@ lpfc_nvmet_get_ctx_for_oxid(struct lpfc_hba *phba, u16 oxid, u32 sid) + #endif + + static void +-lpfc_nvmet_defer_release(struct lpfc_hba *phba, struct lpfc_nvmet_rcv_ctx *ctxp) ++lpfc_nvmet_defer_release(struct lpfc_hba *phba, ++ struct lpfc_async_xchg_ctx *ctxp) + { + lockdep_assert_held(&ctxp->ctxlock); + +@@ -298,7 +299,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + { + struct lpfc_nvmet_tgtport *tgtp; + struct nvmefc_ls_rsp *rsp; +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + uint32_t status, result; + + status = bf_get(lpfc_wcqe_c_status, wcqe); +@@ -330,7 +331,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + } + + out: +- rsp = &ctxp->ctx.ls_rsp; ++ rsp = &ctxp->ls_rsp; + + lpfc_nvmeio_data(phba, "NVMET LS CMPL: xri x%x stat x%x result x%x\n", + ctxp->oxid, status, result); +@@ -364,7 +365,7 @@ void + lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) + { + #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +- struct lpfc_nvmet_rcv_ctx *ctxp = ctx_buf->context; ++ struct lpfc_async_xchg_ctx *ctxp = ctx_buf->context; + struct lpfc_nvmet_tgtport *tgtp; + struct fc_frame_header *fc_hdr; + struct rqb_dmabuf *nvmebuf; +@@ -416,7 +417,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) + size = nvmebuf->bytes_recv; + sid = sli4_sid_from_fc_hdr(fc_hdr); + +- ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context; ++ ctxp = (struct lpfc_async_xchg_ctx *)ctx_buf->context; + ctxp->wqeq = NULL; + ctxp->offset = 0; + ctxp->phba = phba; +@@ -490,7 +491,7 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + static void + lpfc_nvmet_ktime(struct lpfc_hba *phba, +- struct lpfc_nvmet_rcv_ctx *ctxp) ++ struct lpfc_async_xchg_ctx *ctxp) + { + uint64_t seg1, seg2, seg3, seg4, seg5; + uint64_t seg6, seg7, seg8, seg9, seg10; +@@ -699,7 +700,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + { + struct lpfc_nvmet_tgtport *tgtp; + struct nvmefc_tgt_fcp_req *rsp; +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + uint32_t status, result, op, start_clean, logerr; + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + int id; +@@ -708,7 +709,7 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + ctxp = cmdwqe->context2; + ctxp->flag &= ~LPFC_NVMET_IO_INP; + +- rsp = &ctxp->ctx.fcp_req; ++ rsp = &ctxp->hdlrctx.fcp_req; + op = rsp->op; + + status = bf_get(lpfc_wcqe_c_status, wcqe); +@@ -827,8 +828,8 @@ static int + lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, + struct nvmefc_ls_rsp *rsp) + { +- struct lpfc_nvmet_rcv_ctx *ctxp = +- container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.ls_rsp); ++ struct lpfc_async_xchg_ctx *ctxp = ++ container_of(rsp, struct lpfc_async_xchg_ctx, ls_rsp); + struct lpfc_hba *phba = ctxp->phba; + struct hbq_dmabuf *nvmebuf = + (struct hbq_dmabuf *)ctxp->rqb_buffer; +@@ -918,8 +919,8 @@ lpfc_nvmet_xmt_fcp_op(struct nvmet_fc_target_port *tgtport, + struct nvmefc_tgt_fcp_req *rsp) + { + struct lpfc_nvmet_tgtport *lpfc_nvmep = tgtport->private; +- struct lpfc_nvmet_rcv_ctx *ctxp = +- container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); ++ struct lpfc_async_xchg_ctx *ctxp = ++ container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); + struct lpfc_hba *phba = ctxp->phba; + struct lpfc_queue *wq; + struct lpfc_iocbq *nvmewqeq; +@@ -1052,8 +1053,8 @@ lpfc_nvmet_xmt_fcp_abort(struct nvmet_fc_target_port *tgtport, + struct nvmefc_tgt_fcp_req *req) + { + struct lpfc_nvmet_tgtport *lpfc_nvmep = tgtport->private; +- struct lpfc_nvmet_rcv_ctx *ctxp = +- container_of(req, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); ++ struct lpfc_async_xchg_ctx *ctxp = ++ container_of(req, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); + struct lpfc_hba *phba = ctxp->phba; + struct lpfc_queue *wq; + unsigned long flags; +@@ -1114,8 +1115,8 @@ lpfc_nvmet_xmt_fcp_release(struct nvmet_fc_target_port *tgtport, + struct nvmefc_tgt_fcp_req *rsp) + { + struct lpfc_nvmet_tgtport *lpfc_nvmep = tgtport->private; +- struct lpfc_nvmet_rcv_ctx *ctxp = +- container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); ++ struct lpfc_async_xchg_ctx *ctxp = ++ container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); + struct lpfc_hba *phba = ctxp->phba; + unsigned long flags; + bool aborting = false; +@@ -1157,8 +1158,8 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, + struct nvmefc_tgt_fcp_req *rsp) + { + struct lpfc_nvmet_tgtport *tgtp; +- struct lpfc_nvmet_rcv_ctx *ctxp = +- container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.fcp_req); ++ struct lpfc_async_xchg_ctx *ctxp = ++ container_of(rsp, struct lpfc_async_xchg_ctx, hdlrctx.fcp_req); + struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; + struct lpfc_hba *phba = ctxp->phba; + unsigned long iflag; +@@ -1564,7 +1565,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, + #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); + uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); +- struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; ++ struct lpfc_async_xchg_ctx *ctxp, *next_ctxp; + struct lpfc_nvmet_tgtport *tgtp; + struct nvmefc_tgt_fcp_req *req = NULL; + struct lpfc_nodelist *ndlp; +@@ -1650,7 +1651,7 @@ lpfc_sli4_nvmet_xri_aborted(struct lpfc_hba *phba, + "NVMET ABTS RCV: xri x%x CPU %02x rjt %d\n", + xri, raw_smp_processor_id(), 0); + +- req = &ctxp->ctx.fcp_req; ++ req = &ctxp->hdlrctx.fcp_req; + if (req) + nvmet_fc_rcv_fcp_abort(phba->targetport, req); + } +@@ -1663,7 +1664,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, + { + #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + struct lpfc_hba *phba = vport->phba; +- struct lpfc_nvmet_rcv_ctx *ctxp, *next_ctxp; ++ struct lpfc_async_xchg_ctx *ctxp, *next_ctxp; + struct nvmefc_tgt_fcp_req *rsp; + uint32_t sid; + uint16_t oxid, xri; +@@ -1696,7 +1697,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, + "6319 NVMET Rcv ABTS:acc xri x%x\n", xri); + +- rsp = &ctxp->ctx.fcp_req; ++ rsp = &ctxp->hdlrctx.fcp_req; + nvmet_fc_rcv_fcp_abort(phba->targetport, rsp); + + /* Respond with BA_ACC accordingly */ +@@ -1770,7 +1771,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, + if (ctxp->flag & LPFC_NVMET_TNOTIFY) { + /* Notify the transport */ + nvmet_fc_rcv_fcp_abort(phba->targetport, +- &ctxp->ctx.fcp_req); ++ &ctxp->hdlrctx.fcp_req); + } else { + cancel_work_sync(&ctxp->ctxbuf->defer_work); + spin_lock_irqsave(&ctxp->ctxlock, iflag); +@@ -1798,7 +1799,7 @@ lpfc_nvmet_rcv_unsol_abort(struct lpfc_vport *vport, + + static void + lpfc_nvmet_wqfull_flush(struct lpfc_hba *phba, struct lpfc_queue *wq, +- struct lpfc_nvmet_rcv_ctx *ctxp) ++ struct lpfc_async_xchg_ctx *ctxp) + { + struct lpfc_sli_ring *pring; + struct lpfc_iocbq *nvmewqeq; +@@ -1849,7 +1850,7 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, + #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + struct lpfc_sli_ring *pring; + struct lpfc_iocbq *nvmewqeq; +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + unsigned long iflags; + int rc; + +@@ -1863,7 +1864,7 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, + list_remove_head(&wq->wqfull_list, nvmewqeq, struct lpfc_iocbq, + list); + spin_unlock_irqrestore(&pring->ring_lock, iflags); +- ctxp = (struct lpfc_nvmet_rcv_ctx *)nvmewqeq->context2; ++ ctxp = (struct lpfc_async_xchg_ctx *)nvmewqeq->context2; + rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, nvmewqeq); + spin_lock_irqsave(&pring->ring_lock, iflags); + if (rc == -EBUSY) { +@@ -1875,7 +1876,7 @@ lpfc_nvmet_wqfull_process(struct lpfc_hba *phba, + if (rc == WQE_SUCCESS) { + #ifdef CONFIG_SCSI_LPFC_DEBUG_FS + if (ctxp->ts_cmd_nvme) { +- if (ctxp->ctx.fcp_req.op == NVMET_FCOP_RSP) ++ if (ctxp->hdlrctx.fcp_req.op == NVMET_FCOP_RSP) + ctxp->ts_status_wqput = ktime_get_ns(); + else + ctxp->ts_data_wqput = ktime_get_ns(); +@@ -1941,7 +1942,7 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) + struct lpfc_nvmet_tgtport *tgtp; + struct fc_frame_header *fc_hdr; +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + uint32_t *payload; + uint32_t size, oxid, sid, rc; + +@@ -1964,7 +1965,7 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + size = bf_get(lpfc_rcqe_length, &nvmebuf->cq_event.cqe.rcqe_cmpl); + sid = sli4_sid_from_fc_hdr(fc_hdr); + +- ctxp = kzalloc(sizeof(struct lpfc_nvmet_rcv_ctx), GFP_ATOMIC); ++ ctxp = kzalloc(sizeof(struct lpfc_async_xchg_ctx), GFP_ATOMIC); + if (ctxp == NULL) { + atomic_inc(&tgtp->rcv_ls_req_drop); + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, +@@ -1995,7 +1996,7 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + * lpfc_nvmet_xmt_ls_rsp_cmp should free the allocated ctxp. + */ + atomic_inc(&tgtp->rcv_ls_req_in); +- rc = nvmet_fc_rcv_ls_req(phba->targetport, NULL, &ctxp->ctx.ls_rsp, ++ rc = nvmet_fc_rcv_ls_req(phba->targetport, NULL, &ctxp->ls_rsp, + payload, size); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, +@@ -2029,7 +2030,7 @@ static void + lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) + { + #if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) +- struct lpfc_nvmet_rcv_ctx *ctxp = ctx_buf->context; ++ struct lpfc_async_xchg_ctx *ctxp = ctx_buf->context; + struct lpfc_hba *phba = ctxp->phba; + struct rqb_dmabuf *nvmebuf = ctxp->rqb_buffer; + struct lpfc_nvmet_tgtport *tgtp; +@@ -2073,7 +2074,7 @@ lpfc_nvmet_process_rcv_fcp_req(struct lpfc_nvmet_ctxbuf *ctx_buf) + * A buffer has already been reposted for this IO, so just free + * the nvmebuf. + */ +- rc = nvmet_fc_rcv_fcp_req(phba->targetport, &ctxp->ctx.fcp_req, ++ rc = nvmet_fc_rcv_fcp_req(phba->targetport, &ctxp->hdlrctx.fcp_req, + payload, ctxp->size); + /* Process FCP command */ + if (rc == 0) { +@@ -2220,7 +2221,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, + uint64_t isr_timestamp, + uint8_t cqflag) + { +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + struct lpfc_nvmet_tgtport *tgtp; + struct fc_frame_header *fc_hdr; + struct lpfc_nvmet_ctxbuf *ctx_buf; +@@ -2304,7 +2305,7 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, + + sid = sli4_sid_from_fc_hdr(fc_hdr); + +- ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context; ++ ctxp = (struct lpfc_async_xchg_ctx *)ctx_buf->context; + spin_lock_irqsave(&phba->sli4_hba.t_active_list_lock, iflag); + list_add_tail(&ctxp->list, &phba->sli4_hba.t_active_ctx_list); + spin_unlock_irqrestore(&phba->sli4_hba.t_active_list_lock, iflag); +@@ -2460,7 +2461,7 @@ lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, + **/ + static struct lpfc_iocbq * + lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, +- struct lpfc_nvmet_rcv_ctx *ctxp, ++ struct lpfc_async_xchg_ctx *ctxp, + dma_addr_t rspbuf, uint16_t rspsize) + { + struct lpfc_nodelist *ndlp; +@@ -2582,9 +2583,9 @@ lpfc_nvmet_prep_ls_wqe(struct lpfc_hba *phba, + + static struct lpfc_iocbq * + lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, +- struct lpfc_nvmet_rcv_ctx *ctxp) ++ struct lpfc_async_xchg_ctx *ctxp) + { +- struct nvmefc_tgt_fcp_req *rsp = &ctxp->ctx.fcp_req; ++ struct nvmefc_tgt_fcp_req *rsp = &ctxp->hdlrctx.fcp_req; + struct lpfc_nvmet_tgtport *tgtp; + struct sli4_sge *sgl; + struct lpfc_nodelist *ndlp; +@@ -2928,7 +2929,7 @@ static void + lpfc_nvmet_sol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + struct lpfc_wcqe_complete *wcqe) + { +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + struct lpfc_nvmet_tgtport *tgtp; + uint32_t result; + unsigned long flags; +@@ -2997,7 +2998,7 @@ static void + lpfc_nvmet_unsol_fcp_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + struct lpfc_wcqe_complete *wcqe) + { +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + struct lpfc_nvmet_tgtport *tgtp; + unsigned long flags; + uint32_t result; +@@ -3078,7 +3079,7 @@ static void + lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + struct lpfc_wcqe_complete *wcqe) + { +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + struct lpfc_nvmet_tgtport *tgtp; + uint32_t result; + +@@ -3119,7 +3120,7 @@ lpfc_nvmet_xmt_ls_abort_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + + static int + lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, +- struct lpfc_nvmet_rcv_ctx *ctxp, ++ struct lpfc_async_xchg_ctx *ctxp, + uint32_t sid, uint16_t xri) + { + struct lpfc_nvmet_tgtport *tgtp; +@@ -3214,7 +3215,7 @@ lpfc_nvmet_unsol_issue_abort(struct lpfc_hba *phba, + + static int + lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, +- struct lpfc_nvmet_rcv_ctx *ctxp, ++ struct lpfc_async_xchg_ctx *ctxp, + uint32_t sid, uint16_t xri) + { + struct lpfc_nvmet_tgtport *tgtp; +@@ -3340,7 +3341,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, + + static int + lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, +- struct lpfc_nvmet_rcv_ctx *ctxp, ++ struct lpfc_async_xchg_ctx *ctxp, + uint32_t sid, uint16_t xri) + { + struct lpfc_nvmet_tgtport *tgtp; +@@ -3405,7 +3406,7 @@ lpfc_nvmet_unsol_fcp_issue_abort(struct lpfc_hba *phba, + + static int + lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, +- struct lpfc_nvmet_rcv_ctx *ctxp, ++ struct lpfc_async_xchg_ctx *ctxp, + uint32_t sid, uint16_t xri) + { + struct lpfc_nvmet_tgtport *tgtp; +diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c +index b232be81bbd2..730a8ea4ad94 100644 +--- a/drivers/scsi/lpfc/lpfc_sli.c ++++ b/drivers/scsi/lpfc/lpfc_sli.c +@@ -19913,7 +19913,7 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, + struct lpfc_iocbq *pwqe) + { + union lpfc_wqe128 *wqe = &pwqe->wqe; +- struct lpfc_nvmet_rcv_ctx *ctxp; ++ struct lpfc_async_xchg_ctx *ctxp; + struct lpfc_queue *wq; + struct lpfc_sglq *sglq; + struct lpfc_sli_ring *pring; +-- +2.16.4 + diff --git a/patches.suse/lpfc-nvme-Add-Receive-LS-Request-and-Send-LS-Respons.patch b/patches.suse/lpfc-nvme-Add-Receive-LS-Request-and-Send-LS-Respons.patch new file mode 100644 index 0000000..8c29425 --- /dev/null +++ b/patches.suse/lpfc-nvme-Add-Receive-LS-Request-and-Send-LS-Respons.patch @@ -0,0 +1,137 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:09 -0700 +Subject: [PATCH] lpfc: nvme: Add Receive LS Request and Send LS Response +Git-commit: 0fecf788e2df75ce19038455c1348286c969b952 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + support to nvme + +Now that common helpers exist, add the ability to receive NVME LS requests +to the driver. New requests will be delivered to the transport by +nvme_fc_rcv_ls_req(). + +In order to complete the LS, add support for Send LS Response and send +LS response completion handling to the driver. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_nvme.c | 71 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 71 insertions(+) + +diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c +index 776ee547740a..f36b93549a9a 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.c ++++ b/drivers/scsi/lpfc/lpfc_nvme.c +@@ -400,6 +400,10 @@ lpfc_nvme_remoteport_delete(struct nvme_fc_remote_port *remoteport) + * request. Any remaining validation is done and the LS is then forwarded + * to the nvme-fc transport via nvme_fc_rcv_ls_req(). + * ++ * The calling sequence should be: nvme_fc_rcv_ls_req() -> (processing) ++ * -> lpfc_nvme_xmt_ls_rsp/cmp -> req->done. ++ * __lpfc_nvme_xmt_ls_rsp_cmp should free the allocated axchg. ++ * + * Returns 0 if LS was handled and delivered to the transport + * Returns 1 if LS failed to be handled and should be dropped + */ +@@ -407,6 +411,40 @@ int + lpfc_nvme_handle_lsreq(struct lpfc_hba *phba, + struct lpfc_async_xchg_ctx *axchg) + { ++#if (IS_ENABLED(CONFIG_NVME_FC)) ++ struct lpfc_vport *vport; ++ struct lpfc_nvme_rport *lpfc_rport; ++ struct nvme_fc_remote_port *remoteport; ++ struct lpfc_nvme_lport *lport; ++ uint32_t *payload = axchg->payload; ++ int rc; ++ ++ vport = axchg->ndlp->vport; ++ lpfc_rport = axchg->ndlp->nrport; ++ if (!lpfc_rport) ++ return -EINVAL; ++ ++ remoteport = lpfc_rport->remoteport; ++ if (!vport->localport) ++ return -EINVAL; ++ ++ lport = vport->localport->private; ++ if (!lport) ++ return -EINVAL; ++ ++ rc = nvme_fc_rcv_ls_req(remoteport, &axchg->ls_rsp, axchg->payload, ++ axchg->size); ++ ++ lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, ++ "6205 NVME Unsol rcv: sz %d rc %d: %08x %08x %08x " ++ "%08x %08x %08x\n", ++ axchg->size, rc, ++ *payload, *(payload+1), *(payload+2), ++ *(payload+3), *(payload+4), *(payload+5)); ++ ++ if (!rc) ++ return 0; ++#endif + return 1; + } + +@@ -858,6 +896,37 @@ __lpfc_nvme_ls_abort(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + return 1; + } + ++static int ++lpfc_nvme_xmt_ls_rsp(struct nvme_fc_local_port *localport, ++ struct nvme_fc_remote_port *remoteport, ++ struct nvmefc_ls_rsp *ls_rsp) ++{ ++ struct lpfc_async_xchg_ctx *axchg = ++ container_of(ls_rsp, struct lpfc_async_xchg_ctx, ls_rsp); ++ struct lpfc_nvme_lport *lport; ++ int rc; ++ ++ if (axchg->phba->pport->load_flag & FC_UNLOADING) ++ return -ENODEV; ++ ++ lport = (struct lpfc_nvme_lport *)localport->private; ++ ++ rc = __lpfc_nvme_xmt_ls_rsp(axchg, ls_rsp, __lpfc_nvme_xmt_ls_rsp_cmp); ++ ++ if (rc) { ++ /* ++ * unless the failure is due to having already sent ++ * the response, an abort will be generated for the ++ * exchange if the rsp can't be sent. ++ */ ++ if (rc != -EALREADY) ++ atomic_inc(&lport->xmt_ls_abort); ++ return rc; ++ } ++ ++ return 0; ++} ++ + /** + * lpfc_nvme_ls_abort - Abort a prior NVME LS request + * @lpfc_nvme_lport: Transport localport that LS is to be issued from. +@@ -2088,6 +2157,7 @@ static struct nvme_fc_port_template lpfc_nvme_template = { + .fcp_io = lpfc_nvme_fcp_io_submit, + .ls_abort = lpfc_nvme_ls_abort, + .fcp_abort = lpfc_nvme_fcp_abort, ++ .xmt_ls_rsp = lpfc_nvme_xmt_ls_rsp, + + .max_hw_queues = 1, + .max_sgl_segments = LPFC_NVME_DEFAULT_SEGS, +@@ -2283,6 +2353,7 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) + atomic_set(&lport->cmpl_fcp_err, 0); + atomic_set(&lport->cmpl_ls_xb, 0); + atomic_set(&lport->cmpl_ls_err, 0); ++ + atomic_set(&lport->fc4NvmeLsRequests, 0); + atomic_set(&lport->fc4NvmeLsCmpls, 0); + } +-- +2.16.4 + diff --git a/patches.suse/lpfc-nvmet-Add-Send-LS-Request-and-Abort-LS-Request-.patch b/patches.suse/lpfc-nvmet-Add-Send-LS-Request-and-Abort-LS-Request-.patch new file mode 100644 index 0000000..d7205c4 --- /dev/null +++ b/patches.suse/lpfc-nvmet-Add-Send-LS-Request-and-Abort-LS-Request-.patch @@ -0,0 +1,142 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:11 -0700 +Subject: [PATCH] lpfc: nvmet: Add Send LS Request and Abort LS Request support +Git-commit: a0df837e0cabc01224333e37704008a4fdedc899 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Now that common helpers exist, add the ability to Send an NVME LS Request +and to Abort an outstanding LS Request to the nvmet side of the driver. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_nvmet.c | 95 ++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 95 insertions(+) + +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c +index df0378fd4b59..0d137ce7aa0b 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.c ++++ b/drivers/scsi/lpfc/lpfc_nvmet.c +@@ -1283,6 +1283,98 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + } + ++/** ++ * lpfc_nvmet_ls_req_cmp - completion handler for a nvme ls request ++ * @phba: Pointer to HBA context object ++ * @cmdwqe: Pointer to driver command WQE object. ++ * @wcqe: Pointer to driver response CQE object. ++ * ++ * This function is the completion handler for NVME LS requests. ++ * The function updates any states and statistics, then calls the ++ * generic completion handler to finish completion of the request. ++ **/ ++static void ++lpfc_nvmet_ls_req_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, ++ struct lpfc_wcqe_complete *wcqe) ++{ ++ __lpfc_nvme_ls_req_cmp(phba, cmdwqe->vport, cmdwqe, wcqe); ++} ++ ++/** ++ * lpfc_nvmet_ls_req - Issue an Link Service request ++ * @targetport - pointer to target instance registered with nvmet transport. ++ * @hosthandle - hosthandle set by the driver in a prior ls_rqst_rcv. ++ * Driver sets this value to the ndlp pointer. ++ * @pnvme_lsreq - the transport nvme_ls_req structure for the LS ++ * ++ * Driver registers this routine to handle any link service request ++ * from the nvme_fc transport to a remote nvme-aware port. ++ * ++ * Return value : ++ * 0 - Success ++ * non-zero: various error codes, in form of -Exxx ++ **/ ++static int ++lpfc_nvmet_ls_req(struct nvmet_fc_target_port *targetport, ++ void *hosthandle, ++ struct nvmefc_ls_req *pnvme_lsreq) ++{ ++ struct lpfc_nvmet_tgtport *lpfc_nvmet = targetport->private; ++ struct lpfc_hba *phba; ++ struct lpfc_nodelist *ndlp; ++ int ret; ++ u32 hstate; ++ ++ if (!lpfc_nvmet) ++ return -EINVAL; ++ ++ phba = lpfc_nvmet->phba; ++ if (phba->pport->load_flag & FC_UNLOADING) ++ return -EINVAL; ++ ++ hstate = atomic_read(&lpfc_nvmet->state); ++ if (hstate == LPFC_NVMET_INV_HOST_ACTIVE) ++ return -EACCES; ++ ++ ndlp = (struct lpfc_nodelist *)hosthandle; ++ ++ ret = __lpfc_nvme_ls_req(phba->pport, ndlp, pnvme_lsreq, ++ lpfc_nvmet_ls_req_cmp); ++ ++ return ret; ++} ++ ++/** ++ * lpfc_nvmet_ls_abort - Abort a prior NVME LS request ++ * @targetport: Transport targetport, that LS was issued from. ++ * @hosthandle - hosthandle set by the driver in a prior ls_rqst_rcv. ++ * Driver sets this value to the ndlp pointer. ++ * @pnvme_lsreq - the transport nvme_ls_req structure for LS to be aborted ++ * ++ * Driver registers this routine to abort an NVME LS request that is ++ * in progress (from the transports perspective). ++ **/ ++static void ++lpfc_nvmet_ls_abort(struct nvmet_fc_target_port *targetport, ++ void *hosthandle, ++ struct nvmefc_ls_req *pnvme_lsreq) ++{ ++ struct lpfc_nvmet_tgtport *lpfc_nvmet = targetport->private; ++ struct lpfc_hba *phba; ++ struct lpfc_nodelist *ndlp; ++ int ret; ++ ++ phba = lpfc_nvmet->phba; ++ if (phba->pport->load_flag & FC_UNLOADING) ++ return; ++ ++ ndlp = (struct lpfc_nodelist *)hosthandle; ++ ++ ret = __lpfc_nvme_ls_abort(phba->pport, ndlp, pnvme_lsreq); ++ if (!ret) ++ atomic_inc(&lpfc_nvmet->xmt_ls_abort); ++} ++ + static void + lpfc_nvmet_host_release(void *hosthandle) + { +@@ -1325,6 +1417,8 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = { + .fcp_req_release = lpfc_nvmet_xmt_fcp_release, + .defer_rcv = lpfc_nvmet_defer_rcv, + .discovery_event = lpfc_nvmet_discovery_event, ++ .ls_req = lpfc_nvmet_ls_req, ++ .ls_abort = lpfc_nvmet_ls_abort, + .host_release = lpfc_nvmet_host_release, + + .max_hw_queues = 1, +@@ -1336,6 +1430,7 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = { + .target_features = 0, + /* sizes of additional private data for data structures */ + .target_priv_sz = sizeof(struct lpfc_nvmet_tgtport), ++ .lsrqst_priv_sz = 0, + }; + + static void +-- +2.16.4 + diff --git a/patches.suse/lpfc-nvmet-Add-support-for-NVME-LS-request-hosthandl.patch b/patches.suse/lpfc-nvmet-Add-support-for-NVME-LS-request-hosthandl.patch new file mode 100644 index 0000000..d6314b0 --- /dev/null +++ b/patches.suse/lpfc-nvmet-Add-support-for-NVME-LS-request-hosthandl.patch @@ -0,0 +1,199 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:10 -0700 +Subject: [PATCH] lpfc: nvmet: Add support for NVME LS request hosthandle +Git-commit: 99d73379619cfcb6236b000ed77987c8f69521d1 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +As the nvmet layer does not have the concept of a remoteport object, which +can be used to identify the entity on the other end of the fabric that is +to receive an LS, the hosthandle was introduced. The driver passes the +hosthandle, a value representative of the remote port, with a ls request +receive. The LS request will create the association. The transport will +remember the hosthandle for the association, and if there is a need to +initiate a LS request to the remote port for the association, the +hosthandle will be used. When the driver loses connectivity with the +remote port, it needs to notify the transport that the hosthandle is no +longer valid, allowing the transport to terminate associations related to +the hosthandle. + +This patch adds support to the driver for the hosthandle. The driver will +use the ndlp pointer of the remote port for the hosthandle in calls to +nvmet_fc_rcv_ls_req(). The discovery engine is updated to invalidate the +hosthandle whenever connectivity with the remote port is lost. + +Signed-off-by: Paul Ely +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/scsi/lpfc/lpfc_crtn.h | 2 ++ + drivers/scsi/lpfc/lpfc_hbadisc.c | 6 +++++ + drivers/scsi/lpfc/lpfc_nportdisc.c | 11 ++++++++ + drivers/scsi/lpfc/lpfc_nvme.h | 3 +++ + drivers/scsi/lpfc/lpfc_nvmet.c | 53 +++++++++++++++++++++++++++++++++++++- + 5 files changed, 74 insertions(+), 1 deletion(-) + +diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h +index 51b0f01c6206..6bccad7106ee 100644 +--- a/drivers/scsi/lpfc/lpfc_crtn.h ++++ b/drivers/scsi/lpfc/lpfc_crtn.h +@@ -572,6 +572,8 @@ void lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint32_t idx, + struct rqb_dmabuf *nvmebuf, uint64_t isr_ts, + uint8_t cqflag); + void lpfc_nvme_mod_param_dep(struct lpfc_hba *phba); ++void lpfc_nvmet_invalidate_host(struct lpfc_hba *phba, ++ struct lpfc_nodelist *ndlp); + void lpfc_nvme_abort_fcreq_cmpl(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocb, + struct lpfc_wcqe_complete *abts_cmpl); +diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c +index 000a26d46f54..b2278df447d3 100644 +--- a/drivers/scsi/lpfc/lpfc_hbadisc.c ++++ b/drivers/scsi/lpfc/lpfc_hbadisc.c +@@ -823,6 +823,12 @@ lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) + if ((phba->sli_rev < LPFC_SLI_REV4) && + (!remove && ndlp->nlp_type & NLP_FABRIC)) + continue; ++ ++ /* Notify transport of connectivity loss to trigger cleanup. */ ++ if (phba->nvmet_support && ++ ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ++ lpfc_nvmet_invalidate_host(phba, ndlp); ++ + lpfc_disc_state_machine(vport, ndlp, NULL, + remove + ? NLP_EVT_DEVICE_RM +diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c +index 81f4ba1c24b4..d8501bd959e7 100644 +--- a/drivers/scsi/lpfc/lpfc_nportdisc.c ++++ b/drivers/scsi/lpfc/lpfc_nportdisc.c +@@ -489,6 +489,11 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + (unsigned long long) + wwn_to_u64(sp->portName.u.wwn)); + ++ /* Notify transport of connectivity loss to trigger cleanup. */ ++ if (phba->nvmet_support && ++ ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ++ lpfc_nvmet_invalidate_host(phba, ndlp); ++ + ndlp->nlp_prev_state = ndlp->nlp_state; + /* rport needs to be unregistered first */ + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); +@@ -839,6 +844,12 @@ lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); + else + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); ++ ++ /* Notify transport of connectivity loss to trigger cleanup. */ ++ if (phba->nvmet_support && ++ ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) ++ lpfc_nvmet_invalidate_host(phba, ndlp); ++ + if (ndlp->nlp_DID == Fabric_DID) { + if (vport->port_state <= LPFC_FDISC) + goto out; +diff --git a/drivers/scsi/lpfc/lpfc_nvme.h b/drivers/scsi/lpfc/lpfc_nvme.h +index f28a6789e252..4a4c3f780e1f 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.h ++++ b/drivers/scsi/lpfc/lpfc_nvme.h +@@ -98,9 +98,12 @@ struct lpfc_nvme_fcpreq_priv { + #define LPFC_NVMET_WAIT_TMO (5 * MSEC_PER_SEC) + + /* Used for NVME Target */ ++#define LPFC_NVMET_INV_HOST_ACTIVE 1 ++ + struct lpfc_nvmet_tgtport { + struct lpfc_hba *phba; + struct completion *tport_unreg_cmp; ++ atomic_t state; /* tracks nvmet hosthandle invalidation */ + + /* Stats counters - lpfc_nvmet_unsol_ls_buffer */ + atomic_t rcv_ls_req_in; +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c +index edec7c3ffab1..df0378fd4b59 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.c ++++ b/drivers/scsi/lpfc/lpfc_nvmet.c +@@ -1283,6 +1283,24 @@ lpfc_nvmet_defer_rcv(struct nvmet_fc_target_port *tgtport, + spin_unlock_irqrestore(&ctxp->ctxlock, iflag); + } + ++static void ++lpfc_nvmet_host_release(void *hosthandle) ++{ ++ struct lpfc_nodelist *ndlp = hosthandle; ++ struct lpfc_hba *phba = NULL; ++ struct lpfc_nvmet_tgtport *tgtp; ++ ++ phba = ndlp->phba; ++ if (!phba->targetport || !phba->targetport->private) ++ return; ++ ++ lpfc_printf_log(phba, KERN_ERR, LOG_NVME, ++ "6202 NVMET XPT releasing hosthandle x%px\n", ++ hosthandle); ++ tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; ++ atomic_set(&tgtp->state, 0); ++} ++ + static void + lpfc_nvmet_discovery_event(struct nvmet_fc_target_port *tgtport) + { +@@ -1307,6 +1325,7 @@ static struct nvmet_fc_target_template lpfc_tgttemplate = { + .fcp_req_release = lpfc_nvmet_xmt_fcp_release, + .defer_rcv = lpfc_nvmet_defer_rcv, + .discovery_event = lpfc_nvmet_discovery_event, ++ .host_release = lpfc_nvmet_host_release, + + .max_hw_queues = 1, + .max_sgl_segments = LPFC_NVMET_DEFAULT_SEGS, +@@ -2045,7 +2064,12 @@ lpfc_nvmet_handle_lsreq(struct lpfc_hba *phba, + + atomic_inc(&tgtp->rcv_ls_req_in); + +- rc = nvmet_fc_rcv_ls_req(phba->targetport, NULL, &axchg->ls_rsp, ++ /* ++ * Driver passes the ndlp as the hosthandle argument allowing ++ * the transport to generate LS requests for any associateions ++ * that are created. ++ */ ++ rc = nvmet_fc_rcv_ls_req(phba->targetport, axchg->ndlp, &axchg->ls_rsp, + axchg->payload, axchg->size); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, +@@ -3478,3 +3502,30 @@ lpfc_nvme_unsol_ls_issue_abort(struct lpfc_hba *phba, + "6056 Failed to Issue ABTS. Status x%x\n", rc); + return 0; + } ++ ++/** ++ * lpfc_nvmet_invalidate_host ++ * ++ * @phba - pointer to the driver instance bound to an adapter port. ++ * @ndlp - pointer to an lpfc_nodelist type ++ * ++ * This routine upcalls the nvmet transport to invalidate an NVME ++ * host to which this target instance had active connections. ++ */ ++void ++lpfc_nvmet_invalidate_host(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) ++{ ++ struct lpfc_nvmet_tgtport *tgtp; ++ ++ lpfc_printf_log(phba, KERN_INFO, LOG_NVME | LOG_NVME_ABTS, ++ "6203 Invalidating hosthandle x%px\n", ++ ndlp); ++ ++ tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; ++ atomic_set(&tgtp->state, LPFC_NVMET_INV_HOST_ACTIVE); ++ ++#if (IS_ENABLED(CONFIG_NVME_TARGET_FC)) ++ /* Need to get the nvmet_fc_target_port pointer here.*/ ++ nvmet_fc_invalidate_host(phba->targetport, ndlp); ++#endif ++} +-- +2.16.4 + diff --git a/patches.suse/nvme-Add-hardware-monitoring-support.patch b/patches.suse/nvme-Add-hardware-monitoring-support.patch new file mode 100644 index 0000000..bdd139e --- /dev/null +++ b/patches.suse/nvme-Add-hardware-monitoring-support.patch @@ -0,0 +1,315 @@ +From: Guenter Roeck +Date: Wed, 6 Nov 2019 06:35:18 -0800 +Subject: [PATCH] nvme: Add hardware monitoring support +Git-commit: 400b6a7b13a3fd71cff087139ce45dd1e5fff444 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +nvme devices report temperature information in the controller information +(for limits) and in the smart log. Currently, the only means to retrieve +this information is the nvme command line interface, which requires +super-user privileges. + +At the same time, it would be desirable to be able to use NVMe temperature +information for thermal control. + +This patch adds support to read NVMe temperatures from the kernel using the +hwmon API and adds temperature zones for NVMe drives. The thermal subsystem +can use this information to set thermal policies, and userspace can access +it using libsensors and/or the "sensors" command. + +Example output from the "sensors" command: + +nvme0-pci-0100 +Adapter: PCI adapter +Composite: +39.0°C (high = +85.0°C, crit = +85.0°C) +Sensor 1: +39.0°C +Sensor 2: +41.0°C + +Reviewed-by: Christoph Hellwig +Signed-off-by: Guenter Roeck +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/Kconfig | 10 +++ + drivers/nvme/host/Makefile | 1 + + drivers/nvme/host/core.c | 6 ++ + drivers/nvme/host/hwmon.c | 181 +++++++++++++++++++++++++++++++++++++++++++++ + drivers/nvme/host/nvme.h | 8 ++ + 5 files changed, 206 insertions(+) + create mode 100644 drivers/nvme/host/hwmon.c + +diff --git a/drivers/nvme/host/Kconfig b/drivers/nvme/host/Kconfig +index 2b36f052bfb9..c6439638a419 100644 +--- a/drivers/nvme/host/Kconfig ++++ b/drivers/nvme/host/Kconfig +@@ -23,6 +23,16 @@ config NVME_MULTIPATH + /dev/nvmeXnY device will show up for each NVMe namespaces, + even if it is accessible through multiple controllers. + ++config NVME_HWMON ++ bool "NVMe hardware monitoring" ++ depends on (NVME_CORE=y && HWMON=y) || (NVME_CORE=m && HWMON) ++ help ++ This provides support for NVMe hardware monitoring. If enabled, ++ a hardware monitoring device will be created for each NVMe drive ++ in the system. ++ ++ If unsure, say N. ++ + config NVME_FABRICS + tristate + +diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile +index 8a4b671c5f0c..fc7b26be692d 100644 +--- a/drivers/nvme/host/Makefile ++++ b/drivers/nvme/host/Makefile +@@ -14,6 +14,7 @@ nvme-core-$(CONFIG_TRACING) += trace.o + nvme-core-$(CONFIG_NVME_MULTIPATH) += multipath.o + nvme-core-$(CONFIG_NVM) += lightnvm.o + nvme-core-$(CONFIG_FAULT_INJECTION_DEBUG_FS) += fault_inject.o ++nvme-core-$(CONFIG_NVME_HWMON) += hwmon.o + + nvme-y += pci.o + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index b4214e54f2d2..4be64703aa47 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2760,6 +2760,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) + ctrl->oncs = le16_to_cpu(id->oncs); + ctrl->mtfa = le16_to_cpu(id->mtfa); + ctrl->oaes = le32_to_cpu(id->oaes); ++ ctrl->wctemp = le16_to_cpu(id->wctemp); ++ ctrl->cctemp = le16_to_cpu(id->cctemp); ++ + atomic_set(&ctrl->abort_limit, id->acl + 1); + ctrl->vwc = id->vwc; + if (id->mdts) +@@ -2859,6 +2862,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) + if (ret < 0) + return ret; + ++ if (!ctrl->identified) ++ nvme_hwmon_init(ctrl); ++ + ctrl->identified = true; + + return 0; +diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c +new file mode 100644 +index 000000000000..5480cbb84f9f +--- /dev/null ++++ b/drivers/nvme/host/hwmon.c +@@ -0,0 +1,181 @@ ++// SPDX-License-Identifier: GPL-2.0 ++/* ++ * NVM Express hardware monitoring support ++ * Copyright (c) 2019, Guenter Roeck ++ */ ++ ++#include ++#include ++ ++#include "nvme.h" ++ ++struct nvme_hwmon_data { ++ struct nvme_ctrl *ctrl; ++ struct nvme_smart_log log; ++ struct mutex read_lock; ++}; ++ ++static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data) ++{ ++ int ret; ++ ++ ret = nvme_get_log(data->ctrl, NVME_NSID_ALL, NVME_LOG_SMART, 0, ++ &data->log, sizeof(data->log), 0); ++ ++ return ret <= 0 ? ret : -EIO; ++} ++ ++static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long *val) ++{ ++ struct nvme_hwmon_data *data = dev_get_drvdata(dev); ++ struct nvme_smart_log *log = &data->log; ++ int temp; ++ int err; ++ ++ /* ++ * First handle attributes which don't require us to read ++ * the smart log. ++ */ ++ switch (attr) { ++ case hwmon_temp_max: ++ *val = (data->ctrl->wctemp - 273) * 1000; ++ return 0; ++ case hwmon_temp_crit: ++ *val = (data->ctrl->cctemp - 273) * 1000; ++ return 0; ++ default: ++ break; ++ } ++ ++ mutex_lock(&data->read_lock); ++ err = nvme_hwmon_get_smart_log(data); ++ if (err) ++ goto unlock; ++ ++ switch (attr) { ++ case hwmon_temp_input: ++ if (!channel) ++ temp = get_unaligned_le16(log->temperature); ++ else ++ temp = le16_to_cpu(log->temp_sensor[channel - 1]); ++ *val = (temp - 273) * 1000; ++ break; ++ case hwmon_temp_alarm: ++ *val = !!(log->critical_warning & NVME_SMART_CRIT_TEMPERATURE); ++ break; ++ default: ++ err = -EOPNOTSUPP; ++ break; ++ } ++unlock: ++ mutex_unlock(&data->read_lock); ++ return err; ++} ++ ++static const char * const nvme_hwmon_sensor_names[] = { ++ "Composite", ++ "Sensor 1", ++ "Sensor 2", ++ "Sensor 3", ++ "Sensor 4", ++ "Sensor 5", ++ "Sensor 6", ++ "Sensor 7", ++ "Sensor 8", ++}; ++ ++static int nvme_hwmon_read_string(struct device *dev, ++ enum hwmon_sensor_types type, u32 attr, ++ int channel, const char **str) ++{ ++ *str = nvme_hwmon_sensor_names[channel]; ++ return 0; ++} ++ ++static umode_t nvme_hwmon_is_visible(const void *_data, ++ enum hwmon_sensor_types type, ++ u32 attr, int channel) ++{ ++ const struct nvme_hwmon_data *data = _data; ++ ++ switch (attr) { ++ case hwmon_temp_crit: ++ if (!channel && data->ctrl->cctemp) ++ return 0444; ++ break; ++ case hwmon_temp_max: ++ if (!channel && data->ctrl->wctemp) ++ return 0444; ++ break; ++ case hwmon_temp_alarm: ++ if (!channel) ++ return 0444; ++ break; ++ case hwmon_temp_input: ++ case hwmon_temp_label: ++ if (!channel || data->log.temp_sensor[channel - 1]) ++ return 0444; ++ break; ++ default: ++ break; ++ } ++ return 0; ++} ++ ++static const struct hwmon_channel_info *nvme_hwmon_info[] = { ++ HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), ++ HWMON_CHANNEL_INFO(temp, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | ++ HWMON_T_LABEL | HWMON_T_ALARM, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_LABEL), ++ NULL ++}; ++ ++static const struct hwmon_ops nvme_hwmon_ops = { ++ .is_visible = nvme_hwmon_is_visible, ++ .read = nvme_hwmon_read, ++ .read_string = nvme_hwmon_read_string, ++}; ++ ++static const struct hwmon_chip_info nvme_hwmon_chip_info = { ++ .ops = &nvme_hwmon_ops, ++ .info = nvme_hwmon_info, ++}; ++ ++void nvme_hwmon_init(struct nvme_ctrl *ctrl) ++{ ++ struct device *dev = ctrl->dev; ++ struct nvme_hwmon_data *data; ++ struct device *hwmon; ++ int err; ++ ++ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return; ++ ++ data->ctrl = ctrl; ++ mutex_init(&data->read_lock); ++ ++ err = nvme_hwmon_get_smart_log(data); ++ if (err) { ++ dev_warn(dev, "Failed to read smart log (error %d)\n", err); ++ devm_kfree(dev, data); ++ return; ++ } ++ ++ hwmon = devm_hwmon_device_register_with_info(dev, "nvme", data, ++ &nvme_hwmon_chip_info, ++ NULL); ++ if (IS_ERR(hwmon)) { ++ dev_warn(dev, "Failed to instantiate hwmon device\n"); ++ devm_kfree(dev, data); ++ } ++} +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 2637d9dd278f..258534a7bb6c 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -230,6 +230,8 @@ struct nvme_ctrl { + u16 kas; + u8 npss; + u8 apsta; ++ u16 wctemp; ++ u16 cctemp; + u32 oaes; + u32 aen_result; + u32 ctratt; +@@ -665,4 +667,10 @@ static inline struct nvme_ns *nvme_get_ns_from_dev(struct device *dev) + return dev_to_disk(dev)->private_data; + } + ++#ifdef CONFIG_NVME_HWMON ++void nvme_hwmon_init(struct nvme_ctrl *ctrl); ++#else ++static inline void nvme_hwmon_init(struct nvme_ctrl *ctrl) { } ++#endif ++ + #endif /* _NVME_H */ +-- +2.16.4 + diff --git a/patches.suse/nvme-Check-for-readiness-more-quickly-to-speed-up-bo.patch b/patches.suse/nvme-Check-for-readiness-more-quickly-to-speed-up-bo.patch new file mode 100644 index 0000000..9b44df7 --- /dev/null +++ b/patches.suse/nvme-Check-for-readiness-more-quickly-to-speed-up-bo.patch @@ -0,0 +1,59 @@ +From: Josh Triplett +Date: Fri, 28 Feb 2020 18:52:28 -0800 +Subject: [PATCH] nvme: Check for readiness more quickly, to speed up boot time +Git-commit: 3e98c2443f5c7f127b5b7492a3089e92a1c85112 +Patch-mainline: v5.7-rc1 +References: bsc#1161930 + +After initialization, nvme_wait_ready checks for readiness every 100ms, +even though the drive may be ready far sooner than that. This delays +system boot by hundreds of milliseconds. Reduce the delay, checking for +readiness every millisecond instead. + +Boot-time tests on an AWS c5.12xlarge: + +Before: +[ 0.546936] initcall nvme_init+0x0/0x5b returned 0 after 37 usecs +... +[ 0.764178] nvme nvme0: 2/0/0 default/read/poll queues +[ 0.768424] nvme0n1: p1 +[ 0.774132] EXT4-fs (nvme0n1p1): mounted filesystem with ordered data mode. Opts: (null) +[ 0.774146] VFS: Mounted root (ext4 filesystem) on device 259:1. +... +[ 0.788141] Run /sbin/init as init process + +After: +[ 0.537088] initcall nvme_init+0x0/0x5b returned 0 after 37 usecs +... +[ 0.543457] nvme nvme0: 2/0/0 default/read/poll queues +[ 0.548473] nvme0n1: p1 +[ 0.554339] EXT4-fs (nvme0n1p1): mounted filesystem with ordered data mode. Opts: (null) +[ 0.554344] VFS: Mounted root (ext4 filesystem) on device 259:1. +... +[ 0.567931] Run /sbin/init as init process + +Signed-off-by: Josh Triplett +Reviewed-by: Sagi Grimberg +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index c9988942d0aa..0e38e07a302f 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2078,7 +2078,7 @@ static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled) + if ((csts & NVME_CSTS_RDY) == bit) + break; + +- msleep(100); ++ usleep_range(1000, 2000); + if (fatal_signal_pending(current)) + return -EINTR; + if (time_after(jiffies, timeout)) { +-- +2.16.4 + diff --git a/patches.suse/nvme-Cleanup-and-rename-nvme_block_nr.patch b/patches.suse/nvme-Cleanup-and-rename-nvme_block_nr.patch new file mode 100644 index 0000000..43c8c9a --- /dev/null +++ b/patches.suse/nvme-Cleanup-and-rename-nvme_block_nr.patch @@ -0,0 +1,75 @@ +From: Damien Le Moal +Date: Mon, 21 Oct 2019 12:40:03 +0900 +Subject: [PATCH] nvme: Cleanup and rename nvme_block_nr() +Git-commit: 314d48dd224897e35ddcaf5a1d7d133b5adddeb7 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Rename nvme_block_nr() to nvme_sect_to_lba() and use SECTOR_SHIFT +instead of its hard coded value 9. Also add a comment to decribe this +helper. + +Reviewed-by: Johannes Thumshirn +Reviewed-by: Christoph Hellwig +Signed-off-by: Damien Le Moal +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 6 +++--- + drivers/nvme/host/nvme.h | 7 +++++-- + 2 files changed, 8 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 9c743610e6ea..64815fa1a254 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -589,7 +589,7 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req, + } + + __rq_for_each_bio(bio, req) { +- u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector); ++ u64 slba = nvme_sect_to_lba(ns, bio->bi_iter.bi_sector); + u32 nlb = bio->bi_iter.bi_size >> ns->lba_shift; + + if (n < segments) { +@@ -630,7 +630,7 @@ static inline blk_status_t nvme_setup_write_zeroes(struct nvme_ns *ns, + cmnd->write_zeroes.opcode = nvme_cmd_write_zeroes; + cmnd->write_zeroes.nsid = cpu_to_le32(ns->head->ns_id); + cmnd->write_zeroes.slba = +- cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); ++ cpu_to_le64(nvme_sect_to_lba(ns, blk_rq_pos(req))); + cmnd->write_zeroes.length = + cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1); + cmnd->write_zeroes.control = 0; +@@ -654,7 +654,7 @@ static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns, + + cmnd->rw.opcode = (rq_data_dir(req) ? nvme_cmd_write : nvme_cmd_read); + cmnd->rw.nsid = cpu_to_le32(ns->head->ns_id); +- cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); ++ cmnd->rw.slba = cpu_to_le64(nvme_sect_to_lba(ns, blk_rq_pos(req))); + cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1); + + if (req_op(req) == REQ_OP_WRITE && ctrl->nr_streams) +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 912f9500ed11..37eb94fb797d 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -418,9 +418,12 @@ static inline int nvme_reset_subsystem(struct nvme_ctrl *ctrl) + return ctrl->ops->reg_write32(ctrl, NVME_REG_NSSR, 0x4E564D65); + } + +-static inline u64 nvme_block_nr(struct nvme_ns *ns, sector_t sector) ++/* ++ * Convert a 512B sector number to a device logical block number. ++ */ ++static inline u64 nvme_sect_to_lba(struct nvme_ns *ns, sector_t sector) + { +- return (sector >> (ns->lba_shift - 9)); ++ return sector >> (ns->lba_shift - SECTOR_SHIFT); + } + + static inline void nvme_end_request(struct request *req, __le16 status, +-- +2.16.4 + diff --git a/patches.suse/nvme-Discard-workaround-for-non-conformant-devices.patch b/patches.suse/nvme-Discard-workaround-for-non-conformant-devices.patch new file mode 100644 index 0000000..a1a362a --- /dev/null +++ b/patches.suse/nvme-Discard-workaround-for-non-conformant-devices.patch @@ -0,0 +1,61 @@ +From: Eduard Hasenleithner +Date: Tue, 12 Nov 2019 21:55:01 +0100 +Subject: [PATCH] nvme: Discard workaround for non-conformant devices +Git-commit: 530436c45ef2e446c12538a400e465929a0b3ade +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Users observe IOMMU related errors when performing discard on nvme from +non-compliant nvme devices reading beyond the end of the DMA mapped +ranges to discard. + +Two different variants of this behavior have been observed: SM22XX +controllers round up the read size to a multiple of 512 bytes, and Phison +E12 unconditionally reads the maximum discard size allowed by the spec +(256 segments or 4kB). + +Make nvme_setup_discard unconditionally allocate the maximum DSM buffer +so the driver DMA maps a memory range that will always succeed. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=202665 many +Signed-off-by: Eduard Hasenleithner +[changelog, use existing define, kernel coding style] +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 4be64703aa47..9696404a6182 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -574,8 +574,14 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req, + struct nvme_dsm_range *range; + struct bio *bio; + +- range = kmalloc_array(segments, sizeof(*range), +- GFP_ATOMIC | __GFP_NOWARN); ++ /* ++ * Some devices do not consider the DSM 'Number of Ranges' field when ++ * determining how much data to DMA. Always allocate memory for maximum ++ * number of segments to prevent device reading beyond end of buffer. ++ */ ++ static const size_t alloc_size = sizeof(*range) * NVME_DSM_MAX_RANGES; ++ ++ range = kzalloc(alloc_size, GFP_ATOMIC | __GFP_NOWARN); + if (!range) { + /* + * If we fail allocation our range, fallback to the controller +@@ -615,7 +621,7 @@ static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req, + + req->special_vec.bv_page = virt_to_page(range); + req->special_vec.bv_offset = offset_in_page(range); +- req->special_vec.bv_len = sizeof(*range) * segments; ++ req->special_vec.bv_len = alloc_size; + req->rq_flags |= RQF_SPECIAL_PAYLOAD; + + return BLK_STS_OK; +-- +2.16.4 + diff --git a/patches.suse/nvme-Fix-uninitialized-variable-warning.patch b/patches.suse/nvme-Fix-uninitialized-variable-warning.patch new file mode 100644 index 0000000..381fd9b --- /dev/null +++ b/patches.suse/nvme-Fix-uninitialized-variable-warning.patch @@ -0,0 +1,36 @@ +From: Keith Busch +Date: Thu, 20 Feb 2020 00:59:36 +0900 +Subject: [PATCH] nvme: Fix uninitialized-variable warning +Git-commit: 15755854d53b4bbb0bb37a0fce66f0156cfc8a17 +Patch-mainline: v5.6-rc3 +References: bsc#1169045 + +gcc may detect a false positive on nvme using an unintialized variable +if setting features fails. Since this is not a fast path, explicitly +initialize this variable to suppress the warning. + +Reported-by: Arnd Bergmann +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index ada59df642d2..a4d8c90ee7cc 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -1165,8 +1165,8 @@ static int nvme_identify_ns(struct nvme_ctrl *ctrl, + static int nvme_features(struct nvme_ctrl *dev, u8 op, unsigned int fid, + unsigned int dword11, void *buffer, size_t buflen, u32 *result) + { ++ union nvme_result res = { 0 }; + struct nvme_command c; +- union nvme_result res; + int ret; + + memset(&c, 0, sizeof(c)); +-- +2.16.4 + diff --git a/patches.suse/nvme-Introduce-nvme_lba_to_sect.patch b/patches.suse/nvme-Introduce-nvme_lba_to_sect.patch new file mode 100644 index 0000000..5aff476 --- /dev/null +++ b/patches.suse/nvme-Introduce-nvme_lba_to_sect.patch @@ -0,0 +1,92 @@ +From: Damien Le Moal +Date: Mon, 21 Oct 2019 12:40:04 +0900 +Subject: [PATCH] nvme: Introduce nvme_lba_to_sect() +Git-commit: e08f2ae850929d40e66268ee47e443e7ea56eeb7 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Introduce the new helper function nvme_lba_to_sect() to convert a device +logical block number to a 512B sector number. Use this new helper in +obvious places, cleaning up the code. + +Reviewed-by: Johannes Thumshirn +Reviewed-by: Christoph Hellwig +Signed-off-by: Damien Le Moal +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 14 +++++++------- + drivers/nvme/host/nvme.h | 8 ++++++++ + 2 files changed, 15 insertions(+), 7 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 64815fa1a254..b4214e54f2d2 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -1611,7 +1611,7 @@ static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type) + + static void nvme_set_chunk_size(struct nvme_ns *ns) + { +- u32 chunk_size = (((u32)ns->noiob) << (ns->lba_shift - 9)); ++ u32 chunk_size = nvme_lba_to_sect(ns, ns->noiob); + blk_queue_chunk_sectors(ns->queue, rounddown_pow_of_two(chunk_size)); + } + +@@ -1648,8 +1648,7 @@ static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns) + + static void nvme_config_write_zeroes(struct gendisk *disk, struct nvme_ns *ns) + { +- u32 max_sectors; +- unsigned short bs = 1 << ns->lba_shift; ++ u64 max_blocks; + + if (!(ns->ctrl->oncs & NVME_CTRL_ONCS_WRITE_ZEROES) || + (ns->ctrl->quirks & NVME_QUIRK_DISABLE_WRITE_ZEROES)) +@@ -1665,11 +1664,12 @@ static void nvme_config_write_zeroes(struct gendisk *disk, struct nvme_ns *ns) + * nvme_init_identify() if available. + */ + if (ns->ctrl->max_hw_sectors == UINT_MAX) +- max_sectors = ((u32)(USHRT_MAX + 1) * bs) >> 9; ++ max_blocks = (u64)USHRT_MAX + 1; + else +- max_sectors = ((u32)(ns->ctrl->max_hw_sectors + 1) * bs) >> 9; ++ max_blocks = ns->ctrl->max_hw_sectors + 1; + +- blk_queue_max_write_zeroes_sectors(disk->queue, max_sectors); ++ blk_queue_max_write_zeroes_sectors(disk->queue, ++ nvme_lba_to_sect(ns, max_blocks)); + } + + static int nvme_report_ns_ids(struct nvme_ctrl *ctrl, unsigned int nsid, +@@ -1712,7 +1712,7 @@ static bool nvme_ns_ids_equal(struct nvme_ns_ids *a, struct nvme_ns_ids *b) + static void nvme_update_disk_info(struct gendisk *disk, + struct nvme_ns *ns, struct nvme_id_ns *id) + { +- sector_t capacity = le64_to_cpu(id->nsze) << (ns->lba_shift - 9); ++ sector_t capacity = nvme_lba_to_sect(ns, le64_to_cpu(id->nsze)); + unsigned short bs = 1 << ns->lba_shift; + u32 atomic_bs, phys_bs, io_opt; + +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 37eb94fb797d..2637d9dd278f 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -426,6 +426,14 @@ static inline u64 nvme_sect_to_lba(struct nvme_ns *ns, sector_t sector) + return sector >> (ns->lba_shift - SECTOR_SHIFT); + } + ++/* ++ * Convert a device logical block number to a 512B sector number. ++ */ ++static inline sector_t nvme_lba_to_sect(struct nvme_ns *ns, u64 lba) ++{ ++ return lba << (ns->lba_shift - SECTOR_SHIFT); ++} ++ + static inline void nvme_end_request(struct request *req, __le16 status, + union nvme_result result) + { +-- +2.16.4 + diff --git a/patches.suse/nvme-Namepace-identification-descriptor-list-is-opti.patch b/patches.suse/nvme-Namepace-identification-descriptor-list-is-opti.patch new file mode 100644 index 0000000..97f0c2a --- /dev/null +++ b/patches.suse/nvme-Namepace-identification-descriptor-list-is-opti.patch @@ -0,0 +1,44 @@ +From: Keith Busch +Date: Tue, 3 Dec 2019 00:44:59 +0900 +Subject: [PATCH] nvme: Namepace identification descriptor list is optional +Git-commit: 22802bf742c25b1e2473c70b3b99da98af65ef4d +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +Despite NVM Express specification 1.3 requires a controller claiming to +be 1.3 or higher implement Identify CNS 03h (Namespace Identification +Descriptor list), the driver doesn't really need this identification in +order to use a namespace. The code had already documented in comments +that we're not to consider an error to this command. + +Return success if the controller provided any response to an +namespace identification descriptors command. + +Fixes: 538af88ea7d9de24 ("nvme: make nvme_report_ns_ids propagate error back") +Link: https://bugzilla.kernel.org/show_bug.cgi?id=205679 +Reported-by: Ingo Brunberg +Cc: Sagi Grimberg +Cc: stable@vger.kernel.org # 5.4+ +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index e6ee34376c5e..2a84e1402244 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -1735,6 +1735,8 @@ static int nvme_report_ns_ids(struct nvme_ctrl *ctrl, unsigned int nsid, + if (ret) + dev_warn(ctrl->device, + "Identify Descriptors failed (%d)\n", ret); ++ if (ret > 0) ++ ret = 0; + } + return ret; + } +-- +2.16.4 + diff --git a/patches.suse/nvme-Prevent-resets-during-paused-controller-state.patch b/patches.suse/nvme-Prevent-resets-during-paused-controller-state.patch new file mode 100644 index 0000000..8f9c132 --- /dev/null +++ b/patches.suse/nvme-Prevent-resets-during-paused-controller-state.patch @@ -0,0 +1,83 @@ +From: Keith Busch +Date: Fri, 6 Sep 2019 11:23:08 -0600 +Subject: [PATCH] nvme: Prevent resets during paused controller state +Git-commit: 4c75f877853cfa81b12374a07208e07b077f39b8 +Patch-mainline: v5.4-rc4 +References: bsc#1169045 + +A paused controller is doing critical internal activation work in the +background. Prevent subsequent controller resets from occurring during +this period by setting the controller state to RESETTING first. A helper +function, nvme_try_sched_reset_work(), is introduced for these paths so +they may continue with scheduling the reset_work after they've completed +their uninterruptible critical section. + +Tested-by: Edmund Nadolski +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 29 +++++++++++++++++++++++++---- + 1 file changed, 25 insertions(+), 4 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index e451e77005dc..e94fa693dd4b 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -120,6 +120,21 @@ static void nvme_queue_scan(struct nvme_ctrl *ctrl) + queue_work(nvme_wq, &ctrl->scan_work); + } + ++/* ++ * Use this function to proceed with scheduling reset_work for a controller ++ * that had previously been set to the resetting state. This is intended for ++ * code paths that can't be interrupted by other reset attempts. A hot removal ++ * may prevent this from succeeding. ++ */ ++static int nvme_try_sched_reset(struct nvme_ctrl *ctrl) ++{ ++ if (ctrl->state != NVME_CTRL_RESETTING) ++ return -EBUSY; ++ if (!queue_work(nvme_reset_wq, &ctrl->reset_work)) ++ return -EBUSY; ++ return 0; ++} ++ + int nvme_reset_ctrl(struct nvme_ctrl *ctrl) + { + if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING)) +@@ -3828,13 +3843,13 @@ static void nvme_fw_act_work(struct work_struct *work) + if (time_after(jiffies, fw_act_timeout)) { + dev_warn(ctrl->device, + "Fw activation timeout, reset controller\n"); +- nvme_reset_ctrl(ctrl); +- break; ++ nvme_try_sched_reset(ctrl); ++ return; + } + msleep(100); + } + +- if (ctrl->state != NVME_CTRL_LIVE) ++ if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE)) + return; + + nvme_start_queues(ctrl); +@@ -3854,7 +3869,13 @@ static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result) + nvme_queue_scan(ctrl); + break; + case NVME_AER_NOTICE_FW_ACT_STARTING: +- queue_work(nvme_wq, &ctrl->fw_act_work); ++ /* ++ * We are (ab)using the RESETTING state to prevent subsequent ++ * recovery actions from interfering with the controller's ++ * firmware activation. ++ */ ++ if (nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING)) ++ queue_work(nvme_wq, &ctrl->fw_act_work); + break; + #ifdef CONFIG_NVME_MULTIPATH + case NVME_AER_NOTICE_ANA: +-- +2.16.4 + diff --git a/patches.suse/nvme-Remove-ADMIN_ONLY-state.patch b/patches.suse/nvme-Remove-ADMIN_ONLY-state.patch new file mode 100644 index 0000000..2878be4 --- /dev/null +++ b/patches.suse/nvme-Remove-ADMIN_ONLY-state.patch @@ -0,0 +1,226 @@ +From: Keith Busch +Date: Tue, 3 Sep 2019 09:22:24 -0600 +Subject: [PATCH] nvme: Remove ADMIN_ONLY state +Git-commit: 5d02a5c1d6e14534ca4729b055c89a2cd022ca00 +Patch-mainline: v5.4-rc4 +References: bsc#1169045 + +The admin only state was intended to fence off actions that don't +apply to a non-IO capable controller. The only actual user of this is +the scan_work, and pci was the only transport to ever set this state. +The consequence of having this state is placing an additional burden on +every other action that applies to both live and admin only controllers. + +Remove the admin only state and place the admin only burden on the only +place that actually cares: scan_work. + +This also prepares to make it easier to temporarily pause a LIVE state +so that we don't need to remember which state the controller had been in +prior to the pause. + +Tested-by: Edmund Nadolski +Reviewed-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 23 ++++------------------- + drivers/nvme/host/fabrics.h | 3 +-- + drivers/nvme/host/nvme.h | 1 - + drivers/nvme/host/pci.c | 21 ++++++--------------- + 4 files changed, 11 insertions(+), 37 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index ef1d8f81f69e..e451e77005dc 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -116,7 +116,7 @@ static void nvme_queue_scan(struct nvme_ctrl *ctrl) + /* + * Only new queue scan work when admin and IO queues are both alive + */ +- if (ctrl->state == NVME_CTRL_LIVE) ++ if (ctrl->state == NVME_CTRL_LIVE && ctrl->tagset) + queue_work(nvme_wq, &ctrl->scan_work); + } + +@@ -137,8 +137,7 @@ int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl) + ret = nvme_reset_ctrl(ctrl); + if (!ret) { + flush_work(&ctrl->reset_work); +- if (ctrl->state != NVME_CTRL_LIVE && +- ctrl->state != NVME_CTRL_ADMIN_ONLY) ++ if (ctrl->state != NVME_CTRL_LIVE) + ret = -ENETRESET; + } + +@@ -315,15 +314,6 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + + old_state = ctrl->state; + switch (new_state) { +- case NVME_CTRL_ADMIN_ONLY: +- switch (old_state) { +- case NVME_CTRL_CONNECTING: +- changed = true; +- /* FALLTHRU */ +- default: +- break; +- } +- break; + case NVME_CTRL_LIVE: + switch (old_state) { + case NVME_CTRL_NEW: +@@ -339,7 +329,6 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + switch (old_state) { + case NVME_CTRL_NEW: + case NVME_CTRL_LIVE: +- case NVME_CTRL_ADMIN_ONLY: + changed = true; + /* FALLTHRU */ + default: +@@ -359,7 +348,6 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + case NVME_CTRL_DELETING: + switch (old_state) { + case NVME_CTRL_LIVE: +- case NVME_CTRL_ADMIN_ONLY: + case NVME_CTRL_RESETTING: + case NVME_CTRL_CONNECTING: + changed = true; +@@ -2873,7 +2861,6 @@ static int nvme_dev_open(struct inode *inode, struct file *file) + + switch (ctrl->state) { + case NVME_CTRL_LIVE: +- case NVME_CTRL_ADMIN_ONLY: + break; + default: + return -EWOULDBLOCK; +@@ -3167,7 +3154,6 @@ static ssize_t nvme_sysfs_show_state(struct device *dev, + static const char *const state_name[] = { + [NVME_CTRL_NEW] = "new", + [NVME_CTRL_LIVE] = "live", +- [NVME_CTRL_ADMIN_ONLY] = "only-admin", + [NVME_CTRL_RESETTING] = "resetting", + [NVME_CTRL_CONNECTING] = "connecting", + [NVME_CTRL_DELETING] = "deleting", +@@ -3678,11 +3664,10 @@ static void nvme_scan_work(struct work_struct *work) + struct nvme_id_ctrl *id; + unsigned nn; + +- if (ctrl->state != NVME_CTRL_LIVE) ++ /* No tagset on a live ctrl means IO queues could not created */ ++ if (ctrl->state != NVME_CTRL_LIVE || !ctrl->tagset) + return; + +- WARN_ON_ONCE(!ctrl->tagset); +- + if (test_and_clear_bit(NVME_AER_NOTICE_NS_CHANGED, &ctrl->events)) { + dev_info(ctrl->device, "rescanning namespaces.\n"); + nvme_clear_changed_ns_log(ctrl); +diff --git a/drivers/nvme/host/fabrics.h b/drivers/nvme/host/fabrics.h +index 93f08d77c896..a0ec40ab62ee 100644 +--- a/drivers/nvme/host/fabrics.h ++++ b/drivers/nvme/host/fabrics.h +@@ -182,8 +182,7 @@ bool nvmf_ip_options_match(struct nvme_ctrl *ctrl, + static inline bool nvmf_check_ready(struct nvme_ctrl *ctrl, struct request *rq, + bool queue_live) + { +- if (likely(ctrl->state == NVME_CTRL_LIVE || +- ctrl->state == NVME_CTRL_ADMIN_ONLY)) ++ if (likely(ctrl->state == NVME_CTRL_LIVE)) + return true; + return __nvmf_check_ready(ctrl, rq, queue_live); + } +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 38a83ef5bcd3..2ba577271ada 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -161,7 +161,6 @@ static inline u16 nvme_req_qid(struct request *req) + enum nvme_ctrl_state { + NVME_CTRL_NEW, + NVME_CTRL_LIVE, +- NVME_CTRL_ADMIN_ONLY, /* Only admin queue live */ + NVME_CTRL_RESETTING, + NVME_CTRL_CONNECTING, + NVME_CTRL_DELETING, +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 5c04581899f4..e7e79d6af9ba 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2263,10 +2263,7 @@ static bool __nvme_disable_io_queues(struct nvme_dev *dev, u8 opcode) + return true; + } + +-/* +- * return error value only when tagset allocation failed +- */ +-static int nvme_dev_add(struct nvme_dev *dev) ++static void nvme_dev_add(struct nvme_dev *dev) + { + int ret; + +@@ -2296,7 +2293,7 @@ static int nvme_dev_add(struct nvme_dev *dev) + if (ret) { + dev_warn(dev->ctrl.device, + "IO queues tagset allocation failed %d\n", ret); +- return ret; ++ return; + } + dev->ctrl.tagset = &dev->tagset; + } else { +@@ -2307,7 +2304,6 @@ static int nvme_dev_add(struct nvme_dev *dev) + } + + nvme_dbbuf_set(dev); +- return 0; + } + + static int nvme_pci_enable(struct nvme_dev *dev) +@@ -2527,7 +2523,6 @@ static void nvme_reset_work(struct work_struct *work) + container_of(work, struct nvme_dev, ctrl.reset_work); + bool was_suspend = !!(dev->ctrl.ctrl_config & NVME_CC_SHN_NORMAL); + int result; +- enum nvme_ctrl_state new_state = NVME_CTRL_LIVE; + + if (WARN_ON(dev->ctrl.state != NVME_CTRL_RESETTING)) { + result = -ENODEV; +@@ -2621,14 +2616,11 @@ static void nvme_reset_work(struct work_struct *work) + dev_warn(dev->ctrl.device, "IO queues not created\n"); + nvme_kill_queues(&dev->ctrl); + nvme_remove_namespaces(&dev->ctrl); +- new_state = NVME_CTRL_ADMIN_ONLY; + nvme_free_tagset(dev); + } else { + nvme_start_queues(&dev->ctrl); + nvme_wait_freeze(&dev->ctrl); +- /* hit this only when allocate tagset fails */ +- if (nvme_dev_add(dev)) +- new_state = NVME_CTRL_ADMIN_ONLY; ++ nvme_dev_add(dev); + nvme_unfreeze(&dev->ctrl); + } + +@@ -2636,9 +2628,9 @@ static void nvme_reset_work(struct work_struct *work) + * If only admin queue live, keep it to do further investigation or + * recovery. + */ +- if (!nvme_change_ctrl_state(&dev->ctrl, new_state)) { ++ if (!nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_LIVE)) { + dev_warn(dev->ctrl.device, +- "failed to mark controller state %d\n", new_state); ++ "failed to mark controller live state\n"); + result = -ENODEV; + goto out; + } +@@ -2945,8 +2937,7 @@ static int nvme_suspend(struct device *dev) + nvme_wait_freeze(ctrl); + nvme_sync_queues(ctrl); + +- if (ctrl->state != NVME_CTRL_LIVE && +- ctrl->state != NVME_CTRL_ADMIN_ONLY) ++ if (ctrl->state != NVME_CTRL_LIVE) + goto unfreeze; + + ret = nvme_get_power_state(ctrl, &ndev->last_ps); +-- +2.16.4 + diff --git a/patches.suse/nvme-Restart-request-timers-in-resetting-state.patch b/patches.suse/nvme-Restart-request-timers-in-resetting-state.patch new file mode 100644 index 0000000..3dffe6f --- /dev/null +++ b/patches.suse/nvme-Restart-request-timers-in-resetting-state.patch @@ -0,0 +1,64 @@ +From: Keith Busch +Date: Thu, 5 Sep 2019 08:09:33 -0600 +Subject: [PATCH] nvme: Restart request timers in resetting state +Git-commit: 92b98e88d59ab17e65f261fbb5db272143ccf414 +Patch-mainline: v5.4-rc4 +References: bsc#1169045 + +A controller in the resetting state has not yet completed its recovery +actions. The pci and fc transports were already handling this, so update +the remaining transports to not attempt additional recovery in this +state. Instead, just restart the request timer. + +Tested-by: Edmund Nadolski +Reviewed-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/rdma.c | 8 ++++++++ + drivers/nvme/host/tcp.c | 8 ++++++++ + 2 files changed, 16 insertions(+) + +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 4d280160dd3f..f19a28b4e997 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -1701,6 +1701,14 @@ nvme_rdma_timeout(struct request *rq, bool reserved) + dev_warn(ctrl->ctrl.device, "I/O %d QID %d timeout\n", + rq->tag, nvme_rdma_queue_idx(queue)); + ++ /* ++ * Restart the timer if a controller reset is already scheduled. Any ++ * timed out commands would be handled before entering the connecting ++ * state. ++ */ ++ if (ctrl->ctrl.state == NVME_CTRL_RESETTING) ++ return BLK_EH_RESET_TIMER; ++ + if (ctrl->ctrl.state != NVME_CTRL_LIVE) { + /* + * Teardown immediately if controller times out while starting +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 385a5212c10f..33de2fddfbb2 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -2044,6 +2044,14 @@ nvme_tcp_timeout(struct request *rq, bool reserved) + struct nvme_tcp_ctrl *ctrl = req->queue->ctrl; + struct nvme_tcp_cmd_pdu *pdu = req->pdu; + ++ /* ++ * Restart the timer if a controller reset is already scheduled. Any ++ * timed out commands would be handled before entering the connecting ++ * state. ++ */ ++ if (ctrl->ctrl.state == NVME_CTRL_RESETTING) ++ return BLK_EH_RESET_TIMER; ++ + dev_warn(ctrl->ctrl.device, + "queue %d: timeout request %#x type %d\n", + nvme_tcp_queue_id(req->queue), rq->tag, pdu->hdr.type); +-- +2.16.4 + diff --git a/patches.suse/nvme-Wait-for-reset-state-when-required.patch b/patches.suse/nvme-Wait-for-reset-state-when-required.patch new file mode 100644 index 0000000..814eb82 --- /dev/null +++ b/patches.suse/nvme-Wait-for-reset-state-when-required.patch @@ -0,0 +1,260 @@ +From: Keith Busch +Date: Wed, 4 Sep 2019 10:06:11 -0600 +Subject: [PATCH] nvme: Wait for reset state when required +Git-commit: c1ac9a4b0797ca8bb4470f863a5f78ef1ab13bed +Patch-mainline: v5.4-rc4 +References: bsc#1169045 + +Prevent simultaneous controller disabling/enabling tasks from interfering +with each other through a function to wait until the task successfully +transitioned the controller to the RESETTING state. This ensures disabling +the controller will not be interrupted by another reset path, otherwise +a concurrent reset may leave the controller in the wrong state. + +Tested-by: Edmund Nadolski +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 41 +++++++++++++++++++++++++++++++++++++++-- + drivers/nvme/host/nvme.h | 4 ++++ + drivers/nvme/host/pci.c | 46 +++++++++++++++++++++++++++++++--------------- + 3 files changed, 74 insertions(+), 17 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index e94fa693dd4b..fa7ba09dca77 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -126,7 +126,7 @@ static void nvme_queue_scan(struct nvme_ctrl *ctrl) + * code paths that can't be interrupted by other reset attempts. A hot removal + * may prevent this from succeeding. + */ +-static int nvme_try_sched_reset(struct nvme_ctrl *ctrl) ++int nvme_try_sched_reset(struct nvme_ctrl *ctrl) + { + if (ctrl->state != NVME_CTRL_RESETTING) + return -EBUSY; +@@ -134,6 +134,7 @@ static int nvme_try_sched_reset(struct nvme_ctrl *ctrl) + return -EBUSY; + return 0; + } ++EXPORT_SYMBOL_GPL(nvme_try_sched_reset); + + int nvme_reset_ctrl(struct nvme_ctrl *ctrl) + { +@@ -384,8 +385,10 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + break; + } + +- if (changed) ++ if (changed) { + ctrl->state = new_state; ++ wake_up_all(&ctrl->state_wq); ++ } + + spin_unlock_irqrestore(&ctrl->lock, flags); + if (changed && ctrl->state == NVME_CTRL_LIVE) +@@ -394,6 +397,39 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + } + EXPORT_SYMBOL_GPL(nvme_change_ctrl_state); + ++/* ++ * Returns true for sink states that can't ever transition back to live. ++ */ ++static bool nvme_state_terminal(struct nvme_ctrl *ctrl) ++{ ++ switch (ctrl->state) { ++ case NVME_CTRL_NEW: ++ case NVME_CTRL_LIVE: ++ case NVME_CTRL_RESETTING: ++ case NVME_CTRL_CONNECTING: ++ return false; ++ case NVME_CTRL_DELETING: ++ case NVME_CTRL_DEAD: ++ return true; ++ default: ++ WARN_ONCE(1, "Unhandled ctrl state:%d", ctrl->state); ++ return true; ++ } ++} ++ ++/* ++ * Waits for the controller state to be resetting, or returns false if it is ++ * not possible to ever transition to that state. ++ */ ++bool nvme_wait_reset(struct nvme_ctrl *ctrl) ++{ ++ wait_event(ctrl->state_wq, ++ nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING) || ++ nvme_state_terminal(ctrl)); ++ return ctrl->state == NVME_CTRL_RESETTING; ++} ++EXPORT_SYMBOL_GPL(nvme_wait_reset); ++ + static void nvme_free_ns_head(struct kref *ref) + { + struct nvme_ns_head *head = +@@ -3998,6 +4034,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev, + INIT_WORK(&ctrl->async_event_work, nvme_async_event_work); + INIT_WORK(&ctrl->fw_act_work, nvme_fw_act_work); + INIT_WORK(&ctrl->delete_work, nvme_delete_ctrl_work); ++ init_waitqueue_head(&ctrl->state_wq); + + INIT_DELAYED_WORK(&ctrl->ka_work, nvme_keep_alive_work); + memset(&ctrl->ka_cmd, 0, sizeof(ctrl->ka_cmd)); +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 2ba577271ada..22e8401352c2 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + + #include + +@@ -198,6 +199,7 @@ struct nvme_ctrl { + struct cdev cdev; + struct work_struct reset_work; + struct work_struct delete_work; ++ wait_queue_head_t state_wq; + + struct nvme_subsystem *subsys; + struct list_head subsys_entry; +@@ -448,6 +450,7 @@ void nvme_complete_rq(struct request *req); + bool nvme_cancel_request(struct request *req, void *data, bool reserved); + bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, + enum nvme_ctrl_state new_state); ++bool nvme_wait_reset(struct nvme_ctrl *ctrl); + int nvme_disable_ctrl(struct nvme_ctrl *ctrl); + int nvme_enable_ctrl(struct nvme_ctrl *ctrl); + int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl); +@@ -498,6 +501,7 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count); + void nvme_stop_keep_alive(struct nvme_ctrl *ctrl); + int nvme_reset_ctrl(struct nvme_ctrl *ctrl); + int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl); ++int nvme_try_sched_reset(struct nvme_ctrl *ctrl); + int nvme_delete_ctrl(struct nvme_ctrl *ctrl); + + int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index e7e79d6af9ba..4b181969c432 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2463,6 +2463,14 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) + mutex_unlock(&dev->shutdown_lock); + } + ++static int nvme_disable_prepare_reset(struct nvme_dev *dev, bool shutdown) ++{ ++ if (!nvme_wait_reset(&dev->ctrl)) ++ return -EBUSY; ++ nvme_dev_disable(dev, shutdown); ++ return 0; ++} ++ + static int nvme_setup_prp_pools(struct nvme_dev *dev) + { + dev->prp_page_pool = dma_pool_create("prp list page", dev->dev, +@@ -2510,6 +2518,11 @@ static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl) + + static void nvme_remove_dead_ctrl(struct nvme_dev *dev) + { ++ /* ++ * Set state to deleting now to avoid blocking nvme_wait_reset(), which ++ * may be holding this pci_dev's device lock. ++ */ ++ nvme_change_ctrl_state(&dev->ctrl, NVME_CTRL_DELETING); + nvme_get_ctrl(&dev->ctrl); + nvme_dev_disable(dev, false); + nvme_kill_queues(&dev->ctrl); +@@ -2835,19 +2848,28 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) + static void nvme_reset_prepare(struct pci_dev *pdev) + { + struct nvme_dev *dev = pci_get_drvdata(pdev); +- nvme_dev_disable(dev, false); ++ ++ /* ++ * We don't need to check the return value from waiting for the reset ++ * state as pci_dev device lock is held, making it impossible to race ++ * with ->remove(). ++ */ ++ nvme_disable_prepare_reset(dev, false); ++ nvme_sync_queues(&dev->ctrl); + } + + static void nvme_reset_done(struct pci_dev *pdev) + { + struct nvme_dev *dev = pci_get_drvdata(pdev); +- nvme_reset_ctrl_sync(&dev->ctrl); ++ ++ if (!nvme_try_sched_reset(&dev->ctrl)) ++ flush_work(&dev->ctrl.reset_work); + } + + static void nvme_shutdown(struct pci_dev *pdev) + { + struct nvme_dev *dev = pci_get_drvdata(pdev); +- nvme_dev_disable(dev, true); ++ nvme_disable_prepare_reset(dev, true); + } + + /* +@@ -2900,7 +2922,7 @@ static int nvme_resume(struct device *dev) + + if (ndev->last_ps == U32_MAX || + nvme_set_power_state(ctrl, ndev->last_ps) != 0) +- nvme_reset_ctrl(ctrl); ++ return nvme_try_sched_reset(&ndev->ctrl); + return 0; + } + +@@ -2928,10 +2950,8 @@ static int nvme_suspend(struct device *dev) + */ + if (pm_suspend_via_firmware() || !ctrl->npss || + !pcie_aspm_enabled(pdev) || +- (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND)) { +- nvme_dev_disable(ndev, true); +- return 0; +- } ++ (ndev->ctrl.quirks & NVME_QUIRK_SIMPLE_SUSPEND)) ++ return nvme_disable_prepare_reset(ndev, true); + + nvme_start_freeze(ctrl); + nvme_wait_freeze(ctrl); +@@ -2963,9 +2983,8 @@ static int nvme_suspend(struct device *dev) + * Clearing npss forces a controller reset on resume. The + * correct value will be resdicovered then. + */ +- nvme_dev_disable(ndev, true); ++ ret = nvme_disable_prepare_reset(ndev, true); + ctrl->npss = 0; +- ret = 0; + } + unfreeze: + nvme_unfreeze(ctrl); +@@ -2975,9 +2994,7 @@ static int nvme_suspend(struct device *dev) + static int nvme_simple_suspend(struct device *dev) + { + struct nvme_dev *ndev = pci_get_drvdata(to_pci_dev(dev)); +- +- nvme_dev_disable(ndev, true); +- return 0; ++ return nvme_disable_prepare_reset(ndev, true); + } + + static int nvme_simple_resume(struct device *dev) +@@ -2985,8 +3002,7 @@ static int nvme_simple_resume(struct device *dev) + struct pci_dev *pdev = to_pci_dev(dev); + struct nvme_dev *ndev = pci_get_drvdata(pdev); + +- nvme_reset_ctrl(&ndev->ctrl); +- return 0; ++ return nvme_try_sched_reset(&ndev->ctrl); + } + + static const struct dev_pm_ops nvme_dev_pm_ops = { +-- +2.16.4 + diff --git a/patches.suse/nvme-add-error-message-on-mismatching-controller-ids.patch b/patches.suse/nvme-add-error-message-on-mismatching-controller-ids.patch new file mode 100644 index 0000000..4c5cbd4 --- /dev/null +++ b/patches.suse/nvme-add-error-message-on-mismatching-controller-ids.patch @@ -0,0 +1,46 @@ +From: James Smart +Date: Thu, 21 Nov 2019 09:58:10 -0800 +Subject: [PATCH] nvme: add error message on mismatching controller ids +Git-commit: a8157ff3607eccb21efd4eb2ca46ff0cc488d12d +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +We've seen a few devices that return different controller id's to +the Fabric Connect command vs the Identify(controller) command. It's +currently hard to identify this failure by existing error messages. It +comes across as a (re)connect attempt in the transport that fails with +a -22 (-EINVAL) status. The issue is compounded by older kernels not +having the controller id check or had the identify command overwrite the +fabrics controller id value before it checked. Both resulted in cases +where the devices appeared fine until more recent kernels. + +Clarify the reject by adding an error message on controller id mismatches. + +Reviewed-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Reviewed-by: Ewan D. Milne +Signed-off-by: James Smart +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 8e8527408db3..e6ee34376c5e 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2862,6 +2862,10 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) + * admin connect + */ + if (ctrl->cntlid != le16_to_cpu(id->cntlid)) { ++ dev_err(ctrl->device, ++ "Mismatching cntlid: Connect %u vs Identify " ++ "%u, rejecting\n", ++ ctrl->cntlid, le16_to_cpu(id->cntlid)); + ret = -EINVAL; + goto out_free; + } +-- +2.16.4 + diff --git a/patches.suse/nvme-code-cleanup-nvme_identify_ns_desc.patch b/patches.suse/nvme-code-cleanup-nvme_identify_ns_desc.patch new file mode 100644 index 0000000..482fccd --- /dev/null +++ b/patches.suse/nvme-code-cleanup-nvme_identify_ns_desc.patch @@ -0,0 +1,120 @@ +From: Chaitanya Kulkarni +Date: Wed, 19 Feb 2020 08:14:31 -0800 +Subject: [PATCH] nvme: code cleanup nvme_identify_ns_desc() +Git-commit: ad95a613ea447e2404e343ab3636c4d960fa9580 +Patch-mainline: v5.7-rc1 +References: bsc#1161930 + +The function nvme_identify_ns_desc() has 3 levels of nesting which make +error message to exceeded > 80 char per line which is not aligned with +the kernel code standards and rest of the NVMe subsystem code. + +Add a helper function to move the processing of the log when the +command is successful by reducing the nesting and keeping the +code < 80 char per line. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 76 +++++++++++++++++++++++++----------------------- + 1 file changed, 40 insertions(+), 36 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 720840ca875c..c4dbc852b5e9 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -1055,6 +1055,43 @@ static int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id) + return error; + } + ++static int nvme_process_ns_desc(struct nvme_ctrl *ctrl, struct nvme_ns_ids *ids, ++ struct nvme_ns_id_desc *cur) ++{ ++ const char *warn_str = "ctrl returned bogus length:"; ++ void *data = cur; ++ ++ switch (cur->nidt) { ++ case NVME_NIDT_EUI64: ++ if (cur->nidl != NVME_NIDT_EUI64_LEN) { ++ dev_warn(ctrl->device, "%s %d for NVME_NIDT_EUI64\n", ++ warn_str, cur->nidl); ++ return -1; ++ } ++ memcpy(ids->eui64, data + sizeof(*cur), NVME_NIDT_EUI64_LEN); ++ return NVME_NIDT_EUI64_LEN; ++ case NVME_NIDT_NGUID: ++ if (cur->nidl != NVME_NIDT_NGUID_LEN) { ++ dev_warn(ctrl->device, "%s %d for NVME_NIDT_NGUID\n", ++ warn_str, cur->nidl); ++ return -1; ++ } ++ memcpy(ids->nguid, data + sizeof(*cur), NVME_NIDT_NGUID_LEN); ++ return NVME_NIDT_NGUID_LEN; ++ case NVME_NIDT_UUID: ++ if (cur->nidl != NVME_NIDT_UUID_LEN) { ++ dev_warn(ctrl->device, "%s %d for NVME_NIDT_UUID\n", ++ warn_str, cur->nidl); ++ return -1; ++ } ++ uuid_copy(&ids->uuid, data + sizeof(*cur)); ++ return NVME_NIDT_UUID_LEN; ++ default: ++ /* Skip unknown types */ ++ return cur->nidl; ++ } ++} ++ + static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid, + struct nvme_ns_ids *ids) + { +@@ -1083,42 +1120,9 @@ static int nvme_identify_ns_descs(struct nvme_ctrl *ctrl, unsigned nsid, + if (cur->nidl == 0) + break; + +- switch (cur->nidt) { +- case NVME_NIDT_EUI64: +- if (cur->nidl != NVME_NIDT_EUI64_LEN) { +- dev_warn(ctrl->device, +- "ctrl returned bogus length: %d for NVME_NIDT_EUI64\n", +- cur->nidl); +- goto free_data; +- } +- len = NVME_NIDT_EUI64_LEN; +- memcpy(ids->eui64, data + pos + sizeof(*cur), len); +- break; +- case NVME_NIDT_NGUID: +- if (cur->nidl != NVME_NIDT_NGUID_LEN) { +- dev_warn(ctrl->device, +- "ctrl returned bogus length: %d for NVME_NIDT_NGUID\n", +- cur->nidl); +- goto free_data; +- } +- len = NVME_NIDT_NGUID_LEN; +- memcpy(ids->nguid, data + pos + sizeof(*cur), len); +- break; +- case NVME_NIDT_UUID: +- if (cur->nidl != NVME_NIDT_UUID_LEN) { +- dev_warn(ctrl->device, +- "ctrl returned bogus length: %d for NVME_NIDT_UUID\n", +- cur->nidl); +- goto free_data; +- } +- len = NVME_NIDT_UUID_LEN; +- uuid_copy(&ids->uuid, data + pos + sizeof(*cur)); +- break; +- default: +- /* Skip unknown types */ +- len = cur->nidl; +- break; +- } ++ len = nvme_process_ns_desc(ctrl, ids, cur); ++ if (len < 0) ++ goto free_data; + + len += sizeof(*cur); + } +-- +2.16.4 + diff --git a/patches.suse/nvme-else-following-return-is-not-needed.patch b/patches.suse/nvme-else-following-return-is-not-needed.patch new file mode 100644 index 0000000..9624a45 --- /dev/null +++ b/patches.suse/nvme-else-following-return-is-not-needed.patch @@ -0,0 +1,33 @@ +From: Edmund Nadolski +Date: Mon, 25 Nov 2019 09:06:12 -0700 +Subject: [PATCH] nvme: else following return is not needed +Git-commit: c80b36cd9576efa861a080b05382856173a02ae9 +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +Remove unnecessary keyword in nvme_create_queue(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Edmund Nadolski +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index dcaad5831cee..9d307593b94f 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1549,7 +1549,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled) + result = adapter_alloc_sq(dev, qid, nvmeq); + if (result < 0) + return result; +- else if (result) ++ if (result) + goto release_cq; + + nvmeq->cq_vector = vector; +-- +2.16.4 + diff --git a/patches.suse/nvme-fabrics-Use-scnprintf-for-avoiding-potential-bu.patch b/patches.suse/nvme-fabrics-Use-scnprintf-for-avoiding-potential-bu.patch new file mode 100644 index 0000000..80005b2 --- /dev/null +++ b/patches.suse/nvme-fabrics-Use-scnprintf-for-avoiding-potential-bu.patch @@ -0,0 +1,45 @@ +From: Takashi Iwai +Date: Wed, 11 Mar 2020 09:50:37 +0100 +Subject: [PATCH] nvme-fabrics: Use scnprintf() for avoiding potential buffer overflow +Git-commit: 8d8a50e20dc2dc41cb788085968b9024dc36f7a5 +Patch-mainline: v5.7-rc1 +References: bsc#1161930 + +Since snprintf() returns the would-be-output size instead of the +actual output size, the succeeding calls may go beyond the given +buffer limit. Fix it by replacing with scnprintf(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Takashi Iwai +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fabrics.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/nvme/host/fabrics.c b/drivers/nvme/host/fabrics.c +index 74b8818ac9a1..2a6c8190eeb7 100644 +--- a/drivers/nvme/host/fabrics.c ++++ b/drivers/nvme/host/fabrics.c +@@ -105,14 +105,14 @@ int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size) + int len = 0; + + if (ctrl->opts->mask & NVMF_OPT_TRADDR) +- len += snprintf(buf, size, "traddr=%s", ctrl->opts->traddr); ++ len += scnprintf(buf, size, "traddr=%s", ctrl->opts->traddr); + if (ctrl->opts->mask & NVMF_OPT_TRSVCID) +- len += snprintf(buf + len, size - len, "%strsvcid=%s", ++ len += scnprintf(buf + len, size - len, "%strsvcid=%s", + (len) ? "," : "", ctrl->opts->trsvcid); + if (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR) +- len += snprintf(buf + len, size - len, "%shost_traddr=%s", ++ len += scnprintf(buf + len, size - len, "%shost_traddr=%s", + (len) ? "," : "", ctrl->opts->host_traddr); +- len += snprintf(buf + len, size - len, "\n"); ++ len += scnprintf(buf + len, size - len, "\n"); + + return len; + } +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-Add-Disconnect-Association-Rcv-support.patch b/patches.suse/nvme-fc-Add-Disconnect-Association-Rcv-support.patch new file mode 100644 index 0000000..bff269d --- /dev/null +++ b/patches.suse/nvme-fc-Add-Disconnect-Association-Rcv-support.patch @@ -0,0 +1,524 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:54 -0700 +Subject: [PATCH] nvme-fc: Add Disconnect Association Rcv support +Git-commit: 6d00dc01675e73c9269050a43a543b311ce8a3ca +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +The nvme-fc host transport did not support the reception of a +FC-NVME LS. Reception is necessary to implement full compliance +with FC-NVME-2. + +Populate the LS receive handler, and specifically the handling +of a Disconnect Association LS. The response to the LS, if it +matched a controller, must be sent after the aborts for any +I/O on any connection have been sent. + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 363 ++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 359 insertions(+), 4 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index c069ab056202..1921d2195541 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -62,6 +62,17 @@ struct nvmefc_ls_req_op { + bool req_queued; + }; + ++struct nvmefc_ls_rcv_op { ++ struct nvme_fc_rport *rport; ++ struct nvmefc_ls_rsp *lsrsp; ++ union nvmefc_ls_requests *rqstbuf; ++ union nvmefc_ls_responses *rspbuf; ++ u16 rqstdatalen; ++ bool handled; ++ dma_addr_t rspdma; ++ struct list_head lsrcv_list; /* rport->ls_rcv_list */ ++} __aligned(sizeof(u64)); /* alignment for other things alloc'd with */ ++ + enum nvme_fcpop_state { + FCPOP_STATE_UNINIT = 0, + FCPOP_STATE_IDLE = 1, +@@ -118,6 +129,7 @@ struct nvme_fc_rport { + struct list_head endp_list; /* for lport->endp_list */ + struct list_head ctrl_list; + struct list_head ls_req_list; ++ struct list_head ls_rcv_list; + struct list_head disc_list; + struct device *dev; /* physical device for dma */ + struct nvme_fc_lport *lport; +@@ -125,6 +137,7 @@ struct nvme_fc_rport { + struct kref ref; + atomic_t act_ctrl_cnt; + unsigned long dev_loss_end; ++ struct work_struct lsrcv_work; + } __aligned(sizeof(u64)); /* alignment for other things alloc'd with */ + + /* fc_ctrl flags values - specified as bit positions */ +@@ -142,6 +155,7 @@ struct nvme_fc_ctrl { + bool ioq_live; + atomic_t err_work_active; + u64 association_id; ++ struct nvmefc_ls_rcv_op *rcv_disconn; + + struct list_head ctrl_list; /* rport->ctrl_list */ + +@@ -219,6 +233,9 @@ static struct device *fc_udev_device; + static void __nvme_fc_delete_hw_queue(struct nvme_fc_ctrl *, + struct nvme_fc_queue *, unsigned int); + ++static void nvme_fc_handle_ls_rqst_work(struct work_struct *work); ++ ++ + static void + nvme_fc_free_lport(struct kref *ref) + { +@@ -704,6 +721,7 @@ nvme_fc_register_remoteport(struct nvme_fc_local_port *localport, + atomic_set(&newrec->act_ctrl_cnt, 0); + spin_lock_init(&newrec->lock); + newrec->remoteport.localport = &lport->localport; ++ INIT_LIST_HEAD(&newrec->ls_rcv_list); + newrec->dev = lport->dev; + newrec->lport = lport; + if (lport->ops->remote_priv_sz) +@@ -717,6 +735,7 @@ nvme_fc_register_remoteport(struct nvme_fc_local_port *localport, + newrec->remoteport.port_state = FC_OBJSTATE_ONLINE; + newrec->remoteport.port_num = idx; + __nvme_fc_set_dev_loss_tmo(newrec, pinfo); ++ INIT_WORK(&newrec->lsrcv_work, nvme_fc_handle_ls_rqst_work); + + spin_lock_irqsave(&nvme_fc_lock, flags); + list_add_tail(&newrec->endp_list, &lport->endp_list); +@@ -1006,6 +1025,7 @@ fc_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, + static void nvme_fc_ctrl_put(struct nvme_fc_ctrl *); + static int nvme_fc_ctrl_get(struct nvme_fc_ctrl *); + ++static void nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg); + + static void + __nvme_fc_finish_ls_req(struct nvmefc_ls_req_op *lsop) +@@ -1154,6 +1174,7 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, + struct nvmefc_ls_req *lsreq; + struct fcnvme_ls_cr_assoc_rqst *assoc_rqst; + struct fcnvme_ls_cr_assoc_acc *assoc_acc; ++ unsigned long flags; + int ret, fcret = 0; + + lsop = kzalloc((sizeof(*lsop) + +@@ -1243,11 +1264,13 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, + "q %d Create Association LS failed: %s\n", + queue->qnum, validation_errors[fcret]); + } else { ++ spin_lock_irqsave(&ctrl->lock, flags); + ctrl->association_id = + be64_to_cpu(assoc_acc->associd.association_id); + queue->connection_id = + be64_to_cpu(assoc_acc->connectid.connection_id); + set_bit(NVME_FC_Q_CONNECTED, &queue->flags); ++ spin_unlock_irqrestore(&ctrl->lock, flags); + } + + out_free_buffer: +@@ -1428,6 +1451,247 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + kfree(lsop); + } + ++static void ++nvme_fc_xmt_ls_rsp_done(struct nvmefc_ls_rsp *lsrsp) ++{ ++ struct nvmefc_ls_rcv_op *lsop = lsrsp->nvme_fc_private; ++ struct nvme_fc_rport *rport = lsop->rport; ++ struct nvme_fc_lport *lport = rport->lport; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&rport->lock, flags); ++ list_del(&lsop->lsrcv_list); ++ spin_unlock_irqrestore(&rport->lock, flags); ++ ++ fc_dma_sync_single_for_cpu(lport->dev, lsop->rspdma, ++ sizeof(*lsop->rspbuf), DMA_TO_DEVICE); ++ fc_dma_unmap_single(lport->dev, lsop->rspdma, ++ sizeof(*lsop->rspbuf), DMA_TO_DEVICE); ++ ++ kfree(lsop); ++ ++ nvme_fc_rport_put(rport); ++} ++ ++static void ++nvme_fc_xmt_ls_rsp(struct nvmefc_ls_rcv_op *lsop) ++{ ++ struct nvme_fc_rport *rport = lsop->rport; ++ struct nvme_fc_lport *lport = rport->lport; ++ struct fcnvme_ls_rqst_w0 *w0 = &lsop->rqstbuf->w0; ++ int ret; ++ ++ fc_dma_sync_single_for_device(lport->dev, lsop->rspdma, ++ sizeof(*lsop->rspbuf), DMA_TO_DEVICE); ++ ++ ret = lport->ops->xmt_ls_rsp(&lport->localport, &rport->remoteport, ++ lsop->lsrsp); ++ if (ret) { ++ dev_warn(lport->dev, ++ "LLDD rejected LS RSP xmt: LS %d status %d\n", ++ w0->ls_cmd, ret); ++ nvme_fc_xmt_ls_rsp_done(lsop->lsrsp); ++ return; ++ } ++} ++ ++static struct nvme_fc_ctrl * ++nvme_fc_match_disconn_ls(struct nvme_fc_rport *rport, ++ struct nvmefc_ls_rcv_op *lsop) ++{ ++ struct fcnvme_ls_disconnect_assoc_rqst *rqst = ++ &lsop->rqstbuf->rq_dis_assoc; ++ struct nvme_fc_ctrl *ctrl, *ret = NULL; ++ struct nvmefc_ls_rcv_op *oldls = NULL; ++ u64 association_id = be64_to_cpu(rqst->associd.association_id); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&rport->lock, flags); ++ ++ list_for_each_entry(ctrl, &rport->ctrl_list, ctrl_list) { ++ if (!nvme_fc_ctrl_get(ctrl)) ++ continue; ++ spin_lock(&ctrl->lock); ++ if (association_id == ctrl->association_id) { ++ oldls = ctrl->rcv_disconn; ++ ctrl->rcv_disconn = lsop; ++ ret = ctrl; ++ } ++ spin_unlock(&ctrl->lock); ++ if (ret) ++ /* leave the ctrl get reference */ ++ break; ++ nvme_fc_ctrl_put(ctrl); ++ } ++ ++ spin_unlock_irqrestore(&rport->lock, flags); ++ ++ /* transmit a response for anything that was pending */ ++ if (oldls) { ++ dev_info(rport->lport->dev, ++ "NVME-FC{%d}: Multiple Disconnect Association " ++ "LS's received\n", ctrl->cnum); ++ /* overwrite good response with bogus failure */ ++ oldls->lsrsp->rsplen = nvme_fc_format_rjt(oldls->rspbuf, ++ sizeof(*oldls->rspbuf), ++ rqst->w0.ls_cmd, ++ FCNVME_RJT_RC_UNAB, ++ FCNVME_RJT_EXP_NONE, 0); ++ nvme_fc_xmt_ls_rsp(oldls); ++ } ++ ++ return ret; ++} ++ ++/* ++ * returns true to mean LS handled and ls_rsp can be sent ++ * returns false to defer ls_rsp xmt (will be done as part of ++ * association termination) ++ */ ++static bool ++nvme_fc_ls_disconnect_assoc(struct nvmefc_ls_rcv_op *lsop) ++{ ++ struct nvme_fc_rport *rport = lsop->rport; ++ struct fcnvme_ls_disconnect_assoc_rqst *rqst = ++ &lsop->rqstbuf->rq_dis_assoc; ++ struct fcnvme_ls_disconnect_assoc_acc *acc = ++ &lsop->rspbuf->rsp_dis_assoc; ++ struct nvme_fc_ctrl *ctrl = NULL; ++ int ret = 0; ++ ++ memset(acc, 0, sizeof(*acc)); ++ ++ ret = nvmefc_vldt_lsreq_discon_assoc(lsop->rqstdatalen, rqst); ++ if (!ret) { ++ /* match an active association */ ++ ctrl = nvme_fc_match_disconn_ls(rport, lsop); ++ if (!ctrl) ++ ret = VERR_NO_ASSOC; ++ } ++ ++ if (ret) { ++ dev_info(rport->lport->dev, ++ "Disconnect LS failed: %s\n", ++ validation_errors[ret]); ++ lsop->lsrsp->rsplen = nvme_fc_format_rjt(acc, ++ sizeof(*acc), rqst->w0.ls_cmd, ++ (ret == VERR_NO_ASSOC) ? ++ FCNVME_RJT_RC_INV_ASSOC : ++ FCNVME_RJT_RC_LOGIC, ++ FCNVME_RJT_EXP_NONE, 0); ++ return true; ++ } ++ ++ /* format an ACCept response */ ++ ++ lsop->lsrsp->rsplen = sizeof(*acc); ++ ++ nvme_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, ++ fcnvme_lsdesc_len( ++ sizeof(struct fcnvme_ls_disconnect_assoc_acc)), ++ FCNVME_LS_DISCONNECT_ASSOC); ++ ++ /* ++ * the transmit of the response will occur after the exchanges ++ * for the association have been ABTS'd by ++ * nvme_fc_delete_association(). ++ */ ++ ++ /* fail the association */ ++ nvme_fc_error_recovery(ctrl, "Disconnect Association LS received"); ++ ++ /* release the reference taken by nvme_fc_match_disconn_ls() */ ++ nvme_fc_ctrl_put(ctrl); ++ ++ return false; ++} ++ ++/* ++ * Actual Processing routine for received FC-NVME LS Requests from the LLD ++ * returns true if a response should be sent afterward, false if rsp will ++ * be sent asynchronously. ++ */ ++static bool ++nvme_fc_handle_ls_rqst(struct nvmefc_ls_rcv_op *lsop) ++{ ++ struct fcnvme_ls_rqst_w0 *w0 = &lsop->rqstbuf->w0; ++ bool ret = true; ++ ++ lsop->lsrsp->nvme_fc_private = lsop; ++ lsop->lsrsp->rspbuf = lsop->rspbuf; ++ lsop->lsrsp->rspdma = lsop->rspdma; ++ lsop->lsrsp->done = nvme_fc_xmt_ls_rsp_done; ++ /* Be preventative. handlers will later set to valid length */ ++ lsop->lsrsp->rsplen = 0; ++ ++ /* ++ * handlers: ++ * parse request input, execute the request, and format the ++ * LS response ++ */ ++ switch (w0->ls_cmd) { ++ case FCNVME_LS_DISCONNECT_ASSOC: ++ ret = nvme_fc_ls_disconnect_assoc(lsop); ++ break; ++ case FCNVME_LS_DISCONNECT_CONN: ++ lsop->lsrsp->rsplen = nvme_fc_format_rjt(lsop->rspbuf, ++ sizeof(*lsop->rspbuf), w0->ls_cmd, ++ FCNVME_RJT_RC_UNSUP, FCNVME_RJT_EXP_NONE, 0); ++ break; ++ case FCNVME_LS_CREATE_ASSOCIATION: ++ case FCNVME_LS_CREATE_CONNECTION: ++ lsop->lsrsp->rsplen = nvme_fc_format_rjt(lsop->rspbuf, ++ sizeof(*lsop->rspbuf), w0->ls_cmd, ++ FCNVME_RJT_RC_LOGIC, FCNVME_RJT_EXP_NONE, 0); ++ break; ++ default: ++ lsop->lsrsp->rsplen = nvme_fc_format_rjt(lsop->rspbuf, ++ sizeof(*lsop->rspbuf), w0->ls_cmd, ++ FCNVME_RJT_RC_INVAL, FCNVME_RJT_EXP_NONE, 0); ++ break; ++ } ++ ++ return(ret); ++} ++ ++static void ++nvme_fc_handle_ls_rqst_work(struct work_struct *work) ++{ ++ struct nvme_fc_rport *rport = ++ container_of(work, struct nvme_fc_rport, lsrcv_work); ++ struct fcnvme_ls_rqst_w0 *w0; ++ struct nvmefc_ls_rcv_op *lsop; ++ unsigned long flags; ++ bool sendrsp; ++ ++restart: ++ sendrsp = true; ++ spin_lock_irqsave(&rport->lock, flags); ++ list_for_each_entry(lsop, &rport->ls_rcv_list, lsrcv_list) { ++ if (lsop->handled) ++ continue; ++ ++ lsop->handled = true; ++ if (rport->remoteport.port_state == FC_OBJSTATE_ONLINE) { ++ spin_unlock_irqrestore(&rport->lock, flags); ++ sendrsp = nvme_fc_handle_ls_rqst(lsop); ++ } else { ++ spin_unlock_irqrestore(&rport->lock, flags); ++ w0 = &lsop->rqstbuf->w0; ++ lsop->lsrsp->rsplen = nvme_fc_format_rjt( ++ lsop->rspbuf, ++ sizeof(*lsop->rspbuf), ++ w0->ls_cmd, ++ FCNVME_RJT_RC_UNAB, ++ FCNVME_RJT_EXP_NONE, 0); ++ } ++ if (sendrsp) ++ nvme_fc_xmt_ls_rsp(lsop); ++ goto restart; ++ } ++ spin_unlock_irqrestore(&rport->lock, flags); ++} ++ + /** + * nvme_fc_rcv_ls_req - transport entry point called by an LLDD + * upon the reception of a NVME LS request. +@@ -1454,20 +1718,92 @@ nvme_fc_rcv_ls_req(struct nvme_fc_remote_port *portptr, + { + struct nvme_fc_rport *rport = remoteport_to_rport(portptr); + struct nvme_fc_lport *lport = rport->lport; ++ struct fcnvme_ls_rqst_w0 *w0 = (struct fcnvme_ls_rqst_w0 *)lsreqbuf; ++ struct nvmefc_ls_rcv_op *lsop; ++ unsigned long flags; ++ int ret; ++ ++ nvme_fc_rport_get(rport); + + /* validate there's a routine to transmit a response */ +- if (!lport->ops->xmt_ls_rsp) +- return(-EINVAL); ++ if (!lport->ops->xmt_ls_rsp) { ++ dev_info(lport->dev, ++ "RCV %s LS failed: no LLDD xmt_ls_rsp\n", ++ (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? ++ nvmefc_ls_names[w0->ls_cmd] : ""); ++ ret = -EINVAL; ++ goto out_put; ++ } ++ ++ if (lsreqbuf_len > sizeof(union nvmefc_ls_requests)) { ++ dev_info(lport->dev, ++ "RCV %s LS failed: payload too large\n", ++ (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? ++ nvmefc_ls_names[w0->ls_cmd] : ""); ++ ret = -E2BIG; ++ goto out_put; ++ } ++ ++ lsop = kzalloc(sizeof(*lsop) + ++ sizeof(union nvmefc_ls_requests) + ++ sizeof(union nvmefc_ls_responses), ++ GFP_KERNEL); ++ if (!lsop) { ++ dev_info(lport->dev, ++ "RCV %s LS failed: No memory\n", ++ (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? ++ nvmefc_ls_names[w0->ls_cmd] : ""); ++ ret = -ENOMEM; ++ goto out_put; ++ } ++ lsop->rqstbuf = (union nvmefc_ls_requests *)&lsop[1]; ++ lsop->rspbuf = (union nvmefc_ls_responses *)&lsop->rqstbuf[1]; ++ ++ lsop->rspdma = fc_dma_map_single(lport->dev, lsop->rspbuf, ++ sizeof(*lsop->rspbuf), ++ DMA_TO_DEVICE); ++ if (fc_dma_mapping_error(lport->dev, lsop->rspdma)) { ++ dev_info(lport->dev, ++ "RCV %s LS failed: DMA mapping failure\n", ++ (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? ++ nvmefc_ls_names[w0->ls_cmd] : ""); ++ ret = -EFAULT; ++ goto out_free; ++ } ++ ++ lsop->rport = rport; ++ lsop->lsrsp = lsrsp; ++ ++ memcpy(lsop->rqstbuf, lsreqbuf, lsreqbuf_len); ++ lsop->rqstdatalen = lsreqbuf_len; ++ ++ spin_lock_irqsave(&rport->lock, flags); ++ if (rport->remoteport.port_state != FC_OBJSTATE_ONLINE) { ++ spin_unlock_irqrestore(&rport->lock, flags); ++ ret = -ENOTCONN; ++ goto out_unmap; ++ } ++ list_add_tail(&lsop->lsrcv_list, &rport->ls_rcv_list); ++ spin_unlock_irqrestore(&rport->lock, flags); ++ ++ schedule_work(&rport->lsrcv_work); + + return 0; ++ ++out_unmap: ++ fc_dma_unmap_single(lport->dev, lsop->rspdma, ++ sizeof(*lsop->rspbuf), DMA_TO_DEVICE); ++out_free: ++ kfree(lsop); ++out_put: ++ nvme_fc_rport_put(rport); ++ return ret; + } + EXPORT_SYMBOL_GPL(nvme_fc_rcv_ls_req); + + + /* *********************** NVME Ctrl Routines **************************** */ + +-static void nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg); +- + static void + __nvme_fc_exit_request(struct nvme_fc_ctrl *ctrl, + struct nvme_fc_fcp_op *op) +@@ -2612,6 +2948,8 @@ static int + nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + { + struct nvmf_ctrl_options *opts = ctrl->ctrl.opts; ++ struct nvmefc_ls_rcv_op *disls = NULL; ++ unsigned long flags; + int ret; + bool changed; + +@@ -2729,7 +3067,13 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + out_disconnect_admin_queue: + /* send a Disconnect(association) LS to fc-nvme target */ + nvme_fc_xmt_disconnect_assoc(ctrl); ++ spin_lock_irqsave(&ctrl->lock, flags); + ctrl->association_id = 0; ++ disls = ctrl->rcv_disconn; ++ ctrl->rcv_disconn = NULL; ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (disls) ++ nvme_fc_xmt_ls_rsp(disls); + out_delete_hw_queue: + __nvme_fc_delete_hw_queue(ctrl, &ctrl->queues[0], 0); + out_free_queue: +@@ -2749,6 +3093,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + static void + nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) + { ++ struct nvmefc_ls_rcv_op *disls = NULL; + unsigned long flags; + + if (!test_and_clear_bit(ASSOC_ACTIVE, &ctrl->flags)) +@@ -2820,7 +3165,17 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) + if (ctrl->association_id) + nvme_fc_xmt_disconnect_assoc(ctrl); + ++ spin_lock_irqsave(&ctrl->lock, flags); + ctrl->association_id = 0; ++ disls = ctrl->rcv_disconn; ++ ctrl->rcv_disconn = NULL; ++ spin_unlock_irqrestore(&ctrl->lock, flags); ++ if (disls) ++ /* ++ * if a Disconnect Request was waiting for a response, send ++ * now that all ABTS's have been issued (and are complete). ++ */ ++ nvme_fc_xmt_ls_rsp(disls); + + if (ctrl->ctrl.tagset) { + nvme_fc_delete_hw_io_queues(ctrl); +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-Avoid-preallocating-big-SGL-for-data.patch b/patches.suse/nvme-fc-Avoid-preallocating-big-SGL-for-data.patch new file mode 100644 index 0000000..01a844d --- /dev/null +++ b/patches.suse/nvme-fc-Avoid-preallocating-big-SGL-for-data.patch @@ -0,0 +1,76 @@ +From: Israel Rukshin +Date: Sun, 24 Nov 2019 18:38:31 +0200 +Subject: [PATCH] nvme-fc: Avoid preallocating big SGL for data +Git-commit: b1ae1a238900474a9f51431c0f7f169ade1faa19 +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +nvme_fc_create_io_queues() preallocates a big buffer for the IO SGL based +on SG_CHUNK_SIZE. + +Modern DMA engines are often capable of dealing with very big segments so +the SG_CHUNK_SIZE is often too big. SG_CHUNK_SIZE results in a static 4KB +SGL allocation per command. + +If a controller has lots of deep queues, preallocation for the sg list can +consume substantial amounts of memory. For nvme-fc, nr_hw_queues can be +128 and each queue's depth 128. This means the resulting preallocation +for the data SGL is 128*128*4K = 64MB per controller. + +Switch to runtime allocation for SGL for lists longer than 2 entries. This +is the approach used by NVMe PCI so it should be reasonable for NVMeOF as +well. Runtime SGL allocation has always been the case for the legacy I/O +path so this is nothing new. + +Reviewed-by: Max Gurtovoy +Reviewed-by: James Smart +Signed-off-by: Israel Rukshin +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 679a721ae229..13cb00e56cac 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -95,7 +95,7 @@ struct nvme_fc_fcp_op { + + struct nvme_fcp_op_w_sgl { + struct nvme_fc_fcp_op op; +- struct scatterlist sgl[SG_CHUNK_SIZE]; ++ struct scatterlist sgl[NVME_INLINE_SG_CNT]; + uint8_t priv[0]; + }; + +@@ -2141,7 +2141,7 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq, + freq->sg_table.sgl = freq->first_sgl; + ret = sg_alloc_table_chained(&freq->sg_table, + blk_rq_nr_phys_segments(rq), freq->sg_table.sgl, +- SG_CHUNK_SIZE); ++ NVME_INLINE_SG_CNT); + if (ret) + return -ENOMEM; + +@@ -2150,7 +2150,7 @@ nvme_fc_map_data(struct nvme_fc_ctrl *ctrl, struct request *rq, + freq->sg_cnt = fc_dma_map_sg(ctrl->lport->dev, freq->sg_table.sgl, + op->nents, rq_dma_dir(rq)); + if (unlikely(freq->sg_cnt <= 0)) { +- sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE); ++ sg_free_table_chained(&freq->sg_table, NVME_INLINE_SG_CNT); + freq->sg_cnt = 0; + return -EFAULT; + } +@@ -2173,7 +2173,7 @@ nvme_fc_unmap_data(struct nvme_fc_ctrl *ctrl, struct request *rq, + fc_dma_unmap_sg(ctrl->lport->dev, freq->sg_table.sgl, op->nents, + rq_dma_dir(rq)); + +- sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE); ++ sg_free_table_chained(&freq->sg_table, NVME_INLINE_SG_CNT); + + freq->sg_cnt = 0; + } +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-Ensure-private-pointers-are-NULL-if-no-data.patch b/patches.suse/nvme-fc-Ensure-private-pointers-are-NULL-if-no-data.patch new file mode 100644 index 0000000..cf81856 --- /dev/null +++ b/patches.suse/nvme-fc-Ensure-private-pointers-are-NULL-if-no-data.patch @@ -0,0 +1,200 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:50 -0700 +Subject: [PATCH] nvme-fc: Ensure private pointers are NULL if no data +Git-commit: 17dbd219e6ae3b09a967367071427e44d19f2686 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Ensure that when allocations are done, and the lldd options indicate +no private data is needed, that private pointers will be set to NULL +(catches driver error that forgot to set private data size). + +Slightly reorg the allocations so that private data follows allocations +for LS request/response buffers. Ensures better alignments for the buffers +as well as the private pointer. + +Signed-off-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Hannes Reinecke +Reviewed-by: Himanshu Madhani +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 81 ++++++++++++++++++++++++++++++------------------ + drivers/nvme/target/fc.c | 5 ++- + 2 files changed, 54 insertions(+), 32 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 83f9b2ac7c55..bf80b941d739 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -395,7 +395,10 @@ nvme_fc_register_localport(struct nvme_fc_port_info *pinfo, + newrec->ops = template; + newrec->dev = dev; + ida_init(&newrec->endp_cnt); +- newrec->localport.private = &newrec[1]; ++ if (template->local_priv_sz) ++ newrec->localport.private = &newrec[1]; ++ else ++ newrec->localport.private = NULL; + newrec->localport.node_name = pinfo->node_name; + newrec->localport.port_name = pinfo->port_name; + newrec->localport.port_role = pinfo->port_role; +@@ -704,7 +707,10 @@ nvme_fc_register_remoteport(struct nvme_fc_local_port *localport, + newrec->remoteport.localport = &lport->localport; + newrec->dev = lport->dev; + newrec->lport = lport; +- newrec->remoteport.private = &newrec[1]; ++ if (lport->ops->remote_priv_sz) ++ newrec->remoteport.private = &newrec[1]; ++ else ++ newrec->remoteport.private = NULL; + newrec->remoteport.port_role = pinfo->port_role; + newrec->remoteport.node_name = pinfo->node_name; + newrec->remoteport.port_name = pinfo->port_name; +@@ -1152,18 +1158,23 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, + int ret, fcret = 0; + + lsop = kzalloc((sizeof(*lsop) + +- ctrl->lport->ops->lsrqst_priv_sz + +- sizeof(*assoc_rqst) + sizeof(*assoc_acc)), GFP_KERNEL); ++ sizeof(*assoc_rqst) + sizeof(*assoc_acc) + ++ ctrl->lport->ops->lsrqst_priv_sz), GFP_KERNEL); + if (!lsop) { ++ dev_info(ctrl->ctrl.device, ++ "NVME-FC{%d}: send Create Association failed: ENOMEM\n", ++ ctrl->cnum); + ret = -ENOMEM; + goto out_no_memory; + } +- lsreq = &lsop->ls_req; + +- lsreq->private = (void *)&lsop[1]; +- assoc_rqst = (struct fcnvme_ls_cr_assoc_rqst *) +- (lsreq->private + ctrl->lport->ops->lsrqst_priv_sz); ++ assoc_rqst = (struct fcnvme_ls_cr_assoc_rqst *)&lsop[1]; + assoc_acc = (struct fcnvme_ls_cr_assoc_acc *)&assoc_rqst[1]; ++ lsreq = &lsop->ls_req; ++ if (ctrl->lport->ops->lsrqst_priv_sz) ++ lsreq->private = &assoc_acc[1]; ++ else ++ lsreq->private = NULL; + + assoc_rqst->w0.ls_cmd = FCNVME_LS_CREATE_ASSOCIATION; + assoc_rqst->desc_list_len = +@@ -1261,18 +1272,23 @@ nvme_fc_connect_queue(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, + int ret, fcret = 0; + + lsop = kzalloc((sizeof(*lsop) + +- ctrl->lport->ops->lsrqst_priv_sz + +- sizeof(*conn_rqst) + sizeof(*conn_acc)), GFP_KERNEL); ++ sizeof(*conn_rqst) + sizeof(*conn_acc) + ++ ctrl->lport->ops->lsrqst_priv_sz), GFP_KERNEL); + if (!lsop) { ++ dev_info(ctrl->ctrl.device, ++ "NVME-FC{%d}: send Create Connection failed: ENOMEM\n", ++ ctrl->cnum); + ret = -ENOMEM; + goto out_no_memory; + } +- lsreq = &lsop->ls_req; + +- lsreq->private = (void *)&lsop[1]; +- conn_rqst = (struct fcnvme_ls_cr_conn_rqst *) +- (lsreq->private + ctrl->lport->ops->lsrqst_priv_sz); ++ conn_rqst = (struct fcnvme_ls_cr_conn_rqst *)&lsop[1]; + conn_acc = (struct fcnvme_ls_cr_conn_acc *)&conn_rqst[1]; ++ lsreq = &lsop->ls_req; ++ if (ctrl->lport->ops->lsrqst_priv_sz) ++ lsreq->private = (void *)&conn_acc[1]; ++ else ++ lsreq->private = NULL; + + conn_rqst->w0.ls_cmd = FCNVME_LS_CREATE_CONNECTION; + conn_rqst->desc_list_len = cpu_to_be32( +@@ -1386,19 +1402,23 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + int ret; + + lsop = kzalloc((sizeof(*lsop) + +- ctrl->lport->ops->lsrqst_priv_sz + +- sizeof(*discon_rqst) + sizeof(*discon_acc)), +- GFP_KERNEL); +- if (!lsop) +- /* couldn't sent it... too bad */ ++ sizeof(*discon_rqst) + sizeof(*discon_acc) + ++ ctrl->lport->ops->lsrqst_priv_sz), GFP_KERNEL); ++ if (!lsop) { ++ dev_info(ctrl->ctrl.device, ++ "NVME-FC{%d}: send Disconnect Association " ++ "failed: ENOMEM\n", ++ ctrl->cnum); + return; ++ } + +- lsreq = &lsop->ls_req; +- +- lsreq->private = (void *)&lsop[1]; +- discon_rqst = (struct fcnvme_ls_disconnect_assoc_rqst *) +- (lsreq->private + ctrl->lport->ops->lsrqst_priv_sz); ++ discon_rqst = (struct fcnvme_ls_disconnect_assoc_rqst *)&lsop[1]; + discon_acc = (struct fcnvme_ls_disconnect_assoc_acc *)&discon_rqst[1]; ++ lsreq = &lsop->ls_req; ++ if (ctrl->lport->ops->lsrqst_priv_sz) ++ lsreq->private = (void *)&discon_acc[1]; ++ else ++ lsreq->private = NULL; + + discon_rqst->w0.ls_cmd = FCNVME_LS_DISCONNECT_ASSOC; + discon_rqst->desc_list_len = cpu_to_be32( +@@ -1784,15 +1804,17 @@ nvme_fc_init_aen_ops(struct nvme_fc_ctrl *ctrl) + struct nvme_fc_fcp_op *aen_op; + struct nvme_fc_cmd_iu *cmdiu; + struct nvme_command *sqe; +- void *private; ++ void *private = NULL; + int i, ret; + + aen_op = ctrl->aen_ops; + for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++) { +- private = kzalloc(ctrl->lport->ops->fcprqst_priv_sz, ++ if (ctrl->lport->ops->fcprqst_priv_sz) { ++ private = kzalloc(ctrl->lport->ops->fcprqst_priv_sz, + GFP_KERNEL); +- if (!private) +- return -ENOMEM; ++ if (!private) ++ return -ENOMEM; ++ } + + cmdiu = &aen_op->cmd_iu; + sqe = &cmdiu->sqe; +@@ -1823,9 +1845,6 @@ nvme_fc_term_aen_ops(struct nvme_fc_ctrl *ctrl) + + aen_op = ctrl->aen_ops; + for (i = 0; i < NVME_NR_AEN_COMMANDS; i++, aen_op++) { +- if (!aen_op->fcp_req.private) +- continue; +- + __nvme_fc_exit_request(ctrl, aen_op); + + kfree(aen_op->fcp_req.private); +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 66de6bd8f4fd..66a60a218994 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -1047,7 +1047,10 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo, + + newrec->fc_target_port.node_name = pinfo->node_name; + newrec->fc_target_port.port_name = pinfo->port_name; +- newrec->fc_target_port.private = &newrec[1]; ++ if (template->target_priv_sz) ++ newrec->fc_target_port.private = &newrec[1]; ++ else ++ newrec->fc_target_port.private = NULL; + newrec->fc_target_port.port_id = pinfo->port_id; + newrec->fc_target_port.port_num = idx; + INIT_LIST_HEAD(&newrec->tgt_list); +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-Revert-add-module-to-ops-template-to-allow-m.patch b/patches.suse/nvme-fc-Revert-add-module-to-ops-template-to-allow-m.patch new file mode 100644 index 0000000..05eef38 --- /dev/null +++ b/patches.suse/nvme-fc-Revert-add-module-to-ops-template-to-allow-m.patch @@ -0,0 +1,147 @@ +From: James Smart +Date: Fri, 3 Apr 2020 07:33:20 -0700 +Subject: [PATCH] nvme-fc: Revert "add module to ops template to allow module +Git-commit: 8c5c660529209a0e324c1c1a35ce3f83d67a2aa5 +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + references" + +The original patch was to resolve the lldd being able to be unloaded +while being used to talk to the boot device of the system. However, the +end result of the original patch is that any driver unload while a nvme +controller is live via the lldd is now being prohibited. Given the module +reference, the module teardown routine can't be called, thus there's no +way, other than manual actions to terminate the controllers. + +Fixes: 863fbae929c7 ("nvme_fc: add module to ops template to allow module references") +Cc: # v5.4+ +Signed-off-by: James Smart +Reviewed-by: Himanshu Madhani +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 14 ++------------ + drivers/nvme/target/fcloop.c | 1 - + drivers/scsi/lpfc/lpfc_nvme.c | 2 -- + drivers/scsi/qla2xxx/qla_nvme.c | 1 - + include/linux/nvme-fc-driver.h | 4 ---- + 5 files changed, 2 insertions(+), 20 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index a8bf2fb1287b..7dfc4a2ecf1e 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -342,8 +342,7 @@ nvme_fc_register_localport(struct nvme_fc_port_info *pinfo, + !template->ls_req || !template->fcp_io || + !template->ls_abort || !template->fcp_abort || + !template->max_hw_queues || !template->max_sgl_segments || +- !template->max_dif_sgl_segments || !template->dma_boundary || +- !template->module) { ++ !template->max_dif_sgl_segments || !template->dma_boundary) { + ret = -EINVAL; + goto out_reghost_failed; + } +@@ -2016,7 +2015,6 @@ nvme_fc_ctrl_free(struct kref *ref) + { + struct nvme_fc_ctrl *ctrl = + container_of(ref, struct nvme_fc_ctrl, ref); +- struct nvme_fc_lport *lport = ctrl->lport; + unsigned long flags; + + if (ctrl->ctrl.tagset) { +@@ -2043,7 +2041,6 @@ nvme_fc_ctrl_free(struct kref *ref) + if (ctrl->ctrl.opts) + nvmf_free_options(ctrl->ctrl.opts); + kfree(ctrl); +- module_put(lport->ops->module); + } + + static void +@@ -3074,15 +3071,10 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, + goto out_fail; + } + +- if (!try_module_get(lport->ops->module)) { +- ret = -EUNATCH; +- goto out_free_ctrl; +- } +- + idx = ida_simple_get(&nvme_fc_ctrl_cnt, 0, 0, GFP_KERNEL); + if (idx < 0) { + ret = -ENOSPC; +- goto out_mod_put; ++ goto out_free_ctrl; + } + + ctrl->ctrl.opts = opts; +@@ -3232,8 +3224,6 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, + out_free_ida: + put_device(ctrl->dev); + ida_simple_remove(&nvme_fc_ctrl_cnt, ctrl->cnum); +-out_mod_put: +- module_put(lport->ops->module); + out_free_ctrl: + kfree(ctrl); + out_fail: +diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c +index 9861fcea39f6..f69ce66e2d44 100644 +--- a/drivers/nvme/target/fcloop.c ++++ b/drivers/nvme/target/fcloop.c +@@ -875,7 +875,6 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport) + #define FCLOOP_DMABOUND_4G 0xFFFFFFFF + + static struct nvme_fc_port_template fctemplate = { +- .module = THIS_MODULE, + .localport_delete = fcloop_localport_delete, + .remoteport_delete = fcloop_remoteport_delete, + .create_queue = fcloop_create_queue, +diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c +index f6c8963c915d..db4a04a207ec 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.c ++++ b/drivers/scsi/lpfc/lpfc_nvme.c +@@ -1985,8 +1985,6 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, + + /* Declare and initialization an instance of the FC NVME template. */ + static struct nvme_fc_port_template lpfc_nvme_template = { +- .module = THIS_MODULE, +- + /* initiator-based functions */ + .localport_delete = lpfc_nvme_localport_delete, + .remoteport_delete = lpfc_nvme_remoteport_delete, +diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c +index bfcd02fdf2b8..941aa53363f5 100644 +--- a/drivers/scsi/qla2xxx/qla_nvme.c ++++ b/drivers/scsi/qla2xxx/qla_nvme.c +@@ -610,7 +610,6 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) + } + + static struct nvme_fc_port_template qla_nvme_fc_transport = { +- .module = THIS_MODULE, + .localport_delete = qla_nvme_localport_delete, + .remoteport_delete = qla_nvme_remoteport_delete, + .create_queue = qla_nvme_alloc_queue, +diff --git a/include/linux/nvme-fc-driver.h b/include/linux/nvme-fc-driver.h +index 6d0d70f3219c..10f81629b9ce 100644 +--- a/include/linux/nvme-fc-driver.h ++++ b/include/linux/nvme-fc-driver.h +@@ -270,8 +270,6 @@ struct nvme_fc_remote_port { + * + * Host/Initiator Transport Entrypoints/Parameters: + * +- * @module: The LLDD module using the interface +- * + * @localport_delete: The LLDD initiates deletion of a localport via + * nvme_fc_deregister_localport(). However, the teardown is + * asynchronous. This routine is called upon the completion of the +@@ -385,8 +383,6 @@ struct nvme_fc_remote_port { + * Value is Mandatory. Allowed to be zero. + */ + struct nvme_fc_port_template { +- struct module *module; +- + /* initiator-based functions */ + void (*localport_delete)(struct nvme_fc_local_port *); + void (*remoteport_delete)(struct nvme_fc_remote_port *); +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-Set-new-cmd-set-indicator-in-nvme-fc-cmnd-iu.patch b/patches.suse/nvme-fc-Set-new-cmd-set-indicator-in-nvme-fc-cmnd-iu.patch new file mode 100644 index 0000000..19f0d62 --- /dev/null +++ b/patches.suse/nvme-fc-Set-new-cmd-set-indicator-in-nvme-fc-cmnd-iu.patch @@ -0,0 +1,36 @@ +From: James Smart +Date: Fri, 27 Sep 2019 14:51:36 -0700 +Subject: [PATCH] nvme-fc: Set new cmd set indicator in nvme-fc cmnd iu +Git-commit: 44fbf3bb1ac3dbebc6bd07eb68abf2d0badfae65 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Set the new category field in the FC-NVME CMND_IU based on queue number. + +Signed-off-by: James Smart +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index e09c61ec0b96..e099a74f666e 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -1732,6 +1732,11 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl, + cmdiu->format_id = NVME_CMD_FORMAT_ID; + cmdiu->fc_id = NVME_CMD_FC_ID; + cmdiu->iu_len = cpu_to_be16(sizeof(*cmdiu) / sizeof(u32)); ++ if (queue->qnum) ++ cmdiu->rsv_cat = fccmnd_set_cat_css(0, ++ (NVME_CC_CSS_NVM >> NVME_CC_CSS_SHIFT)); ++ else ++ cmdiu->rsv_cat = fccmnd_set_cat_admin(0); + + op->fcp_req.cmddma = fc_dma_map_single(ctrl->lport->dev, + &op->cmd_iu, sizeof(op->cmd_iu), DMA_TO_DEVICE); +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-Sync-header-to-FC-NVME-2-rev-1.08.patch b/patches.suse/nvme-fc-Sync-header-to-FC-NVME-2-rev-1.08.patch new file mode 100644 index 0000000..812f78a --- /dev/null +++ b/patches.suse/nvme-fc-Sync-header-to-FC-NVME-2-rev-1.08.patch @@ -0,0 +1,68 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:46 -0700 +Subject: [PATCH] nvme-fc: Sync header to FC-NVME-2 rev 1.08 +Git-commit: da4baa7f26b06a9e317bd419719bed6b298944ca +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +A couple of minor changes occurred between 1.06 and 1.08: +- Addition of NVME_SR_RSP opcode +- change of SR_RSP status code 1 to Reserved + +Signed-off-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Himanshu Madhani +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + include/linux/nvme-fc.h | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/include/linux/nvme-fc.h b/include/linux/nvme-fc.h +index e8c30b39bb27..51fe44e0328b 100644 +--- a/include/linux/nvme-fc.h ++++ b/include/linux/nvme-fc.h +@@ -4,8 +4,8 @@ + */ + + /* +- * This file contains definitions relative to FC-NVME-2 r1.06 +- * (T11-2019-00210-v001). ++ * This file contains definitions relative to FC-NVME-2 r1.08 ++ * (T11-2019-00210-v004). + */ + + #ifndef _NVME_FC_H +@@ -81,7 +81,8 @@ struct nvme_fc_ersp_iu { + }; + + +-#define FCNVME_NVME_SR_OPCODE 0x01 ++#define FCNVME_NVME_SR_OPCODE 0x01 ++#define FCNVME_NVME_SR_RSP_OPCODE 0x02 + + struct nvme_fc_nvme_sr_iu { + __u8 fc_id; +@@ -94,7 +95,7 @@ struct nvme_fc_nvme_sr_iu { + + enum { + FCNVME_SRSTAT_ACC = 0x0, +- FCNVME_SRSTAT_INV_FCID = 0x1, ++ /* reserved 0x1 */ + /* reserved 0x2 */ + FCNVME_SRSTAT_LOGICAL_ERR = 0x3, + FCNVME_SRSTAT_INV_QUALIF = 0x4, +@@ -397,7 +398,7 @@ struct fcnvme_ls_disconnect_conn_rqst { + struct fcnvme_ls_rqst_w0 w0; + __be32 desc_list_len; + struct fcnvme_lsdesc_assoc_id associd; +- struct fcnvme_lsdesc_disconn_cmd connectid; ++ struct fcnvme_lsdesc_conn_id connectid; + }; + + struct fcnvme_ls_disconnect_conn_acc { +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-Sync-nvme-fc-header-to-FC-NVME-2.patch b/patches.suse/nvme-fc-Sync-nvme-fc-header-to-FC-NVME-2.patch new file mode 100644 index 0000000..b24003a --- /dev/null +++ b/patches.suse/nvme-fc-Sync-nvme-fc-header-to-FC-NVME-2.patch @@ -0,0 +1,328 @@ +From: James Smart +Date: Fri, 27 Sep 2019 14:51:34 -0700 +Subject: [PATCH] nvme-fc: Sync nvme-fc header to FC-NVME-2 +Git-commit: f16583614222d015968541f2e50447c67c277f74 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Sync the header to FC-NVME-2 r1.06 (T11-2019-00210-v001). + +Includes some minor mods where pre-release field names changed +by the time the spec was released. + +Signed-off-by: James Smart +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + include/linux/nvme-fc.h | 182 ++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 137 insertions(+), 45 deletions(-) + +diff --git a/include/linux/nvme-fc.h b/include/linux/nvme-fc.h +index 067c9fea64fe..e8c30b39bb27 100644 +--- a/include/linux/nvme-fc.h ++++ b/include/linux/nvme-fc.h +@@ -4,33 +4,60 @@ + */ + + /* +- * This file contains definitions relative to FC-NVME r1.14 (16-020vB). +- * The fcnvme_lsdesc_cr_assoc_cmd struct reflects expected r1.16 content. ++ * This file contains definitions relative to FC-NVME-2 r1.06 ++ * (T11-2019-00210-v001). + */ + + #ifndef _NVME_FC_H + #define _NVME_FC_H 1 + ++#include + +-#define NVME_CMD_SCSI_ID 0xFD ++#define NVME_CMD_FORMAT_ID 0xFD + #define NVME_CMD_FC_ID FC_TYPE_NVME + + /* FC-NVME Cmd IU Flags */ +-#define FCNVME_CMD_FLAGS_DIRMASK 0x03 +-#define FCNVME_CMD_FLAGS_WRITE 0x01 +-#define FCNVME_CMD_FLAGS_READ 0x02 ++enum { ++ FCNVME_CMD_FLAGS_DIRMASK = 0x03, ++ FCNVME_CMD_FLAGS_WRITE = (1 << 0), ++ FCNVME_CMD_FLAGS_READ = (1 << 1), ++ ++ FCNVME_CMD_FLAGS_PICWP = (1 << 2), ++}; ++ ++enum { ++ FCNVME_CMD_CAT_MASK = 0x0F, ++ FCNVME_CMD_CAT_ADMINQ = 0x01, ++ FCNVME_CMD_CAT_CSSMASK = 0x07, ++ FCNVME_CMD_CAT_CSSFLAG = 0x08, ++}; ++ ++static inline __u8 fccmnd_set_cat_admin(__u8 rsv_cat) ++{ ++ return (rsv_cat & ~FCNVME_CMD_CAT_MASK) | FCNVME_CMD_CAT_ADMINQ; ++} ++ ++static inline __u8 fccmnd_set_cat_css(__u8 rsv_cat, __u8 css) ++{ ++ return (rsv_cat & ~FCNVME_CMD_CAT_MASK) | FCNVME_CMD_CAT_CSSFLAG | ++ (css & FCNVME_CMD_CAT_CSSMASK); ++} + + struct nvme_fc_cmd_iu { +- __u8 scsi_id; ++ __u8 format_id; + __u8 fc_id; + __be16 iu_len; +- __u8 rsvd4[3]; ++ __u8 rsvd4[2]; ++ __u8 rsv_cat; + __u8 flags; + __be64 connection_id; + __be32 csn; + __be32 data_len; + struct nvme_command sqe; +- __be32 rsvd88[2]; ++ __u8 dps; ++ __u8 lbads; ++ __be16 ms; ++ __be32 rsvd92; + }; + + #define NVME_FC_SIZEOF_ZEROS_RSP 12 +@@ -38,11 +65,12 @@ struct nvme_fc_cmd_iu { + enum { + FCNVME_SC_SUCCESS = 0, + FCNVME_SC_INVALID_FIELD = 1, +- FCNVME_SC_INVALID_CONNID = 2, ++ /* reserved 2 */ ++ FCNVME_SC_ILL_CONN_PARAMS = 3, + }; + + struct nvme_fc_ersp_iu { +- __u8 status_code; ++ __u8 ersp_result; + __u8 rsvd1; + __be16 iu_len; + __be32 rsn; +@@ -53,14 +81,44 @@ struct nvme_fc_ersp_iu { + }; + + +-/* FC-NVME Link Services */ ++#define FCNVME_NVME_SR_OPCODE 0x01 ++ ++struct nvme_fc_nvme_sr_iu { ++ __u8 fc_id; ++ __u8 opcode; ++ __u8 rsvd2; ++ __u8 retry_rctl; ++ __be32 rsvd4; ++}; ++ ++ ++enum { ++ FCNVME_SRSTAT_ACC = 0x0, ++ FCNVME_SRSTAT_INV_FCID = 0x1, ++ /* reserved 0x2 */ ++ FCNVME_SRSTAT_LOGICAL_ERR = 0x3, ++ FCNVME_SRSTAT_INV_QUALIF = 0x4, ++ FCNVME_SRSTAT_UNABL2PERFORM = 0x9, ++}; ++ ++struct nvme_fc_nvme_sr_rsp_iu { ++ __u8 fc_id; ++ __u8 opcode; ++ __u8 rsvd2; ++ __u8 status; ++ __be32 rsvd4; ++}; ++ ++ ++/* FC-NVME Link Services - LS cmd values (w0 bits 31:24) */ + enum { + FCNVME_LS_RSVD = 0, + FCNVME_LS_RJT = 1, + FCNVME_LS_ACC = 2, +- FCNVME_LS_CREATE_ASSOCIATION = 3, +- FCNVME_LS_CREATE_CONNECTION = 4, +- FCNVME_LS_DISCONNECT = 5, ++ FCNVME_LS_CREATE_ASSOCIATION = 3, /* Create Association */ ++ FCNVME_LS_CREATE_CONNECTION = 4, /* Create I/O Connection */ ++ FCNVME_LS_DISCONNECT_ASSOC = 5, /* Disconnect Association */ ++ FCNVME_LS_DISCONNECT_CONN = 6, /* Disconnect Connection */ + }; + + /* FC-NVME Link Service Descriptors */ +@@ -117,14 +175,17 @@ enum fcnvme_ls_rjt_reason { + FCNVME_RJT_RC_UNSUP = 0x0b, + /* command not supported */ + +- FCNVME_RJT_RC_INPROG = 0x0e, +- /* command already in progress */ +- + FCNVME_RJT_RC_INV_ASSOC = 0x40, +- /* Invalid Association ID*/ ++ /* Invalid Association ID */ + + FCNVME_RJT_RC_INV_CONN = 0x41, +- /* Invalid Connection ID*/ ++ /* Invalid Connection ID */ ++ ++ FCNVME_RJT_RC_INV_PARAM = 0x42, ++ /* Invalid Parameters */ ++ ++ FCNVME_RJT_RC_INSUF_RES = 0x43, ++ /* Insufficient Resources */ + + FCNVME_RJT_RC_VENDOR = 0xff, + /* vendor specific error */ +@@ -138,14 +199,32 @@ enum fcnvme_ls_rjt_explan { + FCNVME_RJT_EXP_OXID_RXID = 0x17, + /* invalid OX_ID-RX_ID combination */ + +- FCNVME_RJT_EXP_INSUF_RES = 0x29, +- /* insufficient resources */ +- + FCNVME_RJT_EXP_UNAB_DATA = 0x2a, + /* unable to supply requested data */ + + FCNVME_RJT_EXP_INV_LEN = 0x2d, + /* Invalid payload length */ ++ ++ FCNVME_RJT_EXP_INV_ERSP_RAT = 0x40, ++ /* Invalid NVMe_ERSP Ratio */ ++ ++ FCNVME_RJT_EXP_INV_CTLR_ID = 0x41, ++ /* Invalid Controller ID */ ++ ++ FCNVME_RJT_EXP_INV_QUEUE_ID = 0x42, ++ /* Invalid Queue ID */ ++ ++ FCNVME_RJT_EXP_INV_SQSIZE = 0x43, ++ /* Invalid Submission Queue Size */ ++ ++ FCNVME_RJT_EXP_INV_HOSTID = 0x44, ++ /* Invalid HOST ID */ ++ ++ FCNVME_RJT_EXP_INV_HOSTNQN = 0x45, ++ /* Invalid HOSTNQN */ ++ ++ FCNVME_RJT_EXP_INV_SUBNQN = 0x46, ++ /* Invalid SUBNQN */ + }; + + /* FCNVME_LSDESC_RJT */ +@@ -209,21 +288,11 @@ struct fcnvme_lsdesc_cr_conn_cmd { + __be32 rsvd52; + }; + +-/* Disconnect Scope Values */ +-enum { +- FCNVME_DISCONN_ASSOCIATION = 0, +- FCNVME_DISCONN_CONNECTION = 1, +-}; +- + /* FCNVME_LSDESC_DISCONN_CMD */ + struct fcnvme_lsdesc_disconn_cmd { + __be32 desc_tag; /* FCNVME_LSDESC_xxx */ + __be32 desc_len; +- u8 rsvd8[3]; +- /* note: scope is really a 1 bit field */ +- u8 scope; /* FCNVME_DISCONN_xxx */ +- __be32 rsvd12; +- __be64 id; ++ __be32 rsvd8[4]; + }; + + /* FCNVME_LSDESC_CONN_ID */ +@@ -242,9 +311,14 @@ struct fcnvme_lsdesc_assoc_id { + + /* r_ctl values */ + enum { +- FCNVME_RS_RCTL_DATA = 1, +- FCNVME_RS_RCTL_XFER_RDY = 5, +- FCNVME_RS_RCTL_RSP = 8, ++ FCNVME_RS_RCTL_CMND = 0x6, ++ FCNVME_RS_RCTL_DATA = 0x1, ++ FCNVME_RS_RCTL_CONF = 0x3, ++ FCNVME_RS_RCTL_SR = 0x9, ++ FCNVME_RS_RCTL_XFER_RDY = 0x5, ++ FCNVME_RS_RCTL_RSP = 0x7, ++ FCNVME_RS_RCTL_ERSP = 0x8, ++ FCNVME_RS_RCTL_SR_RSP = 0xA, + }; + + +@@ -264,7 +338,10 @@ struct fcnvme_ls_acc_hdr { + struct fcnvme_ls_rqst_w0 w0; + __be32 desc_list_len; + struct fcnvme_lsdesc_rqst rqst; +- /* Followed by cmd-specific ACC descriptors, see next definitions */ ++ /* ++ * Followed by cmd-specific ACCEPT descriptors, see xxx_acc ++ * definitions below ++ */ + }; + + /* FCNVME_LS_CREATE_ASSOCIATION */ +@@ -302,25 +379,39 @@ struct fcnvme_ls_cr_conn_acc { + struct fcnvme_lsdesc_conn_id connectid; + }; + +-/* FCNVME_LS_DISCONNECT */ +-struct fcnvme_ls_disconnect_rqst { ++/* FCNVME_LS_DISCONNECT_ASSOC */ ++struct fcnvme_ls_disconnect_assoc_rqst { + struct fcnvme_ls_rqst_w0 w0; + __be32 desc_list_len; + struct fcnvme_lsdesc_assoc_id associd; + struct fcnvme_lsdesc_disconn_cmd discon_cmd; + }; + +-struct fcnvme_ls_disconnect_acc { ++struct fcnvme_ls_disconnect_assoc_acc { ++ struct fcnvme_ls_acc_hdr hdr; ++}; ++ ++ ++/* FCNVME_LS_DISCONNECT_CONN */ ++struct fcnvme_ls_disconnect_conn_rqst { ++ struct fcnvme_ls_rqst_w0 w0; ++ __be32 desc_list_len; ++ struct fcnvme_lsdesc_assoc_id associd; ++ struct fcnvme_lsdesc_disconn_cmd connectid; ++}; ++ ++struct fcnvme_ls_disconnect_conn_acc { + struct fcnvme_ls_acc_hdr hdr; + }; + + + /* +- * Yet to be defined in FC-NVME: ++ * Default R_A_TOV is pulled in from fc_fs.h but needs conversion ++ * from ms to seconds for our use. + */ +-#define NVME_FC_CONNECT_TIMEOUT_SEC 2 /* 2 seconds */ +-#define NVME_FC_LS_TIMEOUT_SEC 2 /* 2 seconds */ +-#define NVME_FC_TGTOP_TIMEOUT_SEC 2 /* 2 seconds */ ++#define FC_TWO_TIMES_R_A_TOV (2 * (FC_DEF_R_A_TOV / 1000)) ++#define NVME_FC_LS_TIMEOUT_SEC FC_TWO_TIMES_R_A_TOV ++#define NVME_FC_TGTOP_TIMEOUT_SEC FC_TWO_TIMES_R_A_TOV + + /* + * TRADDR string must be of form "nn-<16hexdigits>:pn-<16hexdigits>" +@@ -328,6 +419,7 @@ struct fcnvme_ls_disconnect_acc { + * infront of the <16hexdigits>. Without is considered the "min" string + * and with is considered the "max" string. The hexdigits may be upper + * or lower case. ++ * Note: FC-NVME-2 standard requires a "0x" prefix. + */ + #define NVME_FC_TRADDR_NNLEN 3 /* "?n-" */ + #define NVME_FC_TRADDR_OXNNLEN 5 /* "?n-0x" */ +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-Update-header-and-host-for-common-definition.patch b/patches.suse/nvme-fc-Update-header-and-host-for-common-definition.patch new file mode 100644 index 0000000..f4aeaaa --- /dev/null +++ b/patches.suse/nvme-fc-Update-header-and-host-for-common-definition.patch @@ -0,0 +1,164 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:52 -0700 +Subject: [PATCH] nvme-fc: Update header and host for common definitions for LS +Git-commit: 7ea19f298eff3d22dcc117b15ad18e2592de1e6f +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + handling + +Given that both host and target now generate and receive LS's create +a single table definition for LS names. Each tranport half will have +a local version of the table. + +As Create Association LS is issued by both sides, and received by +both sides, create common routines to format the LS and to validate +the LS. + +Convert the host side transport to use the new common Create +Association LS formatting routine. + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Reviewed-by: Himanshu Madhani +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 25 ++-------------- + drivers/nvme/host/fc.h | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 81 insertions(+), 23 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 0ac246603063..c069ab056202 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -1419,29 +1419,8 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + else + lsreq->private = NULL; + +- discon_rqst->w0.ls_cmd = FCNVME_LS_DISCONNECT_ASSOC; +- discon_rqst->desc_list_len = cpu_to_be32( +- sizeof(struct fcnvme_lsdesc_assoc_id) + +- sizeof(struct fcnvme_lsdesc_disconn_cmd)); +- +- discon_rqst->associd.desc_tag = cpu_to_be32(FCNVME_LSDESC_ASSOC_ID); +- discon_rqst->associd.desc_len = +- fcnvme_lsdesc_len( +- sizeof(struct fcnvme_lsdesc_assoc_id)); +- +- discon_rqst->associd.association_id = cpu_to_be64(ctrl->association_id); +- +- discon_rqst->discon_cmd.desc_tag = cpu_to_be32( +- FCNVME_LSDESC_DISCONN_CMD); +- discon_rqst->discon_cmd.desc_len = +- fcnvme_lsdesc_len( +- sizeof(struct fcnvme_lsdesc_disconn_cmd)); +- +- lsreq->rqstaddr = discon_rqst; +- lsreq->rqstlen = sizeof(*discon_rqst); +- lsreq->rspaddr = discon_acc; +- lsreq->rsplen = sizeof(*discon_acc); +- lsreq->timeout = NVME_FC_LS_TIMEOUT_SEC; ++ nvmefc_fmt_lsreq_discon_assoc(lsreq, discon_rqst, discon_acc, ++ ctrl->association_id); + + ret = nvme_fc_send_ls_req_async(ctrl->rport, lsop, + nvme_fc_disconnect_assoc_done); +diff --git a/drivers/nvme/host/fc.h b/drivers/nvme/host/fc.h +index 08fa88381d45..05ce566f2caf 100644 +--- a/drivers/nvme/host/fc.h ++++ b/drivers/nvme/host/fc.h +@@ -17,6 +17,7 @@ + */ + + union nvmefc_ls_requests { ++ struct fcnvme_ls_rqst_w0 w0; + struct fcnvme_ls_cr_assoc_rqst rq_cr_assoc; + struct fcnvme_ls_cr_conn_rqst rq_cr_conn; + struct fcnvme_ls_disconnect_assoc_rqst rq_dis_assoc; +@@ -145,4 +146,82 @@ static char *validation_errors[] = { + "Bad Disconnect ACC Length", + }; + ++#define NVME_FC_LAST_LS_CMD_VALUE FCNVME_LS_DISCONNECT_CONN ++ ++static char *nvmefc_ls_names[] = { ++ "Reserved (0)", ++ "RJT (1)", ++ "ACC (2)", ++ "Create Association", ++ "Create Connection", ++ "Disconnect Association", ++ "Disconnect Connection", ++}; ++ ++static inline void ++nvmefc_fmt_lsreq_discon_assoc(struct nvmefc_ls_req *lsreq, ++ struct fcnvme_ls_disconnect_assoc_rqst *discon_rqst, ++ struct fcnvme_ls_disconnect_assoc_acc *discon_acc, ++ u64 association_id) ++{ ++ lsreq->rqstaddr = discon_rqst; ++ lsreq->rqstlen = sizeof(*discon_rqst); ++ lsreq->rspaddr = discon_acc; ++ lsreq->rsplen = sizeof(*discon_acc); ++ lsreq->timeout = NVME_FC_LS_TIMEOUT_SEC; ++ ++ discon_rqst->w0.ls_cmd = FCNVME_LS_DISCONNECT_ASSOC; ++ discon_rqst->desc_list_len = cpu_to_be32( ++ sizeof(struct fcnvme_lsdesc_assoc_id) + ++ sizeof(struct fcnvme_lsdesc_disconn_cmd)); ++ ++ discon_rqst->associd.desc_tag = cpu_to_be32(FCNVME_LSDESC_ASSOC_ID); ++ discon_rqst->associd.desc_len = ++ fcnvme_lsdesc_len( ++ sizeof(struct fcnvme_lsdesc_assoc_id)); ++ ++ discon_rqst->associd.association_id = cpu_to_be64(association_id); ++ ++ discon_rqst->discon_cmd.desc_tag = cpu_to_be32( ++ FCNVME_LSDESC_DISCONN_CMD); ++ discon_rqst->discon_cmd.desc_len = ++ fcnvme_lsdesc_len( ++ sizeof(struct fcnvme_lsdesc_disconn_cmd)); ++} ++ ++static inline int ++nvmefc_vldt_lsreq_discon_assoc(u32 rqstlen, ++ struct fcnvme_ls_disconnect_assoc_rqst *rqst) ++{ ++ int ret = 0; ++ ++ if (rqstlen < sizeof(struct fcnvme_ls_disconnect_assoc_rqst)) ++ ret = VERR_DISCONN_LEN; ++ else if (rqst->desc_list_len != ++ fcnvme_lsdesc_len( ++ sizeof(struct fcnvme_ls_disconnect_assoc_rqst))) ++ ret = VERR_DISCONN_RQST_LEN; ++ else if (rqst->associd.desc_tag != cpu_to_be32(FCNVME_LSDESC_ASSOC_ID)) ++ ret = VERR_ASSOC_ID; ++ else if (rqst->associd.desc_len != ++ fcnvme_lsdesc_len( ++ sizeof(struct fcnvme_lsdesc_assoc_id))) ++ ret = VERR_ASSOC_ID_LEN; ++ else if (rqst->discon_cmd.desc_tag != ++ cpu_to_be32(FCNVME_LSDESC_DISCONN_CMD)) ++ ret = VERR_DISCONN_CMD; ++ else if (rqst->discon_cmd.desc_len != ++ fcnvme_lsdesc_len( ++ sizeof(struct fcnvme_lsdesc_disconn_cmd))) ++ ret = VERR_DISCONN_CMD_LEN; ++ /* ++ * As the standard changed on the LS, check if old format and scope ++ * something other than Association (e.g. 0). ++ */ ++ else if (rqst->discon_cmd.rsvd8[0]) ++ ret = VERR_DISCONN_SCOPE; ++ ++ return ret; ++} ++ + #endif /* _NVME_FC_TRANSPORT_H */ +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-and-nvmet-fc-revise-LLDD-api-for-LS-receptio.patch b/patches.suse/nvme-fc-and-nvmet-fc-revise-LLDD-api-for-LS-receptio.patch new file mode 100644 index 0000000..73f5725 --- /dev/null +++ b/patches.suse/nvme-fc-and-nvmet-fc-revise-LLDD-api-for-LS-receptio.patch @@ -0,0 +1,893 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:47 -0700 +Subject: [PATCH] nvme-fc and nvmet-fc: revise LLDD api for LS reception and LS +Git-commit: 7611cfa2c27ff5300695fc965916de1d370ca5fb +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + request + +The current LLDD api has: + nvme-fc: contains api for transport to do LS requests (and aborts of + them). However, there is no interface for reception of LS's and sending + responses for them. + nvmet-fc: contains api for transport to do reception of LS's and sending + of responses for them. However, there is no interface for doing LS + requests. + +Revise the api's so that both nvme-fc and nvmet-fc can send LS's, as well +as receiving LS's and sending their responses. + +Change name of the rcv_ls_req struct to better reflect generic use as +a context to used to send an ls rsp. Specifically: + nvmefc_tgt_ls_req -> nvmefc_ls_rsp + nvmefc_tgt_ls_req.nvmet_fc_private -> nvmefc_ls_rsp.nvme_fc_private + +Change nvmet_fc_rcv_ls_req() calling sequence to provide handle that +can be used by transport in later LS request sequences for an association. + +nvme-fc nvmet_fc nvme_fcloop: + Revise to adapt to changed names in api header. + Change calling sequence to nvmet_fc_rcv_ls_req() for hosthandle. + Add stubs for new interfaces: + host/fc.c: nvme_fc_rcv_ls_req() + target/fc.c: nvmet_fc_invalidate_host() + +lpfc: + Revise to adapt code to changed names in api header. + Change calling sequence to nvmet_fc_rcv_ls_req() for hosthandle. + +Signed-off-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Himanshu Madhani +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 35 ++++ + drivers/nvme/target/fc.c | 77 ++++++--- + drivers/nvme/target/fcloop.c | 20 +-- + drivers/scsi/lpfc/lpfc_nvmet.c | 10 +- + drivers/scsi/lpfc/lpfc_nvmet.h | 2 +- + include/linux/nvme-fc-driver.h | 368 ++++++++++++++++++++++++++++++----------- + 6 files changed, 378 insertions(+), 134 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 7dfc4a2ecf1e..8012099fc3ee 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -1464,6 +1464,41 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + kfree(lsop); + } + ++/** ++ * nvme_fc_rcv_ls_req - transport entry point called by an LLDD ++ * upon the reception of a NVME LS request. ++ * ++ * The nvme-fc layer will copy payload to an internal structure for ++ * processing. As such, upon completion of the routine, the LLDD may ++ * immediately free/reuse the LS request buffer passed in the call. ++ * ++ * If this routine returns error, the LLDD should abort the exchange. ++ * ++ * @remoteport: pointer to the (registered) remote port that the LS ++ * was received from. The remoteport is associated with ++ * a specific localport. ++ * @lsrsp: pointer to a nvmefc_ls_rsp response structure to be ++ * used to reference the exchange corresponding to the LS ++ * when issuing an ls response. ++ * @lsreqbuf: pointer to the buffer containing the LS Request ++ * @lsreqbuf_len: length, in bytes, of the received LS request ++ */ ++int ++nvme_fc_rcv_ls_req(struct nvme_fc_remote_port *portptr, ++ struct nvmefc_ls_rsp *lsrsp, ++ void *lsreqbuf, u32 lsreqbuf_len) ++{ ++ struct nvme_fc_rport *rport = remoteport_to_rport(portptr); ++ struct nvme_fc_lport *lport = rport->lport; ++ ++ /* validate there's a routine to transmit a response */ ++ if (!lport->ops->xmt_ls_rsp) ++ return(-EINVAL); ++ ++ return 0; ++} ++EXPORT_SYMBOL_GPL(nvme_fc_rcv_ls_req); ++ + + /* *********************** NVME Ctrl Routines **************************** */ + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index a8ceb7721640..aac7869a70bb 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -28,7 +28,7 @@ struct nvmet_fc_tgtport; + struct nvmet_fc_tgt_assoc; + + struct nvmet_fc_ls_iod { +- struct nvmefc_tgt_ls_req *lsreq; ++ struct nvmefc_ls_rsp *lsrsp; + struct nvmefc_tgt_fcp_req *fcpreq; /* only if RS */ + + struct list_head ls_list; /* tgtport->ls_list */ +@@ -1146,6 +1146,42 @@ __nvmet_fc_free_assocs(struct nvmet_fc_tgtport *tgtport) + spin_unlock_irqrestore(&tgtport->lock, flags); + } + ++/** ++ * nvmet_fc_invalidate_host - transport entry point called by an LLDD ++ * to remove references to a hosthandle for LS's. ++ * ++ * The nvmet-fc layer ensures that any references to the hosthandle ++ * on the targetport are forgotten (set to NULL). The LLDD will ++ * typically call this when a login with a remote host port has been ++ * lost, thus LS's for the remote host port are no longer possible. ++ * ++ * If an LS request is outstanding to the targetport/hosthandle (or ++ * issued concurrently with the call to invalidate the host), the ++ * LLDD is responsible for terminating/aborting the LS and completing ++ * the LS request. It is recommended that these terminations/aborts ++ * occur after calling to invalidate the host handle to avoid additional ++ * retries by the nvmet-fc transport. The nvmet-fc transport may ++ * continue to reference host handle while it cleans up outstanding ++ * NVME associations. The nvmet-fc transport will call the ++ * ops->host_release() callback to notify the LLDD that all references ++ * are complete and the related host handle can be recovered. ++ * Note: if there are no references, the callback may be called before ++ * the invalidate host call returns. ++ * ++ * @target_port: pointer to the (registered) target port that a prior ++ * LS was received on and which supplied the transport the ++ * hosthandle. ++ * @hosthandle: the handle (pointer) that represents the host port ++ * that no longer has connectivity and that LS's should ++ * no longer be directed to. ++ */ ++void ++nvmet_fc_invalidate_host(struct nvmet_fc_target_port *target_port, ++ void *hosthandle) ++{ ++} ++EXPORT_SYMBOL_GPL(nvmet_fc_invalidate_host); ++ + /* + * nvmet layer has called to terminate an association + */ +@@ -1371,7 +1407,7 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + dev_err(tgtport->dev, + "Create Association LS failed: %s\n", + validation_errors[ret]); +- iod->lsreq->rsplen = nvmet_fc_format_rjt(acc, ++ iod->lsrsp->rsplen = nvmet_fc_format_rjt(acc, + NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, + FCNVME_RJT_RC_LOGIC, + FCNVME_RJT_EXP_NONE, 0); +@@ -1384,7 +1420,7 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + + /* format a response */ + +- iod->lsreq->rsplen = sizeof(*acc); ++ iod->lsrsp->rsplen = sizeof(*acc); + + nvmet_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, + fcnvme_lsdesc_len( +@@ -1462,7 +1498,7 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, + dev_err(tgtport->dev, + "Create Connection LS failed: %s\n", + validation_errors[ret]); +- iod->lsreq->rsplen = nvmet_fc_format_rjt(acc, ++ iod->lsrsp->rsplen = nvmet_fc_format_rjt(acc, + NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, + (ret == VERR_NO_ASSOC) ? + FCNVME_RJT_RC_INV_ASSOC : +@@ -1477,7 +1513,7 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, + + /* format a response */ + +- iod->lsreq->rsplen = sizeof(*acc); ++ iod->lsrsp->rsplen = sizeof(*acc); + + nvmet_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, + fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_cr_conn_acc)), +@@ -1542,7 +1578,7 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + dev_err(tgtport->dev, + "Disconnect LS failed: %s\n", + validation_errors[ret]); +- iod->lsreq->rsplen = nvmet_fc_format_rjt(acc, ++ iod->lsrsp->rsplen = nvmet_fc_format_rjt(acc, + NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, + (ret == VERR_NO_ASSOC) ? + FCNVME_RJT_RC_INV_ASSOC : +@@ -1555,7 +1591,7 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + + /* format a response */ + +- iod->lsreq->rsplen = sizeof(*acc); ++ iod->lsrsp->rsplen = sizeof(*acc); + + nvmet_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, + fcnvme_lsdesc_len( +@@ -1577,9 +1613,9 @@ static void nvmet_fc_fcp_nvme_cmd_done(struct nvmet_req *nvme_req); + static const struct nvmet_fabrics_ops nvmet_fc_tgt_fcp_ops; + + static void +-nvmet_fc_xmt_ls_rsp_done(struct nvmefc_tgt_ls_req *lsreq) ++nvmet_fc_xmt_ls_rsp_done(struct nvmefc_ls_rsp *lsrsp) + { +- struct nvmet_fc_ls_iod *iod = lsreq->nvmet_fc_private; ++ struct nvmet_fc_ls_iod *iod = lsrsp->nvme_fc_private; + struct nvmet_fc_tgtport *tgtport = iod->tgtport; + + fc_dma_sync_single_for_cpu(tgtport->dev, iod->rspdma, +@@ -1597,9 +1633,9 @@ nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport, + fc_dma_sync_single_for_device(tgtport->dev, iod->rspdma, + NVME_FC_MAX_LS_BUFFER_SIZE, DMA_TO_DEVICE); + +- ret = tgtport->ops->xmt_ls_rsp(&tgtport->fc_target_port, iod->lsreq); ++ ret = tgtport->ops->xmt_ls_rsp(&tgtport->fc_target_port, iod->lsrsp); + if (ret) +- nvmet_fc_xmt_ls_rsp_done(iod->lsreq); ++ nvmet_fc_xmt_ls_rsp_done(iod->lsrsp); + } + + /* +@@ -1612,12 +1648,12 @@ nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + struct fcnvme_ls_rqst_w0 *w0 = + (struct fcnvme_ls_rqst_w0 *)iod->rqstbuf; + +- iod->lsreq->nvmet_fc_private = iod; +- iod->lsreq->rspbuf = iod->rspbuf; +- iod->lsreq->rspdma = iod->rspdma; +- iod->lsreq->done = nvmet_fc_xmt_ls_rsp_done; ++ iod->lsrsp->nvme_fc_private = iod; ++ iod->lsrsp->rspbuf = iod->rspbuf; ++ iod->lsrsp->rspdma = iod->rspdma; ++ iod->lsrsp->done = nvmet_fc_xmt_ls_rsp_done; + /* Be preventative. handlers will later set to valid length */ +- iod->lsreq->rsplen = 0; ++ iod->lsrsp->rsplen = 0; + + iod->assoc = NULL; + +@@ -1640,7 +1676,7 @@ nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + nvmet_fc_ls_disconnect(tgtport, iod); + break; + default: +- iod->lsreq->rsplen = nvmet_fc_format_rjt(iod->rspbuf, ++ iod->lsrsp->rsplen = nvmet_fc_format_rjt(iod->rspbuf, + NVME_FC_MAX_LS_BUFFER_SIZE, w0->ls_cmd, + FCNVME_RJT_RC_INVAL, FCNVME_RJT_EXP_NONE, 0); + } +@@ -1674,14 +1710,15 @@ nvmet_fc_handle_ls_rqst_work(struct work_struct *work) + * + * @target_port: pointer to the (registered) target port the LS was + * received on. +- * @lsreq: pointer to a lsreq request structure to be used to reference ++ * @lsrsp: pointer to a lsrsp structure to be used to reference + * the exchange corresponding to the LS. + * @lsreqbuf: pointer to the buffer containing the LS Request + * @lsreqbuf_len: length, in bytes, of the received LS request + */ + int + nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port, +- struct nvmefc_tgt_ls_req *lsreq, ++ void *hosthandle, ++ struct nvmefc_ls_rsp *lsrsp, + void *lsreqbuf, u32 lsreqbuf_len) + { + struct nvmet_fc_tgtport *tgtport = targetport_to_tgtport(target_port); +@@ -1699,7 +1736,7 @@ nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port, + return -ENOENT; + } + +- iod->lsreq = lsreq; ++ iod->lsrsp = lsrsp; + iod->fcpreq = NULL; + memcpy(iod->rqstbuf, lsreqbuf, lsreqbuf_len); + iod->rqstdatalen = lsreqbuf_len; +diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c +index f69ce66e2d44..c11805a155e8 100644 +--- a/drivers/nvme/target/fcloop.c ++++ b/drivers/nvme/target/fcloop.c +@@ -228,7 +228,7 @@ struct fcloop_nport { + + struct fcloop_lsreq { + struct nvmefc_ls_req *lsreq; +- struct nvmefc_tgt_ls_req tgt_ls_req; ++ struct nvmefc_ls_rsp ls_rsp; + int status; + struct list_head ls_list; /* fcloop_rport->ls_list */ + }; +@@ -267,9 +267,9 @@ struct fcloop_ini_fcpreq { + }; + + static inline struct fcloop_lsreq * +-tgt_ls_req_to_lsreq(struct nvmefc_tgt_ls_req *tgt_lsreq) ++ls_rsp_to_lsreq(struct nvmefc_ls_rsp *lsrsp) + { +- return container_of(tgt_lsreq, struct fcloop_lsreq, tgt_ls_req); ++ return container_of(lsrsp, struct fcloop_lsreq, ls_rsp); + } + + static inline struct fcloop_fcpreq * +@@ -344,7 +344,7 @@ fcloop_ls_req(struct nvme_fc_local_port *localport, + } + + tls_req->status = 0; +- ret = nvmet_fc_rcv_ls_req(rport->targetport, &tls_req->tgt_ls_req, ++ ret = nvmet_fc_rcv_ls_req(rport->targetport, NULL, &tls_req->ls_rsp, + lsreq->rqstaddr, lsreq->rqstlen); + + return ret; +@@ -352,19 +352,19 @@ fcloop_ls_req(struct nvme_fc_local_port *localport, + + static int + fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *targetport, +- struct nvmefc_tgt_ls_req *tgt_lsreq) ++ struct nvmefc_ls_rsp *lsrsp) + { +- struct fcloop_lsreq *tls_req = tgt_ls_req_to_lsreq(tgt_lsreq); ++ struct fcloop_lsreq *tls_req = ls_rsp_to_lsreq(lsrsp); + struct nvmefc_ls_req *lsreq = tls_req->lsreq; + struct fcloop_tport *tport = targetport->private; + struct nvme_fc_remote_port *remoteport = tport->remoteport; + struct fcloop_rport *rport; + +- memcpy(lsreq->rspaddr, tgt_lsreq->rspbuf, +- ((lsreq->rsplen < tgt_lsreq->rsplen) ? +- lsreq->rsplen : tgt_lsreq->rsplen)); ++ memcpy(lsreq->rspaddr, lsrsp->rspbuf, ++ ((lsreq->rsplen < lsrsp->rsplen) ? ++ lsreq->rsplen : lsrsp->rsplen)); + +- tgt_lsreq->done(tgt_lsreq); ++ lsrsp->done(lsrsp); + + if (remoteport) { + rport = remoteport->private; +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c +index 9dc9afe1c255..47b983eddbb2 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.c ++++ b/drivers/scsi/lpfc/lpfc_nvmet.c +@@ -302,7 +302,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + struct lpfc_wcqe_complete *wcqe) + { + struct lpfc_nvmet_tgtport *tgtp; +- struct nvmefc_tgt_ls_req *rsp; ++ struct nvmefc_ls_rsp *rsp; + struct lpfc_nvmet_rcv_ctx *ctxp; + uint32_t status, result; + +@@ -335,7 +335,7 @@ lpfc_nvmet_xmt_ls_rsp_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + } + + out: +- rsp = &ctxp->ctx.ls_req; ++ rsp = &ctxp->ctx.ls_rsp; + + lpfc_nvmeio_data(phba, "NVMET LS CMPL: xri x%x stat x%x result x%x\n", + ctxp->oxid, status, result); +@@ -830,10 +830,10 @@ lpfc_nvmet_xmt_fcp_op_cmp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdwqe, + + static int + lpfc_nvmet_xmt_ls_rsp(struct nvmet_fc_target_port *tgtport, +- struct nvmefc_tgt_ls_req *rsp) ++ struct nvmefc_ls_rsp *rsp) + { + struct lpfc_nvmet_rcv_ctx *ctxp = +- container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.ls_req); ++ container_of(rsp, struct lpfc_nvmet_rcv_ctx, ctx.ls_rsp); + struct lpfc_hba *phba = ctxp->phba; + struct hbq_dmabuf *nvmebuf = + (struct hbq_dmabuf *)ctxp->rqb_buffer; +@@ -2000,7 +2000,7 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, + * lpfc_nvmet_xmt_ls_rsp_cmp should free the allocated ctxp. + */ + atomic_inc(&tgtp->rcv_ls_req_in); +- rc = nvmet_fc_rcv_ls_req(phba->targetport, &ctxp->ctx.ls_req, ++ rc = nvmet_fc_rcv_ls_req(phba->targetport, NULL, &ctxp->ctx.ls_rsp, + payload, size); + + lpfc_printf_log(phba, KERN_INFO, LOG_NVME_DISC, +diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h +index b80b1639b9a7..f0196f3ef90d 100644 +--- a/drivers/scsi/lpfc/lpfc_nvmet.h ++++ b/drivers/scsi/lpfc/lpfc_nvmet.h +@@ -105,7 +105,7 @@ struct lpfc_nvmet_ctx_info { + + struct lpfc_nvmet_rcv_ctx { + union { +- struct nvmefc_tgt_ls_req ls_req; ++ struct nvmefc_ls_rsp ls_rsp; + struct nvmefc_tgt_fcp_req fcp_req; + } ctx; + struct list_head list; +diff --git a/include/linux/nvme-fc-driver.h b/include/linux/nvme-fc-driver.h +index 10f81629b9ce..41e7795a3ee4 100644 +--- a/include/linux/nvme-fc-driver.h ++++ b/include/linux/nvme-fc-driver.h +@@ -10,47 +10,26 @@ + + + /* +- * ********************** LLDD FC-NVME Host API ******************** ++ * ********************** FC-NVME LS API ******************** + * +- * For FC LLDD's that are the NVME Host role. ++ * Data structures used by both FC-NVME hosts and FC-NVME ++ * targets to perform FC-NVME LS requests or transmit ++ * responses. + * +- * ****************************************************************** ++ * *********************************************************** + */ + +- +- + /** +- * struct nvme_fc_port_info - port-specific ids and FC connection-specific +- * data element used during NVME Host role +- * registrations +- * +- * Static fields describing the port being registered: +- * @node_name: FC WWNN for the port +- * @port_name: FC WWPN for the port +- * @port_role: What NVME roles are supported (see FC_PORT_ROLE_xxx) +- * @dev_loss_tmo: maximum delay for reconnects to an association on +- * this device. Used only on a remoteport. ++ * struct nvmefc_ls_req - Request structure passed from the transport ++ * to the LLDD to perform a NVME-FC LS request and obtain ++ * a response. ++ * Used by nvme-fc transport (host) to send LS's such as ++ * Create Association, Create Connection and Disconnect ++ * Association. ++ * Used by the nvmet-fc transport (controller) to send ++ * LS's such as Disconnect Association. + * +- * Initialization values for dynamic port fields: +- * @port_id: FC N_Port_ID currently assigned the port. Upper 8 bits must +- * be set to 0. +- */ +-struct nvme_fc_port_info { +- u64 node_name; +- u64 port_name; +- u32 port_role; +- u32 port_id; +- u32 dev_loss_tmo; +-}; +- +- +-/** +- * struct nvmefc_ls_req - Request structure passed from NVME-FC transport +- * to LLDD in order to perform a NVME FC-4 LS +- * request and obtain a response. +- * +- * Values set by the NVME-FC layer prior to calling the LLDD ls_req +- * entrypoint. ++ * Values set by the requestor prior to calling the LLDD ls_req entrypoint: + * @rqstaddr: pointer to request buffer + * @rqstdma: PCI DMA address of request buffer + * @rqstlen: Length, in bytes, of request buffer +@@ -63,8 +42,8 @@ struct nvme_fc_port_info { + * @private: pointer to memory allocated alongside the ls request structure + * that is specifically for the LLDD to use while processing the + * request. The length of the buffer corresponds to the +- * lsrqst_priv_sz value specified in the nvme_fc_port_template +- * supplied by the LLDD. ++ * lsrqst_priv_sz value specified in the xxx_template supplied ++ * by the LLDD. + * @done: The callback routine the LLDD is to invoke upon completion of + * the LS request. req argument is the pointer to the original LS + * request structure. Status argument must be 0 upon success, a +@@ -86,6 +65,101 @@ struct nvmefc_ls_req { + } __aligned(sizeof(u64)); /* alignment for other things alloc'd with */ + + ++/** ++ * struct nvmefc_ls_rsp - Structure passed from the transport to the LLDD ++ * to request the transmit the NVME-FC LS response to a ++ * NVME-FC LS request. The structure originates in the LLDD ++ * and is given to the transport via the xxx_rcv_ls_req() ++ * transport routine. As such, the structure represents the ++ * FC exchange context for the NVME-FC LS request that was ++ * received and which the response is to be sent for. ++ * Used by the LLDD to pass the nvmet-fc transport (controller) ++ * received LS's such as Create Association, Create Connection ++ * and Disconnect Association. ++ * Used by the LLDD to pass the nvme-fc transport (host) ++ * received LS's such as Disconnect Association or Disconnect ++ * Connection. ++ * ++ * The structure is allocated by the LLDD whenever a LS Request is received ++ * from the FC link. The address of the structure is passed to the nvmet-fc ++ * or nvme-fc layer via the xxx_rcv_ls_req() transport routines. ++ * ++ * The address of the structure is to be passed back to the LLDD ++ * when the response is to be transmit. The LLDD will use the address to ++ * map back to the LLDD exchange structure which maintains information such ++ * the remote N_Port that sent the LS as well as any FC exchange context. ++ * Upon completion of the LS response transmit, the LLDD will pass the ++ * address of the structure back to the transport LS rsp done() routine, ++ * allowing the transport release dma resources. Upon completion of ++ * the done() routine, no further access to the structure will be made by ++ * the transport and the LLDD can de-allocate the structure. ++ * ++ * Field initialization: ++ * At the time of the xxx_rcv_ls_req() call, there is no content that ++ * is valid in the structure. ++ * ++ * When the structure is used for the LLDD->xmt_ls_rsp() call, the ++ * transport layer will fully set the fields in order to specify the ++ * response payload buffer and its length as well as the done routine ++ * to be called upon completion of the transmit. The transport layer ++ * will also set a private pointer for its own use in the done routine. ++ * ++ * Values set by the transport layer prior to calling the LLDD xmt_ls_rsp ++ * entrypoint: ++ * @rspbuf: pointer to the LS response buffer ++ * @rspdma: PCI DMA address of the LS response buffer ++ * @rsplen: Length, in bytes, of the LS response buffer ++ * @done: The callback routine the LLDD is to invoke upon completion of ++ * transmitting the LS response. req argument is the pointer to ++ * the original ls request. ++ * @nvme_fc_private: pointer to an internal transport-specific structure ++ * used as part of the transport done() processing. The LLDD is ++ * not to access this pointer. ++ */ ++struct nvmefc_ls_rsp { ++ void *rspbuf; ++ dma_addr_t rspdma; ++ u16 rsplen; ++ ++ void (*done)(struct nvmefc_ls_rsp *rsp); ++ void *nvme_fc_private; /* LLDD is not to access !! */ ++}; ++ ++ ++ ++/* ++ * ********************** LLDD FC-NVME Host API ******************** ++ * ++ * For FC LLDD's that are the NVME Host role. ++ * ++ * ****************************************************************** ++ */ ++ ++ ++/** ++ * struct nvme_fc_port_info - port-specific ids and FC connection-specific ++ * data element used during NVME Host role ++ * registrations ++ * ++ * Static fields describing the port being registered: ++ * @node_name: FC WWNN for the port ++ * @port_name: FC WWPN for the port ++ * @port_role: What NVME roles are supported (see FC_PORT_ROLE_xxx) ++ * @dev_loss_tmo: maximum delay for reconnects to an association on ++ * this device. Used only on a remoteport. ++ * ++ * Initialization values for dynamic port fields: ++ * @port_id: FC N_Port_ID currently assigned the port. Upper 8 bits must ++ * be set to 0. ++ */ ++struct nvme_fc_port_info { ++ u64 node_name; ++ u64 port_name; ++ u32 port_role; ++ u32 port_id; ++ u32 dev_loss_tmo; ++}; ++ + enum nvmefc_fcp_datadir { + NVMEFC_FCP_NODATA, /* payload_length and sg_cnt will be zero */ + NVMEFC_FCP_WRITE, +@@ -337,6 +411,21 @@ struct nvme_fc_remote_port { + * indicating an FC transport Aborted status. + * Entrypoint is Mandatory. + * ++ * @xmt_ls_rsp: Called to transmit the response to a FC-NVME FC-4 LS service. ++ * The nvmefc_ls_rsp structure is the same LLDD-supplied exchange ++ * structure specified in the nvme_fc_rcv_ls_req() call made when ++ * the LS request was received. The structure will fully describe ++ * the buffers for the response payload and the dma address of the ++ * payload. The LLDD is to transmit the response (or return a ++ * non-zero errno status), and upon completion of the transmit, call ++ * the "done" routine specified in the nvmefc_ls_rsp structure ++ * (argument to done is the address of the nvmefc_ls_rsp structure ++ * itself). Upon the completion of the done routine, the LLDD shall ++ * consider the LS handling complete and the nvmefc_ls_rsp structure ++ * may be freed/released. ++ * Entrypoint is mandatory if the LLDD calls the nvme_fc_rcv_ls_req() ++ * entrypoint. ++ * + * @max_hw_queues: indicates the maximum number of hw queues the LLDD + * supports for cpu affinitization. + * Value is Mandatory. Must be at least 1. +@@ -371,7 +460,7 @@ struct nvme_fc_remote_port { + * @lsrqst_priv_sz: The LLDD sets this field to the amount of additional + * memory that it would like fc nvme layer to allocate on the LLDD's + * behalf whenever a ls request structure is allocated. The additional +- * memory area solely for the of the LLDD and its location is ++ * memory area is solely for use by the LLDD and its location is + * specified by the ls_request->private pointer. + * Value is Mandatory. Allowed to be zero. + * +@@ -405,6 +494,9 @@ struct nvme_fc_port_template { + struct nvme_fc_remote_port *, + void *hw_queue_handle, + struct nvmefc_fcp_req *); ++ int (*xmt_ls_rsp)(struct nvme_fc_local_port *localport, ++ struct nvme_fc_remote_port *rport, ++ struct nvmefc_ls_rsp *ls_rsp); + + u32 max_hw_queues; + u16 max_sgl_segments; +@@ -441,6 +533,34 @@ void nvme_fc_rescan_remoteport(struct nvme_fc_remote_port *remoteport); + int nvme_fc_set_remoteport_devloss(struct nvme_fc_remote_port *remoteport, + u32 dev_loss_tmo); + ++/* ++ * Routine called to pass a NVME-FC LS request, received by the lldd, ++ * to the nvme-fc transport. ++ * ++ * If the return value is zero: the LS was successfully accepted by the ++ * transport. ++ * If the return value is non-zero: the transport has not accepted the ++ * LS. The lldd should ABTS-LS the LS. ++ * ++ * Note: if the LLDD receives and ABTS for the LS prior to the transport ++ * calling the ops->xmt_ls_rsp() routine to transmit a response, the LLDD ++ * shall mark the LS as aborted, and when the xmt_ls_rsp() is called: the ++ * response shall not be transmit and the struct nvmefc_ls_rsp() done ++ * routine shall be called. The LLDD may transmit the ABTS response as ++ * soon as the LS was marked or can delay until the xmt_ls_rsp() call is ++ * made. ++ * Note: if an RCV LS was successfully posted to the transport and the ++ * remoteport is then unregistered before xmt_ls_rsp() was called for ++ * the lsrsp structure, the transport will still call xmt_ls_rsp() ++ * afterward to cleanup the outstanding lsrsp structure. The LLDD should ++ * noop the transmission of the rsp and call the lsrsp->done() routine ++ * to allow the lsrsp structure to be released. ++ */ ++int nvme_fc_rcv_ls_req(struct nvme_fc_remote_port *remoteport, ++ struct nvmefc_ls_rsp *lsrsp, ++ void *lsreqbuf, u32 lsreqbuf_len); ++ ++ + + /* + * *************** LLDD FC-NVME Target/Subsystem API *************** +@@ -470,55 +590,6 @@ struct nvmet_fc_port_info { + }; + + +-/** +- * struct nvmefc_tgt_ls_req - Structure used between LLDD and NVMET-FC +- * layer to represent the exchange context for +- * a FC-NVME Link Service (LS). +- * +- * The structure is allocated by the LLDD whenever a LS Request is received +- * from the FC link. The address of the structure is passed to the nvmet-fc +- * layer via the nvmet_fc_rcv_ls_req() call. The address of the structure +- * will be passed back to the LLDD when the response is to be transmit. +- * The LLDD is to use the address to map back to the LLDD exchange structure +- * which maintains information such as the targetport the LS was received +- * on, the remote FC NVME initiator that sent the LS, and any FC exchange +- * context. Upon completion of the LS response transmit, the address of the +- * structure will be passed back to the LS rsp done() routine, allowing the +- * nvmet-fc layer to release dma resources. Upon completion of the done() +- * routine, no further access will be made by the nvmet-fc layer and the +- * LLDD can de-allocate the structure. +- * +- * Field initialization: +- * At the time of the nvmet_fc_rcv_ls_req() call, there is no content that +- * is valid in the structure. +- * +- * When the structure is used for the LLDD->xmt_ls_rsp() call, the nvmet-fc +- * layer will fully set the fields in order to specify the response +- * payload buffer and its length as well as the done routine to be called +- * upon compeletion of the transmit. The nvmet-fc layer will also set a +- * private pointer for its own use in the done routine. +- * +- * Values set by the NVMET-FC layer prior to calling the LLDD xmt_ls_rsp +- * entrypoint. +- * @rspbuf: pointer to the LS response buffer +- * @rspdma: PCI DMA address of the LS response buffer +- * @rsplen: Length, in bytes, of the LS response buffer +- * @done: The callback routine the LLDD is to invoke upon completion of +- * transmitting the LS response. req argument is the pointer to +- * the original ls request. +- * @nvmet_fc_private: pointer to an internal NVMET-FC layer structure used +- * as part of the NVMET-FC processing. The LLDD is not to access +- * this pointer. +- */ +-struct nvmefc_tgt_ls_req { +- void *rspbuf; +- dma_addr_t rspdma; +- u16 rsplen; +- +- void (*done)(struct nvmefc_tgt_ls_req *req); +- void *nvmet_fc_private; /* LLDD is not to access !! */ +-}; +- + /* Operations that NVME-FC layer may request the LLDD to perform for FCP */ + enum { + NVMET_FCOP_READDATA = 1, /* xmt data to initiator */ +@@ -693,17 +764,19 @@ struct nvmet_fc_target_port { + * Entrypoint is Mandatory. + * + * @xmt_ls_rsp: Called to transmit the response to a FC-NVME FC-4 LS service. +- * The nvmefc_tgt_ls_req structure is the same LLDD-supplied exchange ++ * The nvmefc_ls_rsp structure is the same LLDD-supplied exchange + * structure specified in the nvmet_fc_rcv_ls_req() call made when +- * the LS request was received. The structure will fully describe ++ * the LS request was received. The structure will fully describe + * the buffers for the response payload and the dma address of the +- * payload. The LLDD is to transmit the response (or return a non-zero +- * errno status), and upon completion of the transmit, call the +- * "done" routine specified in the nvmefc_tgt_ls_req structure +- * (argument to done is the ls reqwuest structure itself). +- * After calling the done routine, the LLDD shall consider the +- * LS handling complete and the nvmefc_tgt_ls_req structure may +- * be freed/released. ++ * payload. The LLDD is to transmit the response (or return a ++ * non-zero errno status), and upon completion of the transmit, call ++ * the "done" routine specified in the nvmefc_ls_rsp structure ++ * (argument to done is the address of the nvmefc_ls_rsp structure ++ * itself). Upon the completion of the done() routine, the LLDD shall ++ * consider the LS handling complete and the nvmefc_ls_rsp structure ++ * may be freed/released. ++ * The transport will always call the xmt_ls_rsp() routine for any ++ * LS received. + * Entrypoint is Mandatory. + * + * @fcp_op: Called to perform a data transfer or transmit a response. +@@ -798,6 +871,39 @@ struct nvmet_fc_target_port { + * should cause the initiator to rescan the discovery controller + * on the targetport. + * ++ * @ls_req: Called to issue a FC-NVME FC-4 LS service request. ++ * The nvme_fc_ls_req structure will fully describe the buffers for ++ * the request payload and where to place the response payload. ++ * The targetport that is to issue the LS request is identified by ++ * the targetport argument. The remote port that is to receive the ++ * LS request is identified by the hosthandle argument. The nvmet-fc ++ * transport is only allowed to issue FC-NVME LS's on behalf of an ++ * association that was created prior by a Create Association LS. ++ * The hosthandle will originate from the LLDD in the struct ++ * nvmefc_ls_rsp structure for the Create Association LS that ++ * was delivered to the transport. The transport will save the ++ * hosthandle as an attribute of the association. If the LLDD ++ * loses connectivity with the remote port, it must call the ++ * nvmet_fc_invalidate_host() routine to remove any references to ++ * the remote port in the transport. ++ * The LLDD is to allocate an exchange, issue the LS request, obtain ++ * the LS response, and call the "done" routine specified in the ++ * request structure (argument to done is the ls request structure ++ * itself). ++ * Entrypoint is Optional - but highly recommended. ++ * ++ * @ls_abort: called to request the LLDD to abort the indicated ls request. ++ * The call may return before the abort has completed. After aborting ++ * the request, the LLDD must still call the ls request done routine ++ * indicating an FC transport Aborted status. ++ * Entrypoint is Mandatory if the ls_req entry point is specified. ++ * ++ * @host_release: called to inform the LLDD that the request to invalidate ++ * the host port indicated by the hosthandle has been fully completed. ++ * No associations exist with the host port and there will be no ++ * further references to hosthandle. ++ * Entrypoint is Mandatory if the lldd calls nvmet_fc_invalidate_host(). ++ * + * @max_hw_queues: indicates the maximum number of hw queues the LLDD + * supports for cpu affinitization. + * Value is Mandatory. Must be at least 1. +@@ -826,11 +932,19 @@ struct nvmet_fc_target_port { + * area solely for the of the LLDD and its location is specified by + * the targetport->private pointer. + * Value is Mandatory. Allowed to be zero. ++ * ++ * @lsrqst_priv_sz: The LLDD sets this field to the amount of additional ++ * memory that it would like nvmet-fc layer to allocate on the LLDD's ++ * behalf whenever a ls request structure is allocated. The additional ++ * memory area is solely for use by the LLDD and its location is ++ * specified by the ls_request->private pointer. ++ * Value is Mandatory. Allowed to be zero. ++ * + */ + struct nvmet_fc_target_template { + void (*targetport_delete)(struct nvmet_fc_target_port *tgtport); + int (*xmt_ls_rsp)(struct nvmet_fc_target_port *tgtport, +- struct nvmefc_tgt_ls_req *tls_req); ++ struct nvmefc_ls_rsp *ls_rsp); + int (*fcp_op)(struct nvmet_fc_target_port *tgtport, + struct nvmefc_tgt_fcp_req *fcpreq); + void (*fcp_abort)(struct nvmet_fc_target_port *tgtport, +@@ -840,6 +954,11 @@ struct nvmet_fc_target_template { + void (*defer_rcv)(struct nvmet_fc_target_port *tgtport, + struct nvmefc_tgt_fcp_req *fcpreq); + void (*discovery_event)(struct nvmet_fc_target_port *tgtport); ++ int (*ls_req)(struct nvmet_fc_target_port *targetport, ++ void *hosthandle, struct nvmefc_ls_req *lsreq); ++ void (*ls_abort)(struct nvmet_fc_target_port *targetport, ++ void *hosthandle, struct nvmefc_ls_req *lsreq); ++ void (*host_release)(void *hosthandle); + + u32 max_hw_queues; + u16 max_sgl_segments; +@@ -848,7 +967,9 @@ struct nvmet_fc_target_template { + + u32 target_features; + ++ /* sizes of additional private data for data structures */ + u32 target_priv_sz; ++ u32 lsrqst_priv_sz; + }; + + +@@ -859,10 +980,61 @@ int nvmet_fc_register_targetport(struct nvmet_fc_port_info *portinfo, + + int nvmet_fc_unregister_targetport(struct nvmet_fc_target_port *tgtport); + ++/* ++ * Routine called to pass a NVME-FC LS request, received by the lldd, ++ * to the nvmet-fc transport. ++ * ++ * If the return value is zero: the LS was successfully accepted by the ++ * transport. ++ * If the return value is non-zero: the transport has not accepted the ++ * LS. The lldd should ABTS-LS the LS. ++ * ++ * Note: if the LLDD receives and ABTS for the LS prior to the transport ++ * calling the ops->xmt_ls_rsp() routine to transmit a response, the LLDD ++ * shall mark the LS as aborted, and when the xmt_ls_rsp() is called: the ++ * response shall not be transmit and the struct nvmefc_ls_rsp() done ++ * routine shall be called. The LLDD may transmit the ABTS response as ++ * soon as the LS was marked or can delay until the xmt_ls_rsp() call is ++ * made. ++ * Note: if an RCV LS was successfully posted to the transport and the ++ * targetport is then unregistered before xmt_ls_rsp() was called for ++ * the lsrsp structure, the transport will still call xmt_ls_rsp() ++ * afterward to cleanup the outstanding lsrsp structure. The LLDD should ++ * noop the transmission of the rsp and call the lsrsp->done() routine ++ * to allow the lsrsp structure to be released. ++ */ + int nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *tgtport, +- struct nvmefc_tgt_ls_req *lsreq, ++ void *hosthandle, ++ struct nvmefc_ls_rsp *rsp, + void *lsreqbuf, u32 lsreqbuf_len); + ++/* ++ * Routine called by the LLDD whenever it has a logout or loss of ++ * connectivity to a NVME-FC host port which there had been active ++ * NVMe controllers for. The host port is indicated by the ++ * hosthandle. The hosthandle is given to the nvmet-fc transport ++ * when a NVME LS was received, typically to create a new association. ++ * The nvmet-fc transport will cache the hostport value with the ++ * association for use in LS requests for the association. ++ * When the LLDD calls this routine, the nvmet-fc transport will ++ * immediately terminate all associations that were created with ++ * the hosthandle host port. ++ * The LLDD, after calling this routine and having control returned, ++ * must assume the transport may subsequently utilize hosthandle as ++ * part of sending LS's to terminate the association. The LLDD ++ * should reject the LS's if they are attempted. ++ * Once the last association has terminated for the hosthandle host ++ * port, the nvmet-fc transport will call the ops->host_release() ++ * callback. As of the callback, the nvmet-fc transport will no ++ * longer reference hosthandle. ++ */ ++void nvmet_fc_invalidate_host(struct nvmet_fc_target_port *tgtport, ++ void *hosthandle); ++ ++/* ++ * If nvmet_fc_rcv_fcp_req returns non-zero, the transport has not accepted ++ * the FCP cmd. The lldd should ABTS-LS the cmd. ++ */ + int nvmet_fc_rcv_fcp_req(struct nvmet_fc_target_port *tgtport, + struct nvmefc_tgt_fcp_req *fcpreq, + void *cmdiubuf, u32 cmdiubuf_len); +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-and-nvmet-fc-sync-with-FC-NVME-2-header-chan.patch b/patches.suse/nvme-fc-and-nvmet-fc-sync-with-FC-NVME-2-header-chan.patch new file mode 100644 index 0000000..ccfe032 --- /dev/null +++ b/patches.suse/nvme-fc-and-nvmet-fc-sync-with-FC-NVME-2-header-chan.patch @@ -0,0 +1,192 @@ +From: James Smart +Date: Fri, 27 Sep 2019 14:51:35 -0700 +Subject: [PATCH] nvme-fc and nvmet-fc: sync with FC-NVME-2 header changes +Git-commit: 53b2b2f59967c0b7eb4df265136b1cc25b9fb287 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Sync sources with revised structure and field names to correspond with +FC-NVME-2 header sync-up. + +Tested interoperability with success: +- prior initiator with new target +- prior target with new initiator +- new on new + +Signed-off-by: James Smart +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 24 +++++++++++------------- + drivers/nvme/target/fc.c | 27 +++++++++++++++------------ + 2 files changed, 26 insertions(+), 25 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 265f89e11d8b..e09c61ec0b96 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -1224,7 +1224,7 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, + lsreq->rqstlen = sizeof(*assoc_rqst); + lsreq->rspaddr = assoc_acc; + lsreq->rsplen = sizeof(*assoc_acc); +- lsreq->timeout = NVME_FC_CONNECT_TIMEOUT_SEC; ++ lsreq->timeout = NVME_FC_LS_TIMEOUT_SEC; + + ret = nvme_fc_send_ls_req(ctrl->rport, lsop); + if (ret) +@@ -1332,7 +1332,7 @@ nvme_fc_connect_queue(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, + lsreq->rqstlen = sizeof(*conn_rqst); + lsreq->rspaddr = conn_acc; + lsreq->rsplen = sizeof(*conn_acc); +- lsreq->timeout = NVME_FC_CONNECT_TIMEOUT_SEC; ++ lsreq->timeout = NVME_FC_LS_TIMEOUT_SEC; + + ret = nvme_fc_send_ls_req(ctrl->rport, lsop); + if (ret) +@@ -1413,8 +1413,8 @@ nvme_fc_disconnect_assoc_done(struct nvmefc_ls_req *lsreq, int status) + static void + nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + { +- struct fcnvme_ls_disconnect_rqst *discon_rqst; +- struct fcnvme_ls_disconnect_acc *discon_acc; ++ struct fcnvme_ls_disconnect_assoc_rqst *discon_rqst; ++ struct fcnvme_ls_disconnect_assoc_acc *discon_acc; + struct nvmefc_ls_req_op *lsop; + struct nvmefc_ls_req *lsreq; + int ret; +@@ -1430,11 +1430,11 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + lsreq = &lsop->ls_req; + + lsreq->private = (void *)&lsop[1]; +- discon_rqst = (struct fcnvme_ls_disconnect_rqst *) ++ discon_rqst = (struct fcnvme_ls_disconnect_assoc_rqst *) + (lsreq->private + ctrl->lport->ops->lsrqst_priv_sz); +- discon_acc = (struct fcnvme_ls_disconnect_acc *)&discon_rqst[1]; ++ discon_acc = (struct fcnvme_ls_disconnect_assoc_acc *)&discon_rqst[1]; + +- discon_rqst->w0.ls_cmd = FCNVME_LS_DISCONNECT; ++ discon_rqst->w0.ls_cmd = FCNVME_LS_DISCONNECT_ASSOC; + discon_rqst->desc_list_len = cpu_to_be32( + sizeof(struct fcnvme_lsdesc_assoc_id) + + sizeof(struct fcnvme_lsdesc_disconn_cmd)); +@@ -1451,14 +1451,12 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + discon_rqst->discon_cmd.desc_len = + fcnvme_lsdesc_len( + sizeof(struct fcnvme_lsdesc_disconn_cmd)); +- discon_rqst->discon_cmd.scope = FCNVME_DISCONN_ASSOCIATION; +- discon_rqst->discon_cmd.id = cpu_to_be64(ctrl->association_id); + + lsreq->rqstaddr = discon_rqst; + lsreq->rqstlen = sizeof(*discon_rqst); + lsreq->rspaddr = discon_acc; + lsreq->rsplen = sizeof(*discon_acc); +- lsreq->timeout = NVME_FC_CONNECT_TIMEOUT_SEC; ++ lsreq->timeout = NVME_FC_LS_TIMEOUT_SEC; + + ret = nvme_fc_send_ls_req_async(ctrl->rport, lsop, + nvme_fc_disconnect_assoc_done); +@@ -1662,7 +1660,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) + (freq->rcv_rsplen / 4) || + be32_to_cpu(op->rsp_iu.xfrd_len) != + freq->transferred_length || +- op->rsp_iu.status_code || ++ op->rsp_iu.ersp_result || + sqe->common.command_id != cqe->command_id)) { + status = cpu_to_le16(NVME_SC_HOST_PATH_ERROR << 1); + dev_info(ctrl->ctrl.device, +@@ -1672,7 +1670,7 @@ nvme_fc_fcpio_done(struct nvmefc_fcp_req *req) + ctrl->cnum, be16_to_cpu(op->rsp_iu.iu_len), + be32_to_cpu(op->rsp_iu.xfrd_len), + freq->transferred_length, +- op->rsp_iu.status_code, ++ op->rsp_iu.ersp_result, + sqe->common.command_id, + cqe->command_id); + goto done; +@@ -1731,7 +1729,7 @@ __nvme_fc_init_request(struct nvme_fc_ctrl *ctrl, + op->rq = rq; + op->rqno = rqno; + +- cmdiu->scsi_id = NVME_CMD_SCSI_ID; ++ cmdiu->format_id = NVME_CMD_FORMAT_ID; + cmdiu->fc_id = NVME_CMD_FC_ID; + cmdiu->iu_len = cpu_to_be16(sizeof(*cmdiu) / sizeof(u32)); + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index ce8d819f86cc..61b617698d3f 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -1495,20 +1495,20 @@ static void + nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_ls_iod *iod) + { +- struct fcnvme_ls_disconnect_rqst *rqst = +- (struct fcnvme_ls_disconnect_rqst *)iod->rqstbuf; +- struct fcnvme_ls_disconnect_acc *acc = +- (struct fcnvme_ls_disconnect_acc *)iod->rspbuf; ++ struct fcnvme_ls_disconnect_assoc_rqst *rqst = ++ (struct fcnvme_ls_disconnect_assoc_rqst *)iod->rqstbuf; ++ struct fcnvme_ls_disconnect_assoc_acc *acc = ++ (struct fcnvme_ls_disconnect_assoc_acc *)iod->rspbuf; + struct nvmet_fc_tgt_assoc *assoc; + int ret = 0; + + memset(acc, 0, sizeof(*acc)); + +- if (iod->rqstdatalen < sizeof(struct fcnvme_ls_disconnect_rqst)) ++ if (iod->rqstdatalen < sizeof(struct fcnvme_ls_disconnect_assoc_rqst)) + ret = VERR_DISCONN_LEN; + else if (rqst->desc_list_len != + fcnvme_lsdesc_len( +- sizeof(struct fcnvme_ls_disconnect_rqst))) ++ sizeof(struct fcnvme_ls_disconnect_assoc_rqst))) + ret = VERR_DISCONN_RQST_LEN; + else if (rqst->associd.desc_tag != cpu_to_be32(FCNVME_LSDESC_ASSOC_ID)) + ret = VERR_ASSOC_ID; +@@ -1523,8 +1523,11 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + fcnvme_lsdesc_len( + sizeof(struct fcnvme_lsdesc_disconn_cmd))) + ret = VERR_DISCONN_CMD_LEN; +- else if ((rqst->discon_cmd.scope != FCNVME_DISCONN_ASSOCIATION) && +- (rqst->discon_cmd.scope != FCNVME_DISCONN_CONNECTION)) ++ /* ++ * As the standard changed on the LS, check if old format and scope ++ * something other than Association (e.g. 0). ++ */ ++ else if (rqst->discon_cmd.rsvd8[0]) + ret = VERR_DISCONN_SCOPE; + else { + /* match an active association */ +@@ -1556,8 +1559,8 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + + nvmet_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, + fcnvme_lsdesc_len( +- sizeof(struct fcnvme_ls_disconnect_acc)), +- FCNVME_LS_DISCONNECT); ++ sizeof(struct fcnvme_ls_disconnect_assoc_acc)), ++ FCNVME_LS_DISCONNECT_ASSOC); + + /* release get taken in nvmet_fc_find_target_assoc */ + nvmet_fc_tgt_a_put(iod->assoc); +@@ -1632,7 +1635,7 @@ nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + /* Creates an IO Queue/Connection */ + nvmet_fc_ls_create_connection(tgtport, iod); + break; +- case FCNVME_LS_DISCONNECT: ++ case FCNVME_LS_DISCONNECT_ASSOC: + /* Terminate a Queue/Connection or the Association */ + nvmet_fc_ls_disconnect(tgtport, iod); + break; +@@ -2299,7 +2302,7 @@ nvmet_fc_rcv_fcp_req(struct nvmet_fc_target_port *target_port, + + /* validate iu, so the connection id can be used to find the queue */ + if ((cmdiubuf_len != sizeof(*cmdiu)) || +- (cmdiu->scsi_id != NVME_CMD_SCSI_ID) || ++ (cmdiu->format_id != NVME_CMD_FORMAT_ID) || + (cmdiu->fc_id != NVME_CMD_FC_ID) || + (be16_to_cpu(cmdiu->iu_len) != (sizeof(*cmdiu)/4))) + return -EIO; +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-clarify-error-messages.patch b/patches.suse/nvme-fc-clarify-error-messages.patch new file mode 100644 index 0000000..3bcc777 --- /dev/null +++ b/patches.suse/nvme-fc-clarify-error-messages.patch @@ -0,0 +1,71 @@ +From: James Smart +Date: Fri, 27 Sep 2019 15:27:11 -0700 +Subject: [PATCH] nvme-fc: clarify error messages +Git-commit: 7db394848ece0e0706dfe8e4940b24e949f3b88f +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Change wording on a couple of messages to clarify what happened. + +Signed-off-by: Ewan D. Milne +Signed-off-by: James Smart +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index e099a74f666e..2284b7f9e8b9 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -1264,7 +1264,7 @@ nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, + if (fcret) { + ret = -EBADF; + dev_err(ctrl->dev, +- "q %d connect failed: %s\n", ++ "q %d Create Association LS failed: %s\n", + queue->qnum, validation_errors[fcret]); + } else { + ctrl->association_id = +@@ -1363,7 +1363,7 @@ nvme_fc_connect_queue(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, + if (fcret) { + ret = -EBADF; + dev_err(ctrl->dev, +- "q %d connect failed: %s\n", ++ "q %d Create I/O Connection LS failed: %s\n", + queue->qnum, validation_errors[fcret]); + } else { + queue->connection_id = +@@ -1376,7 +1376,7 @@ nvme_fc_connect_queue(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, + out_no_memory: + if (ret) + dev_err(ctrl->dev, +- "queue %d connect command failed (%d).\n", ++ "queue %d connect I/O queue failed (%d).\n", + queue->qnum, ret); + return ret; + } +@@ -2698,7 +2698,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + /* warn if maxcmd is lower than queue_size */ + dev_warn(ctrl->ctrl.device, + "queue_size %zu > ctrl maxcmd %u, reducing " +- "to queue_size\n", ++ "to maxcmd\n", + opts->queue_size, ctrl->ctrl.maxcmd); + opts->queue_size = ctrl->ctrl.maxcmd; + } +@@ -2706,7 +2706,8 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + if (opts->queue_size > ctrl->ctrl.sqsize + 1) { + /* warn if sqsize is lower than queue_size */ + dev_warn(ctrl->ctrl.device, +- "queue_size %zu > ctrl sqsize %u, clamping down\n", ++ "queue_size %zu > ctrl sqsize %u, reducing " ++ "to sqsize\n", + opts->queue_size, ctrl->ctrl.sqsize + 1); + opts->queue_size = ctrl->ctrl.sqsize + 1; + } +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-convert-assoc_active-flag-to-bit-op.patch b/patches.suse/nvme-fc-convert-assoc_active-flag-to-bit-op.patch new file mode 100644 index 0000000..638b5e9 --- /dev/null +++ b/patches.suse/nvme-fc-convert-assoc_active-flag-to-bit-op.patch @@ -0,0 +1,157 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:51 -0700 +Subject: [PATCH] nvme-fc: convert assoc_active flag to bit op +Git-commit: 1b202b79ad142dcabfc84bd1a8ac7cff31b3bade +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Convert the assoc_active boolean flag to a bitop on the flags field. +The bit ops will provide atomicity. + +To make this change, the flags field was converted to a long type, +which also affects the FCCTRL_TERMIO flag. Both FCCTRL_TERMIO and +now ASSOC_ACTIVE flags are set/cleared by bit operations. + +Signed-off-by: James Smart +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 37 +++++++++++++------------------------ + 1 file changed, 13 insertions(+), 24 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index bf80b941d739..0ac246603063 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -127,9 +127,9 @@ struct nvme_fc_rport { + unsigned long dev_loss_end; + } __aligned(sizeof(u64)); /* alignment for other things alloc'd with */ + +-enum nvme_fcctrl_flags { +- FCCTRL_TERMIO = (1 << 0), +-}; ++/* fc_ctrl flags values - specified as bit positions */ ++#define ASSOC_ACTIVE 0 ++#define FCCTRL_TERMIO 1 + + struct nvme_fc_ctrl { + spinlock_t lock; +@@ -140,7 +140,6 @@ struct nvme_fc_ctrl { + u32 cnum; + + bool ioq_live; +- bool assoc_active; + atomic_t err_work_active; + u64 association_id; + +@@ -153,7 +152,7 @@ struct nvme_fc_ctrl { + struct work_struct err_work; + + struct kref ref; +- u32 flags; ++ unsigned long flags; + u32 iocnt; + wait_queue_head_t ioabort_wait; + +@@ -1521,7 +1520,7 @@ __nvme_fc_abort_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_fcp_op *op) + opstate = atomic_xchg(&op->state, FCPOP_STATE_ABORTED); + if (opstate != FCPOP_STATE_ACTIVE) + atomic_set(&op->state, opstate); +- else if (ctrl->flags & FCCTRL_TERMIO) ++ else if (test_bit(FCCTRL_TERMIO, &ctrl->flags)) + ctrl->iocnt++; + spin_unlock_irqrestore(&ctrl->lock, flags); + +@@ -1558,7 +1557,7 @@ __nvme_fc_fcpop_chk_teardowns(struct nvme_fc_ctrl *ctrl, + + if (opstate == FCPOP_STATE_ABORTED) { + spin_lock_irqsave(&ctrl->lock, flags); +- if (ctrl->flags & FCCTRL_TERMIO) { ++ if (test_bit(FCCTRL_TERMIO, &ctrl->flags)) { + if (!--ctrl->iocnt) + wake_up(&ctrl->ioabort_wait); + } +@@ -2386,16 +2385,9 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg) + { + struct nvme_fc_ctrl *ctrl = to_fc_ctrl(arg); + struct nvme_fc_fcp_op *aen_op; +- unsigned long flags; +- bool terminating = false; + blk_status_t ret; + +- spin_lock_irqsave(&ctrl->lock, flags); +- if (ctrl->flags & FCCTRL_TERMIO) +- terminating = true; +- spin_unlock_irqrestore(&ctrl->lock, flags); +- +- if (terminating) ++ if (test_bit(FCCTRL_TERMIO, &ctrl->flags)) + return; + + aen_op = &ctrl->aen_ops[0]; +@@ -2604,10 +2596,9 @@ nvme_fc_ctlr_active_on_rport(struct nvme_fc_ctrl *ctrl) + struct nvme_fc_rport *rport = ctrl->rport; + u32 cnt; + +- if (ctrl->assoc_active) ++ if (test_and_set_bit(ASSOC_ACTIVE, &ctrl->flags)) + return 1; + +- ctrl->assoc_active = true; + cnt = atomic_inc_return(&rport->act_ctrl_cnt); + if (cnt == 1) + nvme_fc_rport_active_on_lport(rport); +@@ -2622,7 +2613,7 @@ nvme_fc_ctlr_inactive_on_rport(struct nvme_fc_ctrl *ctrl) + struct nvme_fc_lport *lport = rport->lport; + u32 cnt; + +- /* ctrl->assoc_active=false will be set independently */ ++ /* clearing of ctrl->flags ASSOC_ACTIVE bit is in association delete */ + + cnt = atomic_dec_return(&rport->act_ctrl_cnt); + if (cnt == 0) { +@@ -2764,7 +2755,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + __nvme_fc_delete_hw_queue(ctrl, &ctrl->queues[0], 0); + out_free_queue: + nvme_fc_free_queue(&ctrl->queues[0]); +- ctrl->assoc_active = false; ++ clear_bit(ASSOC_ACTIVE, &ctrl->flags); + nvme_fc_ctlr_inactive_on_rport(ctrl); + + return ret; +@@ -2781,12 +2772,11 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) + { + unsigned long flags; + +- if (!ctrl->assoc_active) ++ if (!test_and_clear_bit(ASSOC_ACTIVE, &ctrl->flags)) + return; +- ctrl->assoc_active = false; + + spin_lock_irqsave(&ctrl->lock, flags); +- ctrl->flags |= FCCTRL_TERMIO; ++ set_bit(FCCTRL_TERMIO, &ctrl->flags); + ctrl->iocnt = 0; + spin_unlock_irqrestore(&ctrl->lock, flags); + +@@ -2837,7 +2827,7 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) + /* wait for all io that had to be aborted */ + spin_lock_irq(&ctrl->lock); + wait_event_lock_irq(ctrl->ioabort_wait, ctrl->iocnt == 0, ctrl->lock); +- ctrl->flags &= ~FCCTRL_TERMIO; ++ clear_bit(FCCTRL_TERMIO, &ctrl->flags); + spin_unlock_irq(&ctrl->lock); + + nvme_fc_term_aen_ops(ctrl); +@@ -3109,7 +3099,6 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, + ctrl->dev = lport->dev; + ctrl->cnum = idx; + ctrl->ioq_live = false; +- ctrl->assoc_active = false; + atomic_set(&ctrl->err_work_active, 0); + init_waitqueue_head(&ctrl->ioabort_wait); + +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-ensure-association_id-is-cleared-regardless-.patch b/patches.suse/nvme-fc-ensure-association_id-is-cleared-regardless-.patch new file mode 100644 index 0000000..c2344aa --- /dev/null +++ b/patches.suse/nvme-fc-ensure-association_id-is-cleared-regardless-.patch @@ -0,0 +1,55 @@ +From: James Smart +Date: Fri, 27 Sep 2019 14:27:22 -0700 +Subject: [PATCH] nvme-fc: ensure association_id is cleared regardless of a + Disconnect LS +Git-commit: bcde5f0fc7d318c98d4234b52bcc1a87fc2162d9 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Code today only clears the association_id if a Disconnect LS is transmit. + +Remove ambiguity and unconditionally clear the association_id if the +association has been terminated. + +Signed-off-by: James Smart +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 2284b7f9e8b9..714a1c3aa0c5 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -1462,9 +1462,6 @@ nvme_fc_xmt_disconnect_assoc(struct nvme_fc_ctrl *ctrl) + nvme_fc_disconnect_assoc_done); + if (ret) + kfree(lsop); +- +- /* only meaningful part to terminating the association */ +- ctrl->association_id = 0; + } + + +@@ -2743,6 +2740,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl) + out_disconnect_admin_queue: + /* send a Disconnect(association) LS to fc-nvme target */ + nvme_fc_xmt_disconnect_assoc(ctrl); ++ ctrl->association_id = 0; + out_delete_hw_queue: + __nvme_fc_delete_hw_queue(ctrl, &ctrl->queues[0], 0); + out_free_queue: +@@ -2834,6 +2832,8 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl) + if (ctrl->association_id) + nvme_fc_xmt_disconnect_assoc(ctrl); + ++ ctrl->association_id = 0; ++ + if (ctrl->ctrl.tagset) { + nvme_fc_delete_hw_io_queues(ctrl); + nvme_fc_free_io_queues(ctrl); +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-fix-double-free-scenarios-on-hw-queues.patch b/patches.suse/nvme-fc-fix-double-free-scenarios-on-hw-queues.patch new file mode 100644 index 0000000..9296283 --- /dev/null +++ b/patches.suse/nvme-fc-fix-double-free-scenarios-on-hw-queues.patch @@ -0,0 +1,78 @@ +From: James Smart +Date: Thu, 21 Nov 2019 09:59:37 -0800 +Subject: [PATCH] nvme-fc: fix double-free scenarios on hw queues +Git-commit: c869e494ef8b5846d9ba91f1e922c23cd444f0c1 +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +If an error occurs on one of the ios used for creating an +association, the creating routine has error paths that are +invoked by the command failure and the error paths will free +up the controller resources created to that point. + +But... the io was ultimately determined by an asynchronous +completion routine that detected the error and which +unconditionally invokes the error_recovery path which calls +delete_association. Delete association deletes all outstanding +io then tears down the controller resources. So the +create_association thread can be running in parallel with +the error_recovery thread. What was seen was the LLDD received +a call to delete a queue, causing the LLDD to do a free of a +resource, then the transport called the delete queue again +causing the driver to repeat the free call. The second free +routine corrupted the allocator. The transport shouldn't be +making the duplicate call, and the delete queue is just one +of the resources being freed. + +To fix, it is realized that the create_association path is +completely serialized with one command at a time. So the +failed io completion will always be seen by the create_association +path and as of the failure, there are no ios to terminate and there +is no reason to be manipulating queue freeze states, etc. +The serialized condition stays true until the controller is +transitioned to the LIVE state. Thus the fix is to change the +error recovery path to check the controller state and only +invoke the teardown path if not already in the CONNECTING state. + +Reviewed-by: Himanshu Madhani +Reviewed-by: Ewan D. Milne +Signed-off-by: James Smart +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index d61439f8f5a9..5a70ac395d53 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -2913,10 +2913,22 @@ nvme_fc_reconnect_or_delete(struct nvme_fc_ctrl *ctrl, int status) + static void + __nvme_fc_terminate_io(struct nvme_fc_ctrl *ctrl) + { +- nvme_stop_keep_alive(&ctrl->ctrl); ++ /* ++ * if state is connecting - the error occurred as part of a ++ * reconnect attempt. The create_association error paths will ++ * clean up any outstanding io. ++ * ++ * if it's a different state - ensure all pending io is ++ * terminated. Given this can delay while waiting for the ++ * aborted io to return, we recheck adapter state below ++ * before changing state. ++ */ ++ if (ctrl->ctrl.state != NVME_CTRL_CONNECTING) { ++ nvme_stop_keep_alive(&ctrl->ctrl); + +- /* will block will waiting for io to terminate */ +- nvme_fc_delete_association(ctrl); ++ /* will block will waiting for io to terminate */ ++ nvme_fc_delete_association(ctrl); ++ } + + if (ctrl->ctrl.state != NVME_CTRL_CONNECTING && + !nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_CONNECTING)) +-- +2.16.4 + diff --git a/patches.suse/nvme-fc-nvmet-fc-refactor-for-common-LS-definitions.patch b/patches.suse/nvme-fc-nvmet-fc-refactor-for-common-LS-definitions.patch new file mode 100644 index 0000000..c5fbf32 --- /dev/null +++ b/patches.suse/nvme-fc-nvmet-fc-refactor-for-common-LS-definitions.patch @@ -0,0 +1,408 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:48 -0700 +Subject: [PATCH] nvme-fc nvmet-fc: refactor for common LS definitions +Git-commit: c0005a9d63a6127c2914e0b66c7224b0bb5b5fd4 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Routines in the target will want to be used in the host as well. +Error definitions should now shared as both sides will process +requests and responses to requests. + +Moved common declarations to new fc.h header kept in the host +subdirectory. + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Reviewed-by: Himanshu Madhani +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 36 +------------ + drivers/nvme/host/fc.h | 133 +++++++++++++++++++++++++++++++++++++++++++++++ + drivers/nvme/target/fc.c | 115 ++++------------------------------------ + 3 files changed, 143 insertions(+), 141 deletions(-) + create mode 100644 drivers/nvme/host/fc.h + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 8012099fc3ee..83f9b2ac7c55 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -14,6 +14,7 @@ + #include "fabrics.h" + #include + #include ++#include "fc.h" + #include + + /* *************************** Data Structures/Defines ****************** */ +@@ -1140,41 +1141,6 @@ nvme_fc_send_ls_req_async(struct nvme_fc_rport *rport, + return __nvme_fc_send_ls_req(rport, lsop, done); + } + +-/* Validation Error indexes into the string table below */ +-enum { +- VERR_NO_ERROR = 0, +- VERR_LSACC = 1, +- VERR_LSDESC_RQST = 2, +- VERR_LSDESC_RQST_LEN = 3, +- VERR_ASSOC_ID = 4, +- VERR_ASSOC_ID_LEN = 5, +- VERR_CONN_ID = 6, +- VERR_CONN_ID_LEN = 7, +- VERR_CR_ASSOC = 8, +- VERR_CR_ASSOC_ACC_LEN = 9, +- VERR_CR_CONN = 10, +- VERR_CR_CONN_ACC_LEN = 11, +- VERR_DISCONN = 12, +- VERR_DISCONN_ACC_LEN = 13, +-}; +- +-static char *validation_errors[] = { +- "OK", +- "Not LS_ACC", +- "Not LSDESC_RQST", +- "Bad LSDESC_RQST Length", +- "Not Association ID", +- "Bad Association ID Length", +- "Not Connection ID", +- "Bad Connection ID Length", +- "Not CR_ASSOC Rqst", +- "Bad CR_ASSOC ACC Length", +- "Not CR_CONN Rqst", +- "Bad CR_CONN ACC Length", +- "Not Disconnect Rqst", +- "Bad Disconnect ACC Length", +-}; +- + static int + nvme_fc_connect_admin_queue(struct nvme_fc_ctrl *ctrl, + struct nvme_fc_queue *queue, u16 qsize, u16 ersp_ratio) +diff --git a/drivers/nvme/host/fc.h b/drivers/nvme/host/fc.h +new file mode 100644 +index 000000000000..d2861cdd58ee +--- /dev/null ++++ b/drivers/nvme/host/fc.h +@@ -0,0 +1,133 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Copyright (c) 2016, Avago Technologies ++ */ ++ ++#ifndef _NVME_FC_TRANSPORT_H ++#define _NVME_FC_TRANSPORT_H 1 ++ ++ ++/* ++ * Common definitions between the nvme_fc (host) transport and ++ * nvmet_fc (target) transport implementation. ++ */ ++ ++/* ++ * ****************** FC-NVME LS HANDLING ****************** ++ */ ++ ++static inline void ++nvme_fc_format_rsp_hdr(void *buf, u8 ls_cmd, __be32 desc_len, u8 rqst_ls_cmd) ++{ ++ struct fcnvme_ls_acc_hdr *acc = buf; ++ ++ acc->w0.ls_cmd = ls_cmd; ++ acc->desc_list_len = desc_len; ++ acc->rqst.desc_tag = cpu_to_be32(FCNVME_LSDESC_RQST); ++ acc->rqst.desc_len = ++ fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rqst)); ++ acc->rqst.w0.ls_cmd = rqst_ls_cmd; ++} ++ ++static inline int ++nvme_fc_format_rjt(void *buf, u16 buflen, u8 ls_cmd, ++ u8 reason, u8 explanation, u8 vendor) ++{ ++ struct fcnvme_ls_rjt *rjt = buf; ++ ++ nvme_fc_format_rsp_hdr(buf, FCNVME_LSDESC_RQST, ++ fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_rjt)), ++ ls_cmd); ++ rjt->rjt.desc_tag = cpu_to_be32(FCNVME_LSDESC_RJT); ++ rjt->rjt.desc_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rjt)); ++ rjt->rjt.reason_code = reason; ++ rjt->rjt.reason_explanation = explanation; ++ rjt->rjt.vendor = vendor; ++ ++ return sizeof(struct fcnvme_ls_rjt); ++} ++ ++/* Validation Error indexes into the string table below */ ++enum { ++ VERR_NO_ERROR = 0, ++ VERR_CR_ASSOC_LEN = 1, ++ VERR_CR_ASSOC_RQST_LEN = 2, ++ VERR_CR_ASSOC_CMD = 3, ++ VERR_CR_ASSOC_CMD_LEN = 4, ++ VERR_ERSP_RATIO = 5, ++ VERR_ASSOC_ALLOC_FAIL = 6, ++ VERR_QUEUE_ALLOC_FAIL = 7, ++ VERR_CR_CONN_LEN = 8, ++ VERR_CR_CONN_RQST_LEN = 9, ++ VERR_ASSOC_ID = 10, ++ VERR_ASSOC_ID_LEN = 11, ++ VERR_NO_ASSOC = 12, ++ VERR_CONN_ID = 13, ++ VERR_CONN_ID_LEN = 14, ++ VERR_INVAL_CONN = 15, ++ VERR_CR_CONN_CMD = 16, ++ VERR_CR_CONN_CMD_LEN = 17, ++ VERR_DISCONN_LEN = 18, ++ VERR_DISCONN_RQST_LEN = 19, ++ VERR_DISCONN_CMD = 20, ++ VERR_DISCONN_CMD_LEN = 21, ++ VERR_DISCONN_SCOPE = 22, ++ VERR_RS_LEN = 23, ++ VERR_RS_RQST_LEN = 24, ++ VERR_RS_CMD = 25, ++ VERR_RS_CMD_LEN = 26, ++ VERR_RS_RCTL = 27, ++ VERR_RS_RO = 28, ++ VERR_LSACC = 29, ++ VERR_LSDESC_RQST = 30, ++ VERR_LSDESC_RQST_LEN = 31, ++ VERR_CR_ASSOC = 32, ++ VERR_CR_ASSOC_ACC_LEN = 33, ++ VERR_CR_CONN = 34, ++ VERR_CR_CONN_ACC_LEN = 35, ++ VERR_DISCONN = 36, ++ VERR_DISCONN_ACC_LEN = 37, ++}; ++ ++static char *validation_errors[] = { ++ "OK", ++ "Bad CR_ASSOC Length", ++ "Bad CR_ASSOC Rqst Length", ++ "Not CR_ASSOC Cmd", ++ "Bad CR_ASSOC Cmd Length", ++ "Bad Ersp Ratio", ++ "Association Allocation Failed", ++ "Queue Allocation Failed", ++ "Bad CR_CONN Length", ++ "Bad CR_CONN Rqst Length", ++ "Not Association ID", ++ "Bad Association ID Length", ++ "No Association", ++ "Not Connection ID", ++ "Bad Connection ID Length", ++ "Invalid Connection ID", ++ "Not CR_CONN Cmd", ++ "Bad CR_CONN Cmd Length", ++ "Bad DISCONN Length", ++ "Bad DISCONN Rqst Length", ++ "Not DISCONN Cmd", ++ "Bad DISCONN Cmd Length", ++ "Bad Disconnect Scope", ++ "Bad RS Length", ++ "Bad RS Rqst Length", ++ "Not RS Cmd", ++ "Bad RS Cmd Length", ++ "Bad RS R_CTL", ++ "Bad RS Relative Offset", ++ "Not LS_ACC", ++ "Not LSDESC_RQST", ++ "Bad LSDESC_RQST Length", ++ "Not CR_ASSOC Rqst", ++ "Bad CR_ASSOC ACC Length", ++ "Not CR_CONN Rqst", ++ "Bad CR_CONN ACC Length", ++ "Not Disconnect Rqst", ++ "Bad Disconnect ACC Length", ++}; ++ ++#endif /* _NVME_FC_TRANSPORT_H */ +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index aac7869a70bb..1f3118a3b0a3 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -14,6 +14,7 @@ + #include "nvmet.h" + #include + #include ++#include "../host/fc.h" + + + /* *************************** Data Structures/Defines ****************** */ +@@ -1257,102 +1258,6 @@ EXPORT_SYMBOL_GPL(nvmet_fc_unregister_targetport); + /* *********************** FC-NVME LS Handling **************************** */ + + +-static void +-nvmet_fc_format_rsp_hdr(void *buf, u8 ls_cmd, __be32 desc_len, u8 rqst_ls_cmd) +-{ +- struct fcnvme_ls_acc_hdr *acc = buf; +- +- acc->w0.ls_cmd = ls_cmd; +- acc->desc_list_len = desc_len; +- acc->rqst.desc_tag = cpu_to_be32(FCNVME_LSDESC_RQST); +- acc->rqst.desc_len = +- fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rqst)); +- acc->rqst.w0.ls_cmd = rqst_ls_cmd; +-} +- +-static int +-nvmet_fc_format_rjt(void *buf, u16 buflen, u8 ls_cmd, +- u8 reason, u8 explanation, u8 vendor) +-{ +- struct fcnvme_ls_rjt *rjt = buf; +- +- nvmet_fc_format_rsp_hdr(buf, FCNVME_LSDESC_RQST, +- fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_rjt)), +- ls_cmd); +- rjt->rjt.desc_tag = cpu_to_be32(FCNVME_LSDESC_RJT); +- rjt->rjt.desc_len = fcnvme_lsdesc_len(sizeof(struct fcnvme_lsdesc_rjt)); +- rjt->rjt.reason_code = reason; +- rjt->rjt.reason_explanation = explanation; +- rjt->rjt.vendor = vendor; +- +- return sizeof(struct fcnvme_ls_rjt); +-} +- +-/* Validation Error indexes into the string table below */ +-enum { +- VERR_NO_ERROR = 0, +- VERR_CR_ASSOC_LEN = 1, +- VERR_CR_ASSOC_RQST_LEN = 2, +- VERR_CR_ASSOC_CMD = 3, +- VERR_CR_ASSOC_CMD_LEN = 4, +- VERR_ERSP_RATIO = 5, +- VERR_ASSOC_ALLOC_FAIL = 6, +- VERR_QUEUE_ALLOC_FAIL = 7, +- VERR_CR_CONN_LEN = 8, +- VERR_CR_CONN_RQST_LEN = 9, +- VERR_ASSOC_ID = 10, +- VERR_ASSOC_ID_LEN = 11, +- VERR_NO_ASSOC = 12, +- VERR_CONN_ID = 13, +- VERR_CONN_ID_LEN = 14, +- VERR_NO_CONN = 15, +- VERR_CR_CONN_CMD = 16, +- VERR_CR_CONN_CMD_LEN = 17, +- VERR_DISCONN_LEN = 18, +- VERR_DISCONN_RQST_LEN = 19, +- VERR_DISCONN_CMD = 20, +- VERR_DISCONN_CMD_LEN = 21, +- VERR_DISCONN_SCOPE = 22, +- VERR_RS_LEN = 23, +- VERR_RS_RQST_LEN = 24, +- VERR_RS_CMD = 25, +- VERR_RS_CMD_LEN = 26, +- VERR_RS_RCTL = 27, +- VERR_RS_RO = 28, +-}; +- +-static char *validation_errors[] = { +- "OK", +- "Bad CR_ASSOC Length", +- "Bad CR_ASSOC Rqst Length", +- "Not CR_ASSOC Cmd", +- "Bad CR_ASSOC Cmd Length", +- "Bad Ersp Ratio", +- "Association Allocation Failed", +- "Queue Allocation Failed", +- "Bad CR_CONN Length", +- "Bad CR_CONN Rqst Length", +- "Not Association ID", +- "Bad Association ID Length", +- "No Association", +- "Not Connection ID", +- "Bad Connection ID Length", +- "No Connection", +- "Not CR_CONN Cmd", +- "Bad CR_CONN Cmd Length", +- "Bad DISCONN Length", +- "Bad DISCONN Rqst Length", +- "Not DISCONN Cmd", +- "Bad DISCONN Cmd Length", +- "Bad Disconnect Scope", +- "Bad RS Length", +- "Bad RS Rqst Length", +- "Not RS Cmd", +- "Bad RS Cmd Length", +- "Bad RS R_CTL", +- "Bad RS Relative Offset", +-}; +- + static void + nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_ls_iod *iod) +@@ -1407,7 +1312,7 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + dev_err(tgtport->dev, + "Create Association LS failed: %s\n", + validation_errors[ret]); +- iod->lsrsp->rsplen = nvmet_fc_format_rjt(acc, ++ iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, + NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, + FCNVME_RJT_RC_LOGIC, + FCNVME_RJT_EXP_NONE, 0); +@@ -1422,7 +1327,7 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + + iod->lsrsp->rsplen = sizeof(*acc); + +- nvmet_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, ++ nvme_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, + fcnvme_lsdesc_len( + sizeof(struct fcnvme_ls_cr_assoc_acc)), + FCNVME_LS_CREATE_ASSOCIATION); +@@ -1498,7 +1403,7 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, + dev_err(tgtport->dev, + "Create Connection LS failed: %s\n", + validation_errors[ret]); +- iod->lsrsp->rsplen = nvmet_fc_format_rjt(acc, ++ iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, + NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, + (ret == VERR_NO_ASSOC) ? + FCNVME_RJT_RC_INV_ASSOC : +@@ -1515,7 +1420,7 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, + + iod->lsrsp->rsplen = sizeof(*acc); + +- nvmet_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, ++ nvme_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, + fcnvme_lsdesc_len(sizeof(struct fcnvme_ls_cr_conn_acc)), + FCNVME_LS_CREATE_CONNECTION); + acc->connectid.desc_tag = cpu_to_be32(FCNVME_LSDESC_CONN_ID); +@@ -1578,13 +1483,11 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + dev_err(tgtport->dev, + "Disconnect LS failed: %s\n", + validation_errors[ret]); +- iod->lsrsp->rsplen = nvmet_fc_format_rjt(acc, ++ iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, + NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, + (ret == VERR_NO_ASSOC) ? + FCNVME_RJT_RC_INV_ASSOC : +- (ret == VERR_NO_CONN) ? +- FCNVME_RJT_RC_INV_CONN : +- FCNVME_RJT_RC_LOGIC, ++ FCNVME_RJT_RC_LOGIC, + FCNVME_RJT_EXP_NONE, 0); + return; + } +@@ -1593,7 +1496,7 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + + iod->lsrsp->rsplen = sizeof(*acc); + +- nvmet_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, ++ nvme_fc_format_rsp_hdr(acc, FCNVME_LS_ACC, + fcnvme_lsdesc_len( + sizeof(struct fcnvme_ls_disconnect_assoc_acc)), + FCNVME_LS_DISCONNECT_ASSOC); +@@ -1676,7 +1579,7 @@ nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + nvmet_fc_ls_disconnect(tgtport, iod); + break; + default: +- iod->lsrsp->rsplen = nvmet_fc_format_rjt(iod->rspbuf, ++ iod->lsrsp->rsplen = nvme_fc_format_rjt(iod->rspbuf, + NVME_FC_MAX_LS_BUFFER_SIZE, w0->ls_cmd, + FCNVME_RJT_RC_INVAL, FCNVME_RJT_EXP_NONE, 0); + } +-- +2.16.4 + diff --git a/patches.suse/nvme-fcloop-add-target-to-host-LS-request-support.patch b/patches.suse/nvme-fcloop-add-target-to-host-LS-request-support.patch new file mode 100644 index 0000000..05c50f5 --- /dev/null +++ b/patches.suse/nvme-fcloop-add-target-to-host-LS-request-support.patch @@ -0,0 +1,234 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:01 -0700 +Subject: [PATCH] nvme-fcloop: add target to host LS request support +Git-commit: 6cefacbb8f87287de7450d9d0d6c764b809e576b +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Add support for performing LS requests from target to host. +Include sending request from targetport, reception into host, +host sending ls rsp. + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fcloop.c | 130 +++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 118 insertions(+), 12 deletions(-) + +diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c +index fac7dbe572db..2ff1d1334a03 100644 +--- a/drivers/nvme/target/fcloop.c ++++ b/drivers/nvme/target/fcloop.c +@@ -208,10 +208,13 @@ struct fcloop_rport { + }; + + struct fcloop_tport { +- struct nvmet_fc_target_port *targetport; +- struct nvme_fc_remote_port *remoteport; +- struct fcloop_nport *nport; +- struct fcloop_lport *lport; ++ struct nvmet_fc_target_port *targetport; ++ struct nvme_fc_remote_port *remoteport; ++ struct fcloop_nport *nport; ++ struct fcloop_lport *lport; ++ spinlock_t lock; ++ struct list_head ls_list; ++ struct work_struct ls_work; + }; + + struct fcloop_nport { +@@ -226,11 +229,6 @@ struct fcloop_nport { + u32 port_id; + }; + +-enum { +- H2T = 0, +- T2H = 1, +-}; +- + struct fcloop_lsreq { + struct nvmefc_ls_req *lsreq; + struct nvmefc_ls_rsp ls_rsp; +@@ -337,7 +335,6 @@ fcloop_h2t_ls_req(struct nvme_fc_local_port *localport, + struct fcloop_rport *rport = remoteport->private; + int ret = 0; + +- tls_req->lsdir = H2T; + tls_req->lsreq = lsreq; + INIT_LIST_HEAD(&tls_req->ls_list); + +@@ -351,8 +348,9 @@ fcloop_h2t_ls_req(struct nvme_fc_local_port *localport, + } + + tls_req->status = 0; +- ret = nvmet_fc_rcv_ls_req(rport->targetport, NULL, &tls_req->ls_rsp, +- lsreq->rqstaddr, lsreq->rqstlen); ++ ret = nvmet_fc_rcv_ls_req(rport->targetport, rport, ++ &tls_req->ls_rsp, ++ lsreq->rqstaddr, lsreq->rqstlen); + + return ret; + } +@@ -384,6 +382,99 @@ fcloop_h2t_xmt_ls_rsp(struct nvmet_fc_target_port *targetport, + return 0; + } + ++static void ++fcloop_tport_lsrqst_work(struct work_struct *work) ++{ ++ struct fcloop_tport *tport = ++ container_of(work, struct fcloop_tport, ls_work); ++ struct fcloop_lsreq *tls_req; ++ ++ spin_lock(&tport->lock); ++ for (;;) { ++ tls_req = list_first_entry_or_null(&tport->ls_list, ++ struct fcloop_lsreq, ls_list); ++ if (!tls_req) ++ break; ++ ++ list_del(&tls_req->ls_list); ++ spin_unlock(&tport->lock); ++ ++ tls_req->lsreq->done(tls_req->lsreq, tls_req->status); ++ /* ++ * callee may free memory containing tls_req. ++ * do not reference lsreq after this. ++ */ ++ ++ spin_lock(&tport->lock); ++ } ++ spin_unlock(&tport->lock); ++} ++ ++static int ++fcloop_t2h_ls_req(struct nvmet_fc_target_port *targetport, void *hosthandle, ++ struct nvmefc_ls_req *lsreq) ++{ ++ struct fcloop_lsreq *tls_req = lsreq->private; ++ struct fcloop_tport *tport = targetport->private; ++ int ret = 0; ++ ++ /* ++ * hosthandle should be the dst.rport value. ++ * hosthandle ignored as fcloop currently is ++ * 1:1 tgtport vs remoteport ++ */ ++ tls_req->lsreq = lsreq; ++ INIT_LIST_HEAD(&tls_req->ls_list); ++ ++ if (!tport->remoteport) { ++ tls_req->status = -ECONNREFUSED; ++ spin_lock(&tport->lock); ++ list_add_tail(&tport->ls_list, &tls_req->ls_list); ++ spin_unlock(&tport->lock); ++ schedule_work(&tport->ls_work); ++ return ret; ++ } ++ ++ tls_req->status = 0; ++ ret = nvme_fc_rcv_ls_req(tport->remoteport, &tls_req->ls_rsp, ++ lsreq->rqstaddr, lsreq->rqstlen); ++ ++ return ret; ++} ++ ++static int ++fcloop_t2h_xmt_ls_rsp(struct nvme_fc_local_port *localport, ++ struct nvme_fc_remote_port *remoteport, ++ struct nvmefc_ls_rsp *lsrsp) ++{ ++ struct fcloop_lsreq *tls_req = ls_rsp_to_lsreq(lsrsp); ++ struct nvmefc_ls_req *lsreq = tls_req->lsreq; ++ struct fcloop_rport *rport = remoteport->private; ++ struct nvmet_fc_target_port *targetport = rport->targetport; ++ struct fcloop_tport *tport; ++ ++ memcpy(lsreq->rspaddr, lsrsp->rspbuf, ++ ((lsreq->rsplen < lsrsp->rsplen) ? ++ lsreq->rsplen : lsrsp->rsplen)); ++ lsrsp->done(lsrsp); ++ ++ if (targetport) { ++ tport = targetport->private; ++ spin_lock(&tport->lock); ++ list_add_tail(&tport->ls_list, &tls_req->ls_list); ++ spin_unlock(&tport->lock); ++ schedule_work(&tport->ls_work); ++ } ++ ++ return 0; ++} ++ ++static void ++fcloop_t2h_host_release(void *hosthandle) ++{ ++ /* host handle ignored for now */ ++} ++ + /* + * Simulate reception of RSCN and converting it to a initiator transport + * call to rescan a remote port. +@@ -775,6 +866,12 @@ fcloop_h2t_ls_abort(struct nvme_fc_local_port *localport, + { + } + ++static void ++fcloop_t2h_ls_abort(struct nvmet_fc_target_port *targetport, ++ void *hosthandle, struct nvmefc_ls_req *lsreq) ++{ ++} ++ + static void + fcloop_fcp_abort(struct nvme_fc_local_port *localport, + struct nvme_fc_remote_port *remoteport, +@@ -874,6 +971,7 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport) + { + struct fcloop_tport *tport = targetport->private; + ++ flush_work(&tport->ls_work); + fcloop_nport_put(tport->nport); + } + +@@ -890,6 +988,7 @@ static struct nvme_fc_port_template fctemplate = { + .fcp_io = fcloop_fcp_req, + .ls_abort = fcloop_h2t_ls_abort, + .fcp_abort = fcloop_fcp_abort, ++ .xmt_ls_rsp = fcloop_t2h_xmt_ls_rsp, + .max_hw_queues = FCLOOP_HW_QUEUES, + .max_sgl_segments = FCLOOP_SGL_SEGS, + .max_dif_sgl_segments = FCLOOP_SGL_SEGS, +@@ -908,6 +1007,9 @@ static struct nvmet_fc_target_template tgttemplate = { + .fcp_abort = fcloop_tgt_fcp_abort, + .fcp_req_release = fcloop_fcp_req_release, + .discovery_event = fcloop_tgt_discovery_evt, ++ .ls_req = fcloop_t2h_ls_req, ++ .ls_abort = fcloop_t2h_ls_abort, ++ .host_release = fcloop_t2h_host_release, + .max_hw_queues = FCLOOP_HW_QUEUES, + .max_sgl_segments = FCLOOP_SGL_SEGS, + .max_dif_sgl_segments = FCLOOP_SGL_SEGS, +@@ -916,6 +1018,7 @@ static struct nvmet_fc_target_template tgttemplate = { + .target_features = 0, + /* sizes of additional private data for data structures */ + .target_priv_sz = sizeof(struct fcloop_tport), ++ .lsrqst_priv_sz = sizeof(struct fcloop_lsreq), + }; + + static ssize_t +@@ -1265,6 +1368,9 @@ fcloop_create_target_port(struct device *dev, struct device_attribute *attr, + tport->nport = nport; + tport->lport = nport->lport; + nport->tport = tport; ++ spin_lock_init(&tport->lock); ++ INIT_WORK(&tport->ls_work, fcloop_tport_lsrqst_work); ++ INIT_LIST_HEAD(&tport->ls_list); + + return count; + } +-- +2.16.4 + diff --git a/patches.suse/nvme-fcloop-fix-deallocation-of-working-context.patch b/patches.suse/nvme-fcloop-fix-deallocation-of-working-context.patch new file mode 100644 index 0000000..b3d4b66 --- /dev/null +++ b/patches.suse/nvme-fcloop-fix-deallocation-of-working-context.patch @@ -0,0 +1,178 @@ +From: James Smart +Date: Wed, 18 Mar 2020 14:41:12 -0700 +Subject: [PATCH] nvme-fcloop: fix deallocation of working context +Git-commit: 38803fcffb5baf40cd403c1bd980f22308aefee8 +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +There's been a longstanding bug of LS completions which freed ls ops, +particularly the disconnect LS, while executing on a work context that +is in the memory being free. Not a good thing to do. + +Rework LS handling to make callbacks in the rport context rather than +the ls_request context. + +Signed-off-by: James Smart +Reviewed-by: Himanshu Madhani +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fcloop.c | 76 ++++++++++++++++++++++++++++++-------------- + 1 file changed, 52 insertions(+), 24 deletions(-) + +diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c +index 1c50af6219f3..9861fcea39f6 100644 +--- a/drivers/nvme/target/fcloop.c ++++ b/drivers/nvme/target/fcloop.c +@@ -198,10 +198,13 @@ struct fcloop_lport_priv { + }; + + struct fcloop_rport { +- struct nvme_fc_remote_port *remoteport; +- struct nvmet_fc_target_port *targetport; +- struct fcloop_nport *nport; +- struct fcloop_lport *lport; ++ struct nvme_fc_remote_port *remoteport; ++ struct nvmet_fc_target_port *targetport; ++ struct fcloop_nport *nport; ++ struct fcloop_lport *lport; ++ spinlock_t lock; ++ struct list_head ls_list; ++ struct work_struct ls_work; + }; + + struct fcloop_tport { +@@ -224,11 +227,10 @@ struct fcloop_nport { + }; + + struct fcloop_lsreq { +- struct fcloop_tport *tport; + struct nvmefc_ls_req *lsreq; +- struct work_struct work; + struct nvmefc_tgt_ls_req tgt_ls_req; + int status; ++ struct list_head ls_list; /* fcloop_rport->ls_list */ + }; + + struct fcloop_rscn { +@@ -292,21 +294,32 @@ fcloop_delete_queue(struct nvme_fc_local_port *localport, + { + } + +- +-/* +- * Transmit of LS RSP done (e.g. buffers all set). call back up +- * initiator "done" flows. +- */ + static void +-fcloop_tgt_lsrqst_done_work(struct work_struct *work) ++fcloop_rport_lsrqst_work(struct work_struct *work) + { +- struct fcloop_lsreq *tls_req = +- container_of(work, struct fcloop_lsreq, work); +- struct fcloop_tport *tport = tls_req->tport; +- struct nvmefc_ls_req *lsreq = tls_req->lsreq; ++ struct fcloop_rport *rport = ++ container_of(work, struct fcloop_rport, ls_work); ++ struct fcloop_lsreq *tls_req; + +- if (!tport || tport->remoteport) +- lsreq->done(lsreq, tls_req->status); ++ spin_lock(&rport->lock); ++ for (;;) { ++ tls_req = list_first_entry_or_null(&rport->ls_list, ++ struct fcloop_lsreq, ls_list); ++ if (!tls_req) ++ break; ++ ++ list_del(&tls_req->ls_list); ++ spin_unlock(&rport->lock); ++ ++ tls_req->lsreq->done(tls_req->lsreq, tls_req->status); ++ /* ++ * callee may free memory containing tls_req. ++ * do not reference lsreq after this. ++ */ ++ ++ spin_lock(&rport->lock); ++ } ++ spin_unlock(&rport->lock); + } + + static int +@@ -319,17 +332,18 @@ fcloop_ls_req(struct nvme_fc_local_port *localport, + int ret = 0; + + tls_req->lsreq = lsreq; +- INIT_WORK(&tls_req->work, fcloop_tgt_lsrqst_done_work); ++ INIT_LIST_HEAD(&tls_req->ls_list); + + if (!rport->targetport) { + tls_req->status = -ECONNREFUSED; +- tls_req->tport = NULL; +- schedule_work(&tls_req->work); ++ spin_lock(&rport->lock); ++ list_add_tail(&rport->ls_list, &tls_req->ls_list); ++ spin_unlock(&rport->lock); ++ schedule_work(&rport->ls_work); + return ret; + } + + tls_req->status = 0; +- tls_req->tport = rport->targetport->private; + ret = nvmet_fc_rcv_ls_req(rport->targetport, &tls_req->tgt_ls_req, + lsreq->rqstaddr, lsreq->rqstlen); + +@@ -337,18 +351,28 @@ fcloop_ls_req(struct nvme_fc_local_port *localport, + } + + static int +-fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *tport, ++fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *targetport, + struct nvmefc_tgt_ls_req *tgt_lsreq) + { + struct fcloop_lsreq *tls_req = tgt_ls_req_to_lsreq(tgt_lsreq); + struct nvmefc_ls_req *lsreq = tls_req->lsreq; ++ struct fcloop_tport *tport = targetport->private; ++ struct nvme_fc_remote_port *remoteport = tport->remoteport; ++ struct fcloop_rport *rport; + + memcpy(lsreq->rspaddr, tgt_lsreq->rspbuf, + ((lsreq->rsplen < tgt_lsreq->rsplen) ? + lsreq->rsplen : tgt_lsreq->rsplen)); ++ + tgt_lsreq->done(tgt_lsreq); + +- schedule_work(&tls_req->work); ++ if (remoteport) { ++ rport = remoteport->private; ++ spin_lock(&rport->lock); ++ list_add_tail(&rport->ls_list, &tls_req->ls_list); ++ spin_unlock(&rport->lock); ++ schedule_work(&rport->ls_work); ++ } + + return 0; + } +@@ -834,6 +858,7 @@ fcloop_remoteport_delete(struct nvme_fc_remote_port *remoteport) + { + struct fcloop_rport *rport = remoteport->private; + ++ flush_work(&rport->ls_work); + fcloop_nport_put(rport->nport); + } + +@@ -1136,6 +1161,9 @@ fcloop_create_remote_port(struct device *dev, struct device_attribute *attr, + rport->nport = nport; + rport->lport = nport->lport; + nport->rport = rport; ++ spin_lock_init(&rport->lock); ++ INIT_WORK(&rport->ls_work, fcloop_rport_lsrqst_work); ++ INIT_LIST_HEAD(&rport->ls_list); + + return count; + } +-- +2.16.4 + diff --git a/patches.suse/nvme-fcloop-refactor-to-enable-target-to-host-LS.patch b/patches.suse/nvme-fcloop-refactor-to-enable-target-to-host-LS.patch new file mode 100644 index 0000000..1cd45ee --- /dev/null +++ b/patches.suse/nvme-fcloop-refactor-to-enable-target-to-host-LS.patch @@ -0,0 +1,100 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:50:00 -0700 +Subject: [PATCH] nvme-fcloop: refactor to enable target to host LS +Git-commit: 43b722380017429f9f09fb19ceda5a30a9a5f5ed +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Currently nvmefc-loop only sends LS's from host to target. +Slightly rework data structures and routine names to reflect this +path. Allows a straight-forward conversion to be used by ls's +from target to host. + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fcloop.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c +index c11805a155e8..fac7dbe572db 100644 +--- a/drivers/nvme/target/fcloop.c ++++ b/drivers/nvme/target/fcloop.c +@@ -226,9 +226,15 @@ struct fcloop_nport { + u32 port_id; + }; + ++enum { ++ H2T = 0, ++ T2H = 1, ++}; ++ + struct fcloop_lsreq { + struct nvmefc_ls_req *lsreq; + struct nvmefc_ls_rsp ls_rsp; ++ int lsdir; /* H2T or T2H */ + int status; + struct list_head ls_list; /* fcloop_rport->ls_list */ + }; +@@ -323,7 +329,7 @@ fcloop_rport_lsrqst_work(struct work_struct *work) + } + + static int +-fcloop_ls_req(struct nvme_fc_local_port *localport, ++fcloop_h2t_ls_req(struct nvme_fc_local_port *localport, + struct nvme_fc_remote_port *remoteport, + struct nvmefc_ls_req *lsreq) + { +@@ -331,6 +337,7 @@ fcloop_ls_req(struct nvme_fc_local_port *localport, + struct fcloop_rport *rport = remoteport->private; + int ret = 0; + ++ tls_req->lsdir = H2T; + tls_req->lsreq = lsreq; + INIT_LIST_HEAD(&tls_req->ls_list); + +@@ -351,7 +358,7 @@ fcloop_ls_req(struct nvme_fc_local_port *localport, + } + + static int +-fcloop_xmt_ls_rsp(struct nvmet_fc_target_port *targetport, ++fcloop_h2t_xmt_ls_rsp(struct nvmet_fc_target_port *targetport, + struct nvmefc_ls_rsp *lsrsp) + { + struct fcloop_lsreq *tls_req = ls_rsp_to_lsreq(lsrsp); +@@ -762,7 +769,7 @@ fcloop_fcp_req_release(struct nvmet_fc_target_port *tgtport, + } + + static void +-fcloop_ls_abort(struct nvme_fc_local_port *localport, ++fcloop_h2t_ls_abort(struct nvme_fc_local_port *localport, + struct nvme_fc_remote_port *remoteport, + struct nvmefc_ls_req *lsreq) + { +@@ -879,9 +886,9 @@ static struct nvme_fc_port_template fctemplate = { + .remoteport_delete = fcloop_remoteport_delete, + .create_queue = fcloop_create_queue, + .delete_queue = fcloop_delete_queue, +- .ls_req = fcloop_ls_req, ++ .ls_req = fcloop_h2t_ls_req, + .fcp_io = fcloop_fcp_req, +- .ls_abort = fcloop_ls_abort, ++ .ls_abort = fcloop_h2t_ls_abort, + .fcp_abort = fcloop_fcp_abort, + .max_hw_queues = FCLOOP_HW_QUEUES, + .max_sgl_segments = FCLOOP_SGL_SEGS, +@@ -896,7 +903,7 @@ static struct nvme_fc_port_template fctemplate = { + + static struct nvmet_fc_target_template tgttemplate = { + .targetport_delete = fcloop_targetport_delete, +- .xmt_ls_rsp = fcloop_xmt_ls_rsp, ++ .xmt_ls_rsp = fcloop_h2t_xmt_ls_rsp, + .fcp_op = fcloop_fcp_op, + .fcp_abort = fcloop_tgt_fcp_abort, + .fcp_req_release = fcloop_fcp_req_release, +-- +2.16.4 + diff --git a/patches.suse/nvme-fix-deadlock-caused-by-ANA-update-wrong-locking.patch b/patches.suse/nvme-fix-deadlock-caused-by-ANA-update-wrong-locking.patch new file mode 100644 index 0000000..789ed82 --- /dev/null +++ b/patches.suse/nvme-fix-deadlock-caused-by-ANA-update-wrong-locking.patch @@ -0,0 +1,70 @@ +From: Sagi Grimberg +Date: Thu, 2 Apr 2020 09:34:54 -0700 +Subject: [PATCH] nvme: fix deadlock caused by ANA update wrong locking +Git-commit: 657f1975e9d9c880fa13030e88ba6cc84964f1db +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +The deadlock combines 4 flows in parallel: +- ns scanning (triggered from reconnect) +- request timeout +- ANA update (triggered from reconnect) +- I/O coming into the mpath device + +(1) ns scanning triggers disk revalidation -> update disk info -> + freeze queue -> but blocked, due to (2) + +(2) timeout handler reference the g_usage_counter - > but blocks in + the transport .timeout() handler, due to (3) + +(3) the transport timeout handler (indirectly) calls nvme_stop_queue() -> + which takes the (down_read) namespaces_rwsem - > but blocks, due to (4) + +(4) ANA update takes the (down_write) namespaces_rwsem -> calls + nvme_mpath_set_live() -> which synchronize the ns_head srcu + (see commit 504db087aacc) -> but blocks, due to (5) + +(5) I/O came into nvme_mpath_make_request -> took srcu_read_lock -> + direct_make_request > blk_queue_enter -> but blocked, due to (1) + +==> the request queue is under freeze -> deadlock. + +The fix is making ANA update take a read lock as the namespaces list +is not manipulated, it is just the ns and ns->head that are being +updated (which is protected with the ns->head lock). + +Fixes: 0d0b660f214dc ("nvme: add ANA support") +Signed-off-by: Sagi Grimberg +Reviewed-by: Keith Busch +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/multipath.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index 61bf87592570..54603bd3e02d 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -510,7 +510,7 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl, + if (!nr_nsids) + return 0; + +- down_write(&ctrl->namespaces_rwsem); ++ down_read(&ctrl->namespaces_rwsem); + list_for_each_entry(ns, &ctrl->namespaces, list) { + unsigned nsid = le32_to_cpu(desc->nsids[n]); + +@@ -521,7 +521,7 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl, + if (++n == nr_nsids) + break; + } +- up_write(&ctrl->namespaces_rwsem); ++ up_read(&ctrl->namespaces_rwsem); + return 0; + } + +-- +2.16.4 + diff --git a/patches.suse/nvme-fix-possible-deadlock-when-nvme_update_formats-.patch b/patches.suse/nvme-fix-possible-deadlock-when-nvme_update_formats-.patch new file mode 100644 index 0000000..3b9f4e8 --- /dev/null +++ b/patches.suse/nvme-fix-possible-deadlock-when-nvme_update_formats-.patch @@ -0,0 +1,46 @@ +From: Sagi Grimberg +Date: Wed, 2 Oct 2019 10:52:25 -0700 +Subject: [PATCH] nvme: fix possible deadlock when nvme_update_formats fails +Git-commit: 6abff1b9f7b8884a46b7bd80b49e7af0b5625aeb +Patch-mainline: v5.4-rc4 +References: bsc#1169045 + +nvme_update_formats may fail to revalidate the namespace and +attempt to remove the namespace. This may lead to a deadlock +as nvme_ns_remove will attempt to acquire the subsystem lock +which is already acquired by the passthru command with effects. + +Move the invalid namepsace removal to after the passthru command +releases the subsystem lock. + +Reported-by: Judy Brock +Signed-off-by: Sagi Grimberg +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index fd7dea36c3b6..ef1d8f81f69e 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -1306,8 +1306,6 @@ static void nvme_update_formats(struct nvme_ctrl *ctrl) + if (ns->disk && nvme_revalidate_disk(ns->disk)) + nvme_set_queue_dying(ns); + up_read(&ctrl->namespaces_rwsem); +- +- nvme_remove_invalid_namespaces(ctrl, NVME_NSID_ALL); + } + + static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects) +@@ -1323,6 +1321,7 @@ static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects) + nvme_unfreeze(ctrl); + nvme_mpath_unfreeze(ctrl->subsys); + mutex_unlock(&ctrl->subsys->lock); ++ nvme_remove_invalid_namespaces(ctrl, NVME_NSID_ALL); + mutex_unlock(&ctrl->scan_lock); + } + if (effects & NVME_CMD_EFFECTS_CCC) +-- +2.16.4 + diff --git a/patches.suse/nvme-hwmon-add-quirk-to-avoid-changing-temperature-t.patch b/patches.suse/nvme-hwmon-add-quirk-to-avoid-changing-temperature-t.patch new file mode 100644 index 0000000..c154e0b --- /dev/null +++ b/patches.suse/nvme-hwmon-add-quirk-to-avoid-changing-temperature-t.patch @@ -0,0 +1,92 @@ +From: Akinobu Mita +Date: Fri, 15 Nov 2019 00:40:01 +0900 +Subject: [PATCH] nvme: hwmon: add quirk to avoid changing temperature +Git-commit: 6c6aa2f26c6813af38d88718881c0307bb9a54c0 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + threshold + +This adds a new quirk NVME_QUIRK_NO_TEMP_THRESH_CHANGE to avoid changing +the value of the temperature threshold feature for specific devices that +show undesirable behavior. + +Guenter reported: + +"On my Intel NVME drive (SSDPEKKW512G7), writing any minimum limit on the +Composite temperature sensor results in a temperature warning, and that +warning is sticky until I reset the controller. + +It doesn't seem to matter which temperature I write; writing -273000 has +the same result." + +The Intel NVMe has the latest firmware version installed, so this isn't +a problem that was ever fixed. + +Reported-by: Guenter Roeck +Cc: Keith Busch +Cc: Jens Axboe +Cc: Christoph Hellwig +Cc: Sagi Grimberg +Cc: Jean Delvare +Reviewed-by: Guenter Roeck +Tested-by: Guenter Roeck +Signed-off-by: Akinobu Mita +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/hwmon.c | 6 +++++- + drivers/nvme/host/nvme.h | 5 +++++ + drivers/nvme/host/pci.c | 3 ++- + 3 files changed, 12 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c +index 97a84b4b45db..a5af21f5d370 100644 +--- a/drivers/nvme/host/hwmon.c ++++ b/drivers/nvme/host/hwmon.c +@@ -170,8 +170,12 @@ static umode_t nvme_hwmon_is_visible(const void *_data, + case hwmon_temp_max: + case hwmon_temp_min: + if ((!channel && data->ctrl->wctemp) || +- (channel && data->log.temp_sensor[channel - 1])) ++ (channel && data->log.temp_sensor[channel - 1])) { ++ if (data->ctrl->quirks & ++ NVME_QUIRK_NO_TEMP_THRESH_CHANGE) ++ return 0444; + return 0644; ++ } + break; + case hwmon_temp_alarm: + if (!channel) +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 258534a7bb6c..34ac79c5e309 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -114,6 +114,11 @@ enum nvme_quirks { + * Prevent tag overlap between queues + */ + NVME_QUIRK_SHARED_TAGS = (1 << 13), ++ ++ /* ++ * Don't change the value of the temperature threshold feature ++ */ ++ NVME_QUIRK_NO_TEMP_THRESH_CHANGE = (1 << 14), + }; + + /* +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 1b1b0db45567..c40a672e5047 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3065,7 +3065,8 @@ static const struct pci_device_id nvme_id_table[] = { + NVME_QUIRK_DEALLOCATE_ZEROES, }, + { PCI_VDEVICE(INTEL, 0xf1a5), /* Intel 600P/P3100 */ + .driver_data = NVME_QUIRK_NO_DEEPEST_PS | +- NVME_QUIRK_MEDIUM_PRIO_SQ }, ++ NVME_QUIRK_MEDIUM_PRIO_SQ | ++ NVME_QUIRK_NO_TEMP_THRESH_CHANGE }, + { PCI_VDEVICE(INTEL, 0xf1a6), /* Intel 760p/Pro 7600p */ + .driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_VDEVICE(INTEL, 0x5845), /* Qemu emulated controller */ +-- +2.16.4 + diff --git a/patches.suse/nvme-hwmon-provide-temperature-min-and-max-values-fo.patch b/patches.suse/nvme-hwmon-provide-temperature-min-and-max-values-fo.patch new file mode 100644 index 0000000..825470c --- /dev/null +++ b/patches.suse/nvme-hwmon-provide-temperature-min-and-max-values-fo.patch @@ -0,0 +1,246 @@ +From: Akinobu Mita +Date: Fri, 15 Nov 2019 00:40:00 +0900 +Subject: [PATCH] nvme: hwmon: provide temperature min and max values for each +Git-commit: 52deba0f02a98c150677a9c381cc1991a928bcff +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + sensor +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +According to the NVMe specification, the over temperature threshold and +under temperature threshold features shall be implemented for Composite +Temperature if a non-zero WCTEMP field value is reported in the Identify +Controller data structure. The features are also implemented for all +implemented temperature sensors (i.e., all Temperature Sensor fields that +report a non-zero value). + +This provides the over temperature threshold and under temperature +threshold for each sensor as temperature min and max values of hwmon +sysfs attributes. + +The WCTEMP is already provided as a temperature max value for Composite +Temperature, but this change isn't incompatible. Because the default +value of the over temperature threshold for Composite Temperature is +the WCTEMP. + +Now the alarm attribute for Composite Temperature indicates one of the +temperature is outside of a temperature threshold. Because there is only +a single bit in Critical Warning field that indicates a temperature is +outside of a threshold. + +Example output from the "sensors" command: + +nvme-pci-0100 +Adapter: PCI adapter +Composite: +33.9°C (low = -273.1°C, high = +69.8°C) + (crit = +79.8°C) +Sensor 1: +34.9°C (low = -273.1°C, high = +65261.8°C) +Sensor 2: +31.9°C (low = -273.1°C, high = +65261.8°C) +Sensor 5: +47.9°C (low = -273.1°C, high = +65261.8°C) + +This also adds helper macros for kelvin from/to milli Celsius conversion, +and replaces the repeated code in hwmon.c. + +Cc: Keith Busch +Cc: Jens Axboe +Cc: Christoph Hellwig +Cc: Sagi Grimberg +Cc: Jean Delvare +Reviewed-by: Guenter Roeck +Tested-by: Guenter Roeck +Signed-off-by: Akinobu Mita +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/hwmon.c | 106 +++++++++++++++++++++++++++++++++++++++------- + include/linux/nvme.h | 6 +++ + 2 files changed, 96 insertions(+), 16 deletions(-) + +diff --git a/drivers/nvme/host/hwmon.c b/drivers/nvme/host/hwmon.c +index 5480cbb84f9f..97a84b4b45db 100644 +--- a/drivers/nvme/host/hwmon.c ++++ b/drivers/nvme/host/hwmon.c +@@ -9,12 +9,57 @@ + + #include "nvme.h" + ++/* These macros should be moved to linux/temperature.h */ ++#define MILLICELSIUS_TO_KELVIN(t) DIV_ROUND_CLOSEST((t) + 273150, 1000) ++#define KELVIN_TO_MILLICELSIUS(t) ((t) * 1000L - 273150) ++ + struct nvme_hwmon_data { + struct nvme_ctrl *ctrl; + struct nvme_smart_log log; + struct mutex read_lock; + }; + ++static int nvme_get_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under, ++ long *temp) ++{ ++ unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT; ++ u32 status; ++ int ret; ++ ++ if (under) ++ threshold |= NVME_TEMP_THRESH_TYPE_UNDER; ++ ++ ret = nvme_get_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0, ++ &status); ++ if (ret > 0) ++ return -EIO; ++ if (ret < 0) ++ return ret; ++ *temp = KELVIN_TO_MILLICELSIUS(status & NVME_TEMP_THRESH_MASK); ++ ++ return 0; ++} ++ ++static int nvme_set_temp_thresh(struct nvme_ctrl *ctrl, int sensor, bool under, ++ long temp) ++{ ++ unsigned int threshold = sensor << NVME_TEMP_THRESH_SELECT_SHIFT; ++ int ret; ++ ++ temp = MILLICELSIUS_TO_KELVIN(temp); ++ threshold |= clamp_val(temp, 0, NVME_TEMP_THRESH_MASK); ++ ++ if (under) ++ threshold |= NVME_TEMP_THRESH_TYPE_UNDER; ++ ++ ret = nvme_set_features(ctrl, NVME_FEAT_TEMP_THRESH, threshold, NULL, 0, ++ NULL); ++ if (ret > 0) ++ return -EIO; ++ ++ return ret; ++} ++ + static int nvme_hwmon_get_smart_log(struct nvme_hwmon_data *data) + { + int ret; +@@ -39,10 +84,11 @@ static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + */ + switch (attr) { + case hwmon_temp_max: +- *val = (data->ctrl->wctemp - 273) * 1000; +- return 0; ++ return nvme_get_temp_thresh(data->ctrl, channel, false, val); ++ case hwmon_temp_min: ++ return nvme_get_temp_thresh(data->ctrl, channel, true, val); + case hwmon_temp_crit: +- *val = (data->ctrl->cctemp - 273) * 1000; ++ *val = KELVIN_TO_MILLICELSIUS(data->ctrl->cctemp); + return 0; + default: + break; +@@ -59,7 +105,7 @@ static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + temp = get_unaligned_le16(log->temperature); + else + temp = le16_to_cpu(log->temp_sensor[channel - 1]); +- *val = (temp - 273) * 1000; ++ *val = KELVIN_TO_MILLICELSIUS(temp); + break; + case hwmon_temp_alarm: + *val = !!(log->critical_warning & NVME_SMART_CRIT_TEMPERATURE); +@@ -73,6 +119,23 @@ static int nvme_hwmon_read(struct device *dev, enum hwmon_sensor_types type, + return err; + } + ++static int nvme_hwmon_write(struct device *dev, enum hwmon_sensor_types type, ++ u32 attr, int channel, long val) ++{ ++ struct nvme_hwmon_data *data = dev_get_drvdata(dev); ++ ++ switch (attr) { ++ case hwmon_temp_max: ++ return nvme_set_temp_thresh(data->ctrl, channel, false, val); ++ case hwmon_temp_min: ++ return nvme_set_temp_thresh(data->ctrl, channel, true, val); ++ default: ++ break; ++ } ++ ++ return -EOPNOTSUPP; ++} ++ + static const char * const nvme_hwmon_sensor_names[] = { + "Composite", + "Sensor 1", +@@ -105,8 +168,10 @@ static umode_t nvme_hwmon_is_visible(const void *_data, + return 0444; + break; + case hwmon_temp_max: +- if (!channel && data->ctrl->wctemp) +- return 0444; ++ case hwmon_temp_min: ++ if ((!channel && data->ctrl->wctemp) || ++ (channel && data->log.temp_sensor[channel - 1])) ++ return 0644; + break; + case hwmon_temp_alarm: + if (!channel) +@@ -126,16 +191,24 @@ static umode_t nvme_hwmon_is_visible(const void *_data, + static const struct hwmon_channel_info *nvme_hwmon_info[] = { + HWMON_CHANNEL_INFO(chip, HWMON_C_REGISTER_TZ), + HWMON_CHANNEL_INFO(temp, +- HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_CRIT | +- HWMON_T_LABEL | HWMON_T_ALARM, +- HWMON_T_INPUT | HWMON_T_LABEL, +- HWMON_T_INPUT | HWMON_T_LABEL, +- HWMON_T_INPUT | HWMON_T_LABEL, +- HWMON_T_INPUT | HWMON_T_LABEL, +- HWMON_T_INPUT | HWMON_T_LABEL, +- HWMON_T_INPUT | HWMON_T_LABEL, +- HWMON_T_INPUT | HWMON_T_LABEL, +- HWMON_T_INPUT | HWMON_T_LABEL), ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_CRIT | HWMON_T_LABEL | HWMON_T_ALARM, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_LABEL, ++ HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MIN | ++ HWMON_T_LABEL), + NULL + }; + +@@ -143,6 +216,7 @@ static const struct hwmon_ops nvme_hwmon_ops = { + .is_visible = nvme_hwmon_is_visible, + .read = nvme_hwmon_read, + .read_string = nvme_hwmon_read_string, ++ .write = nvme_hwmon_write, + }; + + static const struct hwmon_chip_info nvme_hwmon_chip_info = { +diff --git a/include/linux/nvme.h b/include/linux/nvme.h +index 3eca4f7d8510..3d5189f46cb1 100644 +--- a/include/linux/nvme.h ++++ b/include/linux/nvme.h +@@ -804,6 +804,12 @@ struct nvme_write_zeroes_cmd { + + /* Features */ + ++enum { ++ NVME_TEMP_THRESH_MASK = 0xffff, ++ NVME_TEMP_THRESH_SELECT_SHIFT = 16, ++ NVME_TEMP_THRESH_TYPE_UNDER = 0x100000, ++}; ++ + struct nvme_feat_auto_pst { + __le64 entries[32]; + }; +-- +2.16.4 + diff --git a/patches.suse/nvme-inherit-stable-pages-constraint-in-the-mpath-st.patch b/patches.suse/nvme-inherit-stable-pages-constraint-in-the-mpath-st.patch new file mode 100644 index 0000000..47fd2fd --- /dev/null +++ b/patches.suse/nvme-inherit-stable-pages-constraint-in-the-mpath-st.patch @@ -0,0 +1,40 @@ +From: Sagi Grimberg +Date: Wed, 1 Apr 2020 22:44:43 -0700 +Subject: [PATCH] nvme: inherit stable pages constraint in the mpath stack +Git-commit: 74e4d20e2f43cf09a35543d960ac8f7a1ffcbbb5 +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + device + +If the backing device require stable pages, we need to set it on the +stack mpath device as well. This applies to rdma/fc transports when +doing data integrity and tcp transport calculating digests. + +Signed-off-by: Sagi Grimberg +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 2db8563aeb2d..91c1bd659947 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -1897,6 +1897,13 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id) + if (ns->head->disk) { + nvme_update_disk_info(ns->head->disk, ns, id); + blk_queue_stack_limits(ns->head->disk->queue, ns->queue); ++ if (bdi_cap_stable_pages_required(ns->queue->backing_dev_info)) { ++ struct backing_dev_info *info = ++ ns->head->disk->queue->backing_dev_info; ++ ++ info->capabilities |= BDI_CAP_STABLE_WRITES; ++ } ++ + revalidate_disk(ns->head->disk); + } + #endif +-- +2.16.4 + diff --git a/patches.suse/nvme-introduce-Command-Aborted-By-host-status-code.patch b/patches.suse/nvme-introduce-Command-Aborted-By-host-status-code.patch new file mode 100644 index 0000000..202a6a6 --- /dev/null +++ b/patches.suse/nvme-introduce-Command-Aborted-By-host-status-code.patch @@ -0,0 +1,67 @@ +From: Max Gurtovoy +Date: Sun, 13 Oct 2019 19:57:35 +0300 +Subject: [PATCH] nvme: introduce "Command Aborted By host" status code +Git-commit: 2dc3947b53f573e8a75ea9cbec5588df88ca502e +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Fix the status code of canceled requests initiated by the host according +to TP4028 (Status Code 0x371): +"Command Aborted By host: The command was aborted as a result of host +action (e.g., the host disconnected the Fabric connection)." + +Also in a multipath environment, unless otherwise specified, errors of +this type (path related) should be retried using a different path, if +one is available. + +Signed-off-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 2 +- + drivers/nvme/host/multipath.c | 1 + + include/linux/nvme.h | 1 + + 3 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index fd7dea36c3b6..dfa122beb4cf 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -298,7 +298,7 @@ bool nvme_cancel_request(struct request *req, void *data, bool reserved) + if (blk_mq_request_completed(req)) + return true; + +- nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR; ++ nvme_req(req)->status = NVME_SC_HOST_ABORTED_CMD; + blk_mq_complete_request(req); + return true; + } +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index 30de7efef003..103c04fa7746 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -95,6 +95,7 @@ void nvme_failover_req(struct request *req) + } + break; + case NVME_SC_HOST_PATH_ERROR: ++ case NVME_SC_HOST_ABORTED_CMD: + /* + * Temporary transport disruption in talking to the controller. + * Try to send on a new path. +diff --git a/include/linux/nvme.h b/include/linux/nvme.h +index f61d6906e59d..a260cd754f28 100644 +--- a/include/linux/nvme.h ++++ b/include/linux/nvme.h +@@ -1368,6 +1368,7 @@ enum { + NVME_SC_ANA_INACCESSIBLE = 0x302, + NVME_SC_ANA_TRANSITION = 0x303, + NVME_SC_HOST_PATH_ERROR = 0x370, ++ NVME_SC_HOST_ABORTED_CMD = 0x371, + + NVME_SC_CRD = 0x1800, + NVME_SC_DNR = 0x4000, +-- +2.16.4 + diff --git a/patches.suse/nvme-introduce-nvme_is_aen_req-function.patch b/patches.suse/nvme-introduce-nvme_is_aen_req-function.patch new file mode 100644 index 0000000..b771160 --- /dev/null +++ b/patches.suse/nvme-introduce-nvme_is_aen_req-function.patch @@ -0,0 +1,101 @@ +From: Israel Rukshin +Date: Sun, 13 Oct 2019 19:57:31 +0300 +Subject: [PATCH] nvme: introduce nvme_is_aen_req function +Git-commit: 58a8df67e057e979e76f8dc881766da3f7137f99 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +This function improves code readability and reduces code duplication. + +Signed-off-by: Israel Rukshin +Signed-off-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/nvme.h | 5 +++++ + drivers/nvme/host/pci.c | 3 +-- + drivers/nvme/host/rdma.c | 4 ++-- + drivers/nvme/host/tcp.c | 4 ++-- + drivers/nvme/target/loop.c | 4 ++-- + 5 files changed, 12 insertions(+), 8 deletions(-) + +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 38a83ef5bcd3..912f9500ed11 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -445,6 +445,11 @@ static inline void nvme_put_ctrl(struct nvme_ctrl *ctrl) + put_device(ctrl->device); + } + ++static inline bool nvme_is_aen_req(u16 qid, __u16 command_id) ++{ ++ return !qid && command_id >= NVME_AQ_BLK_MQ_DEPTH; ++} ++ + void nvme_complete_rq(struct request *req); + bool nvme_cancel_request(struct request *req, void *data, bool reserved); + bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl, +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index bb88681f4dc3..7082116e9206 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -967,8 +967,7 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx) + * aborts. We don't even bother to allocate a struct request + * for them but rather special case them here. + */ +- if (unlikely(nvmeq->qid == 0 && +- cqe->command_id >= NVME_AQ_BLK_MQ_DEPTH)) { ++ if (unlikely(nvme_is_aen_req(nvmeq->qid, cqe->command_id))) { + nvme_complete_async_event(&nvmeq->dev->ctrl, + cqe->status, &cqe->result); + return; +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 4d280160dd3f..154fa4e32ad8 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -1501,8 +1501,8 @@ static void nvme_rdma_recv_done(struct ib_cq *cq, struct ib_wc *wc) + * aborts. We don't even bother to allocate a struct request + * for them but rather special case them here. + */ +- if (unlikely(nvme_rdma_queue_idx(queue) == 0 && +- cqe->command_id >= NVME_AQ_BLK_MQ_DEPTH)) ++ if (unlikely(nvme_is_aen_req(nvme_rdma_queue_idx(queue), ++ cqe->command_id))) + nvme_complete_async_event(&queue->ctrl->ctrl, cqe->status, + &cqe->result); + else +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 385a5212c10f..124fda67613a 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -491,8 +491,8 @@ static int nvme_tcp_handle_comp(struct nvme_tcp_queue *queue, + * aborts. We don't even bother to allocate a struct request + * for them but rather special case them here. + */ +- if (unlikely(nvme_tcp_queue_id(queue) == 0 && +- cqe->command_id >= NVME_AQ_BLK_MQ_DEPTH)) ++ if (unlikely(nvme_is_aen_req(nvme_tcp_queue_id(queue), ++ cqe->command_id))) + nvme_complete_async_event(&queue->ctrl->ctrl, cqe->status, + &cqe->result); + else +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index 748a39fca771..bd1f81f97ab7 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -102,8 +102,8 @@ static void nvme_loop_queue_response(struct nvmet_req *req) + * aborts. We don't even bother to allocate a struct request + * for them but rather special case them here. + */ +- if (unlikely(nvme_loop_queue_idx(queue) == 0 && +- cqe->command_id >= NVME_AQ_BLK_MQ_DEPTH)) { ++ if (unlikely(nvme_is_aen_req(nvme_loop_queue_idx(queue), ++ cqe->command_id))) { + nvme_complete_async_event(&queue->ctrl->ctrl, cqe->status, + &cqe->result); + } else { +-- +2.16.4 + diff --git a/patches.suse/nvme-log-additional-message-for-controller-status.patch b/patches.suse/nvme-log-additional-message-for-controller-status.patch new file mode 100644 index 0000000..fe694db --- /dev/null +++ b/patches.suse/nvme-log-additional-message-for-controller-status.patch @@ -0,0 +1,37 @@ +From: Rupesh Girase +Date: Thu, 27 Feb 2020 22:15:26 +0530 +Subject: [PATCH] nvme: log additional message for controller status +Git-commit: 94d2e705b6a6fe9c56a990c0cd31a7298cfcee9a +Patch-mainline: v5.7-rc1 +References: bsc#1161930 + +Log the controller status to know more about issue if it +lies within kernel nvme subsytem or controller is unhealthy. + +Signed-off-by: Rupesh Girase +Reviewed-by: Sagi Grimberg +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index c4dbc852b5e9..c9988942d0aa 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -2083,8 +2083,8 @@ static int nvme_wait_ready(struct nvme_ctrl *ctrl, u64 cap, bool enabled) + return -EINTR; + if (time_after(jiffies, timeout)) { + dev_err(ctrl->device, +- "Device not ready; aborting %s\n", enabled ? +- "initialisation" : "reset"); ++ "Device not ready; aborting %s, CSTS=0x%x\n", ++ enabled ? "initialisation" : "reset", csts); + return -ENODEV; + } + } +-- +2.16.4 + diff --git a/patches.suse/nvme-move-common-call-to-nvme_cleanup_cmd-to-core-la.patch b/patches.suse/nvme-move-common-call-to-nvme_cleanup_cmd-to-core-la.patch new file mode 100644 index 0000000..197b9b5 --- /dev/null +++ b/patches.suse/nvme-move-common-call-to-nvme_cleanup_cmd-to-core-la.patch @@ -0,0 +1,133 @@ +From: Max Gurtovoy +Date: Sun, 13 Oct 2019 19:57:36 +0300 +Subject: [PATCH] nvme: move common call to nvme_cleanup_cmd to core layer +Git-commit: 16686f3a6c3cd6316dbc5cba886242c73f713237 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +nvme_cleanup_cmd should be called for each call to nvme_setup_cmd +(symmetrical functions). Move the call for nvme_cleanup_cmd to the common +core layer and call it during nvme_complete_rq for the good flow. For +error flow, each transport will call nvme_cleanup_cmd independently. Also +take care of a special case of path failure, where we call +nvme_complete_rq without doing nvme_setup_cmd. + +Signed-off-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 2 ++ + drivers/nvme/host/fc.c | 3 +-- + drivers/nvme/host/pci.c | 1 - + drivers/nvme/host/rdma.c | 12 +++++------- + drivers/nvme/target/loop.c | 1 - + 5 files changed, 8 insertions(+), 11 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index dfa122beb4cf..9c743610e6ea 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -268,6 +268,8 @@ void nvme_complete_rq(struct request *req) + + trace_nvme_complete_rq(req); + ++ nvme_cleanup_cmd(req); ++ + if (nvme_req(req)->ctrl->kas) + nvme_req(req)->ctrl->comp_seen = true; + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 714a1c3aa0c5..679a721ae229 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -2173,8 +2173,6 @@ nvme_fc_unmap_data(struct nvme_fc_ctrl *ctrl, struct request *rq, + fc_dma_unmap_sg(ctrl->lport->dev, freq->sg_table.sgl, op->nents, + rq_dma_dir(rq)); + +- nvme_cleanup_cmd(rq); +- + sg_free_table_chained(&freq->sg_table, SG_CHUNK_SIZE); + + freq->sg_cnt = 0; +@@ -2305,6 +2303,7 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue, + if (!(op->flags & FCOP_FLAGS_AEN)) + nvme_fc_unmap_data(ctrl, op->rq, op); + ++ nvme_cleanup_cmd(op->rq); + nvme_fc_ctrl_put(ctrl); + + if (ctrl->rport->remoteport.port_state == FC_OBJSTATE_ONLINE && +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 7082116e9206..612f92255f9d 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -924,7 +924,6 @@ static void nvme_pci_complete_rq(struct request *req) + struct nvme_iod *iod = blk_mq_rq_to_pdu(req); + struct nvme_dev *dev = iod->nvmeq->dev; + +- nvme_cleanup_cmd(req); + if (blk_integrity_rq(req)) + dma_unmap_page(dev->dev, iod->meta_dma, + rq_integrity_vec(req)->bv_len, rq_data_dir(req)); +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 154fa4e32ad8..05f2dfa3d218 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -1160,8 +1160,6 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue, + } + + ib_dma_unmap_sg(ibdev, req->sg_table.sgl, req->nents, rq_dma_dir(rq)); +- +- nvme_cleanup_cmd(rq); + sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE); + } + +@@ -1760,7 +1758,6 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, + if (unlikely(err < 0)) { + dev_err(queue->ctrl->ctrl.device, + "Failed to map data (%d)\n", err); +- nvme_cleanup_cmd(rq); + goto err; + } + +@@ -1771,18 +1768,19 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx, + + err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge, + req->mr ? &req->reg_wr.wr : NULL); +- if (unlikely(err)) { +- nvme_rdma_unmap_data(queue, rq); +- goto err; +- } ++ if (unlikely(err)) ++ goto err_unmap; + + return BLK_STS_OK; + ++err_unmap: ++ nvme_rdma_unmap_data(queue, rq); + err: + if (err == -ENOMEM || err == -EAGAIN) + ret = BLK_STS_RESOURCE; + else + ret = BLK_STS_IOERR; ++ nvme_cleanup_cmd(rq); + unmap_qe: + ib_dma_unmap_single(dev, req->sqe.dma, sizeof(struct nvme_command), + DMA_TO_DEVICE); +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index bd1f81f97ab7..5b7b19774bb0 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -76,7 +76,6 @@ static void nvme_loop_complete_rq(struct request *req) + { + struct nvme_loop_iod *iod = blk_mq_rq_to_pdu(req); + +- nvme_cleanup_cmd(req); + sg_free_table_chained(&iod->sg_table, SG_CHUNK_SIZE); + nvme_complete_rq(req); + } +-- +2.16.4 + diff --git a/patches.suse/nvme-multipath-Fix-memory-leak-with-ana_log_buf.patch b/patches.suse/nvme-multipath-Fix-memory-leak-with-ana_log_buf.patch new file mode 100644 index 0000000..e9e5428 --- /dev/null +++ b/patches.suse/nvme-multipath-Fix-memory-leak-with-ana_log_buf.patch @@ -0,0 +1,68 @@ +From: Logan Gunthorpe +Date: Thu, 20 Feb 2020 13:29:53 -0700 +Subject: [PATCH] nvme-multipath: Fix memory leak with ana_log_buf +Git-commit: 3b7830904e17202524bad1974505a9bfc718d31f +Patch-mainline: v5.6-rc3 +References: bsc#1169045 + +kmemleak reports a memory leak with the ana_log_buf allocated by +nvme_mpath_init(): + +unreferenced object 0xffff888120e94000 (size 8208): + comm "nvme", pid 6884, jiffies 4295020435 (age 78786.312s) + hex dump (first 32 bytes): + 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 ................ + 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 ................ + backtrace: + [<00000000e2360188>] kmalloc_order+0x97/0xc0 + [<0000000079b18dd4>] kmalloc_order_trace+0x24/0x100 + [<00000000f50c0406>] __kmalloc+0x24c/0x2d0 + [<00000000f31a10b9>] nvme_mpath_init+0x23c/0x2b0 + [<000000005802589e>] nvme_init_identify+0x75f/0x1600 + [<0000000058ef911b>] nvme_loop_configure_admin_queue+0x26d/0x280 + [<00000000673774b9>] nvme_loop_create_ctrl+0x2a7/0x710 + [<00000000f1c7a233>] nvmf_dev_write+0xc66/0x10b9 + [<000000004199f8d0>] __vfs_write+0x50/0xa0 + [<0000000065466fef>] vfs_write+0xf3/0x280 + [<00000000b0db9a8b>] ksys_write+0xc6/0x160 + [<0000000082156b91>] __x64_sys_write+0x43/0x50 + [<00000000c34fbb6d>] do_syscall_64+0x77/0x2f0 + [<00000000bbc574c9>] entry_SYSCALL_64_after_hwframe+0x49/0xbe + +nvme_mpath_init() is called by nvme_init_identify() which is called in +multiple places (nvme_reset_work(), nvme_passthru_end(), etc). This +means nvme_mpath_init() may be called multiple times before +nvme_mpath_uninit() (which is only called on nvme_free_ctrl()). + +When nvme_mpath_init() is called multiple times, it overwrites the +ana_log_buf pointer with a new allocation, thus leaking the previous +allocation. + +To fix this, free ana_log_buf before allocating a new one. + +Fixes: 0d0b660f214dc490 ("nvme: add ANA support") +Cc: +Reviewed-by: Sagi Grimberg +Reviewed-by: Christoph Hellwig +Signed-off-by: Logan Gunthorpe +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/multipath.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index 797c18337d96..a11900cf3a36 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -715,6 +715,7 @@ int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) + } + + INIT_WORK(&ctrl->ana_work, nvme_ana_work); ++ kfree(ctrl->ana_log_buf); + ctrl->ana_log_buf = kmalloc(ctrl->ana_log_size, GFP_KERNEL); + if (!ctrl->ana_log_buf) { + error = -ENOMEM; +-- +2.16.4 + diff --git a/patches.suse/nvme-multipath-do-not-reset-on-unknown-status.patch b/patches.suse/nvme-multipath-do-not-reset-on-unknown-status.patch new file mode 100644 index 0000000..ca76f00 --- /dev/null +++ b/patches.suse/nvme-multipath-do-not-reset-on-unknown-status.patch @@ -0,0 +1,118 @@ +From: John Meneghini +Date: Thu, 20 Feb 2020 10:05:38 +0900 +Subject: [PATCH] nvme-multipath: do not reset on unknown status +Git-commit: 764e9332098c0e60251386a507fe46ac91276120 +Patch-mainline: v5.7-rc1 +References: bsc#1161930 + +The nvme multipath error handling defaults to controller reset if the +error is unknown. There are, however, no existing nvme status codes that +indicate a reset should be used, and resetting causes unnecessary +disruption to the rest of IO. + +Change nvme's error handling to first check if failover should happen. +If not, let the normal error handling take over rather than reset the +controller. + +Based-on-a-patch-by: Christoph Hellwig +Reviewed-by: Hannes Reinecke +Signed-off-by: John Meneghini +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 5 +---- + drivers/nvme/host/multipath.c | 21 +++++++++------------ + drivers/nvme/host/nvme.h | 5 +++-- + 3 files changed, 13 insertions(+), 18 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 0e38e07a302f..fde4b3a526ad 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -291,11 +291,8 @@ void nvme_complete_rq(struct request *req) + nvme_req(req)->ctrl->comp_seen = true; + + if (unlikely(status != BLK_STS_OK && nvme_req_needs_retry(req))) { +- if ((req->cmd_flags & REQ_NVME_MPATH) && +- blk_path_error(status)) { +- nvme_failover_req(req); ++ if ((req->cmd_flags & REQ_NVME_MPATH) && nvme_failover_req(req)) + return; +- } + + if (!blk_queue_dying(req->q)) { + nvme_retry_req(req); +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index a11900cf3a36..90dd1d641b7b 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -64,17 +64,12 @@ void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns, + } + } + +-void nvme_failover_req(struct request *req) ++bool nvme_failover_req(struct request *req) + { + struct nvme_ns *ns = req->q->queuedata; + u16 status = nvme_req(req)->status; + unsigned long flags; + +- spin_lock_irqsave(&ns->head->requeue_lock, flags); +- blk_steal_bios(&ns->head->requeue_list, req); +- spin_unlock_irqrestore(&ns->head->requeue_lock, flags); +- blk_mq_end_request(req, 0); +- + switch (status & 0x7ff) { + case NVME_SC_ANA_TRANSITION: + case NVME_SC_ANA_INACCESSIBLE: +@@ -103,15 +98,17 @@ void nvme_failover_req(struct request *req) + nvme_mpath_clear_current_path(ns); + break; + default: +- /* +- * Reset the controller for any non-ANA error as we don't know +- * what caused the error. +- */ +- nvme_reset_ctrl(ns->ctrl); +- break; ++ /* This was a non-ANA error so follow the normal error path. */ ++ return false; + } + ++ spin_lock_irqsave(&ns->head->requeue_lock, flags); ++ blk_steal_bios(&ns->head->requeue_list, req); ++ spin_unlock_irqrestore(&ns->head->requeue_lock, flags); ++ blk_mq_end_request(req, 0); ++ + kblockd_schedule_work(&ns->head->requeue_work); ++ return true; + } + + void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl) +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 1024fec7914c..d800b9a51c2c 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -550,7 +550,7 @@ void nvme_mpath_wait_freeze(struct nvme_subsystem *subsys); + void nvme_mpath_start_freeze(struct nvme_subsystem *subsys); + void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns, + struct nvme_ctrl *ctrl, int *flags); +-void nvme_failover_req(struct request *req); ++bool nvme_failover_req(struct request *req); + void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl); + int nvme_mpath_alloc_disk(struct nvme_ctrl *ctrl,struct nvme_ns_head *head); + void nvme_mpath_add_disk(struct nvme_ns *ns, struct nvme_id_ns *id); +@@ -599,8 +599,9 @@ static inline void nvme_set_disk_name(char *disk_name, struct nvme_ns *ns, + sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->head->instance); + } + +-static inline void nvme_failover_req(struct request *req) ++static inline bool nvme_failover_req(struct request *req) + { ++ return false; + } + static inline void nvme_kick_requeue_lists(struct nvme_ctrl *ctrl) + { +-- +2.16.4 + diff --git a/patches.suse/nvme-multipath-remove-unused-groups_only-mode-in-ana.patch b/patches.suse/nvme-multipath-remove-unused-groups_only-mode-in-ana.patch new file mode 100644 index 0000000..a29f8a6 --- /dev/null +++ b/patches.suse/nvme-multipath-remove-unused-groups_only-mode-in-ana.patch @@ -0,0 +1,60 @@ +From: Anton Eidelman +Date: Fri, 18 Oct 2019 11:32:51 -0700 +Subject: [PATCH] nvme-multipath: remove unused groups_only mode in ana log +Git-commit: 86cccfbf773fafb88898c5627aa3727b02bc4708 +Patch-mainline: v5.4-rc6 +References: bsc#1169045 + +groups_only mode in nvme_read_ana_log() is no longer used: remove it. + +Reviewed-by: Sagi Grimberg +Signed-off-by: Anton Eidelman +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/multipath.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c +index d320684d25b2..fc99a40c1ec4 100644 +--- a/drivers/nvme/host/multipath.c ++++ b/drivers/nvme/host/multipath.c +@@ -522,14 +522,13 @@ static int nvme_update_ana_state(struct nvme_ctrl *ctrl, + return 0; + } + +-static int nvme_read_ana_log(struct nvme_ctrl *ctrl, bool groups_only) ++static int nvme_read_ana_log(struct nvme_ctrl *ctrl) + { + u32 nr_change_groups = 0; + int error; + + mutex_lock(&ctrl->ana_lock); +- error = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_ANA, +- groups_only ? NVME_ANA_LOG_RGO : 0, ++ error = nvme_get_log(ctrl, NVME_NSID_ALL, NVME_LOG_ANA, 0, + ctrl->ana_log_buf, ctrl->ana_log_size, 0); + if (error) { + dev_warn(ctrl->device, "Failed to get ANA log: %d\n", error); +@@ -565,7 +564,7 @@ static void nvme_ana_work(struct work_struct *work) + { + struct nvme_ctrl *ctrl = container_of(work, struct nvme_ctrl, ana_work); + +- nvme_read_ana_log(ctrl, false); ++ nvme_read_ana_log(ctrl); + } + + static void nvme_anatt_timeout(struct timer_list *t) +@@ -715,7 +714,7 @@ int nvme_mpath_init(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id) + goto out; + } + +- error = nvme_read_ana_log(ctrl, false); ++ error = nvme_read_ana_log(ctrl); + if (error) + goto out_free_ana_log_buf; + return 0; +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-Add-sleep-quirk-for-Samsung-and-Toshiba-dri.patch b/patches.suse/nvme-pci-Add-sleep-quirk-for-Samsung-and-Toshiba-dri.patch new file mode 100644 index 0000000..c4e4775 --- /dev/null +++ b/patches.suse/nvme-pci-Add-sleep-quirk-for-Samsung-and-Toshiba-dri.patch @@ -0,0 +1,49 @@ +From: Shyjumon N +Date: Thu, 6 Feb 2020 13:17:25 -0700 +Subject: [PATCH] nvme/pci: Add sleep quirk for Samsung and Toshiba drives +Git-commit: 1fae37accfc5872af3905d4ba71dc6ab15829be7 +Patch-mainline: v5.6-rc3 +References: bsc#1169045 + +The Samsung SSD SM981/PM981 and Toshiba SSD KBG40ZNT256G on the Lenovo +C640 platform experience runtime resume issues when the SSDs are kept in +sleep/suspend mode for long time. + +This patch applies the 'Simple Suspend' quirk to these configurations. +With this patch, the issue had not been observed in a 1+ day test. + +Reviewed-by: Jon Derrick +Reviewed-by: Christoph Hellwig +Signed-off-by: Shyjumon N +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 9c80f9f08149..b0434b687b17 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2747,6 +2747,18 @@ static unsigned long check_vendor_combination_bug(struct pci_dev *pdev) + (dmi_match(DMI_BOARD_NAME, "PRIME B350M-A") || + dmi_match(DMI_BOARD_NAME, "PRIME Z370-A"))) + return NVME_QUIRK_NO_APST; ++ } else if ((pdev->vendor == 0x144d && (pdev->device == 0xa801 || ++ pdev->device == 0xa808 || pdev->device == 0xa809)) || ++ (pdev->vendor == 0x1e0f && pdev->device == 0x0001)) { ++ /* ++ * Forcing to use host managed nvme power settings for ++ * lowest idle power with quick resume latency on ++ * Samsung and Toshiba SSDs based on suspend behavior ++ * on Coffee Lake board for LENOVO C640 ++ */ ++ if ((dmi_match(DMI_BOARD_VENDOR, "LENOVO")) && ++ dmi_match(DMI_BOARD_NAME, "LNVNB161216")) ++ return NVME_QUIRK_SIMPLE_SUSPEND; + } + + return 0; +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-Fix-read-queue-count.patch b/patches.suse/nvme-pci-Fix-read-queue-count.patch new file mode 100644 index 0000000..5852771 --- /dev/null +++ b/patches.suse/nvme-pci-Fix-read-queue-count.patch @@ -0,0 +1,47 @@ +From: Keith Busch +Date: Fri, 6 Dec 2019 08:11:17 +0900 +Subject: [PATCH] nvme/pci: Fix read queue count +Git-commit: 7e4c6b9a5d22485acf009b3c3510a370f096dd54 +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +If nvme.write_queues equals the number of CPUs, the driver had decreased +the number of interrupts available such that there could only be one read +queue even if the controller could support more. Remove the interrupt +count reduction in this case. The driver wouldn't request more IRQs than +it wants queues anyway. + +Reviewed-by: Jens Axboe +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index fe81e1581e5f..365a2ddbeaa7 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2054,7 +2054,6 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) + .priv = dev, + }; + unsigned int irq_queues, this_p_queues; +- unsigned int nr_cpus = num_possible_cpus(); + + /* + * Poll queues don't need interrupts, but we need at least one IO +@@ -2065,10 +2064,7 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues) + this_p_queues = nr_io_queues - 1; + irq_queues = 1; + } else { +- if (nr_cpus < nr_io_queues - this_p_queues) +- irq_queues = nr_cpus + 1; +- else +- irq_queues = nr_io_queues - this_p_queues + 1; ++ irq_queues = nr_io_queues - this_p_queues + 1; + } + dev->io_queues[HCTX_TYPE_POLL] = this_p_queues; + +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-Fix-write-and-poll-queue-types.patch b/patches.suse/nvme-pci-Fix-write-and-poll-queue-types.patch new file mode 100644 index 0000000..a9e1c94 --- /dev/null +++ b/patches.suse/nvme-pci-Fix-write-and-poll-queue-types.patch @@ -0,0 +1,44 @@ +From: Keith Busch +Date: Sat, 7 Dec 2019 01:51:54 +0900 +Subject: [PATCH] nvme/pci: Fix write and poll queue types +Git-commit: 3f68baf706ec68c4120867c25bc439c845fe3e17 +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +The number of poll or write queues should never be negative. Use unsigned +types so that it's not possible to break have the driver not allocate +any queues. + +Reviewed-by: Jens Axboe +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 0590640ba62c..446ea9c175fe 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -68,14 +68,14 @@ static int io_queue_depth = 1024; + module_param_cb(io_queue_depth, &io_queue_depth_ops, &io_queue_depth, 0644); + MODULE_PARM_DESC(io_queue_depth, "set io queue depth, should >= 2"); + +-static int write_queues; +-module_param(write_queues, int, 0644); ++static unsigned int write_queues; ++module_param(write_queues, uint, 0644); + MODULE_PARM_DESC(write_queues, + "Number of queues to use for writes. If not set, reads and writes " + "will share a queue set."); + +-static int poll_queues; +-module_param(poll_queues, int, 0644); ++static unsigned int poll_queues; ++module_param(poll_queues, uint, 0644); + MODULE_PARM_DESC(poll_queues, "Number of queues to use for polled IO."); + + struct nvme_dev; +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-Free-tagset-if-no-IO-queues.patch b/patches.suse/nvme-pci-Free-tagset-if-no-IO-queues.patch new file mode 100644 index 0000000..468bc42 --- /dev/null +++ b/patches.suse/nvme-pci-Free-tagset-if-no-IO-queues.patch @@ -0,0 +1,60 @@ +From: Keith Busch +Date: Thu, 5 Sep 2019 07:52:33 -0600 +Subject: [PATCH] nvme-pci: Free tagset if no IO queues +Git-commit: 770597ecb2075390c01c425b8b1f551347f1bd70 +Patch-mainline: v5.4-rc4 +References: bsc#1169045 + +If a controller becomes degraded after a reset, we will not be able to +perform any IO. We currently teardown previously created request +queues and namespaces, but we had kept the unusable tagset. Free +it after all queues using it have been released. + +Tested-by: Edmund Nadolski +Reviewed-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 78e403823646..5c04581899f4 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2490,14 +2490,20 @@ static void nvme_release_prp_pools(struct nvme_dev *dev) + dma_pool_destroy(dev->prp_small_pool); + } + ++static void nvme_free_tagset(struct nvme_dev *dev) ++{ ++ if (dev->tagset.tags) ++ blk_mq_free_tag_set(&dev->tagset); ++ dev->ctrl.tagset = NULL; ++} ++ + static void nvme_pci_free_ctrl(struct nvme_ctrl *ctrl) + { + struct nvme_dev *dev = to_nvme_dev(ctrl); + + nvme_dbbuf_dma_free(dev); + put_device(dev->dev); +- if (dev->tagset.tags) +- blk_mq_free_tag_set(&dev->tagset); ++ nvme_free_tagset(dev); + if (dev->ctrl.admin_q) + blk_put_queue(dev->ctrl.admin_q); + kfree(dev->queues); +@@ -2616,6 +2622,7 @@ static void nvme_reset_work(struct work_struct *work) + nvme_kill_queues(&dev->ctrl); + nvme_remove_namespaces(&dev->ctrl); + new_state = NVME_CTRL_ADMIN_ONLY; ++ nvme_free_tagset(dev); + } else { + nvme_start_queues(&dev->ctrl); + nvme_wait_freeze(&dev->ctrl); +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-Hold-cq_poll_lock-while-completing-CQEs.patch b/patches.suse/nvme-pci-Hold-cq_poll_lock-while-completing-CQEs.patch new file mode 100644 index 0000000..bb2ce90 --- /dev/null +++ b/patches.suse/nvme-pci-Hold-cq_poll_lock-while-completing-CQEs.patch @@ -0,0 +1,40 @@ +From: Bijan Mottahedeh +Date: Wed, 26 Feb 2020 18:53:43 -0800 +Subject: [PATCH] nvme-pci: Hold cq_poll_lock while completing CQEs +Git-commit: 9515743bfb39c61aaf3d4f3219a645c8d1fe9a0e +Patch-mainline: v5.6-rc4 +References: bsc#1169045 + +Completions need to consumed in the same order the controller submitted +them, otherwise future completion entries may overwrite ones we haven't +handled yet. Hold the nvme queue's poll lock while completing new CQEs to +prevent another thread from freeing command tags for reuse out-of-order. + +Fixes: dabcefab45d3 ("nvme: provide optimized poll function for separate poll queues") +Signed-off-by: Bijan Mottahedeh +Reviewed-by: Sagi Grimberg +Reviewed-by: Jens Axboe +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index ace4dd9e953c..d3f23d6254e4 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1078,9 +1078,9 @@ static int nvme_poll(struct blk_mq_hw_ctx *hctx) + + spin_lock(&nvmeq->cq_poll_lock); + found = nvme_process_cq(nvmeq, &start, &end, -1); ++ nvme_complete_cqes(nvmeq, start, end); + spin_unlock(&nvmeq->cq_poll_lock); + +- nvme_complete_cqes(nvmeq, start, end); + return found; + } + +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-Limit-write-queue-sizes-to-possible-cpus.patch b/patches.suse/nvme-pci-Limit-write-queue-sizes-to-possible-cpus.patch new file mode 100644 index 0000000..a5acead --- /dev/null +++ b/patches.suse/nvme-pci-Limit-write-queue-sizes-to-possible-cpus.patch @@ -0,0 +1,36 @@ +From: Keith Busch +Date: Sat, 7 Dec 2019 01:16:59 +0900 +Subject: [PATCH] nvme/pci Limit write queue sizes to possible cpus +Git-commit: 17c3316734ae2e51f74078cd955ab855caea7d73 +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +The driver can never use more queues of any type than the number of +possible CPUs, so a higher value causes the driver to allocate more +memory for IO queues than it could ever use. Limit the parameter at +module load time to the number of possible cpus. + +Reviewed-by: Jens Axboe +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 446ea9c175fe..fe81e1581e5f 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3138,6 +3138,9 @@ static int __init nvme_init(void) + BUILD_BUG_ON(sizeof(struct nvme_create_sq) != 64); + BUILD_BUG_ON(sizeof(struct nvme_delete_queue) != 64); + BUILD_BUG_ON(IRQ_AFFINITY_MAX_SETS < 2); ++ ++ write_queues = min(write_queues, num_possible_cpus()); ++ poll_queues = min(poll_queues, num_possible_cpus()); + return pci_register_driver(&nvme_driver); + } + +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-Remove-last_cq_head.patch b/patches.suse/nvme-pci-Remove-last_cq_head.patch new file mode 100644 index 0000000..fcb0178 --- /dev/null +++ b/patches.suse/nvme-pci-Remove-last_cq_head.patch @@ -0,0 +1,45 @@ +From: Keith Busch +Date: Tue, 3 Dec 2019 05:53:30 +0900 +Subject: [PATCH] nvme/pci: Remove last_cq_head +Git-commit: f6c4d97b0d82ed1240690c91f06214018b1531ef +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +We had been saving the last_cq_head seen from an interrupt so that a +polled queue wouldn't mistakenly trigger spruious interrupt detection. We +don't poll interrupt driven queues any more, so saving this value is +pointless. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 9d307593b94f..0590640ba62c 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -176,7 +176,6 @@ struct nvme_queue { + u16 sq_tail; + u16 last_sq_tail; + u16 cq_head; +- u16 last_cq_head; + u16 qid; + u8 cq_phase; + u8 sqes; +@@ -1026,10 +1025,7 @@ static irqreturn_t nvme_irq(int irq, void *data) + * the irq handler, even if that was on another CPU. + */ + rmb(); +- if (nvmeq->cq_head != nvmeq->last_cq_head) +- ret = IRQ_HANDLED; + nvme_process_cq(nvmeq, &start, &end, -1); +- nvmeq->last_cq_head = nvmeq->cq_head; + wmb(); + + if (start != end) { +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-Use-single-IRQ-vector-for-old-Apple-models.patch b/patches.suse/nvme-pci-Use-single-IRQ-vector-for-old-Apple-models.patch new file mode 100644 index 0000000..1f760c4 --- /dev/null +++ b/patches.suse/nvme-pci-Use-single-IRQ-vector-for-old-Apple-models.patch @@ -0,0 +1,41 @@ +From: Andy Shevchenko +Date: Wed, 12 Feb 2020 12:32:18 +0200 +Subject: [PATCH] nvme-pci: Use single IRQ vector for old Apple models +Git-commit: 98f7b86a0becc1154b1a6df6e75c9695dfd87e0d +Patch-mainline: v5.6-rc3 +References: bsc#1169045 + +People reported that old Apple machines are not working properly +if the non-first IRQ vector is in use. + +Set quirk for that models to limit IRQ to use first vector only. + +Based on original patch by GitHub user npx001. + +Link: https://github.com/Dunedan/mbp-2016-linux/issues/9 +Cc: Benjamin Herrenschmidt +Cc: Leif Liddy +Signed-off-by: Andy Shevchenko +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index b0434b687b17..ace4dd9e953c 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -3121,7 +3121,8 @@ static const struct pci_device_id nvme_id_table[] = { + .driver_data = NVME_QUIRK_NO_DEEPEST_PS | + NVME_QUIRK_IGNORE_DEV_SUBNQN, }, + { PCI_DEVICE_CLASS(PCI_CLASS_STORAGE_EXPRESS, 0xffffff) }, +- { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2001), ++ .driver_data = NVME_QUIRK_SINGLE_VECTOR }, + { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2003) }, + { PCI_DEVICE(PCI_VENDOR_ID_APPLE, 0x2005), + .driver_data = NVME_QUIRK_SINGLE_VECTOR | +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-move-cqe-check-after-device-shutdown.patch b/patches.suse/nvme-pci-move-cqe-check-after-device-shutdown.patch new file mode 100644 index 0000000..01dc2e6 --- /dev/null +++ b/patches.suse/nvme-pci-move-cqe-check-after-device-shutdown.patch @@ -0,0 +1,77 @@ +From: Keith Busch +Date: Thu, 13 Feb 2020 01:41:05 +0900 +Subject: [PATCH] nvme/pci: move cqe check after device shutdown +Git-commit: fa46c6fb5d61b1f17b06d7c6ef75478b576304c7 +Patch-mainline: v5.6-rc2 +References: bsc#1169045 + +Many users have reported nvme triggered irq_startup() warnings during +shutdown. The driver uses the nvme queue's irq to synchronize scanning +for completions, and enabling an interrupt affined to only offline CPUs +triggers the alarming warning. + +Move the final CQE check to after disabling the device and all +registered interrupts have been torn down so that we do not have any +IRQ to synchronize. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=206509 +Reviewed-by: Sagi Grimberg +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 23 ++++++++++++++++++----- + 1 file changed, 18 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index da392b50f73e..9c80f9f08149 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -1401,6 +1401,23 @@ static void nvme_disable_admin_queue(struct nvme_dev *dev, bool shutdown) + nvme_poll_irqdisable(nvmeq, -1); + } + ++/* ++ * Called only on a device that has been disabled and after all other threads ++ * that can check this device's completion queues have synced. This is the ++ * last chance for the driver to see a natural completion before ++ * nvme_cancel_request() terminates all incomplete requests. ++ */ ++static void nvme_reap_pending_cqes(struct nvme_dev *dev) ++{ ++ u16 start, end; ++ int i; ++ ++ for (i = dev->ctrl.queue_count - 1; i > 0; i--) { ++ nvme_process_cq(&dev->queues[i], &start, &end, -1); ++ nvme_complete_cqes(&dev->queues[i], start, end); ++ } ++} ++ + static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, + int entry_size) + { +@@ -2235,11 +2252,6 @@ static bool __nvme_disable_io_queues(struct nvme_dev *dev, u8 opcode) + if (timeout == 0) + return false; + +- /* handle any remaining CQEs */ +- if (opcode == nvme_admin_delete_cq && +- !test_bit(NVMEQ_DELETE_ERROR, &nvmeq->flags)) +- nvme_poll_irqdisable(nvmeq, -1); +- + sent--; + if (nr_queues) + goto retry; +@@ -2428,6 +2440,7 @@ static void nvme_dev_disable(struct nvme_dev *dev, bool shutdown) + nvme_suspend_io_queues(dev); + nvme_suspend_queue(&dev->queues[0]); + nvme_pci_disable(dev); ++ nvme_reap_pending_cqes(dev); + + blk_mq_tagset_busy_iter(&dev->tagset, nvme_cancel_request, &dev->ctrl); + blk_mq_tagset_busy_iter(&dev->admin_tagset, nvme_cancel_request, &dev->ctrl); +-- +2.16.4 + diff --git a/patches.suse/nvme-pci-remove-nvmeq-tags.patch b/patches.suse/nvme-pci-remove-nvmeq-tags.patch new file mode 100644 index 0000000..32b8194 --- /dev/null +++ b/patches.suse/nvme-pci-remove-nvmeq-tags.patch @@ -0,0 +1,98 @@ +From: Christoph Hellwig +Date: Thu, 30 Jan 2020 19:40:24 +0100 +Subject: [PATCH] nvme-pci: remove nvmeq->tags +Git-commit: cfa27356f835dc7755192e7b941d4f4851acbcc7 +Patch-mainline: v5.6-rc1 +References: bsc#1169045 + +There is no real need to have a pointer to the tagset in +struct nvme_queue, as we only need it in a single place, and that place +can derive the used tagset from the device and qid trivially. This +fixes a problem with stale pointer exposure when tagsets are reset, +and also shrinks the nvme_queue structure. It also matches what most +other transports have done since day 1. + +Reported-by: Edmund Nadolski +Signed-off-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 23 ++++++++--------------- + 1 file changed, 8 insertions(+), 15 deletions(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index 365a2ddbeaa7..da392b50f73e 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -167,7 +167,6 @@ struct nvme_queue { + /* only used for poll queues: */ + spinlock_t cq_poll_lock ____cacheline_aligned_in_smp; + volatile struct nvme_completion *cqes; +- struct blk_mq_tags **tags; + dma_addr_t sq_dma_addr; + dma_addr_t cq_dma_addr; + u32 __iomem *q_db; +@@ -376,29 +375,17 @@ static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, + + WARN_ON(hctx_idx != 0); + WARN_ON(dev->admin_tagset.tags[0] != hctx->tags); +- WARN_ON(nvmeq->tags); + + hctx->driver_data = nvmeq; +- nvmeq->tags = &dev->admin_tagset.tags[0]; + return 0; + } + +-static void nvme_admin_exit_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx) +-{ +- struct nvme_queue *nvmeq = hctx->driver_data; +- +- nvmeq->tags = NULL; +-} +- + static int nvme_init_hctx(struct blk_mq_hw_ctx *hctx, void *data, + unsigned int hctx_idx) + { + struct nvme_dev *dev = data; + struct nvme_queue *nvmeq = &dev->queues[hctx_idx + 1]; + +- if (!nvmeq->tags) +- nvmeq->tags = &dev->tagset.tags[hctx_idx]; +- + WARN_ON(dev->tagset.tags[hctx_idx] != hctx->tags); + hctx->driver_data = nvmeq; + return 0; +@@ -948,6 +935,13 @@ static inline void nvme_ring_cq_doorbell(struct nvme_queue *nvmeq) + writel(head, nvmeq->q_db + nvmeq->dev->db_stride); + } + ++static inline struct blk_mq_tags *nvme_queue_tagset(struct nvme_queue *nvmeq) ++{ ++ if (!nvmeq->qid) ++ return nvmeq->dev->admin_tagset.tags[0]; ++ return nvmeq->dev->tagset.tags[nvmeq->qid - 1]; ++} ++ + static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx) + { + volatile struct nvme_completion *cqe = &nvmeq->cqes[idx]; +@@ -972,7 +966,7 @@ static inline void nvme_handle_cqe(struct nvme_queue *nvmeq, u16 idx) + return; + } + +- req = blk_mq_tag_to_rq(*nvmeq->tags, cqe->command_id); ++ req = blk_mq_tag_to_rq(nvme_queue_tagset(nvmeq), cqe->command_id); + trace_nvme_sq(req, cqe->sq_head, nvmeq->sq_tail); + nvme_end_request(req, cqe->status, cqe->result); + } +@@ -1572,7 +1566,6 @@ static const struct blk_mq_ops nvme_mq_admin_ops = { + .queue_rq = nvme_queue_rq, + .complete = nvme_pci_complete_rq, + .init_hctx = nvme_admin_init_hctx, +- .exit_hctx = nvme_admin_exit_hctx, + .init_request = nvme_init_request, + .timeout = nvme_timeout, + }; +-- +2.16.4 + diff --git a/patches.suse/nvme-prevent-warning-triggered-by-nvme_stop_keep_ali.patch b/patches.suse/nvme-prevent-warning-triggered-by-nvme_stop_keep_ali.patch new file mode 100644 index 0000000..d345967 --- /dev/null +++ b/patches.suse/nvme-prevent-warning-triggered-by-nvme_stop_keep_ali.patch @@ -0,0 +1,117 @@ +From: Nigel Kirkland +Date: Mon, 10 Feb 2020 16:01:45 -0800 +Subject: [PATCH] nvme: prevent warning triggered by nvme_stop_keep_alive +Git-commit: 97b2512ad000a409b4073dd1a71e4157d76675cb +Patch-mainline: v5.6-rc2 +References: bsc#1169045 + +Delayed keep alive work is queued on system workqueue and may be cancelled +via nvme_stop_keep_alive from nvme_reset_wq, nvme_fc_wq or nvme_wq. + +Check_flush_dependency detects mismatched attributes between the work-queue +context used to cancel the keep alive work and system-wq. Specifically +system-wq does not have the WQ_MEM_RECLAIM flag, whereas the contexts used +to cancel keep alive work have WQ_MEM_RECLAIM flag. + +Example warning: + + workqueue: WQ_MEM_RECLAIM nvme-reset-wq:nvme_fc_reset_ctrl_work [nvme_fc] + is flushing !WQ_MEM_RECLAIM events:nvme_keep_alive_work [nvme_core] + +To avoid the flags mismatch, delayed keep alive work is queued on nvme_wq. + +However this creates a secondary concern where work and a request to cancel +that work may be in the same work queue - namely err_work in the rdma and +tcp transports, which will want to flush/cancel the keep alive work which +will now be on nvme_wq. + +After reviewing the transports, it looks like err_work can be moved to +nvme_reset_wq. In fact that aligns them better with transition into +RESETTING and performing related reset work in nvme_reset_wq. + +Change nvme-rdma and nvme-tcp to perform err_work in nvme_reset_wq. + +Signed-off-by: Nigel Kirkland +Signed-off-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 10 +++++----- + drivers/nvme/host/rdma.c | 2 +- + drivers/nvme/host/tcp.c | 2 +- + 3 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index 5dc32b72e7fa..7f05deada7f4 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -66,8 +66,8 @@ MODULE_PARM_DESC(streams, "turn on support for Streams write directives"); + * nvme_reset_wq - hosts nvme reset works + * nvme_delete_wq - hosts nvme delete works + * +- * nvme_wq will host works such are scan, aen handling, fw activation, +- * keep-alive error recovery, periodic reconnects etc. nvme_reset_wq ++ * nvme_wq will host works such as scan, aen handling, fw activation, ++ * keep-alive, periodic reconnects etc. nvme_reset_wq + * runs reset works which also flush works hosted on nvme_wq for + * serialization purposes. nvme_delete_wq host controller deletion + * works which flush reset works for serialization. +@@ -976,7 +976,7 @@ static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status) + startka = true; + spin_unlock_irqrestore(&ctrl->lock, flags); + if (startka) +- schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); ++ queue_delayed_work(nvme_wq, &ctrl->ka_work, ctrl->kato * HZ); + } + + static int nvme_keep_alive(struct nvme_ctrl *ctrl) +@@ -1006,7 +1006,7 @@ static void nvme_keep_alive_work(struct work_struct *work) + dev_dbg(ctrl->device, + "reschedule traffic based keep-alive timer\n"); + ctrl->comp_seen = false; +- schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); ++ queue_delayed_work(nvme_wq, &ctrl->ka_work, ctrl->kato * HZ); + return; + } + +@@ -1023,7 +1023,7 @@ static void nvme_start_keep_alive(struct nvme_ctrl *ctrl) + if (unlikely(ctrl->kato == 0)) + return; + +- schedule_delayed_work(&ctrl->ka_work, ctrl->kato * HZ); ++ queue_delayed_work(nvme_wq, &ctrl->ka_work, ctrl->kato * HZ); + } + + void nvme_stop_keep_alive(struct nvme_ctrl *ctrl) +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 2a47c6c5007e..3e85c5cacefd 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -1088,7 +1088,7 @@ static void nvme_rdma_error_recovery(struct nvme_rdma_ctrl *ctrl) + if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RESETTING)) + return; + +- queue_work(nvme_wq, &ctrl->err_work); ++ queue_work(nvme_reset_wq, &ctrl->err_work); + } + + static void nvme_rdma_wr_error(struct ib_cq *cq, struct ib_wc *wc, +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index f8fa5c5b79f1..49d4373b84eb 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -422,7 +422,7 @@ static void nvme_tcp_error_recovery(struct nvme_ctrl *ctrl) + if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING)) + return; + +- queue_work(nvme_wq, &to_tcp_ctrl(ctrl)->err_work); ++ queue_work(nvme_reset_wq, &to_tcp_ctrl(ctrl)->err_work); + } + + static int nvme_tcp_process_nvme_cqe(struct nvme_tcp_queue *queue, +-- +2.16.4 + diff --git a/patches.suse/nvme-rdma-Avoid-double-freeing-of-async-event-data.patch b/patches.suse/nvme-rdma-Avoid-double-freeing-of-async-event-data.patch new file mode 100644 index 0000000..6a2c6e2 --- /dev/null +++ b/patches.suse/nvme-rdma-Avoid-double-freeing-of-async-event-data.patch @@ -0,0 +1,54 @@ +From: Prabhath Sajeepa +Date: Mon, 9 Mar 2020 15:07:53 -0600 +Subject: [PATCH] nvme-rdma: Avoid double freeing of async event data +Git-commit: 9134ae2a2546cb96abddcd4469a79c77ee3a4480 +Patch-mainline: v5.6-rc7 +References: bsc#1169045 + +The timeout of identify cmd, which is invoked as part of admin queue +creation, can result in freeing of async event data both in +nvme_rdma_timeout handler and error handling path of +nvme_rdma_configure_admin queue thus causing NULL pointer reference. +Call Trace: + ? nvme_rdma_setup_ctrl+0x223/0x800 [nvme_rdma] + nvme_rdma_create_ctrl+0x2ba/0x3f7 [nvme_rdma] + nvmf_dev_write+0xa54/0xcc6 [nvme_fabrics] + __vfs_write+0x1b/0x40 + vfs_write+0xb2/0x1b0 + ksys_write+0x61/0xd0 + __x64_sys_write+0x1a/0x20 + do_syscall_64+0x60/0x1e0 + entry_SYSCALL_64_after_hwframe+0x44/0xa9 + +Reviewed-by: Roland Dreier +Reviewed-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Prabhath Sajeepa +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/rdma.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 3e85c5cacefd..0fe08c4dfd2f 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -850,9 +850,11 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl, + if (new) + blk_mq_free_tag_set(ctrl->ctrl.admin_tagset); + out_free_async_qe: +- nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe, +- sizeof(struct nvme_command), DMA_TO_DEVICE); +- ctrl->async_event_sqe.data = NULL; ++ if (ctrl->async_event_sqe.data) { ++ nvme_rdma_free_qe(ctrl->device->dev, &ctrl->async_event_sqe, ++ sizeof(struct nvme_command), DMA_TO_DEVICE); ++ ctrl->async_event_sqe.data = NULL; ++ } + out_free_queue: + nvme_rdma_free_queue(&ctrl->queues[0]); + return error; +-- +2.16.4 + diff --git a/patches.suse/nvme-rdma-Avoid-preallocating-big-SGL-for-data.patch b/patches.suse/nvme-rdma-Avoid-preallocating-big-SGL-for-data.patch new file mode 100644 index 0000000..f2b3104 --- /dev/null +++ b/patches.suse/nvme-rdma-Avoid-preallocating-big-SGL-for-data.patch @@ -0,0 +1,111 @@ +From: Israel Rukshin +Date: Sun, 24 Nov 2019 18:38:30 +0200 +Subject: [PATCH] nvme-rdma: Avoid preallocating big SGL for data +Git-commit: 38e1800275d3af607e4df92ff49dc2cf442586a4 +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + +nvme_rdma_alloc_tagset() preallocates a big buffer for the IO SGL based +on SG_CHUNK_SIZE. + +Modern DMA engines are often capable of dealing with very big segments so +the SG_CHUNK_SIZE is often too big. SG_CHUNK_SIZE results in a static 4KB +SGL allocation per command. + +If a controller has lots of deep queues, preallocation for the sg list can +consume substantial amounts of memory. For nvme-rdma, nr_hw_queues can be +128 and each queue's depth 128. This means the resulting preallocation +for the data SGL is 128*128*4K = 64MB per controller. + +Switch to runtime allocation for SGL for lists longer than 2 entries. This +is the approach used by NVMe PCI so it should be reasonable for NVMeOF as +well. Runtime SGL allocation has always been the case for the legacy I/O +path so this is nothing new. + +The preallocated small SGL depends on SG_CHAIN so if the ARCH doesn't +support SG_CHAIN, use only runtime allocation for the SGL. + +We didn't notice of a performance degradation, since for small IOs we'll +use the inline SG and for the bigger IOs the allocation of a bigger SGL +from slab is fast enough. + +Suggested-by: Christoph Hellwig +Reviewed-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Israel Rukshin +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/nvme.h | 6 ++++++ + drivers/nvme/host/rdma.c | 10 +++++----- + 2 files changed, 11 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h +index 3b9cbe0668fa..1024fec7914c 100644 +--- a/drivers/nvme/host/nvme.h ++++ b/drivers/nvme/host/nvme.h +@@ -28,6 +28,12 @@ extern unsigned int admin_timeout; + #define NVME_DEFAULT_KATO 5 + #define NVME_KATO_GRACE 10 + ++#ifdef CONFIG_ARCH_NO_SG_CHAIN ++#define NVME_INLINE_SG_CNT 0 ++#else ++#define NVME_INLINE_SG_CNT 2 ++#endif ++ + extern struct workqueue_struct *nvme_wq; + extern struct workqueue_struct *nvme_reset_wq; + extern struct workqueue_struct *nvme_delete_wq; +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index dce59459ed41..2a47c6c5007e 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -731,7 +731,7 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl, + set->reserved_tags = 2; /* connect + keep-alive */ + set->numa_node = nctrl->numa_node; + set->cmd_size = sizeof(struct nvme_rdma_request) + +- SG_CHUNK_SIZE * sizeof(struct scatterlist); ++ NVME_INLINE_SG_CNT * sizeof(struct scatterlist); + set->driver_data = ctrl; + set->nr_hw_queues = 1; + set->timeout = ADMIN_TIMEOUT; +@@ -745,7 +745,7 @@ static struct blk_mq_tag_set *nvme_rdma_alloc_tagset(struct nvme_ctrl *nctrl, + set->numa_node = nctrl->numa_node; + set->flags = BLK_MQ_F_SHOULD_MERGE; + set->cmd_size = sizeof(struct nvme_rdma_request) + +- SG_CHUNK_SIZE * sizeof(struct scatterlist); ++ NVME_INLINE_SG_CNT * sizeof(struct scatterlist); + set->driver_data = ctrl; + set->nr_hw_queues = nctrl->queue_count - 1; + set->timeout = NVME_IO_TIMEOUT; +@@ -1160,7 +1160,7 @@ static void nvme_rdma_unmap_data(struct nvme_rdma_queue *queue, + } + + ib_dma_unmap_sg(ibdev, req->sg_table.sgl, req->nents, rq_dma_dir(rq)); +- sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE); ++ sg_free_table_chained(&req->sg_table, NVME_INLINE_SG_CNT); + } + + static int nvme_rdma_set_sg_null(struct nvme_command *c) +@@ -1276,7 +1276,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue, + req->sg_table.sgl = req->first_sgl; + ret = sg_alloc_table_chained(&req->sg_table, + blk_rq_nr_phys_segments(rq), req->sg_table.sgl, +- SG_CHUNK_SIZE); ++ NVME_INLINE_SG_CNT); + if (ret) + return -ENOMEM; + +@@ -1314,7 +1314,7 @@ static int nvme_rdma_map_data(struct nvme_rdma_queue *queue, + out_unmap_sg: + ib_dma_unmap_sg(ibdev, req->sg_table.sgl, req->nents, rq_dma_dir(rq)); + out_free_table: +- sg_free_table_chained(&req->sg_table, SG_CHUNK_SIZE); ++ sg_free_table_chained(&req->sg_table, NVME_INLINE_SG_CNT); + return ret; + } + +-- +2.16.4 + diff --git a/patches.suse/nvme-rdma-Replace-comma-with-a-semicolon.patch b/patches.suse/nvme-rdma-Replace-comma-with-a-semicolon.patch new file mode 100644 index 0000000..565f6ba --- /dev/null +++ b/patches.suse/nvme-rdma-Replace-comma-with-a-semicolon.patch @@ -0,0 +1,33 @@ +From: Israel Rukshin +Date: Tue, 31 Mar 2020 15:46:33 +0300 +Subject: [PATCH] nvme-rdma: Replace comma with a semicolon +Git-commit: a62315b83664dc9a7a6c6170ba2d174bb9fbed3c +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +Use a semicolon at the end of an assignment expression. + +Signed-off-by: Israel Rukshin +Reviewed-by: Max Gurtovoy +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/rdma.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c +index 86603d9b0cef..f704e7227d05 100644 +--- a/drivers/nvme/host/rdma.c ++++ b/drivers/nvme/host/rdma.c +@@ -1350,7 +1350,7 @@ static int nvme_rdma_post_send(struct nvme_rdma_queue *queue, + int ret; + + sge->addr = qe->dma; +- sge->length = sizeof(struct nvme_command), ++ sge->length = sizeof(struct nvme_command); + sge->lkey = queue->device->pd->local_dma_lkey; + + wr.next = NULL; +-- +2.16.4 + diff --git a/patches.suse/nvme-remove-unused-return-code-from-nvme_alloc_ns.patch b/patches.suse/nvme-remove-unused-return-code-from-nvme_alloc_ns.patch new file mode 100644 index 0000000..c230ed5 --- /dev/null +++ b/patches.suse/nvme-remove-unused-return-code-from-nvme_alloc_ns.patch @@ -0,0 +1,93 @@ +From: Edmund Nadolski +Date: Wed, 27 Nov 2019 10:17:43 -0700 +Subject: [PATCH] nvme: remove unused return code from nvme_alloc_ns +Git-commit: adce7e9856798d4883f42c3d8429123707fa34e8 +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +The return code of nvme_alloc_ns is never used, so change it +to void. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Edmund Nadolski +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/core.c | 21 ++++++--------------- + 1 file changed, 6 insertions(+), 15 deletions(-) + +diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c +index a4d8c90ee7cc..414076aaf52b 100644 +--- a/drivers/nvme/host/core.c ++++ b/drivers/nvme/host/core.c +@@ -3480,7 +3480,7 @@ static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns) + return 0; + } + +-static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) ++static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + { + struct nvme_ns *ns; + struct gendisk *disk; +@@ -3490,13 +3490,11 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + + ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node); + if (!ns) +- return -ENOMEM; ++ return; + + ns->queue = blk_mq_init_queue(ctrl->tagset); +- if (IS_ERR(ns->queue)) { +- ret = PTR_ERR(ns->queue); ++ if (IS_ERR(ns->queue)) + goto out_free_ns; +- } + + if (ctrl->opts && ctrl->opts->data_digest) + ns->queue->backing_dev_info->capabilities +@@ -3519,10 +3517,8 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + if (ret) + goto out_free_queue; + +- if (id->ncap == 0) { +- ret = -EINVAL; ++ if (id->ncap == 0) /* no namespace (legacy quirk) */ + goto out_free_id; +- } + + ret = nvme_init_ns_head(ns, nsid, id); + if (ret) +@@ -3531,10 +3527,8 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + nvme_set_disk_name(disk_name, ns, ctrl, &flags); + + disk = alloc_disk_node(0, node); +- if (!disk) { +- ret = -ENOMEM; ++ if (!disk) + goto out_unlink_ns; +- } + + disk->fops = &nvme_fops; + disk->private_data = ns; +@@ -3565,7 +3559,7 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + nvme_fault_inject_init(&ns->fault_inject, ns->disk->disk_name); + kfree(id); + +- return 0; ++ return; + out_put_disk: + put_disk(ns->disk); + out_unlink_ns: +@@ -3579,9 +3573,6 @@ static int nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid) + blk_cleanup_queue(ns->queue); + out_free_ns: + kfree(ns); +- if (ret > 0) +- ret = blk_status_to_errno(nvme_error_status(ret)); +- return ret; + } + + static void nvme_ns_remove(struct nvme_ns *ns) +-- +2.16.4 + diff --git a/patches.suse/nvme-retain-split-access-workaround-for-capability-r.patch b/patches.suse/nvme-retain-split-access-workaround-for-capability-r.patch new file mode 100644 index 0000000..0feb5b3 --- /dev/null +++ b/patches.suse/nvme-retain-split-access-workaround-for-capability-r.patch @@ -0,0 +1,55 @@ +From: Ard Biesheuvel +Date: Thu, 3 Oct 2019 13:57:29 +0200 +Subject: [PATCH] nvme: retain split access workaround for capability reads +Git-commit: 3a8ecc935efabdad106b5e06d07b150c394b4465 +Patch-mainline: v5.4-rc4 +References: bsc#1169045 + +Commit 7fd8930f26be4 + + "nvme: add a common helper to read Identify Controller data" + +has re-introduced an issue that we have attempted to work around in the +past, in commit a310acd7a7ea ("NVMe: use split lo_hi_{read,write}q"). + +The problem is that some PCIe NVMe controllers do not implement 64-bit +outbound accesses correctly, which is why the commit above switched +to using lo_hi_[read|write]q for all 64-bit BAR accesses occuring in +the code. + +In the mean time, the NVMe subsystem has been refactored, and now calls +into the PCIe support layer for NVMe via a .reg_read64() method, which +fails to use lo_hi_readq(), and thus reintroduces the problem that the +workaround above aimed to address. + +Given that, at the moment, .reg_read64() is only used to read the +capability register [which is known to tolerate split reads], let's +switch .reg_read64() to lo_hi_readq() as well. + +This fixes a boot issue on some ARM boxes with NVMe behind a Synopsys +DesignWare PCIe host controller. + +Fixes: 7fd8930f26be4 ("nvme: add a common helper to read Identify Controller data") +Signed-off-by: Ard Biesheuvel +Signed-off-by: Sagi Grimberg +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/pci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c +index bb88681f4dc3..78e403823646 100644 +--- a/drivers/nvme/host/pci.c ++++ b/drivers/nvme/host/pci.c +@@ -2672,7 +2672,7 @@ static int nvme_pci_reg_write32(struct nvme_ctrl *ctrl, u32 off, u32 val) + + static int nvme_pci_reg_read64(struct nvme_ctrl *ctrl, u32 off, u64 *val) + { +- *val = readq(to_nvme_dev(ctrl)->bar + off); ++ *val = lo_hi_readq(to_nvme_dev(ctrl)->bar + off); + return 0; + } + +-- +2.16.4 + diff --git a/patches.suse/nvme-tcp-Set-SO_PRIORITY-for-all-host-sockets.patch b/patches.suse/nvme-tcp-Set-SO_PRIORITY-for-all-host-sockets.patch new file mode 100644 index 0000000..e0ba184 --- /dev/null +++ b/patches.suse/nvme-tcp-Set-SO_PRIORITY-for-all-host-sockets.patch @@ -0,0 +1,63 @@ +From: "Wunderlich, Mark" +Date: Thu, 16 Jan 2020 00:46:12 +0000 +Subject: [PATCH] nvme-tcp: Set SO_PRIORITY for all host sockets +Git-commit: 9912ade355902adb9dacbec640fac23c4e73019d +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +Enable ability to associate all sockets related to NVMf TCP traffic +to a priority group that will perform optimized network processing for +this traffic class. Maintain initial default behavior of using priority +of zero. + +Signed-off-by: Kiran Patil +Signed-off-by: Mark Wunderlich +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/tcp.c | 21 +++++++++++++++++++++ + 1 file changed, 21 insertions(+) + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 49d4373b84eb..e384239af880 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -20,6 +20,16 @@ + + struct nvme_tcp_queue; + ++/* Define the socket priority to use for connections were it is desirable ++ * that the NIC consider performing optimized packet processing or filtering. ++ * A non-zero value being sufficient to indicate general consideration of any ++ * possible optimization. Making it a module param allows for alternative ++ * values that may be unique for some NIC implementations. ++ */ ++static int so_priority; ++module_param(so_priority, int, 0644); ++MODULE_PARM_DESC(so_priority, "nvme tcp socket optimize priority"); ++ + enum nvme_tcp_send_state { + NVME_TCP_SEND_CMD_PDU = 0, + NVME_TCP_SEND_H2C_PDU, +@@ -1309,6 +1319,17 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, + goto err_sock; + } + ++ if (so_priority > 0) { ++ ret = kernel_setsockopt(queue->sock, SOL_SOCKET, SO_PRIORITY, ++ (char *)&so_priority, sizeof(so_priority)); ++ if (ret) { ++ dev_err(ctrl->ctrl.device, ++ "failed to set SO_PRIORITY sock opt, ret %d\n", ++ ret); ++ goto err_sock; ++ } ++ } ++ + /* Set socket type of service */ + if (nctrl->opts->tos >= 0) { + opt = nctrl->opts->tos; +-- +2.16.4 + diff --git a/patches.suse/nvme-tcp-fix-bug-on-double-requeue-when-send-fails.patch b/patches.suse/nvme-tcp-fix-bug-on-double-requeue-when-send-fails.patch new file mode 100644 index 0000000..a70c996 --- /dev/null +++ b/patches.suse/nvme-tcp-fix-bug-on-double-requeue-when-send-fails.patch @@ -0,0 +1,52 @@ +From: Anton Eidelman +Date: Mon, 10 Feb 2020 10:37:18 -0800 +Subject: [PATCH] nvme/tcp: fix bug on double requeue when send fails +Git-commit: 2d570a7c0251c594489a2c16b82b14ae30345c03 +Patch-mainline: v5.6-rc2 +References: bsc#1169045 + +When nvme_tcp_io_work() fails to send to socket due to +connection close/reset, error_recovery work is triggered +from nvme_tcp_state_change() socket callback. +This cancels all the active requests in the tagset, +which requeues them. + +The failed request, however, was ended and thus requeued +individually as well unless send returned -EPIPE. +Another return code to be treated the same way is -ECONNRESET. + +Double requeue caused BUG_ON(blk_queued_rq(rq)) +in blk_mq_requeue_request() from either the individual requeue +of the failed request or the bulk requeue from +blk_mq_tagset_busy_iter(, nvme_cancel_request, ); + +Signed-off-by: Anton Eidelman +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/tcp.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c +index 6d43b23a0fc8..f8fa5c5b79f1 100644 +--- a/drivers/nvme/host/tcp.c ++++ b/drivers/nvme/host/tcp.c +@@ -1054,7 +1054,12 @@ static void nvme_tcp_io_work(struct work_struct *w) + } else if (unlikely(result < 0)) { + dev_err(queue->ctrl->ctrl.device, + "failed to send request %d\n", result); +- if (result != -EPIPE) ++ ++ /* ++ * Fail the request unless peer closed the connection, ++ * in which case error recovery flow will complete all. ++ */ ++ if ((result != -EPIPE) && (result != -ECONNRESET)) + nvme_tcp_fail_request(queue->request); + nvme_tcp_done_send_req(queue); + return; +-- +2.16.4 + diff --git a/patches.suse/nvme_fc-add-module-to-ops-template-to-allow-module-r.patch b/patches.suse/nvme_fc-add-module-to-ops-template-to-allow-module-r.patch new file mode 100644 index 0000000..73ca7c2 --- /dev/null +++ b/patches.suse/nvme_fc-add-module-to-ops-template-to-allow-module-r.patch @@ -0,0 +1,153 @@ +From: James Smart +Date: Thu, 14 Nov 2019 15:15:26 -0800 +Subject: [PATCH] nvme_fc: add module to ops template to allow module +Git-commit: 863fbae929c7a5b64e96b8a3ffb34a29eefb9f8f +Patch-mainline: v5.5-rc2 +References: bsc#1169045 + references + +In nvme-fc: it's possible to have connected active controllers +and as no references are taken on the LLDD, the LLDD can be +unloaded. The controller would enter a reconnect state and as +long as the LLDD resumed within the reconnect timeout, the +controller would resume. But if a namespace on the controller +is the root device, allowing the driver to unload can be problematic. +To reload the driver, it may require new io to the boot device, +and as it's no longer connected we get into a catch-22 that +eventually fails, and the system locks up. + +Fix this issue by taking a module reference for every connected +controller (which is what the core layer did to the transport +module). Reference is cleared when the controller is removed. + +Acked-by: Himanshu Madhani +Reviewed-by: Christoph Hellwig +Signed-off-by: James Smart +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.c | 14 ++++++++++++-- + drivers/nvme/target/fcloop.c | 1 + + drivers/scsi/lpfc/lpfc_nvme.c | 2 ++ + drivers/scsi/qla2xxx/qla_nvme.c | 1 + + include/linux/nvme-fc-driver.h | 4 ++++ + 5 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c +index 13cb00e56cac..d61439f8f5a9 100644 +--- a/drivers/nvme/host/fc.c ++++ b/drivers/nvme/host/fc.c +@@ -342,7 +342,8 @@ nvme_fc_register_localport(struct nvme_fc_port_info *pinfo, + !template->ls_req || !template->fcp_io || + !template->ls_abort || !template->fcp_abort || + !template->max_hw_queues || !template->max_sgl_segments || +- !template->max_dif_sgl_segments || !template->dma_boundary) { ++ !template->max_dif_sgl_segments || !template->dma_boundary || ++ !template->module) { + ret = -EINVAL; + goto out_reghost_failed; + } +@@ -2015,6 +2016,7 @@ nvme_fc_ctrl_free(struct kref *ref) + { + struct nvme_fc_ctrl *ctrl = + container_of(ref, struct nvme_fc_ctrl, ref); ++ struct nvme_fc_lport *lport = ctrl->lport; + unsigned long flags; + + if (ctrl->ctrl.tagset) { +@@ -2041,6 +2043,7 @@ nvme_fc_ctrl_free(struct kref *ref) + if (ctrl->ctrl.opts) + nvmf_free_options(ctrl->ctrl.opts); + kfree(ctrl); ++ module_put(lport->ops->module); + } + + static void +@@ -3059,10 +3062,15 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, + goto out_fail; + } + ++ if (!try_module_get(lport->ops->module)) { ++ ret = -EUNATCH; ++ goto out_free_ctrl; ++ } ++ + idx = ida_simple_get(&nvme_fc_ctrl_cnt, 0, 0, GFP_KERNEL); + if (idx < 0) { + ret = -ENOSPC; +- goto out_free_ctrl; ++ goto out_mod_put; + } + + ctrl->ctrl.opts = opts; +@@ -3215,6 +3223,8 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, + out_free_ida: + put_device(ctrl->dev); + ida_simple_remove(&nvme_fc_ctrl_cnt, ctrl->cnum); ++out_mod_put: ++ module_put(lport->ops->module); + out_free_ctrl: + kfree(ctrl); + out_fail: +diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c +index b50b53db3746..1c50af6219f3 100644 +--- a/drivers/nvme/target/fcloop.c ++++ b/drivers/nvme/target/fcloop.c +@@ -850,6 +850,7 @@ fcloop_targetport_delete(struct nvmet_fc_target_port *targetport) + #define FCLOOP_DMABOUND_4G 0xFFFFFFFF + + static struct nvme_fc_port_template fctemplate = { ++ .module = THIS_MODULE, + .localport_delete = fcloop_localport_delete, + .remoteport_delete = fcloop_remoteport_delete, + .create_queue = fcloop_create_queue, +diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c +index a227e36cbdc2..8e0f03ef346b 100644 +--- a/drivers/scsi/lpfc/lpfc_nvme.c ++++ b/drivers/scsi/lpfc/lpfc_nvme.c +@@ -1976,6 +1976,8 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, + + /* Declare and initialization an instance of the FC NVME template. */ + static struct nvme_fc_port_template lpfc_nvme_template = { ++ .module = THIS_MODULE, ++ + /* initiator-based functions */ + .localport_delete = lpfc_nvme_localport_delete, + .remoteport_delete = lpfc_nvme_remoteport_delete, +diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c +index 6cc19e060afc..6e4d71302534 100644 +--- a/drivers/scsi/qla2xxx/qla_nvme.c ++++ b/drivers/scsi/qla2xxx/qla_nvme.c +@@ -610,6 +610,7 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) + } + + static struct nvme_fc_port_template qla_nvme_fc_transport = { ++ .module = THIS_MODULE, + .localport_delete = qla_nvme_localport_delete, + .remoteport_delete = qla_nvme_remoteport_delete, + .create_queue = qla_nvme_alloc_queue, +diff --git a/include/linux/nvme-fc-driver.h b/include/linux/nvme-fc-driver.h +index 10f81629b9ce..6d0d70f3219c 100644 +--- a/include/linux/nvme-fc-driver.h ++++ b/include/linux/nvme-fc-driver.h +@@ -270,6 +270,8 @@ struct nvme_fc_remote_port { + * + * Host/Initiator Transport Entrypoints/Parameters: + * ++ * @module: The LLDD module using the interface ++ * + * @localport_delete: The LLDD initiates deletion of a localport via + * nvme_fc_deregister_localport(). However, the teardown is + * asynchronous. This routine is called upon the completion of the +@@ -383,6 +385,8 @@ struct nvme_fc_remote_port { + * Value is Mandatory. Allowed to be zero. + */ + struct nvme_fc_port_template { ++ struct module *module; ++ + /* initiator-based functions */ + void (*localport_delete)(struct nvme_fc_local_port *); + void (*remoteport_delete)(struct nvme_fc_remote_port *); +-- +2.16.4 + diff --git a/patches.suse/nvmet-Cleanup-discovery-execute-handlers.patch b/patches.suse/nvmet-Cleanup-discovery-execute-handlers.patch new file mode 100644 index 0000000..0c250e7 --- /dev/null +++ b/patches.suse/nvmet-Cleanup-discovery-execute-handlers.patch @@ -0,0 +1,107 @@ +From: Christoph Hellwig +Date: Wed, 23 Oct 2019 10:35:42 -0600 +Subject: [PATCH] nvmet: Cleanup discovery execute handlers +Git-commit: 6f86f2c9d94d55c4d3a6f1ffbc2e1115b5cb38a8 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Push the lid and cns check into their respective handlers and, while +we're at it, rename the functions to be consistent with other +discovery handlers. + +Signed-off-by: Christoph Hellwig +[split patch, update changelog] +Signed-off-by: Logan Gunthorpe +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/discovery.c | 44 ++++++++++++++++++----------------------- + 1 file changed, 19 insertions(+), 25 deletions(-) + +diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c +index 3764a8900850..825e61e61b0c 100644 +--- a/drivers/nvme/target/discovery.c ++++ b/drivers/nvme/target/discovery.c +@@ -157,7 +157,7 @@ static size_t discovery_log_entries(struct nvmet_req *req) + return entries; + } + +-static void nvmet_execute_get_disc_log_page(struct nvmet_req *req) ++static void nvmet_execute_disc_get_log_page(struct nvmet_req *req) + { + const int entry_size = sizeof(struct nvmf_disc_rsp_page_entry); + struct nvmet_ctrl *ctrl = req->sq->ctrl; +@@ -171,6 +171,13 @@ static void nvmet_execute_get_disc_log_page(struct nvmet_req *req) + u16 status = 0; + void *buffer; + ++ if (req->cmd->get_log_page.lid != NVME_LOG_DISC) { ++ req->error_loc = ++ offsetof(struct nvme_get_log_page_command, lid); ++ status = NVME_SC_INVALID_OPCODE | NVME_SC_DNR; ++ goto out; ++ } ++ + /* Spec requires dword aligned offsets */ + if (offset & 0x3) { + status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; +@@ -227,12 +234,18 @@ static void nvmet_execute_get_disc_log_page(struct nvmet_req *req) + nvmet_req_complete(req, status); + } + +-static void nvmet_execute_identify_disc_ctrl(struct nvmet_req *req) ++static void nvmet_execute_disc_identify(struct nvmet_req *req) + { + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvme_id_ctrl *id; + u16 status = 0; + ++ if (req->cmd->identify.cns != NVME_ID_CNS_CTRL) { ++ req->error_loc = offsetof(struct nvme_identify, cns); ++ status = NVME_SC_INVALID_OPCODE | NVME_SC_DNR; ++ goto out; ++ } ++ + id = kzalloc(sizeof(*id), GFP_KERNEL); + if (!id) { + status = NVME_SC_INTERNAL; +@@ -344,31 +357,12 @@ u16 nvmet_parse_discovery_cmd(struct nvmet_req *req) + return 0; + case nvme_admin_get_log_page: + req->data_len = nvmet_get_log_page_len(cmd); +- +- switch (cmd->get_log_page.lid) { +- case NVME_LOG_DISC: +- req->execute = nvmet_execute_get_disc_log_page; +- return 0; +- default: +- pr_err("unsupported get_log_page lid %d\n", +- cmd->get_log_page.lid); +- req->error_loc = +- offsetof(struct nvme_get_log_page_command, lid); +- return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; +- } ++ req->execute = nvmet_execute_disc_get_log_page; ++ return 0; + case nvme_admin_identify: + req->data_len = NVME_IDENTIFY_DATA_SIZE; +- switch (cmd->identify.cns) { +- case NVME_ID_CNS_CTRL: +- req->execute = +- nvmet_execute_identify_disc_ctrl; +- return 0; +- default: +- pr_err("unsupported identify cns %d\n", +- cmd->identify.cns); +- req->error_loc = offsetof(struct nvme_identify, cns); +- return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; +- } ++ req->execute = nvmet_execute_disc_identify; ++ return 0; + default: + pr_err("unhandled cmd %d\n", cmd->common.opcode); + req->error_loc = offsetof(struct nvme_common_command, opcode); +-- +2.16.4 + diff --git a/patches.suse/nvmet-Fix-controller-use-after-free.patch b/patches.suse/nvmet-Fix-controller-use-after-free.patch new file mode 100644 index 0000000..f058322 --- /dev/null +++ b/patches.suse/nvmet-Fix-controller-use-after-free.patch @@ -0,0 +1,89 @@ +From: Israel Rukshin +Date: Tue, 4 Feb 2020 14:38:10 +0200 +Subject: [PATCH] nvmet: Fix controller use after free +Git-commit: 1a3f540d63152b8db0a12de508bfa03776217d83 +Patch-mainline: v5.6-rc1 +References: bsc#1169045 + +After nvmet_install_queue() sets sq->ctrl calling to nvmet_sq_destroy() +reduces the controller refcount. In case nvmet_install_queue() fails, +calling to nvmet_ctrl_put() is done twice (at nvmet_sq_destroy and +nvmet_execute_io_connect/nvmet_execute_admin_connect) instead of once for +the queue which leads to use after free of the controller. Fix this by set +NULL at sq->ctrl in case of a failure at nvmet_install_queue(). + +The bug leads to the following Call Trace: + +[65857.994862] refcount_t: underflow; use-after-free. +[65858.108304] Workqueue: events nvmet_rdma_release_queue_work [nvmet_rdma] +[65858.115557] RIP: 0010:refcount_warn_saturate+0xe5/0xf0 +[65858.208141] Call Trace: +[65858.211203] nvmet_sq_destroy+0xe1/0xf0 [nvmet] +[65858.216383] nvmet_rdma_release_queue_work+0x37/0xf0 [nvmet_rdma] +[65858.223117] process_one_work+0x167/0x370 +[65858.227776] worker_thread+0x49/0x3e0 +[65858.232089] kthread+0xf5/0x130 +[65858.235895] ? max_active_store+0x80/0x80 +[65858.240504] ? kthread_bind+0x10/0x10 +[65858.244832] ret_from_fork+0x1f/0x30 +[65858.249074] ---[ end trace f82d59250b54beb7 ]--- + +Fixes: bb1cc74790eb ("nvmet: implement valid sqhd values in completions") +Fixes: 1672ddb8d691 ("nvmet: Add install_queue callout") +Signed-off-by: Israel Rukshin +Reviewed-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fabrics-cmd.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c +index 45ebc2e20458..feef15c38ec9 100644 +--- a/drivers/nvme/target/fabrics-cmd.c ++++ b/drivers/nvme/target/fabrics-cmd.c +@@ -109,6 +109,7 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req) + u16 qid = le16_to_cpu(c->qid); + u16 sqsize = le16_to_cpu(c->sqsize); + struct nvmet_ctrl *old; ++ u16 ret; + + old = cmpxchg(&req->sq->ctrl, NULL, ctrl); + if (old) { +@@ -119,7 +120,8 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req) + if (!sqsize) { + pr_warn("queue size zero!\n"); + req->error_loc = offsetof(struct nvmf_connect_command, sqsize); +- return NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR; ++ ret = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR; ++ goto err; + } + + /* note: convert queue size from 0's-based value to 1's-based value */ +@@ -132,16 +134,19 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req) + } + + if (ctrl->ops->install_queue) { +- u16 ret = ctrl->ops->install_queue(req->sq); +- ++ ret = ctrl->ops->install_queue(req->sq); + if (ret) { + pr_err("failed to install queue %d cntlid %d ret %x\n", + qid, ctrl->cntlid, ret); +- return ret; ++ goto err; + } + } + + return 0; ++ ++err: ++ req->sq->ctrl = NULL; ++ return ret; + } + + static void nvmet_execute_admin_connect(struct nvmet_req *req) +-- +2.16.4 + diff --git a/patches.suse/nvmet-Fix-error-print-message-at-nvmet_install_queue.patch b/patches.suse/nvmet-Fix-error-print-message-at-nvmet_install_queue.patch new file mode 100644 index 0000000..880438e --- /dev/null +++ b/patches.suse/nvmet-Fix-error-print-message-at-nvmet_install_queue.patch @@ -0,0 +1,36 @@ +From: Israel Rukshin +Date: Tue, 4 Feb 2020 14:38:09 +0200 +Subject: [PATCH] nvmet: Fix error print message at nvmet_install_queue +Git-commit: 0b87a2b795d66be7b54779848ef0f3901c5e46fc +Patch-mainline: v5.6-rc1 +References: bsc#1169045 + function + +Place the arguments in the correct order. + +Fixes: 1672ddb8d691 ("nvmet: Add install_queue callout") +Signed-off-by: Israel Rukshin +Reviewed-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fabrics-cmd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c +index f7297473d9eb..45ebc2e20458 100644 +--- a/drivers/nvme/target/fabrics-cmd.c ++++ b/drivers/nvme/target/fabrics-cmd.c +@@ -136,7 +136,7 @@ static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req) + + if (ret) { + pr_err("failed to install queue %d cntlid %d ret %x\n", +- qid, ret, ctrl->cntlid); ++ qid, ctrl->cntlid, ret); + return ret; + } + } +-- +2.16.4 + diff --git a/patches.suse/nvmet-Introduce-common-execute-function-for-get_log_.patch b/patches.suse/nvmet-Introduce-common-execute-function-for-get_log_.patch new file mode 100644 index 0000000..989d9f8 --- /dev/null +++ b/patches.suse/nvmet-Introduce-common-execute-function-for-get_log_.patch @@ -0,0 +1,150 @@ +From: Christoph Hellwig +Date: Wed, 23 Oct 2019 10:35:41 -0600 +Subject: [PATCH] nvmet: Introduce common execute function for get_log_page and + identify +Git-commit: 2cb6963a16e9e114486decf591af7cb2d69cb154 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Instead of picking the sub-command handler to execute in a nested +switch statement introduce a landing functions that calls out +to the appropriate sub-command handler. + +This will allow us to have a common place in the handler to check +the transfer length in a future patch. + +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Christoph Hellwig +[split patch, update change log] +Signed-off-by: Logan Gunthorpe +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/admin-cmd.c | 93 ++++++++++++++++++++++------------------- + 1 file changed, 50 insertions(+), 43 deletions(-) + +diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c +index 831a062d27cb..3665b45d6515 100644 +--- a/drivers/nvme/target/admin-cmd.c ++++ b/drivers/nvme/target/admin-cmd.c +@@ -282,6 +282,33 @@ static void nvmet_execute_get_log_page_ana(struct nvmet_req *req) + nvmet_req_complete(req, status); + } + ++static void nvmet_execute_get_log_page(struct nvmet_req *req) ++{ ++ switch (req->cmd->get_log_page.lid) { ++ case NVME_LOG_ERROR: ++ return nvmet_execute_get_log_page_error(req); ++ case NVME_LOG_SMART: ++ return nvmet_execute_get_log_page_smart(req); ++ case NVME_LOG_FW_SLOT: ++ /* ++ * We only support a single firmware slot which always is ++ * active, so we can zero out the whole firmware slot log and ++ * still claim to fully implement this mandatory log page. ++ */ ++ return nvmet_execute_get_log_page_noop(req); ++ case NVME_LOG_CHANGED_NS: ++ return nvmet_execute_get_log_changed_ns(req); ++ case NVME_LOG_CMD_EFFECTS: ++ return nvmet_execute_get_log_cmd_effects_ns(req); ++ case NVME_LOG_ANA: ++ return nvmet_execute_get_log_page_ana(req); ++ } ++ pr_err("unhandled lid %d on qid %d\n", ++ req->cmd->get_log_page.lid, req->sq->qid); ++ req->error_loc = offsetof(struct nvme_get_log_page_command, lid); ++ nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR); ++} ++ + static void nvmet_execute_identify_ctrl(struct nvmet_req *req) + { + struct nvmet_ctrl *ctrl = req->sq->ctrl; +@@ -565,6 +592,25 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req) + nvmet_req_complete(req, status); + } + ++static void nvmet_execute_identify(struct nvmet_req *req) ++{ ++ switch (req->cmd->identify.cns) { ++ case NVME_ID_CNS_NS: ++ return nvmet_execute_identify_ns(req); ++ case NVME_ID_CNS_CTRL: ++ return nvmet_execute_identify_ctrl(req); ++ case NVME_ID_CNS_NS_ACTIVE_LIST: ++ return nvmet_execute_identify_nslist(req); ++ case NVME_ID_CNS_NS_DESC_LIST: ++ return nvmet_execute_identify_desclist(req); ++ } ++ ++ pr_err("unhandled identify cns %d on qid %d\n", ++ req->cmd->identify.cns, req->sq->qid); ++ req->error_loc = offsetof(struct nvme_identify, cns); ++ nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR); ++} ++ + /* + * A "minimum viable" abort implementation: the command is mandatory in the + * spec, but we are not required to do any useful work. We couldn't really +@@ -819,52 +865,13 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req) + + switch (cmd->common.opcode) { + case nvme_admin_get_log_page: ++ req->execute = nvmet_execute_get_log_page; + req->data_len = nvmet_get_log_page_len(cmd); +- +- switch (cmd->get_log_page.lid) { +- case NVME_LOG_ERROR: +- req->execute = nvmet_execute_get_log_page_error; +- return 0; +- case NVME_LOG_SMART: +- req->execute = nvmet_execute_get_log_page_smart; +- return 0; +- case NVME_LOG_FW_SLOT: +- /* +- * We only support a single firmware slot which always +- * is active, so we can zero out the whole firmware slot +- * log and still claim to fully implement this mandatory +- * log page. +- */ +- req->execute = nvmet_execute_get_log_page_noop; +- return 0; +- case NVME_LOG_CHANGED_NS: +- req->execute = nvmet_execute_get_log_changed_ns; +- return 0; +- case NVME_LOG_CMD_EFFECTS: +- req->execute = nvmet_execute_get_log_cmd_effects_ns; +- return 0; +- case NVME_LOG_ANA: +- req->execute = nvmet_execute_get_log_page_ana; +- return 0; +- } +- break; ++ return 0; + case nvme_admin_identify: ++ req->execute = nvmet_execute_identify; + req->data_len = NVME_IDENTIFY_DATA_SIZE; +- switch (cmd->identify.cns) { +- case NVME_ID_CNS_NS: +- req->execute = nvmet_execute_identify_ns; +- return 0; +- case NVME_ID_CNS_CTRL: +- req->execute = nvmet_execute_identify_ctrl; +- return 0; +- case NVME_ID_CNS_NS_ACTIVE_LIST: +- req->execute = nvmet_execute_identify_nslist; +- return 0; +- case NVME_ID_CNS_NS_DESC_LIST: +- req->execute = nvmet_execute_identify_desclist; +- return 0; +- } +- break; ++ return 0; + case nvme_admin_abort_cmd: + req->execute = nvmet_execute_abort; + req->data_len = 0; +-- +2.16.4 + diff --git a/patches.suse/nvmet-Introduce-nvmet_dsm_len-helper.patch b/patches.suse/nvmet-Introduce-nvmet_dsm_len-helper.patch new file mode 100644 index 0000000..0ffb330 --- /dev/null +++ b/patches.suse/nvmet-Introduce-nvmet_dsm_len-helper.patch @@ -0,0 +1,55 @@ +From: Christoph Hellwig +Date: Wed, 23 Oct 2019 10:35:43 -0600 +Subject: [PATCH] nvmet: Introduce nvmet_dsm_len() helper +Git-commit: 59ef0eaa7741c3543f98220cc132c61bf0230bce +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Similar to the nvmet_rw_len helper. + +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Christoph Hellwig +[split patch, update changelog] +Signed-off-by: Logan Gunthorpe +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/io-cmd-file.c | 3 +-- + drivers/nvme/target/nvmet.h | 6 ++++++ + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c +index 05453f5d1448..7481556da6e6 100644 +--- a/drivers/nvme/target/io-cmd-file.c ++++ b/drivers/nvme/target/io-cmd-file.c +@@ -379,8 +379,7 @@ u16 nvmet_file_parse_io_cmd(struct nvmet_req *req) + return 0; + case nvme_cmd_dsm: + req->execute = nvmet_file_execute_dsm; +- req->data_len = (le32_to_cpu(cmd->dsm.nr) + 1) * +- sizeof(struct nvme_dsm_range); ++ req->data_len = nvmet_dsm_len(req); + return 0; + case nvme_cmd_write_zeroes: + req->execute = nvmet_file_execute_write_zeroes; +diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h +index c51f8dd01dc4..6ccf2d098d9f 100644 +--- a/drivers/nvme/target/nvmet.h ++++ b/drivers/nvme/target/nvmet.h +@@ -495,6 +495,12 @@ static inline u32 nvmet_rw_len(struct nvmet_req *req) + req->ns->blksize_shift; + } + ++static inline u32 nvmet_dsm_len(struct nvmet_req *req) ++{ ++ return (le32_to_cpu(req->cmd->dsm.nr) + 1) * ++ sizeof(struct nvme_dsm_range); ++} ++ + u16 errno_to_nvme_status(struct nvmet_req *req, int errno); + + /* Convert a 32-bit number to a 16-bit 0's based number */ +-- +2.16.4 + diff --git a/patches.suse/nvmet-Open-code-nvmet_req_execute.patch b/patches.suse/nvmet-Open-code-nvmet_req_execute.patch new file mode 100644 index 0000000..6f1b620 --- /dev/null +++ b/patches.suse/nvmet-Open-code-nvmet_req_execute.patch @@ -0,0 +1,145 @@ +From: Christoph Hellwig +Date: Wed, 23 Oct 2019 10:35:45 -0600 +Subject: [PATCH] nvmet: Open code nvmet_req_execute() +Git-commit: be3f3114ddd58d12f64b872247bb1bc46df56b36 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Now that nvmet_req_execute does nothing, open code it. + +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Christoph Hellwig +[split patch, update changelog] +Signed-off-by: Logan Gunthorpe +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/core.c | 6 ------ + drivers/nvme/target/fc.c | 4 ++-- + drivers/nvme/target/loop.c | 2 +- + drivers/nvme/target/nvmet.h | 1 - + drivers/nvme/target/rdma.c | 4 ++-- + drivers/nvme/target/tcp.c | 6 +++--- + 6 files changed, 8 insertions(+), 15 deletions(-) + +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 565def19d593..cde58c001b23 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -942,12 +942,6 @@ bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len) + } + EXPORT_SYMBOL_GPL(nvmet_check_data_len); + +-void nvmet_req_execute(struct nvmet_req *req) +-{ +- req->execute(req); +-} +-EXPORT_SYMBOL_GPL(nvmet_req_execute); +- + int nvmet_req_alloc_sgl(struct nvmet_req *req) + { + struct pci_dev *p2p_dev = NULL; +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 61b617698d3f..a0db6371b43e 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -2018,7 +2018,7 @@ nvmet_fc_fod_op_done(struct nvmet_fc_fcp_iod *fod) + } + + /* data transfer complete, resume with nvmet layer */ +- nvmet_req_execute(&fod->req); ++ fod->req.execute(&fod->req); + break; + + case NVMET_FCOP_READDATA: +@@ -2234,7 +2234,7 @@ nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport, + * can invoke the nvmet_layer now. If read data, cmd completion will + * push the data + */ +- nvmet_req_execute(&fod->req); ++ fod->req.execute(&fod->req); + return; + + transport_error: +diff --git a/drivers/nvme/target/loop.c b/drivers/nvme/target/loop.c +index 5b7b19774bb0..856eb0652f89 100644 +--- a/drivers/nvme/target/loop.c ++++ b/drivers/nvme/target/loop.c +@@ -125,7 +125,7 @@ static void nvme_loop_execute_work(struct work_struct *work) + struct nvme_loop_iod *iod = + container_of(work, struct nvme_loop_iod, work); + +- nvmet_req_execute(&iod->req); ++ iod->req.execute(&iod->req); + } + + static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx, +diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h +index ff55f1005b35..46df45e837c9 100644 +--- a/drivers/nvme/target/nvmet.h ++++ b/drivers/nvme/target/nvmet.h +@@ -374,7 +374,6 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, + struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops); + void nvmet_req_uninit(struct nvmet_req *req); + bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len); +-void nvmet_req_execute(struct nvmet_req *req); + void nvmet_req_complete(struct nvmet_req *req, u16 status); + int nvmet_req_alloc_sgl(struct nvmet_req *req); + void nvmet_req_free_sgl(struct nvmet_req *req); +diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c +index ccf982164136..37d262a65877 100644 +--- a/drivers/nvme/target/rdma.c ++++ b/drivers/nvme/target/rdma.c +@@ -603,7 +603,7 @@ static void nvmet_rdma_read_data_done(struct ib_cq *cq, struct ib_wc *wc) + return; + } + +- nvmet_req_execute(&rsp->req); ++ rsp->req.execute(&rsp->req); + } + + static void nvmet_rdma_use_inline_sg(struct nvmet_rdma_rsp *rsp, u32 len, +@@ -746,7 +746,7 @@ static bool nvmet_rdma_execute_command(struct nvmet_rdma_rsp *rsp) + queue->cm_id->port_num, &rsp->read_cqe, NULL)) + nvmet_req_complete(&rsp->req, NVME_SC_DATA_XFER_ERROR); + } else { +- nvmet_req_execute(&rsp->req); ++ rsp->req.execute(&rsp->req); + } + + return true; +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 3378480c49f6..af674fc0bb1e 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -930,7 +930,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) + goto out; + } + +- nvmet_req_execute(&queue->cmd->req); ++ queue->cmd->req.execute(&queue->cmd->req); + out: + nvmet_prepare_receive_pdu(queue); + return ret; +@@ -1050,7 +1050,7 @@ static int nvmet_tcp_try_recv_data(struct nvmet_tcp_queue *queue) + nvmet_tcp_prep_recv_ddgst(cmd); + return 0; + } +- nvmet_req_execute(&cmd->req); ++ cmd->req.execute(&cmd->req); + } + + nvmet_prepare_receive_pdu(queue); +@@ -1090,7 +1090,7 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue) + + if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED) && + cmd->rbytes_done == cmd->req.transfer_len) +- nvmet_req_execute(&cmd->req); ++ cmd->req.execute(&cmd->req); + ret = 0; + out: + nvmet_prepare_receive_pdu(queue); +-- +2.16.4 + diff --git a/patches.suse/nvmet-Remove-the-data_len-field-from-the-nvmet_req-s.patch b/patches.suse/nvmet-Remove-the-data_len-field-from-the-nvmet_req-s.patch new file mode 100644 index 0000000..a997ef8 --- /dev/null +++ b/patches.suse/nvmet-Remove-the-data_len-field-from-the-nvmet_req-s.patch @@ -0,0 +1,521 @@ +From: Christoph Hellwig +Date: Wed, 23 Oct 2019 10:35:44 -0600 +Subject: [PATCH] nvmet: Remove the data_len field from the nvmet_req struct +Git-commit: e9061c397839eea34207668bfedce0a6c18c5015 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Instead of storing the expected length and checking it when it's +executed, just check the length inside the command themselves. + +A new helper, nvmet_check_data_len() is created to help with this +check. + +Signed-off-by: Christoph Hellwig +[split patch, udpate changelog] +Signed-off-by: Logan Gunthorpe +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/admin-cmd.c | 35 ++++++++++++++++++++++++----------- + drivers/nvme/target/core.c | 16 ++++++++++++---- + drivers/nvme/target/discovery.c | 18 ++++++++++++------ + drivers/nvme/target/fabrics-cmd.c | 15 ++++++++++++--- + drivers/nvme/target/io-cmd-bdev.c | 19 +++++++++++++------ + drivers/nvme/target/io-cmd-file.c | 19 ++++++++++++------- + drivers/nvme/target/nvmet.h | 3 +-- + 7 files changed, 86 insertions(+), 39 deletions(-) + +diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c +index 3665b45d6515..cd2c3a79f3b5 100644 +--- a/drivers/nvme/target/admin-cmd.c ++++ b/drivers/nvme/target/admin-cmd.c +@@ -31,7 +31,7 @@ u64 nvmet_get_log_page_offset(struct nvme_command *cmd) + + static void nvmet_execute_get_log_page_noop(struct nvmet_req *req) + { +- nvmet_req_complete(req, nvmet_zero_sgl(req, 0, req->data_len)); ++ nvmet_req_complete(req, nvmet_zero_sgl(req, 0, req->transfer_len)); + } + + static void nvmet_execute_get_log_page_error(struct nvmet_req *req) +@@ -134,7 +134,7 @@ static void nvmet_execute_get_log_page_smart(struct nvmet_req *req) + u16 status = NVME_SC_INTERNAL; + unsigned long flags; + +- if (req->data_len != sizeof(*log)) ++ if (req->transfer_len != sizeof(*log)) + goto out; + + log = kzalloc(sizeof(*log), GFP_KERNEL); +@@ -196,7 +196,7 @@ static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req) + u16 status = NVME_SC_INTERNAL; + size_t len; + +- if (req->data_len != NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32)) ++ if (req->transfer_len != NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32)) + goto out; + + mutex_lock(&ctrl->lock); +@@ -206,7 +206,7 @@ static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req) + len = ctrl->nr_changed_ns * sizeof(__le32); + status = nvmet_copy_to_sgl(req, 0, ctrl->changed_ns_list, len); + if (!status) +- status = nvmet_zero_sgl(req, len, req->data_len - len); ++ status = nvmet_zero_sgl(req, len, req->transfer_len - len); + ctrl->nr_changed_ns = 0; + nvmet_clear_aen_bit(req, NVME_AEN_BIT_NS_ATTR); + mutex_unlock(&ctrl->lock); +@@ -284,6 +284,9 @@ static void nvmet_execute_get_log_page_ana(struct nvmet_req *req) + + static void nvmet_execute_get_log_page(struct nvmet_req *req) + { ++ if (!nvmet_check_data_len(req, nvmet_get_log_page_len(req->cmd))) ++ return; ++ + switch (req->cmd->get_log_page.lid) { + case NVME_LOG_ERROR: + return nvmet_execute_get_log_page_error(req); +@@ -594,6 +597,9 @@ static void nvmet_execute_identify_desclist(struct nvmet_req *req) + + static void nvmet_execute_identify(struct nvmet_req *req) + { ++ if (!nvmet_check_data_len(req, NVME_IDENTIFY_DATA_SIZE)) ++ return; ++ + switch (req->cmd->identify.cns) { + case NVME_ID_CNS_NS: + return nvmet_execute_identify_ns(req); +@@ -620,6 +626,8 @@ static void nvmet_execute_identify(struct nvmet_req *req) + */ + static void nvmet_execute_abort(struct nvmet_req *req) + { ++ if (!nvmet_check_data_len(req, 0)) ++ return; + nvmet_set_result(req, 1); + nvmet_req_complete(req, 0); + } +@@ -704,6 +712,9 @@ static void nvmet_execute_set_features(struct nvmet_req *req) + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + u16 status = 0; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + switch (cdw10 & 0xff) { + case NVME_FEAT_NUM_QUEUES: + nvmet_set_result(req, +@@ -767,6 +778,9 @@ static void nvmet_execute_get_features(struct nvmet_req *req) + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + u16 status = 0; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + switch (cdw10 & 0xff) { + /* + * These features are mandatory in the spec, but we don't +@@ -831,6 +845,9 @@ void nvmet_execute_async_event(struct nvmet_req *req) + { + struct nvmet_ctrl *ctrl = req->sq->ctrl; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + mutex_lock(&ctrl->lock); + if (ctrl->nr_async_event_cmds >= NVMET_ASYNC_EVENTS) { + mutex_unlock(&ctrl->lock); +@@ -847,6 +864,9 @@ void nvmet_execute_keep_alive(struct nvmet_req *req) + { + struct nvmet_ctrl *ctrl = req->sq->ctrl; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + pr_debug("ctrl %d update keep-alive timer for %d secs\n", + ctrl->cntlid, ctrl->kato); + +@@ -866,31 +886,24 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req) + switch (cmd->common.opcode) { + case nvme_admin_get_log_page: + req->execute = nvmet_execute_get_log_page; +- req->data_len = nvmet_get_log_page_len(cmd); + return 0; + case nvme_admin_identify: + req->execute = nvmet_execute_identify; +- req->data_len = NVME_IDENTIFY_DATA_SIZE; + return 0; + case nvme_admin_abort_cmd: + req->execute = nvmet_execute_abort; +- req->data_len = 0; + return 0; + case nvme_admin_set_features: + req->execute = nvmet_execute_set_features; +- req->data_len = 0; + return 0; + case nvme_admin_get_features: + req->execute = nvmet_execute_get_features; +- req->data_len = 0; + return 0; + case nvme_admin_async_event: + req->execute = nvmet_execute_async_event; +- req->data_len = 0; + return 0; + case nvme_admin_keep_alive: + req->execute = nvmet_execute_keep_alive; +- req->data_len = 0; + return 0; + } + +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 6b39cfc6ade1..565def19d593 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -930,13 +930,21 @@ void nvmet_req_uninit(struct nvmet_req *req) + } + EXPORT_SYMBOL_GPL(nvmet_req_uninit); + +-void nvmet_req_execute(struct nvmet_req *req) ++bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len) + { +- if (unlikely(req->data_len != req->transfer_len)) { ++ if (unlikely(data_len != req->transfer_len)) { + req->error_loc = offsetof(struct nvme_common_command, dptr); + nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR); +- } else +- req->execute(req); ++ return false; ++ } ++ ++ return true; ++} ++EXPORT_SYMBOL_GPL(nvmet_check_data_len); ++ ++void nvmet_req_execute(struct nvmet_req *req) ++{ ++ req->execute(req); + } + EXPORT_SYMBOL_GPL(nvmet_req_execute); + +diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c +index 825e61e61b0c..7a868c3e8e95 100644 +--- a/drivers/nvme/target/discovery.c ++++ b/drivers/nvme/target/discovery.c +@@ -171,6 +171,9 @@ static void nvmet_execute_disc_get_log_page(struct nvmet_req *req) + u16 status = 0; + void *buffer; + ++ if (!nvmet_check_data_len(req, data_len)) ++ return; ++ + if (req->cmd->get_log_page.lid != NVME_LOG_DISC) { + req->error_loc = + offsetof(struct nvme_get_log_page_command, lid); +@@ -240,6 +243,9 @@ static void nvmet_execute_disc_identify(struct nvmet_req *req) + struct nvme_id_ctrl *id; + u16 status = 0; + ++ if (!nvmet_check_data_len(req, NVME_IDENTIFY_DATA_SIZE)) ++ return; ++ + if (req->cmd->identify.cns != NVME_ID_CNS_CTRL) { + req->error_loc = offsetof(struct nvme_identify, cns); + status = NVME_SC_INVALID_OPCODE | NVME_SC_DNR; +@@ -286,6 +292,9 @@ static void nvmet_execute_disc_set_features(struct nvmet_req *req) + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + u16 stat; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + switch (cdw10 & 0xff) { + case NVME_FEAT_KATO: + stat = nvmet_set_feat_kato(req); +@@ -309,6 +318,9 @@ static void nvmet_execute_disc_get_features(struct nvmet_req *req) + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + u16 stat = 0; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + switch (cdw10 & 0xff) { + case NVME_FEAT_KATO: + nvmet_get_feat_kato(req); +@@ -341,26 +353,20 @@ u16 nvmet_parse_discovery_cmd(struct nvmet_req *req) + switch (cmd->common.opcode) { + case nvme_admin_set_features: + req->execute = nvmet_execute_disc_set_features; +- req->data_len = 0; + return 0; + case nvme_admin_get_features: + req->execute = nvmet_execute_disc_get_features; +- req->data_len = 0; + return 0; + case nvme_admin_async_event: + req->execute = nvmet_execute_async_event; +- req->data_len = 0; + return 0; + case nvme_admin_keep_alive: + req->execute = nvmet_execute_keep_alive; +- req->data_len = 0; + return 0; + case nvme_admin_get_log_page: +- req->data_len = nvmet_get_log_page_len(cmd); + req->execute = nvmet_execute_disc_get_log_page; + return 0; + case nvme_admin_identify: +- req->data_len = NVME_IDENTIFY_DATA_SIZE; + req->execute = nvmet_execute_disc_identify; + return 0; + default: +diff --git a/drivers/nvme/target/fabrics-cmd.c b/drivers/nvme/target/fabrics-cmd.c +index d16b55ffe79f..f7297473d9eb 100644 +--- a/drivers/nvme/target/fabrics-cmd.c ++++ b/drivers/nvme/target/fabrics-cmd.c +@@ -12,6 +12,9 @@ static void nvmet_execute_prop_set(struct nvmet_req *req) + u64 val = le64_to_cpu(req->cmd->prop_set.value); + u16 status = 0; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + if (req->cmd->prop_set.attrib & 1) { + req->error_loc = + offsetof(struct nvmf_property_set_command, attrib); +@@ -38,6 +41,9 @@ static void nvmet_execute_prop_get(struct nvmet_req *req) + u16 status = 0; + u64 val = 0; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + if (req->cmd->prop_get.attrib & 1) { + switch (le32_to_cpu(req->cmd->prop_get.offset)) { + case NVME_REG_CAP: +@@ -82,11 +88,9 @@ u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req) + + switch (cmd->fabrics.fctype) { + case nvme_fabrics_type_property_set: +- req->data_len = 0; + req->execute = nvmet_execute_prop_set; + break; + case nvme_fabrics_type_property_get: +- req->data_len = 0; + req->execute = nvmet_execute_prop_get; + break; + default: +@@ -147,6 +151,9 @@ static void nvmet_execute_admin_connect(struct nvmet_req *req) + struct nvmet_ctrl *ctrl = NULL; + u16 status = 0; + ++ if (!nvmet_check_data_len(req, sizeof(struct nvmf_connect_data))) ++ return; ++ + d = kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + status = NVME_SC_INTERNAL; +@@ -211,6 +218,9 @@ static void nvmet_execute_io_connect(struct nvmet_req *req) + u16 qid = le16_to_cpu(c->qid); + u16 status = 0; + ++ if (!nvmet_check_data_len(req, sizeof(struct nvmf_connect_data))) ++ return; ++ + d = kmalloc(sizeof(*d), GFP_KERNEL); + if (!d) { + status = NVME_SC_INTERNAL; +@@ -281,7 +291,6 @@ u16 nvmet_parse_connect_cmd(struct nvmet_req *req) + return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; + } + +- req->data_len = sizeof(struct nvmf_connect_data); + if (cmd->connect.qid == 0) + req->execute = nvmet_execute_admin_connect; + else +diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c +index f2618dc2ef3a..04a9cd2a2604 100644 +--- a/drivers/nvme/target/io-cmd-bdev.c ++++ b/drivers/nvme/target/io-cmd-bdev.c +@@ -150,6 +150,9 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + sector_t sector; + int op, op_flags = 0, i; + ++ if (!nvmet_check_data_len(req, nvmet_rw_len(req))) ++ return; ++ + if (!req->sg_cnt) { + nvmet_req_complete(req, 0); + return; +@@ -170,7 +173,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + sector = le64_to_cpu(req->cmd->rw.slba); + sector <<= (req->ns->blksize_shift - 9); + +- if (req->data_len <= NVMET_MAX_INLINE_DATA_LEN) { ++ if (req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN) { + bio = &req->b.inline_bio; + bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec)); + } else { +@@ -207,6 +210,9 @@ static void nvmet_bdev_execute_flush(struct nvmet_req *req) + { + struct bio *bio = &req->b.inline_bio; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + bio_init(bio, req->inline_bvec, ARRAY_SIZE(req->inline_bvec)); + bio_set_dev(bio, req->ns->bdev); + bio->bi_private = req; +@@ -272,6 +278,9 @@ static void nvmet_bdev_execute_discard(struct nvmet_req *req) + + static void nvmet_bdev_execute_dsm(struct nvmet_req *req) + { ++ if (!nvmet_check_data_len(req, nvmet_dsm_len(req))) ++ return; ++ + switch (le32_to_cpu(req->cmd->dsm.attributes)) { + case NVME_DSMGMT_AD: + nvmet_bdev_execute_discard(req); +@@ -293,6 +302,9 @@ static void nvmet_bdev_execute_write_zeroes(struct nvmet_req *req) + sector_t nr_sector; + int ret; + ++ if (!nvmet_check_data_len(req, 0)) ++ return; ++ + sector = le64_to_cpu(write_zeroes->slba) << + (req->ns->blksize_shift - 9); + nr_sector = (((sector_t)le16_to_cpu(write_zeroes->length) + 1) << +@@ -317,20 +329,15 @@ u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req) + case nvme_cmd_read: + case nvme_cmd_write: + req->execute = nvmet_bdev_execute_rw; +- req->data_len = nvmet_rw_len(req); + return 0; + case nvme_cmd_flush: + req->execute = nvmet_bdev_execute_flush; +- req->data_len = 0; + return 0; + case nvme_cmd_dsm: + req->execute = nvmet_bdev_execute_dsm; +- req->data_len = (le32_to_cpu(cmd->dsm.nr) + 1) * +- sizeof(struct nvme_dsm_range); + return 0; + case nvme_cmd_write_zeroes: + req->execute = nvmet_bdev_execute_write_zeroes; +- req->data_len = 0; + return 0; + default: + pr_err("unhandled cmd %d on qid %d\n", cmd->common.opcode, +diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c +index 7481556da6e6..caebfce06605 100644 +--- a/drivers/nvme/target/io-cmd-file.c ++++ b/drivers/nvme/target/io-cmd-file.c +@@ -126,7 +126,7 @@ static void nvmet_file_io_done(struct kiocb *iocb, long ret, long ret2) + mempool_free(req->f.bvec, req->ns->bvec_pool); + } + +- if (unlikely(ret != req->data_len)) ++ if (unlikely(ret != req->transfer_len)) + status = errno_to_nvme_status(req, ret); + nvmet_req_complete(req, status); + } +@@ -146,7 +146,7 @@ static bool nvmet_file_execute_io(struct nvmet_req *req, int ki_flags) + is_sync = true; + + pos = le64_to_cpu(req->cmd->rw.slba) << req->ns->blksize_shift; +- if (unlikely(pos + req->data_len > req->ns->size)) { ++ if (unlikely(pos + req->transfer_len > req->ns->size)) { + nvmet_req_complete(req, errno_to_nvme_status(req, -ENOSPC)); + return true; + } +@@ -173,7 +173,7 @@ static bool nvmet_file_execute_io(struct nvmet_req *req, int ki_flags) + nr_bvec--; + } + +- if (WARN_ON_ONCE(total_len != req->data_len)) { ++ if (WARN_ON_ONCE(total_len != req->transfer_len)) { + ret = -EIO; + goto complete; + } +@@ -232,6 +232,9 @@ static void nvmet_file_execute_rw(struct nvmet_req *req) + { + ssize_t nr_bvec = req->sg_cnt; + ++ if (!nvmet_check_data_len(req, nvmet_rw_len(req))) ++ return; ++ + if (!req->sg_cnt || !nr_bvec) { + nvmet_req_complete(req, 0); + return; +@@ -273,6 +276,8 @@ static void nvmet_file_flush_work(struct work_struct *w) + + static void nvmet_file_execute_flush(struct nvmet_req *req) + { ++ if (!nvmet_check_data_len(req, 0)) ++ return; + INIT_WORK(&req->f.work, nvmet_file_flush_work); + schedule_work(&req->f.work); + } +@@ -331,6 +336,8 @@ static void nvmet_file_dsm_work(struct work_struct *w) + + static void nvmet_file_execute_dsm(struct nvmet_req *req) + { ++ if (!nvmet_check_data_len(req, nvmet_dsm_len(req))) ++ return; + INIT_WORK(&req->f.work, nvmet_file_dsm_work); + schedule_work(&req->f.work); + } +@@ -359,6 +366,8 @@ static void nvmet_file_write_zeroes_work(struct work_struct *w) + + static void nvmet_file_execute_write_zeroes(struct nvmet_req *req) + { ++ if (!nvmet_check_data_len(req, 0)) ++ return; + INIT_WORK(&req->f.work, nvmet_file_write_zeroes_work); + schedule_work(&req->f.work); + } +@@ -371,19 +380,15 @@ u16 nvmet_file_parse_io_cmd(struct nvmet_req *req) + case nvme_cmd_read: + case nvme_cmd_write: + req->execute = nvmet_file_execute_rw; +- req->data_len = nvmet_rw_len(req); + return 0; + case nvme_cmd_flush: + req->execute = nvmet_file_execute_flush; +- req->data_len = 0; + return 0; + case nvme_cmd_dsm: + req->execute = nvmet_file_execute_dsm; +- req->data_len = nvmet_dsm_len(req); + return 0; + case nvme_cmd_write_zeroes: + req->execute = nvmet_file_execute_write_zeroes; +- req->data_len = 0; + return 0; + default: + pr_err("unhandled cmd for file ns %d on qid %d\n", +diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h +index 6ccf2d098d9f..ff55f1005b35 100644 +--- a/drivers/nvme/target/nvmet.h ++++ b/drivers/nvme/target/nvmet.h +@@ -304,8 +304,6 @@ struct nvmet_req { + } f; + }; + int sg_cnt; +- /* data length as parsed from the command: */ +- size_t data_len; + /* data length as parsed from the SGL descriptor: */ + size_t transfer_len; + +@@ -375,6 +373,7 @@ u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req); + bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, + struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops); + void nvmet_req_uninit(struct nvmet_req *req); ++bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len); + void nvmet_req_execute(struct nvmet_req *req); + void nvmet_req_complete(struct nvmet_req *req, u16 status); + int nvmet_req_alloc_sgl(struct nvmet_req *req); +-- +2.16.4 + diff --git a/patches.suse/nvmet-add-plugging-for-read-write-when-ns-is-bdev.patch b/patches.suse/nvmet-add-plugging-for-read-write-when-ns-is-bdev.patch new file mode 100644 index 0000000..17dcbb5 --- /dev/null +++ b/patches.suse/nvmet-add-plugging-for-read-write-when-ns-is-bdev.patch @@ -0,0 +1,77 @@ +From: Christoph Hellwig +Date: Mon, 28 Oct 2019 11:23:26 -0700 +Subject: [PATCH] nvmet: add plugging for read/write when ns is bdev +Git-commit: 9dea0c81ee4a7b5d8e5bc0d4cfa2ee4f0e7b13f0 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +With reference to the following issue reported on the mailing list :- +http://lists.infradead.org/pipermail/linux-nvme/2019-October/027604.html +this patch adds plugging for the bdev-ns under nvmet_bdev_execute_rw(). + +We can see the following performance improvement in random write +workload I/Os with the setup described in the link when device_path +configured as /dev/md0. + +Without this patch :- + +  write: IOPS=40.8k, BW=159MiB/s (167MB/s)(4777MiB/30002msec) +  write: IOPS=41.2k, BW=161MiB/s (169MB/s)(4831MiB/30011msec) +    slat (usec): min=8,  max=10823, avg=15.64,  stdev=16.85 +    slat (usec): min=8,  max=401,   avg=15.40,  stdev= 9.56 +    clat (usec): min=54, max=2492,  avg=759.07, stdev=172.62 +    clat (usec): min=56, max=1997,  avg=768.06, stdev=178.72 + +With this patch :- + +  write: IOPS=123k, BW=480MiB/s (504MB/s)(14.1GiB/30011msec) +  write: IOPS=123k, BW=481MiB/s (504MB/s)(14.1GiB/30002msec) +    slat (usec): min=8,  max=9941,  avg=13.31,  stdev= 8.04 +    slat (usec): min=8,  max=289,   avg=13.31,  stdev= 3.37 +    clat (usec): min=43, max=17635, avg=245.46, stdev=171.23 +    clat (usec): min=44, max=17751, avg=245.25, stdev=183.14 + +Reviewed-by: Sagi Grimberg +Signed-off-by: Christoph Hellwig +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/io-cmd-bdev.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c +index 04a9cd2a2604..07e4f8c579d3 100644 +--- a/drivers/nvme/target/io-cmd-bdev.c ++++ b/drivers/nvme/target/io-cmd-bdev.c +@@ -147,6 +147,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + int sg_cnt = req->sg_cnt; + struct bio *bio; + struct scatterlist *sg; ++ struct blk_plug plug; + sector_t sector; + int op, op_flags = 0, i; + +@@ -185,6 +186,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + bio->bi_end_io = nvmet_bio_done; + bio_set_op_attrs(bio, op, op_flags); + ++ blk_start_plug(&plug); + for_each_sg(req->sg, sg, req->sg_cnt, i) { + while (bio_add_page(bio, sg_page(sg), sg->length, sg->offset) + != sg->length) { +@@ -204,6 +206,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + } + + submit_bio(bio); ++ blk_finish_plug(&plug); + } + + static void nvmet_bdev_execute_flush(struct nvmet_req *req) +-- +2.16.4 + diff --git a/patches.suse/nvmet-add-unlikely-check-at-nvmet_req_alloc_sgl.patch b/patches.suse/nvmet-add-unlikely-check-at-nvmet_req_alloc_sgl.patch new file mode 100644 index 0000000..2ea1257 --- /dev/null +++ b/patches.suse/nvmet-add-unlikely-check-at-nvmet_req_alloc_sgl.patch @@ -0,0 +1,36 @@ +From: Israel Rukshin +Date: Sun, 13 Oct 2019 19:57:33 +0300 +Subject: [PATCH] nvmet: add unlikely check at nvmet_req_alloc_sgl +Git-commit: e522f446027845e3c8b563d021f37e8f3d30c9d9 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +The call to sgl_alloc shouldn't fail so add this simple optimization to +the fast path. + +Signed-off-by: Israel Rukshin +Reviewed-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 3a67e244e568..6b39cfc6ade1 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -966,7 +966,7 @@ int nvmet_req_alloc_sgl(struct nvmet_req *req) + } + + req->sg = sgl_alloc(req->transfer_len, GFP_KERNEL, &req->sg_cnt); +- if (!req->sg) ++ if (unlikely(!req->sg)) + return -ENOMEM; + + return 0; +-- +2.16.4 + diff --git a/patches.suse/nvmet-check-sscanf-value-for-subsys-serial-attr.patch b/patches.suse/nvmet-check-sscanf-value-for-subsys-serial-attr.patch new file mode 100644 index 0000000..fbd1a8d --- /dev/null +++ b/patches.suse/nvmet-check-sscanf-value-for-subsys-serial-attr.patch @@ -0,0 +1,42 @@ +From: Chaitanya Kulkarni +Date: Thu, 30 Jan 2020 10:29:33 -0800 +Subject: [PATCH] nvmet: check sscanf value for subsys serial attr +Git-commit: d3a9b0cadf8cea1746a6bf525d049198e705836a +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +For nvmet in configfs.c we check return values for all the sscanf() +calls. Add similar check into the nvmet_subsys_attr_serial_store(). + +Reviewed-by: Christoph Hellwig +Reviewed-by: Sagi Grimberg +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/configfs.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c +index 1654064deea5..7aa10788b7c8 100644 +--- a/drivers/nvme/target/configfs.c ++++ b/drivers/nvme/target/configfs.c +@@ -849,10 +849,13 @@ static ssize_t nvmet_subsys_attr_serial_show(struct config_item *item, + static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item, + const char *page, size_t count) + { +- struct nvmet_subsys *subsys = to_subsys(item); ++ u64 serial; ++ ++ if (sscanf(page, "%llx\n", &serial) != 1) ++ return -EINVAL; + + down_write(&nvmet_config_sem); +- sscanf(page, "%llx\n", &subsys->serial); ++ to_subsys(item)->serial = serial; + up_write(&nvmet_config_sem); + + return count; +-- +2.16.4 + diff --git a/patches.suse/nvmet-clean-up-command-parsing-a-bit.patch b/patches.suse/nvmet-clean-up-command-parsing-a-bit.patch new file mode 100644 index 0000000..fcd7094 --- /dev/null +++ b/patches.suse/nvmet-clean-up-command-parsing-a-bit.patch @@ -0,0 +1,59 @@ +From: Christoph Hellwig +Date: Fri, 25 Oct 2019 15:38:58 +0200 +Subject: [PATCH] nvmet: clean up command parsing a bit +Git-commit: d84dd8cde6742054a2c802df841fa5aab5b99122 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Move the special cases for fabrics commands and the discovery controller +to nvmet_parse_admin_cmd in preparation for adding passthrough support. + +Reviewed-by: Sagi Grimberg +Signed-off-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/admin-cmd.c | 5 +++++ + drivers/nvme/target/core.c | 6 +----- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c +index cd2c3a79f3b5..56c21b501185 100644 +--- a/drivers/nvme/target/admin-cmd.c ++++ b/drivers/nvme/target/admin-cmd.c +@@ -879,6 +879,11 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req) + struct nvme_command *cmd = req->cmd; + u16 ret; + ++ if (nvme_is_fabrics(cmd)) ++ return nvmet_parse_fabrics_cmd(req); ++ if (req->sq->ctrl->subsys->type == NVME_NQN_DISC) ++ return nvmet_parse_discovery_cmd(req); ++ + ret = nvmet_check_ctrl_status(req, cmd); + if (unlikely(ret)) + return ret; +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index cde58c001b23..28438b833c1b 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -892,14 +892,10 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, + } + + if (unlikely(!req->sq->ctrl)) +- /* will return an error for any Non-connect command: */ ++ /* will return an error for any non-connect command: */ + status = nvmet_parse_connect_cmd(req); + else if (likely(req->sq->qid != 0)) + status = nvmet_parse_io_cmd(req); +- else if (nvme_is_fabrics(req->cmd)) +- status = nvmet_parse_fabrics_cmd(req); +- else if (req->sq->ctrl->subsys->type == NVME_NQN_DISC) +- status = nvmet_parse_discovery_cmd(req); + else + status = nvmet_parse_admin_cmd(req); + +-- +2.16.4 + diff --git a/patches.suse/nvmet-configfs-code-cleanup.patch b/patches.suse/nvmet-configfs-code-cleanup.patch new file mode 100644 index 0000000..f1b37c9 --- /dev/null +++ b/patches.suse/nvmet-configfs-code-cleanup.patch @@ -0,0 +1,64 @@ +From: Chaitanya Kulkarni +Date: Sun, 26 Jan 2020 12:35:44 -0800 +Subject: [PATCH] nvmet: configfs code cleanup +Git-commit: 527123c7deafd5aa921773f739887d610d59b437 +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +This is a pure code cleanup patch which does not change any +functionality. This patch removes the extra lines, get rid of +else which is duplicate for return. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/configfs.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c +index 98613a45bd3b..403508a52e17 100644 +--- a/drivers/nvme/target/configfs.c ++++ b/drivers/nvme/target/configfs.c +@@ -395,14 +395,12 @@ static ssize_t nvmet_ns_device_uuid_store(struct config_item *item, + struct nvmet_subsys *subsys = ns->subsys; + int ret = 0; + +- + mutex_lock(&subsys->lock); + if (ns->enabled) { + ret = -EBUSY; + goto out_unlock; + } + +- + if (uuid_parse(page, &ns->uuid)) + ret = -EINVAL; + +@@ -815,10 +813,10 @@ static ssize_t nvmet_subsys_attr_version_show(struct config_item *item, + (int)NVME_MAJOR(subsys->ver), + (int)NVME_MINOR(subsys->ver), + (int)NVME_TERTIARY(subsys->ver)); +- else +- return snprintf(page, PAGE_SIZE, "%d.%d\n", +- (int)NVME_MAJOR(subsys->ver), +- (int)NVME_MINOR(subsys->ver)); ++ ++ return snprintf(page, PAGE_SIZE, "%d.%d\n", ++ (int)NVME_MAJOR(subsys->ver), ++ (int)NVME_MINOR(subsys->ver)); + } + + static ssize_t nvmet_subsys_attr_version_store(struct config_item *item, +@@ -828,7 +826,6 @@ static ssize_t nvmet_subsys_attr_version_store(struct config_item *item, + int major, minor, tertiary = 0; + int ret; + +- + ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary); + if (ret != 2 && ret != 3) + return -EINVAL; +-- +2.16.4 + diff --git a/patches.suse/nvmet-fc-Add-Disconnect-Association-Xmt-support.patch b/patches.suse/nvmet-fc-Add-Disconnect-Association-Xmt-support.patch new file mode 100644 index 0000000..0d8f267 --- /dev/null +++ b/patches.suse/nvmet-fc-Add-Disconnect-Association-Xmt-support.patch @@ -0,0 +1,507 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:59 -0700 +Subject: [PATCH] nvmet-fc: Add Disconnect Association Xmt support +Git-commit: d1ac0c39498ad5ebcb8669cb49f24592856aeddc +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +As part of FC-NVME-2 (and ammendment on FC-NVME), the target is to +send a Disconnect LS after an association is terminated and any +exchanges for the association have been ABTS'd. The target is also +not to send the receipt to any Disconnect Association LS, received +to initiate the association termination or received while the +association is terminating, until the Disconnect LS has been transmit. + +Add support for sending Disconnect Association LS after all I/O's +complete (which is after ABTS'd certainly). Utilizes the new LLDD +api to send ls requests. + +There is no need to track the Disconnect LS response or to retry +after timeout. All spec requirements will have been met by waiting +for i/o completion to initiate the transmission. + +Add support for tracking the reception of Disconnect Association +and defering the response transmission until after the Disconnect +Association LS has been transmit. + +Signed-off-by: James Smart +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fc.c | 296 +++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 286 insertions(+), 10 deletions(-) + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 6a5af99f19ba..02d9751bb7ee 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -25,7 +25,7 @@ + struct nvmet_fc_tgtport; + struct nvmet_fc_tgt_assoc; + +-struct nvmet_fc_ls_iod { ++struct nvmet_fc_ls_iod { /* for an LS RQST RCV */ + struct nvmefc_ls_rsp *lsrsp; + struct nvmefc_tgt_fcp_req *fcpreq; /* only if RS */ + +@@ -45,6 +45,18 @@ struct nvmet_fc_ls_iod { + struct work_struct work; + } __aligned(sizeof(unsigned long long)); + ++struct nvmet_fc_ls_req_op { /* for an LS RQST XMT */ ++ struct nvmefc_ls_req ls_req; ++ ++ struct nvmet_fc_tgtport *tgtport; ++ void *hosthandle; ++ ++ int ls_error; ++ struct list_head lsreq_list; /* tgtport->ls_req_list */ ++ bool req_queued; ++}; ++ ++ + /* desired maximum for a single sequence - if sg list allows it */ + #define NVMET_FC_MAX_SEQ_LENGTH (256 * 1024) + +@@ -91,6 +103,7 @@ struct nvmet_fc_tgtport { + struct nvmet_fc_ls_iod *iod; + spinlock_t lock; + struct list_head ls_rcv_list; ++ struct list_head ls_req_list; + struct list_head ls_busylist; + struct list_head assoc_list; + struct list_head host_list; +@@ -146,8 +159,10 @@ struct nvmet_fc_hostport { + struct nvmet_fc_tgt_assoc { + u64 association_id; + u32 a_id; ++ atomic_t terminating; + struct nvmet_fc_tgtport *tgtport; + struct nvmet_fc_hostport *hostport; ++ struct nvmet_fc_ls_iod *rcv_disconn; + struct list_head a_list; + struct nvmet_fc_tgt_queue *queues[NVMET_NR_QUEUES + 1]; + struct kref ref; +@@ -236,6 +251,8 @@ static int nvmet_fc_tgtport_get(struct nvmet_fc_tgtport *tgtport); + static void nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_fcp_iod *fod); + static void nvmet_fc_delete_target_assoc(struct nvmet_fc_tgt_assoc *assoc); ++static void nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport, ++ struct nvmet_fc_ls_iod *iod); + + + /* *********************** FC-NVME DMA Handling **************************** */ +@@ -327,6 +344,188 @@ fc_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, + } + + ++/* ********************** FC-NVME LS XMT Handling ************************* */ ++ ++ ++static void ++__nvmet_fc_finish_ls_req(struct nvmet_fc_ls_req_op *lsop) ++{ ++ struct nvmet_fc_tgtport *tgtport = lsop->tgtport; ++ struct nvmefc_ls_req *lsreq = &lsop->ls_req; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tgtport->lock, flags); ++ ++ if (!lsop->req_queued) { ++ spin_unlock_irqrestore(&tgtport->lock, flags); ++ return; ++ } ++ ++ list_del(&lsop->lsreq_list); ++ ++ lsop->req_queued = false; ++ ++ spin_unlock_irqrestore(&tgtport->lock, flags); ++ ++ fc_dma_unmap_single(tgtport->dev, lsreq->rqstdma, ++ (lsreq->rqstlen + lsreq->rsplen), ++ DMA_BIDIRECTIONAL); ++ ++ nvmet_fc_tgtport_put(tgtport); ++} ++ ++static int ++__nvmet_fc_send_ls_req(struct nvmet_fc_tgtport *tgtport, ++ struct nvmet_fc_ls_req_op *lsop, ++ void (*done)(struct nvmefc_ls_req *req, int status)) ++{ ++ struct nvmefc_ls_req *lsreq = &lsop->ls_req; ++ unsigned long flags; ++ int ret = 0; ++ ++ if (!tgtport->ops->ls_req) ++ return -EOPNOTSUPP; ++ ++ if (!nvmet_fc_tgtport_get(tgtport)) ++ return -ESHUTDOWN; ++ ++ lsreq->done = done; ++ lsop->req_queued = false; ++ INIT_LIST_HEAD(&lsop->lsreq_list); ++ ++ lsreq->rqstdma = fc_dma_map_single(tgtport->dev, lsreq->rqstaddr, ++ lsreq->rqstlen + lsreq->rsplen, ++ DMA_BIDIRECTIONAL); ++ if (fc_dma_mapping_error(tgtport->dev, lsreq->rqstdma)) { ++ ret = -EFAULT; ++ goto out_puttgtport; ++ } ++ lsreq->rspdma = lsreq->rqstdma + lsreq->rqstlen; ++ ++ spin_lock_irqsave(&tgtport->lock, flags); ++ ++ list_add_tail(&lsop->lsreq_list, &tgtport->ls_req_list); ++ ++ lsop->req_queued = true; ++ ++ spin_unlock_irqrestore(&tgtport->lock, flags); ++ ++ ret = tgtport->ops->ls_req(&tgtport->fc_target_port, lsop->hosthandle, ++ lsreq); ++ if (ret) ++ goto out_unlink; ++ ++ return 0; ++ ++out_unlink: ++ lsop->ls_error = ret; ++ spin_lock_irqsave(&tgtport->lock, flags); ++ lsop->req_queued = false; ++ list_del(&lsop->lsreq_list); ++ spin_unlock_irqrestore(&tgtport->lock, flags); ++ fc_dma_unmap_single(tgtport->dev, lsreq->rqstdma, ++ (lsreq->rqstlen + lsreq->rsplen), ++ DMA_BIDIRECTIONAL); ++out_puttgtport: ++ nvmet_fc_tgtport_put(tgtport); ++ ++ return ret; ++} ++ ++static int ++nvmet_fc_send_ls_req_async(struct nvmet_fc_tgtport *tgtport, ++ struct nvmet_fc_ls_req_op *lsop, ++ void (*done)(struct nvmefc_ls_req *req, int status)) ++{ ++ /* don't wait for completion */ ++ ++ return __nvmet_fc_send_ls_req(tgtport, lsop, done); ++} ++ ++static void ++nvmet_fc_disconnect_assoc_done(struct nvmefc_ls_req *lsreq, int status) ++{ ++ struct nvmet_fc_ls_req_op *lsop = ++ container_of(lsreq, struct nvmet_fc_ls_req_op, ls_req); ++ ++ __nvmet_fc_finish_ls_req(lsop); ++ ++ /* fc-nvme target doesn't care about success or failure of cmd */ ++ ++ kfree(lsop); ++} ++ ++/* ++ * This routine sends a FC-NVME LS to disconnect (aka terminate) ++ * the FC-NVME Association. Terminating the association also ++ * terminates the FC-NVME connections (per queue, both admin and io ++ * queues) that are part of the association. E.g. things are torn ++ * down, and the related FC-NVME Association ID and Connection IDs ++ * become invalid. ++ * ++ * The behavior of the fc-nvme target is such that it's ++ * understanding of the association and connections will implicitly ++ * be torn down. The action is implicit as it may be due to a loss of ++ * connectivity with the fc-nvme host, so the target may never get a ++ * response even if it tried. As such, the action of this routine ++ * is to asynchronously send the LS, ignore any results of the LS, and ++ * continue on with terminating the association. If the fc-nvme host ++ * is present and receives the LS, it too can tear down. ++ */ ++static void ++nvmet_fc_xmt_disconnect_assoc(struct nvmet_fc_tgt_assoc *assoc) ++{ ++ struct nvmet_fc_tgtport *tgtport = assoc->tgtport; ++ struct fcnvme_ls_disconnect_assoc_rqst *discon_rqst; ++ struct fcnvme_ls_disconnect_assoc_acc *discon_acc; ++ struct nvmet_fc_ls_req_op *lsop; ++ struct nvmefc_ls_req *lsreq; ++ int ret; ++ ++ /* ++ * If ls_req is NULL or no hosthandle, it's an older lldd and no ++ * message is normal. Otherwise, send unless the hostport has ++ * already been invalidated by the lldd. ++ */ ++ if (!tgtport->ops->ls_req || !assoc->hostport || ++ assoc->hostport->invalid) ++ return; ++ ++ lsop = kzalloc((sizeof(*lsop) + ++ sizeof(*discon_rqst) + sizeof(*discon_acc) + ++ tgtport->ops->lsrqst_priv_sz), GFP_KERNEL); ++ if (!lsop) { ++ dev_info(tgtport->dev, ++ "{%d:%d} send Disconnect Association failed: ENOMEM\n", ++ tgtport->fc_target_port.port_num, assoc->a_id); ++ return; ++ } ++ ++ discon_rqst = (struct fcnvme_ls_disconnect_assoc_rqst *)&lsop[1]; ++ discon_acc = (struct fcnvme_ls_disconnect_assoc_acc *)&discon_rqst[1]; ++ lsreq = &lsop->ls_req; ++ if (tgtport->ops->lsrqst_priv_sz) ++ lsreq->private = (void *)&discon_acc[1]; ++ else ++ lsreq->private = NULL; ++ ++ lsop->tgtport = tgtport; ++ lsop->hosthandle = assoc->hostport->hosthandle; ++ ++ nvmefc_fmt_lsreq_discon_assoc(lsreq, discon_rqst, discon_acc, ++ assoc->association_id); ++ ++ ret = nvmet_fc_send_ls_req_async(tgtport, lsop, ++ nvmet_fc_disconnect_assoc_done); ++ if (ret) { ++ dev_info(tgtport->dev, ++ "{%d:%d} XMT Disconnect Association failed: %d\n", ++ tgtport->fc_target_port.port_num, assoc->a_id, ret); ++ kfree(lsop); ++ } ++} ++ ++ + /* *********************** FC-NVME Port Management ************************ */ + + +@@ -693,6 +892,10 @@ nvmet_fc_delete_target_queue(struct nvmet_fc_tgt_queue *queue) + + disconnect = atomic_xchg(&queue->connected, 0); + ++ /* if not connected, nothing to do */ ++ if (!disconnect) ++ return; ++ + spin_lock_irqsave(&queue->qlock, flags); + /* abort outstanding io's */ + for (i = 0; i < queue->sqsize; fod++, i++) { +@@ -921,6 +1124,7 @@ nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport, void *hosthandle) + kref_init(&assoc->ref); + INIT_WORK(&assoc->del_work, nvmet_fc_delete_assoc); + atomic_set(&assoc->del_work_active, 0); ++ atomic_set(&assoc->terminating, 0); + + while (needrandom) { + get_random_bytes(&ran, sizeof(ran) - BYTES_FOR_QID); +@@ -957,13 +1161,24 @@ nvmet_fc_target_assoc_free(struct kref *ref) + struct nvmet_fc_tgt_assoc *assoc = + container_of(ref, struct nvmet_fc_tgt_assoc, ref); + struct nvmet_fc_tgtport *tgtport = assoc->tgtport; ++ struct nvmet_fc_ls_iod *oldls; + unsigned long flags; + ++ /* Send Disconnect now that all i/o has completed */ ++ nvmet_fc_xmt_disconnect_assoc(assoc); ++ + nvmet_fc_free_hostport(assoc->hostport); + spin_lock_irqsave(&tgtport->lock, flags); + list_del(&assoc->a_list); ++ oldls = assoc->rcv_disconn; + spin_unlock_irqrestore(&tgtport->lock, flags); ++ /* if pending Rcv Disconnect Association LS, send rsp now */ ++ if (oldls) ++ nvmet_fc_xmt_ls_rsp(tgtport, oldls); + ida_simple_remove(&tgtport->assoc_cnt, assoc->a_id); ++ dev_info(tgtport->dev, ++ "{%d:%d} Association freed\n", ++ tgtport->fc_target_port.port_num, assoc->a_id); + kfree(assoc); + nvmet_fc_tgtport_put(tgtport); + } +@@ -986,7 +1201,13 @@ nvmet_fc_delete_target_assoc(struct nvmet_fc_tgt_assoc *assoc) + struct nvmet_fc_tgtport *tgtport = assoc->tgtport; + struct nvmet_fc_tgt_queue *queue; + unsigned long flags; +- int i; ++ int i, terminating; ++ ++ terminating = atomic_xchg(&assoc->terminating, 1); ++ ++ /* if already terminating, do nothing */ ++ if (terminating) ++ return; + + spin_lock_irqsave(&tgtport->lock, flags); + for (i = NVMET_NR_QUEUES; i >= 0; i--) { +@@ -1002,6 +1223,10 @@ nvmet_fc_delete_target_assoc(struct nvmet_fc_tgt_assoc *assoc) + } + spin_unlock_irqrestore(&tgtport->lock, flags); + ++ dev_info(tgtport->dev, ++ "{%d:%d} Association deleted\n", ++ tgtport->fc_target_port.port_num, assoc->a_id); ++ + nvmet_fc_tgt_a_put(assoc); + } + +@@ -1171,6 +1396,7 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo, + newrec->ops = template; + spin_lock_init(&newrec->lock); + INIT_LIST_HEAD(&newrec->ls_rcv_list); ++ INIT_LIST_HEAD(&newrec->ls_req_list); + INIT_LIST_HEAD(&newrec->ls_busylist); + INIT_LIST_HEAD(&newrec->assoc_list); + INIT_LIST_HEAD(&newrec->host_list); +@@ -1407,6 +1633,13 @@ nvmet_fc_unregister_targetport(struct nvmet_fc_target_port *target_port) + /* terminate any outstanding associations */ + __nvmet_fc_free_assocs(tgtport); + ++ /* ++ * should terminate LS's as well. However, LS's will be generated ++ * at the tail end of association termination, so they likely don't ++ * exist yet. And even if they did, it's worthwhile to just let ++ * them finish and targetport ref counting will clean things up. ++ */ ++ + nvmet_fc_tgtport_put(tgtport); + + return 0; +@@ -1414,7 +1647,7 @@ nvmet_fc_unregister_targetport(struct nvmet_fc_target_port *target_port) + EXPORT_SYMBOL_GPL(nvmet_fc_unregister_targetport); + + +-/* *********************** FC-NVME LS Handling **************************** */ ++/* ********************** FC-NVME LS RCV Handling ************************* */ + + + static void +@@ -1481,6 +1714,10 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + atomic_set(&queue->connected, 1); + queue->sqhd = 0; /* best place to init value */ + ++ dev_info(tgtport->dev, ++ "{%d:%d} Association created\n", ++ tgtport->fc_target_port.port_num, iod->assoc->a_id); ++ + /* format a response */ + + iod->lsrsp->rsplen = sizeof(*acc); +@@ -1588,7 +1825,11 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, + be16_to_cpu(rqst->connect_cmd.qid))); + } + +-static void ++/* ++ * Returns true if the LS response is to be transmit ++ * Returns false if the LS response is to be delayed ++ */ ++static int + nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_ls_iod *iod) + { +@@ -1597,13 +1838,15 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + struct fcnvme_ls_disconnect_assoc_acc *acc = + &iod->rspbuf->rsp_dis_assoc; + struct nvmet_fc_tgt_assoc *assoc; ++ struct nvmet_fc_ls_iod *oldls = NULL; ++ unsigned long flags; + int ret = 0; + + memset(acc, 0, sizeof(*acc)); + + ret = nvmefc_vldt_lsreq_discon_assoc(iod->rqstdatalen, rqst); + if (!ret) { +- /* match an active association */ ++ /* match an active association - takes an assoc ref if !NULL */ + assoc = nvmet_fc_find_target_assoc(tgtport, + be64_to_cpu(rqst->associd.association_id)); + iod->assoc = assoc; +@@ -1621,7 +1864,7 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + FCNVME_RJT_RC_INV_ASSOC : + FCNVME_RJT_RC_LOGIC, + FCNVME_RJT_EXP_NONE, 0); +- return; ++ return true; + } + + /* format a response */ +@@ -1634,9 +1877,40 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + FCNVME_LS_DISCONNECT_ASSOC); + + /* release get taken in nvmet_fc_find_target_assoc */ +- nvmet_fc_tgt_a_put(iod->assoc); ++ nvmet_fc_tgt_a_put(assoc); ++ ++ /* ++ * The rules for LS response says the response cannot ++ * go back until ABTS's have been sent for all outstanding ++ * I/O and a Disconnect Association LS has been sent. ++ * So... save off the Disconnect LS to send the response ++ * later. If there was a prior LS already saved, replace ++ * it with the newer one and send a can't perform reject ++ * on the older one. ++ */ ++ spin_lock_irqsave(&tgtport->lock, flags); ++ oldls = assoc->rcv_disconn; ++ assoc->rcv_disconn = iod; ++ spin_unlock_irqrestore(&tgtport->lock, flags); + +- nvmet_fc_delete_target_assoc(iod->assoc); ++ nvmet_fc_delete_target_assoc(assoc); ++ ++ if (oldls) { ++ dev_info(tgtport->dev, ++ "{%d:%d} Multiple Disconnect Association LS's " ++ "received\n", ++ tgtport->fc_target_port.port_num, assoc->a_id); ++ /* overwrite good response with bogus failure */ ++ oldls->lsrsp->rsplen = nvme_fc_format_rjt(oldls->rspbuf, ++ sizeof(*iod->rspbuf), ++ /* ok to use rqst, LS is same */ ++ rqst->w0.ls_cmd, ++ FCNVME_RJT_RC_UNAB, ++ FCNVME_RJT_EXP_NONE, 0); ++ nvmet_fc_xmt_ls_rsp(tgtport, oldls); ++ } ++ ++ return false; + } + + +@@ -1681,6 +1955,7 @@ nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_ls_iod *iod) + { + struct fcnvme_ls_rqst_w0 *w0 = &iod->rqstbuf->rq_cr_assoc.w0; ++ bool sendrsp = true; + + iod->lsrsp->nvme_fc_private = iod; + iod->lsrsp->rspbuf = iod->rspbuf; +@@ -1707,7 +1982,7 @@ nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + break; + case FCNVME_LS_DISCONNECT_ASSOC: + /* Terminate a Queue/Connection or the Association */ +- nvmet_fc_ls_disconnect(tgtport, iod); ++ sendrsp = nvmet_fc_ls_disconnect(tgtport, iod); + break; + default: + iod->lsrsp->rsplen = nvme_fc_format_rjt(iod->rspbuf, +@@ -1715,7 +1990,8 @@ nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + FCNVME_RJT_RC_INVAL, FCNVME_RJT_EXP_NONE, 0); + } + +- nvmet_fc_xmt_ls_rsp(tgtport, iod); ++ if (sendrsp) ++ nvmet_fc_xmt_ls_rsp(tgtport, iod); + } + + /* +-- +2.16.4 + diff --git a/patches.suse/nvmet-fc-Better-size-LS-buffers.patch b/patches.suse/nvmet-fc-Better-size-LS-buffers.patch new file mode 100644 index 0000000..8820342 --- /dev/null +++ b/patches.suse/nvmet-fc-Better-size-LS-buffers.patch @@ -0,0 +1,229 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:49 -0700 +Subject: [PATCH] nvmet-fc: Better size LS buffers +Git-commit: 3ac7870a98f1ac063a8474f997e28d9f2aa53798 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Current code uses NVME_FC_MAX_LS_BUFFER_SIZE (2KB) when allocating +buffers for LS requests and responses. This is considerable overkill +for what is actually defined. + +Rework code to have unions for all possible requests and responses +and size based on the unions. Remove NVME_FC_MAX_LS_BUFFER_SIZE. + +Signed-off-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/host/fc.h | 15 ++++++++++++++ + drivers/nvme/target/fc.c | 53 +++++++++++++++++++++--------------------------- + 2 files changed, 38 insertions(+), 30 deletions(-) + +diff --git a/drivers/nvme/host/fc.h b/drivers/nvme/host/fc.h +index d2861cdd58ee..08fa88381d45 100644 +--- a/drivers/nvme/host/fc.h ++++ b/drivers/nvme/host/fc.h +@@ -16,6 +16,21 @@ + * ****************** FC-NVME LS HANDLING ****************** + */ + ++union nvmefc_ls_requests { ++ struct fcnvme_ls_cr_assoc_rqst rq_cr_assoc; ++ struct fcnvme_ls_cr_conn_rqst rq_cr_conn; ++ struct fcnvme_ls_disconnect_assoc_rqst rq_dis_assoc; ++ struct fcnvme_ls_disconnect_conn_rqst rq_dis_conn; ++} __aligned(128); /* alignment for other things alloc'd with */ ++ ++union nvmefc_ls_responses { ++ struct fcnvme_ls_rjt rsp_rjt; ++ struct fcnvme_ls_cr_assoc_acc rsp_cr_assoc; ++ struct fcnvme_ls_cr_conn_acc rsp_cr_conn; ++ struct fcnvme_ls_disconnect_assoc_acc rsp_dis_assoc; ++ struct fcnvme_ls_disconnect_conn_acc rsp_dis_conn; ++} __aligned(128); /* alignment for other things alloc'd with */ ++ + static inline void + nvme_fc_format_rsp_hdr(void *buf, u8 ls_cmd, __be32 desc_len, u8 rqst_ls_cmd) + { +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 1f3118a3b0a3..66de6bd8f4fd 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -22,9 +22,6 @@ + + #define NVMET_LS_CTX_COUNT 256 + +-/* for this implementation, assume small single frame rqst/rsp */ +-#define NVME_FC_MAX_LS_BUFFER_SIZE 2048 +- + struct nvmet_fc_tgtport; + struct nvmet_fc_tgt_assoc; + +@@ -37,8 +34,8 @@ struct nvmet_fc_ls_iod { + struct nvmet_fc_tgtport *tgtport; + struct nvmet_fc_tgt_assoc *assoc; + +- u8 *rqstbuf; +- u8 *rspbuf; ++ union nvmefc_ls_requests *rqstbuf; ++ union nvmefc_ls_responses *rspbuf; + u16 rqstdatalen; + dma_addr_t rspdma; + +@@ -340,15 +337,16 @@ nvmet_fc_alloc_ls_iodlist(struct nvmet_fc_tgtport *tgtport) + iod->tgtport = tgtport; + list_add_tail(&iod->ls_list, &tgtport->ls_list); + +- iod->rqstbuf = kcalloc(2, NVME_FC_MAX_LS_BUFFER_SIZE, +- GFP_KERNEL); ++ iod->rqstbuf = kzalloc(sizeof(union nvmefc_ls_requests) + ++ sizeof(union nvmefc_ls_responses), ++ GFP_KERNEL); + if (!iod->rqstbuf) + goto out_fail; + +- iod->rspbuf = iod->rqstbuf + NVME_FC_MAX_LS_BUFFER_SIZE; ++ iod->rspbuf = (union nvmefc_ls_responses *)&iod->rqstbuf[1]; + + iod->rspdma = fc_dma_map_single(tgtport->dev, iod->rspbuf, +- NVME_FC_MAX_LS_BUFFER_SIZE, ++ sizeof(*iod->rspbuf), + DMA_TO_DEVICE); + if (fc_dma_mapping_error(tgtport->dev, iod->rspdma)) + goto out_fail; +@@ -361,7 +359,7 @@ nvmet_fc_alloc_ls_iodlist(struct nvmet_fc_tgtport *tgtport) + list_del(&iod->ls_list); + for (iod--, i--; i >= 0; iod--, i--) { + fc_dma_unmap_single(tgtport->dev, iod->rspdma, +- NVME_FC_MAX_LS_BUFFER_SIZE, DMA_TO_DEVICE); ++ sizeof(*iod->rspbuf), DMA_TO_DEVICE); + kfree(iod->rqstbuf); + list_del(&iod->ls_list); + } +@@ -379,7 +377,7 @@ nvmet_fc_free_ls_iodlist(struct nvmet_fc_tgtport *tgtport) + + for (i = 0; i < NVMET_LS_CTX_COUNT; iod++, i++) { + fc_dma_unmap_single(tgtport->dev, +- iod->rspdma, NVME_FC_MAX_LS_BUFFER_SIZE, ++ iod->rspdma, sizeof(*iod->rspbuf), + DMA_TO_DEVICE); + kfree(iod->rqstbuf); + list_del(&iod->ls_list); +@@ -1262,10 +1260,8 @@ static void + nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_ls_iod *iod) + { +- struct fcnvme_ls_cr_assoc_rqst *rqst = +- (struct fcnvme_ls_cr_assoc_rqst *)iod->rqstbuf; +- struct fcnvme_ls_cr_assoc_acc *acc = +- (struct fcnvme_ls_cr_assoc_acc *)iod->rspbuf; ++ struct fcnvme_ls_cr_assoc_rqst *rqst = &iod->rqstbuf->rq_cr_assoc; ++ struct fcnvme_ls_cr_assoc_acc *acc = &iod->rspbuf->rsp_cr_assoc; + struct nvmet_fc_tgt_queue *queue; + int ret = 0; + +@@ -1313,7 +1309,7 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + "Create Association LS failed: %s\n", + validation_errors[ret]); + iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, +- NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, ++ sizeof(*acc), rqst->w0.ls_cmd, + FCNVME_RJT_RC_LOGIC, + FCNVME_RJT_EXP_NONE, 0); + return; +@@ -1348,10 +1344,8 @@ static void + nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_ls_iod *iod) + { +- struct fcnvme_ls_cr_conn_rqst *rqst = +- (struct fcnvme_ls_cr_conn_rqst *)iod->rqstbuf; +- struct fcnvme_ls_cr_conn_acc *acc = +- (struct fcnvme_ls_cr_conn_acc *)iod->rspbuf; ++ struct fcnvme_ls_cr_conn_rqst *rqst = &iod->rqstbuf->rq_cr_conn; ++ struct fcnvme_ls_cr_conn_acc *acc = &iod->rspbuf->rsp_cr_conn; + struct nvmet_fc_tgt_queue *queue; + int ret = 0; + +@@ -1404,7 +1398,7 @@ nvmet_fc_ls_create_connection(struct nvmet_fc_tgtport *tgtport, + "Create Connection LS failed: %s\n", + validation_errors[ret]); + iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, +- NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, ++ sizeof(*acc), rqst->w0.ls_cmd, + (ret == VERR_NO_ASSOC) ? + FCNVME_RJT_RC_INV_ASSOC : + FCNVME_RJT_RC_LOGIC, +@@ -1437,9 +1431,9 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_ls_iod *iod) + { + struct fcnvme_ls_disconnect_assoc_rqst *rqst = +- (struct fcnvme_ls_disconnect_assoc_rqst *)iod->rqstbuf; ++ &iod->rqstbuf->rq_dis_assoc; + struct fcnvme_ls_disconnect_assoc_acc *acc = +- (struct fcnvme_ls_disconnect_assoc_acc *)iod->rspbuf; ++ &iod->rspbuf->rsp_dis_assoc; + struct nvmet_fc_tgt_assoc *assoc; + int ret = 0; + +@@ -1484,7 +1478,7 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + "Disconnect LS failed: %s\n", + validation_errors[ret]); + iod->lsrsp->rsplen = nvme_fc_format_rjt(acc, +- NVME_FC_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd, ++ sizeof(*acc), rqst->w0.ls_cmd, + (ret == VERR_NO_ASSOC) ? + FCNVME_RJT_RC_INV_ASSOC : + FCNVME_RJT_RC_LOGIC, +@@ -1522,7 +1516,7 @@ nvmet_fc_xmt_ls_rsp_done(struct nvmefc_ls_rsp *lsrsp) + struct nvmet_fc_tgtport *tgtport = iod->tgtport; + + fc_dma_sync_single_for_cpu(tgtport->dev, iod->rspdma, +- NVME_FC_MAX_LS_BUFFER_SIZE, DMA_TO_DEVICE); ++ sizeof(*iod->rspbuf), DMA_TO_DEVICE); + nvmet_fc_free_ls_iod(tgtport, iod); + nvmet_fc_tgtport_put(tgtport); + } +@@ -1534,7 +1528,7 @@ nvmet_fc_xmt_ls_rsp(struct nvmet_fc_tgtport *tgtport, + int ret; + + fc_dma_sync_single_for_device(tgtport->dev, iod->rspdma, +- NVME_FC_MAX_LS_BUFFER_SIZE, DMA_TO_DEVICE); ++ sizeof(*iod->rspbuf), DMA_TO_DEVICE); + + ret = tgtport->ops->xmt_ls_rsp(&tgtport->fc_target_port, iod->lsrsp); + if (ret) +@@ -1548,8 +1542,7 @@ static void + nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + struct nvmet_fc_ls_iod *iod) + { +- struct fcnvme_ls_rqst_w0 *w0 = +- (struct fcnvme_ls_rqst_w0 *)iod->rqstbuf; ++ struct fcnvme_ls_rqst_w0 *w0 = &iod->rqstbuf->rq_cr_assoc.w0; + + iod->lsrsp->nvme_fc_private = iod; + iod->lsrsp->rspbuf = iod->rspbuf; +@@ -1580,7 +1573,7 @@ nvmet_fc_handle_ls_rqst(struct nvmet_fc_tgtport *tgtport, + break; + default: + iod->lsrsp->rsplen = nvme_fc_format_rjt(iod->rspbuf, +- NVME_FC_MAX_LS_BUFFER_SIZE, w0->ls_cmd, ++ sizeof(*iod->rspbuf), w0->ls_cmd, + FCNVME_RJT_RC_INVAL, FCNVME_RJT_EXP_NONE, 0); + } + +@@ -1627,7 +1620,7 @@ nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port, + struct nvmet_fc_tgtport *tgtport = targetport_to_tgtport(target_port); + struct nvmet_fc_ls_iod *iod; + +- if (lsreqbuf_len > NVME_FC_MAX_LS_BUFFER_SIZE) ++ if (lsreqbuf_len > sizeof(union nvmefc_ls_requests)) + return -E2BIG; + + if (!nvmet_fc_tgtport_get(tgtport)) +-- +2.16.4 + diff --git a/patches.suse/nvmet-fc-Update-target-for-common-definitions-for-LS.patch b/patches.suse/nvmet-fc-Update-target-for-common-definitions-for-LS.patch new file mode 100644 index 0000000..2c32ea0 --- /dev/null +++ b/patches.suse/nvmet-fc-Update-target-for-common-definitions-for-LS.patch @@ -0,0 +1,67 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:53 -0700 +Subject: [PATCH] nvmet-fc: Update target for common definitions for LS +Git-commit: a2370227742d569adb48cd347bb8d6ced81dfd0a +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + handling + +Given that both host and target now generate and receive LS's create +a single table definition for LS names. Each tranport half will have +a local version of the table. + +Convert the target side transport to use the new common Create +Association LS validation routine. + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Reviewed-by: Himanshu Madhani +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fc.c | 28 ++-------------------------- + 1 file changed, 2 insertions(+), 26 deletions(-) + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 66a60a218994..5739df7edc59 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -1442,32 +1442,8 @@ nvmet_fc_ls_disconnect(struct nvmet_fc_tgtport *tgtport, + + memset(acc, 0, sizeof(*acc)); + +- if (iod->rqstdatalen < sizeof(struct fcnvme_ls_disconnect_assoc_rqst)) +- ret = VERR_DISCONN_LEN; +- else if (rqst->desc_list_len != +- fcnvme_lsdesc_len( +- sizeof(struct fcnvme_ls_disconnect_assoc_rqst))) +- ret = VERR_DISCONN_RQST_LEN; +- else if (rqst->associd.desc_tag != cpu_to_be32(FCNVME_LSDESC_ASSOC_ID)) +- ret = VERR_ASSOC_ID; +- else if (rqst->associd.desc_len != +- fcnvme_lsdesc_len( +- sizeof(struct fcnvme_lsdesc_assoc_id))) +- ret = VERR_ASSOC_ID_LEN; +- else if (rqst->discon_cmd.desc_tag != +- cpu_to_be32(FCNVME_LSDESC_DISCONN_CMD)) +- ret = VERR_DISCONN_CMD; +- else if (rqst->discon_cmd.desc_len != +- fcnvme_lsdesc_len( +- sizeof(struct fcnvme_lsdesc_disconn_cmd))) +- ret = VERR_DISCONN_CMD_LEN; +- /* +- * As the standard changed on the LS, check if old format and scope +- * something other than Association (e.g. 0). +- */ +- else if (rqst->discon_cmd.rsvd8[0]) +- ret = VERR_DISCONN_SCOPE; +- else { ++ ret = nvmefc_vldt_lsreq_discon_assoc(iod->rqstdatalen, rqst); ++ if (!ret) { + /* match an active association */ + assoc = nvmet_fc_find_target_assoc(tgtport, + be64_to_cpu(rqst->associd.association_id)); +-- +2.16.4 + diff --git a/patches.suse/nvmet-fc-add-LS-failure-messages.patch b/patches.suse/nvmet-fc-add-LS-failure-messages.patch new file mode 100644 index 0000000..f015b4f --- /dev/null +++ b/patches.suse/nvmet-fc-add-LS-failure-messages.patch @@ -0,0 +1,60 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:55 -0700 +Subject: [PATCH] nvmet-fc: add LS failure messages +Git-commit: 1b435f26db2eb9d13ebcf4a53b58039ae99ac093 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +Add LS reception failure messages + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fc.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 5739df7edc59..a91c443c9098 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -1598,15 +1598,31 @@ nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port, + { + struct nvmet_fc_tgtport *tgtport = targetport_to_tgtport(target_port); + struct nvmet_fc_ls_iod *iod; +- +- if (lsreqbuf_len > sizeof(union nvmefc_ls_requests)) ++ struct fcnvme_ls_rqst_w0 *w0 = (struct fcnvme_ls_rqst_w0 *)lsreqbuf; ++ ++ if (lsreqbuf_len > sizeof(union nvmefc_ls_requests)) { ++ dev_info(tgtport->dev, ++ "RCV %s LS failed: payload too large (%d)\n", ++ (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? ++ nvmefc_ls_names[w0->ls_cmd] : "", ++ lsreqbuf_len); + return -E2BIG; ++ } + +- if (!nvmet_fc_tgtport_get(tgtport)) ++ if (!nvmet_fc_tgtport_get(tgtport)) { ++ dev_info(tgtport->dev, ++ "RCV %s LS failed: target deleting\n", ++ (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? ++ nvmefc_ls_names[w0->ls_cmd] : ""); + return -ESHUTDOWN; ++ } + + iod = nvmet_fc_alloc_ls_iod(tgtport); + if (!iod) { ++ dev_info(tgtport->dev, ++ "RCV %s LS failed: context allocation failed\n", ++ (w0->ls_cmd <= NVME_FC_LAST_LS_CMD_VALUE) ? ++ nvmefc_ls_names[w0->ls_cmd] : ""); + nvmet_fc_tgtport_put(tgtport); + return -ENOENT; + } +-- +2.16.4 + diff --git a/patches.suse/nvmet-fc-fix-typo-in-comment.patch b/patches.suse/nvmet-fc-fix-typo-in-comment.patch new file mode 100644 index 0000000..2483de7 --- /dev/null +++ b/patches.suse/nvmet-fc-fix-typo-in-comment.patch @@ -0,0 +1,35 @@ +From: James Smart +Date: Wed, 18 Mar 2020 14:40:43 -0700 +Subject: [PATCH] nvmet-fc: fix typo in comment +Git-commit: d038dd815fc56cd77ae8a51bb6d1d11e3aab9609 +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +Fix typo in comment: about should be abort + +Signed-off-by: James Smart +Reviewed-by: Sagi Grimberg +Reviewed-by: Chiatanya Kulkarni +Reviewed-by: Himanshu Madhani +Reviewed-by: Hannes Reinecke +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index a0db6371b43e..a8ceb7721640 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -684,7 +684,7 @@ nvmet_fc_delete_target_queue(struct nvmet_fc_tgt_queue *queue) + disconnect = atomic_xchg(&queue->connected, 0); + + spin_lock_irqsave(&queue->qlock, flags); +- /* about outstanding io's */ ++ /* abort outstanding io's */ + for (i = 0; i < queue->sqsize; fod++, i++) { + if (fod->active) { + spin_lock(&fod->flock); +-- +2.16.4 + diff --git a/patches.suse/nvmet-fc-perform-small-cleanups-on-unneeded-checks.patch b/patches.suse/nvmet-fc-perform-small-cleanups-on-unneeded-checks.patch new file mode 100644 index 0000000..418e530 --- /dev/null +++ b/patches.suse/nvmet-fc-perform-small-cleanups-on-unneeded-checks.patch @@ -0,0 +1,72 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:56 -0700 +Subject: [PATCH] nvmet-fc: perform small cleanups on unneeded checks +Git-commit: e72914f70db194d98ade0711b088fd062a72c033 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +While code reviewing saw a couple of items that can be cleaned up: +- In nvmet_fc_delete_target_queue(), the routine unlocks, then checks + and relocks. Reorganize to avoid the unlock/relock. +- In nvmet_fc_delete_target_queue(), there's a check on the disconnect + state that is unnecessary as the routine validates the state before + starting any action. + +Signed-off-by: James Smart +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fc.c | 13 +++++-------- + 1 file changed, 5 insertions(+), 8 deletions(-) + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index a91c443c9098..01488fc35d46 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -677,7 +677,7 @@ nvmet_fc_delete_target_queue(struct nvmet_fc_tgt_queue *queue) + struct nvmet_fc_fcp_iod *fod = queue->fod; + struct nvmet_fc_defer_fcp_req *deferfcp, *tempptr; + unsigned long flags; +- int i, writedataactive; ++ int i; + bool disconnect; + + disconnect = atomic_xchg(&queue->connected, 0); +@@ -688,20 +688,18 @@ nvmet_fc_delete_target_queue(struct nvmet_fc_tgt_queue *queue) + if (fod->active) { + spin_lock(&fod->flock); + fod->abort = true; +- writedataactive = fod->writedataactive; +- spin_unlock(&fod->flock); + /* + * only call lldd abort routine if waiting for + * writedata. other outstanding ops should finish + * on their own. + */ +- if (writedataactive) { +- spin_lock(&fod->flock); ++ if (fod->writedataactive) { + fod->aborted = true; + spin_unlock(&fod->flock); + tgtport->ops->fcp_abort( + &tgtport->fc_target_port, fod->fcpreq); +- } ++ } else ++ spin_unlock(&fod->flock); + } + } + +@@ -741,8 +739,7 @@ nvmet_fc_delete_target_queue(struct nvmet_fc_tgt_queue *queue) + + flush_workqueue(queue->work_q); + +- if (disconnect) +- nvmet_sq_destroy(&queue->nvme_sq); ++ nvmet_sq_destroy(&queue->nvme_sq); + + nvmet_fc_tgt_q_put(queue); + } +-- +2.16.4 + diff --git a/patches.suse/nvmet-fc-rename-ls_list-to-ls_rcv_list.patch b/patches.suse/nvmet-fc-rename-ls_list-to-ls_rcv_list.patch new file mode 100644 index 0000000..c9dc10e --- /dev/null +++ b/patches.suse/nvmet-fc-rename-ls_list-to-ls_rcv_list.patch @@ -0,0 +1,109 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:58 -0700 +Subject: [PATCH] nvmet-fc: rename ls_list to ls_rcv_list +Git-commit: 11951fc60ecbba15990e072ce103c191e90cd17b +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +In preparation to add ls request support, rename the current ls_list, +which is RCV LS request only, to ls_rcv_list. + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fc.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 3ccf27c328b2..6a5af99f19ba 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -29,7 +29,7 @@ struct nvmet_fc_ls_iod { + struct nvmefc_ls_rsp *lsrsp; + struct nvmefc_tgt_fcp_req *fcpreq; /* only if RS */ + +- struct list_head ls_list; /* tgtport->ls_list */ ++ struct list_head ls_rcv_list; /* tgtport->ls_rcv_list */ + + struct nvmet_fc_tgtport *tgtport; + struct nvmet_fc_tgt_assoc *assoc; +@@ -90,7 +90,7 @@ struct nvmet_fc_tgtport { + + struct nvmet_fc_ls_iod *iod; + spinlock_t lock; +- struct list_head ls_list; ++ struct list_head ls_rcv_list; + struct list_head ls_busylist; + struct list_head assoc_list; + struct list_head host_list; +@@ -346,7 +346,7 @@ nvmet_fc_alloc_ls_iodlist(struct nvmet_fc_tgtport *tgtport) + for (i = 0; i < NVMET_LS_CTX_COUNT; iod++, i++) { + INIT_WORK(&iod->work, nvmet_fc_handle_ls_rqst_work); + iod->tgtport = tgtport; +- list_add_tail(&iod->ls_list, &tgtport->ls_list); ++ list_add_tail(&iod->ls_rcv_list, &tgtport->ls_rcv_list); + + iod->rqstbuf = kzalloc(sizeof(union nvmefc_ls_requests) + + sizeof(union nvmefc_ls_responses), +@@ -367,12 +367,12 @@ nvmet_fc_alloc_ls_iodlist(struct nvmet_fc_tgtport *tgtport) + + out_fail: + kfree(iod->rqstbuf); +- list_del(&iod->ls_list); ++ list_del(&iod->ls_rcv_list); + for (iod--, i--; i >= 0; iod--, i--) { + fc_dma_unmap_single(tgtport->dev, iod->rspdma, + sizeof(*iod->rspbuf), DMA_TO_DEVICE); + kfree(iod->rqstbuf); +- list_del(&iod->ls_list); ++ list_del(&iod->ls_rcv_list); + } + + kfree(iod); +@@ -391,7 +391,7 @@ nvmet_fc_free_ls_iodlist(struct nvmet_fc_tgtport *tgtport) + iod->rspdma, sizeof(*iod->rspbuf), + DMA_TO_DEVICE); + kfree(iod->rqstbuf); +- list_del(&iod->ls_list); ++ list_del(&iod->ls_rcv_list); + } + kfree(tgtport->iod); + } +@@ -403,10 +403,10 @@ nvmet_fc_alloc_ls_iod(struct nvmet_fc_tgtport *tgtport) + unsigned long flags; + + spin_lock_irqsave(&tgtport->lock, flags); +- iod = list_first_entry_or_null(&tgtport->ls_list, +- struct nvmet_fc_ls_iod, ls_list); ++ iod = list_first_entry_or_null(&tgtport->ls_rcv_list, ++ struct nvmet_fc_ls_iod, ls_rcv_list); + if (iod) +- list_move_tail(&iod->ls_list, &tgtport->ls_busylist); ++ list_move_tail(&iod->ls_rcv_list, &tgtport->ls_busylist); + spin_unlock_irqrestore(&tgtport->lock, flags); + return iod; + } +@@ -419,7 +419,7 @@ nvmet_fc_free_ls_iod(struct nvmet_fc_tgtport *tgtport, + unsigned long flags; + + spin_lock_irqsave(&tgtport->lock, flags); +- list_move(&iod->ls_list, &tgtport->ls_list); ++ list_move(&iod->ls_rcv_list, &tgtport->ls_rcv_list); + spin_unlock_irqrestore(&tgtport->lock, flags); + } + +@@ -1170,7 +1170,7 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo, + newrec->dev = dev; + newrec->ops = template; + spin_lock_init(&newrec->lock); +- INIT_LIST_HEAD(&newrec->ls_list); ++ INIT_LIST_HEAD(&newrec->ls_rcv_list); + INIT_LIST_HEAD(&newrec->ls_busylist); + INIT_LIST_HEAD(&newrec->assoc_list); + INIT_LIST_HEAD(&newrec->host_list); +-- +2.16.4 + diff --git a/patches.suse/nvmet-fc-track-hostport-handle-for-associations.patch b/patches.suse/nvmet-fc-track-hostport-handle-for-associations.patch new file mode 100644 index 0000000..808c0c1 --- /dev/null +++ b/patches.suse/nvmet-fc-track-hostport-handle-for-associations.patch @@ -0,0 +1,368 @@ +From: James Smart +Date: Tue, 31 Mar 2020 09:49:57 -0700 +Subject: [PATCH] nvmet-fc: track hostport handle for associations +Git-commit: 1e2c6c38f8fd06c67d515c919ab300576f131d39 +Git-repo: git://git.infradead.org/nvme.git +Patch-mainline: Queued in subsystem maintainer repository +References: bsc#1169045 + +In preparation for sending LS requests for an association that +terminates, save and track the hosthandle that is part of the +LS's that are received to create associations. + +Support consists of: +- Create a hostport structure that will be 1:1 mapped to a + host port handle. The hostport structure is specific to + a targetport. +- Whenever an association is created, create a host port for + the hosthandle the Create Association LS was received from. + There will be only 1 hostport structure created, with all + associations that have the same hosthandle sharing the + hostport structure. +- When the association is terminated, the hostport reference + will be removed. After the last association for the host + port is removed, the hostport will be deleted. +- Add support for the new nvmet_fc_invalidate_host() interface. + In the past, the LLDD didn't notify loss of connectivity to + host ports - the LLD would simply reject new requests and wait + for the kato timeout to kill the association. Now, when host + port connectivity is lost, the LLDD can notify the transport. + The transport will initiate the termination of all associations + for that host port. When the last association has been terminated + and the hosthandle will no longer be referenced, the new + host_release callback will be made to the lldd. +- For compatibility with prior behavior which didn't report the + hosthandle: the LLDD must set hosthandle to NULL. In these + cases, not LS request will be made, and no host_release callbacks + will be made either. + +Signed-off-by: James Smart +Reviewed-by: Hannes Reinecke +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/fc.c | 177 +++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 170 insertions(+), 7 deletions(-) + +diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c +index 01488fc35d46..3ccf27c328b2 100644 +--- a/drivers/nvme/target/fc.c ++++ b/drivers/nvme/target/fc.c +@@ -33,6 +33,7 @@ struct nvmet_fc_ls_iod { + + struct nvmet_fc_tgtport *tgtport; + struct nvmet_fc_tgt_assoc *assoc; ++ void *hosthandle; + + union nvmefc_ls_requests *rqstbuf; + union nvmefc_ls_responses *rspbuf; +@@ -81,7 +82,6 @@ struct nvmet_fc_fcp_iod { + }; + + struct nvmet_fc_tgtport { +- + struct nvmet_fc_target_port fc_target_port; + + struct list_head tgt_list; /* nvmet_fc_target_list */ +@@ -93,6 +93,7 @@ struct nvmet_fc_tgtport { + struct list_head ls_list; + struct list_head ls_busylist; + struct list_head assoc_list; ++ struct list_head host_list; + struct ida assoc_cnt; + struct nvmet_fc_port_entry *pe; + struct kref ref; +@@ -134,14 +135,24 @@ struct nvmet_fc_tgt_queue { + struct nvmet_fc_fcp_iod fod[]; /* array of fcp_iods */ + } __aligned(sizeof(unsigned long long)); + ++struct nvmet_fc_hostport { ++ struct nvmet_fc_tgtport *tgtport; ++ void *hosthandle; ++ struct list_head host_list; ++ struct kref ref; ++ u8 invalid; ++}; ++ + struct nvmet_fc_tgt_assoc { + u64 association_id; + u32 a_id; + struct nvmet_fc_tgtport *tgtport; ++ struct nvmet_fc_hostport *hostport; + struct list_head a_list; + struct nvmet_fc_tgt_queue *queues[NVMET_NR_QUEUES + 1]; + struct kref ref; + struct work_struct del_work; ++ atomic_t del_work_active; + }; + + +@@ -773,6 +784,102 @@ nvmet_fc_find_target_queue(struct nvmet_fc_tgtport *tgtport, + return NULL; + } + ++static void ++nvmet_fc_hostport_free(struct kref *ref) ++{ ++ struct nvmet_fc_hostport *hostport = ++ container_of(ref, struct nvmet_fc_hostport, ref); ++ struct nvmet_fc_tgtport *tgtport = hostport->tgtport; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&tgtport->lock, flags); ++ list_del(&hostport->host_list); ++ spin_unlock_irqrestore(&tgtport->lock, flags); ++ if (tgtport->ops->host_release && hostport->invalid) ++ tgtport->ops->host_release(hostport->hosthandle); ++ kfree(hostport); ++ nvmet_fc_tgtport_put(tgtport); ++} ++ ++static void ++nvmet_fc_hostport_put(struct nvmet_fc_hostport *hostport) ++{ ++ kref_put(&hostport->ref, nvmet_fc_hostport_free); ++} ++ ++static int ++nvmet_fc_hostport_get(struct nvmet_fc_hostport *hostport) ++{ ++ return kref_get_unless_zero(&hostport->ref); ++} ++ ++static void ++nvmet_fc_free_hostport(struct nvmet_fc_hostport *hostport) ++{ ++ /* if LLDD not implemented, leave as NULL */ ++ if (!hostport->hosthandle) ++ return; ++ ++ nvmet_fc_hostport_put(hostport); ++} ++ ++static struct nvmet_fc_hostport * ++nvmet_fc_alloc_hostport(struct nvmet_fc_tgtport *tgtport, void *hosthandle) ++{ ++ struct nvmet_fc_hostport *newhost, *host, *match = NULL; ++ unsigned long flags; ++ ++ /* if LLDD not implemented, leave as NULL */ ++ if (!hosthandle) ++ return NULL; ++ ++ /* take reference for what will be the newly allocated hostport */ ++ if (!nvmet_fc_tgtport_get(tgtport)) ++ return ERR_PTR(-EINVAL); ++ ++ newhost = kzalloc(sizeof(*newhost), GFP_KERNEL); ++ if (!newhost) { ++ spin_lock_irqsave(&tgtport->lock, flags); ++ list_for_each_entry(host, &tgtport->host_list, host_list) { ++ if (host->hosthandle == hosthandle && !host->invalid) { ++ if (nvmet_fc_hostport_get(host)) { ++ match = host; ++ break; ++ } ++ } ++ } ++ spin_unlock_irqrestore(&tgtport->lock, flags); ++ /* no allocation - release reference */ ++ nvmet_fc_tgtport_put(tgtport); ++ return (match) ? match : ERR_PTR(-ENOMEM); ++ } ++ ++ newhost->tgtport = tgtport; ++ newhost->hosthandle = hosthandle; ++ INIT_LIST_HEAD(&newhost->host_list); ++ kref_init(&newhost->ref); ++ ++ spin_lock_irqsave(&tgtport->lock, flags); ++ list_for_each_entry(host, &tgtport->host_list, host_list) { ++ if (host->hosthandle == hosthandle && !host->invalid) { ++ if (nvmet_fc_hostport_get(host)) { ++ match = host; ++ break; ++ } ++ } ++ } ++ if (match) { ++ kfree(newhost); ++ newhost = NULL; ++ /* releasing allocation - release reference */ ++ nvmet_fc_tgtport_put(tgtport); ++ } else ++ list_add_tail(&newhost->host_list, &tgtport->host_list); ++ spin_unlock_irqrestore(&tgtport->lock, flags); ++ ++ return (match) ? match : newhost; ++} ++ + static void + nvmet_fc_delete_assoc(struct work_struct *work) + { +@@ -780,11 +887,12 @@ nvmet_fc_delete_assoc(struct work_struct *work) + container_of(work, struct nvmet_fc_tgt_assoc, del_work); + + nvmet_fc_delete_target_assoc(assoc); ++ atomic_set(&assoc->del_work_active, 0); + nvmet_fc_tgt_a_put(assoc); + } + + static struct nvmet_fc_tgt_assoc * +-nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport) ++nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport, void *hosthandle) + { + struct nvmet_fc_tgt_assoc *assoc, *tmpassoc; + unsigned long flags; +@@ -801,13 +909,18 @@ nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport) + goto out_free_assoc; + + if (!nvmet_fc_tgtport_get(tgtport)) +- goto out_ida_put; ++ goto out_ida; ++ ++ assoc->hostport = nvmet_fc_alloc_hostport(tgtport, hosthandle); ++ if (IS_ERR(assoc->hostport)) ++ goto out_put; + + assoc->tgtport = tgtport; + assoc->a_id = idx; + INIT_LIST_HEAD(&assoc->a_list); + kref_init(&assoc->ref); + INIT_WORK(&assoc->del_work, nvmet_fc_delete_assoc); ++ atomic_set(&assoc->del_work_active, 0); + + while (needrandom) { + get_random_bytes(&ran, sizeof(ran) - BYTES_FOR_QID); +@@ -829,7 +942,9 @@ nvmet_fc_alloc_target_assoc(struct nvmet_fc_tgtport *tgtport) + + return assoc; + +-out_ida_put: ++out_put: ++ nvmet_fc_tgtport_put(tgtport); ++out_ida: + ida_simple_remove(&tgtport->assoc_cnt, idx); + out_free_assoc: + kfree(assoc); +@@ -844,6 +959,7 @@ nvmet_fc_target_assoc_free(struct kref *ref) + struct nvmet_fc_tgtport *tgtport = assoc->tgtport; + unsigned long flags; + ++ nvmet_fc_free_hostport(assoc->hostport); + spin_lock_irqsave(&tgtport->lock, flags); + list_del(&assoc->a_list); + spin_unlock_irqrestore(&tgtport->lock, flags); +@@ -1057,6 +1173,7 @@ nvmet_fc_register_targetport(struct nvmet_fc_port_info *pinfo, + INIT_LIST_HEAD(&newrec->ls_list); + INIT_LIST_HEAD(&newrec->ls_busylist); + INIT_LIST_HEAD(&newrec->assoc_list); ++ INIT_LIST_HEAD(&newrec->host_list); + kref_init(&newrec->ref); + ida_init(&newrec->assoc_cnt); + newrec->max_sg_cnt = template->max_sgl_segments; +@@ -1133,14 +1250,21 @@ __nvmet_fc_free_assocs(struct nvmet_fc_tgtport *tgtport) + { + struct nvmet_fc_tgt_assoc *assoc, *next; + unsigned long flags; ++ int ret; + + spin_lock_irqsave(&tgtport->lock, flags); + list_for_each_entry_safe(assoc, next, + &tgtport->assoc_list, a_list) { + if (!nvmet_fc_tgt_a_get(assoc)) + continue; +- if (!schedule_work(&assoc->del_work)) ++ ret = atomic_cmpxchg(&assoc->del_work_active, 0, 1); ++ if (ret == 0) { ++ if (!schedule_work(&assoc->del_work)) ++ nvmet_fc_tgt_a_put(assoc); ++ } else { ++ /* already deleting - release local reference */ + nvmet_fc_tgt_a_put(assoc); ++ } + } + spin_unlock_irqrestore(&tgtport->lock, flags); + } +@@ -1178,6 +1302,36 @@ void + nvmet_fc_invalidate_host(struct nvmet_fc_target_port *target_port, + void *hosthandle) + { ++ struct nvmet_fc_tgtport *tgtport = targetport_to_tgtport(target_port); ++ struct nvmet_fc_tgt_assoc *assoc, *next; ++ unsigned long flags; ++ bool noassoc = true; ++ int ret; ++ ++ spin_lock_irqsave(&tgtport->lock, flags); ++ list_for_each_entry_safe(assoc, next, ++ &tgtport->assoc_list, a_list) { ++ if (!assoc->hostport || ++ assoc->hostport->hosthandle != hosthandle) ++ continue; ++ if (!nvmet_fc_tgt_a_get(assoc)) ++ continue; ++ assoc->hostport->invalid = 1; ++ noassoc = false; ++ ret = atomic_cmpxchg(&assoc->del_work_active, 0, 1); ++ if (ret == 0) { ++ if (!schedule_work(&assoc->del_work)) ++ nvmet_fc_tgt_a_put(assoc); ++ } else { ++ /* already deleting - release local reference */ ++ nvmet_fc_tgt_a_put(assoc); ++ } ++ } ++ spin_unlock_irqrestore(&tgtport->lock, flags); ++ ++ /* if there's nothing to wait for - call the callback */ ++ if (noassoc && tgtport->ops->host_release) ++ tgtport->ops->host_release(hosthandle); + } + EXPORT_SYMBOL_GPL(nvmet_fc_invalidate_host); + +@@ -1192,6 +1346,7 @@ nvmet_fc_delete_ctrl(struct nvmet_ctrl *ctrl) + struct nvmet_fc_tgt_queue *queue; + unsigned long flags; + bool found_ctrl = false; ++ int ret; + + /* this is a bit ugly, but don't want to make locks layered */ + spin_lock_irqsave(&nvmet_fc_tgtlock, flags); +@@ -1215,8 +1370,14 @@ nvmet_fc_delete_ctrl(struct nvmet_ctrl *ctrl) + nvmet_fc_tgtport_put(tgtport); + + if (found_ctrl) { +- if (!schedule_work(&assoc->del_work)) ++ ret = atomic_cmpxchg(&assoc->del_work_active, 0, 1); ++ if (ret == 0) { ++ if (!schedule_work(&assoc->del_work)) ++ nvmet_fc_tgt_a_put(assoc); ++ } else { ++ /* already deleting - release local reference */ + nvmet_fc_tgt_a_put(assoc); ++ } + return; + } + +@@ -1293,7 +1454,8 @@ nvmet_fc_ls_create_association(struct nvmet_fc_tgtport *tgtport, + + else { + /* new association w/ admin queue */ +- iod->assoc = nvmet_fc_alloc_target_assoc(tgtport); ++ iod->assoc = nvmet_fc_alloc_target_assoc( ++ tgtport, iod->hosthandle); + if (!iod->assoc) + ret = VERR_ASSOC_ALLOC_FAIL; + else { +@@ -1628,6 +1790,7 @@ nvmet_fc_rcv_ls_req(struct nvmet_fc_target_port *target_port, + iod->fcpreq = NULL; + memcpy(iod->rqstbuf, lsreqbuf, lsreqbuf_len); + iod->rqstdatalen = lsreqbuf_len; ++ iod->hosthandle = hosthandle; + + schedule_work(&iod->work); + +-- +2.16.4 + diff --git a/patches.suse/nvmet-fill-discovery-controller-sn-fr-and-mn-correct.patch b/patches.suse/nvmet-fill-discovery-controller-sn-fr-and-mn-correct.patch new file mode 100644 index 0000000..ead737b --- /dev/null +++ b/patches.suse/nvmet-fill-discovery-controller-sn-fr-and-mn-correct.patch @@ -0,0 +1,47 @@ +From: Sagi Grimberg +Date: Thu, 24 Oct 2019 09:55:58 -0700 +Subject: [PATCH] nvmet: fill discovery controller sn, fr and mn correctly +Git-commit: d4b3a1741130dfc812b0825db4cb1c61032da183 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +Discovery controllers need this information as well. + +Signed-off-by: Sagi Grimberg +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/discovery.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/discovery.c b/drivers/nvme/target/discovery.c +index 7a868c3e8e95..0c2274b21e15 100644 +--- a/drivers/nvme/target/discovery.c ++++ b/drivers/nvme/target/discovery.c +@@ -241,6 +241,7 @@ static void nvmet_execute_disc_identify(struct nvmet_req *req) + { + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvme_id_ctrl *id; ++ const char model[] = "Linux"; + u16 status = 0; + + if (!nvmet_check_data_len(req, NVME_IDENTIFY_DATA_SIZE)) +@@ -258,8 +259,13 @@ static void nvmet_execute_disc_identify(struct nvmet_req *req) + goto out; + } + ++ memset(id->sn, ' ', sizeof(id->sn)); ++ bin2hex(id->sn, &ctrl->subsys->serial, ++ min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2)); + memset(id->fr, ' ', sizeof(id->fr)); +- strncpy((char *)id->fr, UTS_RELEASE, sizeof(id->fr)); ++ memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' '); ++ memcpy_and_pad(id->fr, sizeof(id->fr), ++ UTS_RELEASE, strlen(UTS_RELEASE), ' '); + + /* no limit on data transfer sizes for now */ + id->mdts = 0; +-- +2.16.4 + diff --git a/patches.suse/nvmet-fix-NULL-dereference-when-removing-a-referral.patch b/patches.suse/nvmet-fix-NULL-dereference-when-removing-a-referral.patch new file mode 100644 index 0000000..54d1d64 --- /dev/null +++ b/patches.suse/nvmet-fix-NULL-dereference-when-removing-a-referral.patch @@ -0,0 +1,56 @@ +From: Sagi Grimberg +Date: Wed, 1 Apr 2020 16:16:27 -0700 +Subject: [PATCH] nvmet: fix NULL dereference when removing a referral +Git-commit: f0e656e4f253120eb871a53ffab7664530c1d9f4 +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +When item release is called, the parent is already null. We need the +parent to pass to nvmet_referral_disable so hook it up to +->disconnect_notify. + +Reported-by: Tony Asleson +Signed-off-by: Sagi Grimberg +Reviewed-by: Chaitanya Kulkarni +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/configfs.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c +index 7aa10788b7c8..58cabd7b6fc5 100644 +--- a/drivers/nvme/target/configfs.c ++++ b/drivers/nvme/target/configfs.c +@@ -1098,12 +1098,19 @@ static struct configfs_attribute *nvmet_referral_attrs[] = { + NULL, + }; + +-static void nvmet_referral_release(struct config_item *item) ++static void nvmet_referral_notify(struct config_group *group, ++ struct config_item *item) + { + struct nvmet_port *parent = to_nvmet_port(item->ci_parent->ci_parent); + struct nvmet_port *port = to_nvmet_port(item); + + nvmet_referral_disable(parent, port); ++} ++ ++static void nvmet_referral_release(struct config_item *item) ++{ ++ struct nvmet_port *port = to_nvmet_port(item); ++ + kfree(port); + } + +@@ -1134,6 +1141,7 @@ static struct config_group *nvmet_referral_make( + + static struct configfs_group_operations nvmet_referral_group_ops = { + .make_group = nvmet_referral_make, ++ .disconnect_notify = nvmet_referral_notify, + }; + + static const struct config_item_type nvmet_referrals_type = { +-- +2.16.4 + diff --git a/patches.suse/nvmet-fix-dsm-failure-when-payload-does-not-match-sg.patch b/patches.suse/nvmet-fix-dsm-failure-when-payload-does-not-match-sg.patch new file mode 100644 index 0000000..e009ee6 --- /dev/null +++ b/patches.suse/nvmet-fix-dsm-failure-when-payload-does-not-match-sg.patch @@ -0,0 +1,88 @@ +From: Sagi Grimberg +Date: Sun, 26 Jan 2020 23:23:28 -0800 +Subject: [PATCH] nvmet: fix dsm failure when payload does not match sgl +Git-commit: b716e6889c95f64ba32af492461f6cc9341f3f05 +Patch-mainline: v5.6-rc1 +References: bsc#1169045 + descriptor + +The host is allowed to pass the controller an sgl describing a buffer +that is larger than the dsm payload itself, allow it when executing +dsm. + +Reported-by: Dakshaja Uppalapati +Reviewed-by: Christoph Hellwig , +Reviewed-by: Max Gurtovoy +Signed-off-by: Sagi Grimberg +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/core.c | 11 +++++++++++ + drivers/nvme/target/io-cmd-bdev.c | 2 +- + drivers/nvme/target/io-cmd-file.c | 2 +- + drivers/nvme/target/nvmet.h | 1 + + 4 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 35810a0a8d21..461987f669c5 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -939,6 +939,17 @@ bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len) + } + EXPORT_SYMBOL_GPL(nvmet_check_data_len); + ++bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len) ++{ ++ if (unlikely(data_len > req->transfer_len)) { ++ req->error_loc = offsetof(struct nvme_common_command, dptr); ++ nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR); ++ return false; ++ } ++ ++ return true; ++} ++ + int nvmet_req_alloc_sgl(struct nvmet_req *req) + { + struct pci_dev *p2p_dev = NULL; +diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c +index b6fca0e421ef..ea0e596be15d 100644 +--- a/drivers/nvme/target/io-cmd-bdev.c ++++ b/drivers/nvme/target/io-cmd-bdev.c +@@ -280,7 +280,7 @@ static void nvmet_bdev_execute_discard(struct nvmet_req *req) + + static void nvmet_bdev_execute_dsm(struct nvmet_req *req) + { +- if (!nvmet_check_data_len(req, nvmet_dsm_len(req))) ++ if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req))) + return; + + switch (le32_to_cpu(req->cmd->dsm.attributes)) { +diff --git a/drivers/nvme/target/io-cmd-file.c b/drivers/nvme/target/io-cmd-file.c +index caebfce06605..cd5670b83118 100644 +--- a/drivers/nvme/target/io-cmd-file.c ++++ b/drivers/nvme/target/io-cmd-file.c +@@ -336,7 +336,7 @@ static void nvmet_file_dsm_work(struct work_struct *w) + + static void nvmet_file_execute_dsm(struct nvmet_req *req) + { +- if (!nvmet_check_data_len(req, nvmet_dsm_len(req))) ++ if (!nvmet_check_data_len_lte(req, nvmet_dsm_len(req))) + return; + INIT_WORK(&req->f.work, nvmet_file_dsm_work); + schedule_work(&req->f.work); +diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h +index 46df45e837c9..eda28b22a2c8 100644 +--- a/drivers/nvme/target/nvmet.h ++++ b/drivers/nvme/target/nvmet.h +@@ -374,6 +374,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, + struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops); + void nvmet_req_uninit(struct nvmet_req *req); + bool nvmet_check_data_len(struct nvmet_req *req, size_t data_len); ++bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len); + void nvmet_req_complete(struct nvmet_req *req, u16 status); + int nvmet_req_alloc_sgl(struct nvmet_req *req); + void nvmet_req_free_sgl(struct nvmet_req *req); +-- +2.16.4 + diff --git a/patches.suse/nvmet-fix-per-feat-data-len-for-get_feature.patch b/patches.suse/nvmet-fix-per-feat-data-len-for-get_feature.patch new file mode 100644 index 0000000..5c747fa --- /dev/null +++ b/patches.suse/nvmet-fix-per-feat-data-len-for-get_feature.patch @@ -0,0 +1,58 @@ +From: Amit Engel +Date: Wed, 8 Jan 2020 01:47:24 +0900 +Subject: [PATCH] nvmet: fix per feat data len for get_feature +Git-commit: e17016f6dcb047f91a8fc9f46bbf81a21d15ca73 +Patch-mainline: v5.5-rc6 +References: bsc#1169045 + +The existing implementation for the get_feature admin-cmd does not +use per-feature data len. This patch introduces a new helper function +nvmet_feat_data_len(), which is used to calculate per feature data len. +Right now we only set data len for fid 0x81 (NVME_FEAT_HOST_ID). + +Fixes: commit e9061c397839 ("nvmet: Remove the data_len field from the nvmet_req struct") + +Reviewed-by: Christoph Hellwig +Signed-off-by: Amit Engel +[endiness, naming, and kernel style fixes] +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/admin-cmd.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c +index 56c21b501185..72a7e41f3018 100644 +--- a/drivers/nvme/target/admin-cmd.c ++++ b/drivers/nvme/target/admin-cmd.c +@@ -24,6 +24,16 @@ u32 nvmet_get_log_page_len(struct nvme_command *cmd) + return len; + } + ++static u32 nvmet_feat_data_len(struct nvmet_req *req, u32 cdw10) ++{ ++ switch (cdw10 & 0xff) { ++ case NVME_FEAT_HOST_ID: ++ return sizeof(req->sq->ctrl->hostid); ++ default: ++ return 0; ++ } ++} ++ + u64 nvmet_get_log_page_offset(struct nvme_command *cmd) + { + return le64_to_cpu(cmd->get_log_page.lpo); +@@ -778,7 +788,7 @@ static void nvmet_execute_get_features(struct nvmet_req *req) + u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10); + u16 status = 0; + +- if (!nvmet_check_data_len(req, 0)) ++ if (!nvmet_check_data_len(req, nvmet_feat_data_len(req, cdw10))) + return; + + switch (cdw10 & 0xff) { +-- +2.16.4 + diff --git a/patches.suse/nvmet-make-ctrl-id-configurable.patch b/patches.suse/nvmet-make-ctrl-id-configurable.patch new file mode 100644 index 0000000..43a6060 --- /dev/null +++ b/patches.suse/nvmet-make-ctrl-id-configurable.patch @@ -0,0 +1,157 @@ +From: Chaitanya Kulkarni +Date: Thu, 30 Jan 2020 10:29:31 -0800 +Subject: [PATCH] nvmet: make ctrl-id configurable +Git-commit: 94a39d61f80fcd679debda11e1ca02b88d90e67e +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +This patch adds a new target subsys attribute which allows user to +optionally specify target controller IDs which then used in the +nvmet_execute_identify_ctrl() to fill up the nvme_id_ctrl structure. + +For example, when using a cluster setup with two nodes, with a dual +ported NVMe drive and exporting the drive from both the nodes, +The connection to the host fails due to the same controller ID and +results in the following error message:- + +"nvme nvmeX: Duplicate cntlid XXX with nvmeX, rejecting" + +With this patch now user can partition the controller IDs for each +subsystem by setting up the cntlid_min and cntlid_max. These values +will be used at the time of the controller ID creation. By partitioning +the ctrl-ids for each subsystem results in the unique ctrl-id space +which avoids the collision. + +When new attribute is not specified target will fall back to original +cntlid calculation method. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/configfs.c | 62 ++++++++++++++++++++++++++++++++++++++++++ + drivers/nvme/target/core.c | 8 ++++-- + drivers/nvme/target/nvmet.h | 2 ++ + 3 files changed, 70 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c +index 403508a52e17..71c50751b5a6 100644 +--- a/drivers/nvme/target/configfs.c ++++ b/drivers/nvme/target/configfs.c +@@ -859,10 +859,72 @@ static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item, + } + CONFIGFS_ATTR(nvmet_subsys_, attr_serial); + ++static ssize_t nvmet_subsys_attr_cntlid_min_show(struct config_item *item, ++ char *page) ++{ ++ return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->cntlid_min); ++} ++ ++static ssize_t nvmet_subsys_attr_cntlid_min_store(struct config_item *item, ++ const char *page, size_t cnt) ++{ ++ u16 cntlid_min; ++ ++ if (sscanf(page, "%hu\n", &cntlid_min) != 1) ++ return -EINVAL; ++ ++ if (cntlid_min == 0) ++ return -EINVAL; ++ ++ down_write(&nvmet_config_sem); ++ if (cntlid_min >= to_subsys(item)->cntlid_max) ++ goto out_unlock; ++ to_subsys(item)->cntlid_min = cntlid_min; ++ up_write(&nvmet_config_sem); ++ return cnt; ++ ++out_unlock: ++ up_write(&nvmet_config_sem); ++ return -EINVAL; ++} ++CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_min); ++ ++static ssize_t nvmet_subsys_attr_cntlid_max_show(struct config_item *item, ++ char *page) ++{ ++ return snprintf(page, PAGE_SIZE, "%u\n", to_subsys(item)->cntlid_max); ++} ++ ++static ssize_t nvmet_subsys_attr_cntlid_max_store(struct config_item *item, ++ const char *page, size_t cnt) ++{ ++ u16 cntlid_max; ++ ++ if (sscanf(page, "%hu\n", &cntlid_max) != 1) ++ return -EINVAL; ++ ++ if (cntlid_max == 0) ++ return -EINVAL; ++ ++ down_write(&nvmet_config_sem); ++ if (cntlid_max <= to_subsys(item)->cntlid_min) ++ goto out_unlock; ++ to_subsys(item)->cntlid_max = cntlid_max; ++ up_write(&nvmet_config_sem); ++ return cnt; ++ ++out_unlock: ++ up_write(&nvmet_config_sem); ++ return -EINVAL; ++} ++CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_max); ++ + static struct configfs_attribute *nvmet_subsys_attrs[] = { + &nvmet_subsys_attr_attr_allow_any_host, + &nvmet_subsys_attr_attr_version, + &nvmet_subsys_attr_attr_serial, ++ &nvmet_subsys_attr_attr_cntlid_min, ++ &nvmet_subsys_attr_attr_cntlid_max, + NULL, + }; + +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 576de773b4db..48080c948692 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -1289,8 +1289,11 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, + if (!ctrl->sqs) + goto out_free_cqs; + ++ if (subsys->cntlid_min > subsys->cntlid_max) ++ goto out_free_cqs; ++ + ret = ida_simple_get(&cntlid_ida, +- NVME_CNTLID_MIN, NVME_CNTLID_MAX, ++ subsys->cntlid_min, subsys->cntlid_max, + GFP_KERNEL); + if (ret < 0) { + status = NVME_SC_CONNECT_CTRL_BUSY | NVME_SC_DNR; +@@ -1438,7 +1441,8 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn, + kfree(subsys); + return ERR_PTR(-ENOMEM); + } +- ++ subsys->cntlid_min = NVME_CNTLID_MIN; ++ subsys->cntlid_max = NVME_CNTLID_MAX; + kref_init(&subsys->ref); + + mutex_init(&subsys->lock); +diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h +index eda28b22a2c8..c2d518fb1789 100644 +--- a/drivers/nvme/target/nvmet.h ++++ b/drivers/nvme/target/nvmet.h +@@ -211,6 +211,8 @@ struct nvmet_subsys { + struct list_head namespaces; + unsigned int nr_namespaces; + unsigned int max_nsid; ++ u16 cntlid_min; ++ u16 cntlid_max; + + struct list_head ctrls; + +-- +2.16.4 + diff --git a/patches.suse/nvmet-make-ctrl-model-configurable.patch b/patches.suse/nvmet-make-ctrl-model-configurable.patch new file mode 100644 index 0000000..232e436 --- /dev/null +++ b/patches.suse/nvmet-make-ctrl-model-configurable.patch @@ -0,0 +1,203 @@ +From: Mark Ruijter +Date: Thu, 30 Jan 2020 10:29:32 -0800 +Subject: [PATCH] nvmet: make ctrl model configurable +Git-commit: 013b7ebe5a0d70e2a02fd225174595e79c591b3e +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +This patch adds a new target subsys attribute which allows user to +optionally specify model name which then used in the +nvmet_execute_identify_ctrl() to fill up the nvme_id_ctrl structure. + +The default value for the model is set to "Linux" for backward +compatibility. + +Reviewed-by: Christoph Hellwig +Reviewed-by: Sagi Grimberg +Signed-off-by: Mark Ruijter +[chaitanya.kulkarni@wdc.com + *Use macro for default model, coding style fixes. + *Use RCU for accessing model in for configfs and in + nvmet_execute_identify_ctrl(). +] +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/admin-cmd.c | 17 +++++++++-- + drivers/nvme/target/configfs.c | 66 +++++++++++++++++++++++++++++++++++++++++ + drivers/nvme/target/core.c | 1 + + drivers/nvme/target/nvmet.h | 8 +++++ + 4 files changed, 90 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c +index 72a7e41f3018..19f949570625 100644 +--- a/drivers/nvme/target/admin-cmd.c ++++ b/drivers/nvme/target/admin-cmd.c +@@ -322,12 +322,25 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req) + nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR); + } + ++static void nvmet_id_set_model_number(struct nvme_id_ctrl *id, ++ struct nvmet_subsys *subsys) ++{ ++ const char *model = NVMET_DEFAULT_CTRL_MODEL; ++ struct nvmet_subsys_model *subsys_model; ++ ++ rcu_read_lock(); ++ subsys_model = rcu_dereference(subsys->model); ++ if (subsys_model) ++ model = subsys_model->number; ++ memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' '); ++ rcu_read_unlock(); ++} ++ + static void nvmet_execute_identify_ctrl(struct nvmet_req *req) + { + struct nvmet_ctrl *ctrl = req->sq->ctrl; + struct nvme_id_ctrl *id; + u16 status = 0; +- const char model[] = "Linux"; + + id = kzalloc(sizeof(*id), GFP_KERNEL); + if (!id) { +@@ -342,7 +355,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req) + memset(id->sn, ' ', sizeof(id->sn)); + bin2hex(id->sn, &ctrl->subsys->serial, + min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2)); +- memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' '); ++ nvmet_id_set_model_number(id, ctrl->subsys); + memcpy_and_pad(id->fr, sizeof(id->fr), + UTS_RELEASE, strlen(UTS_RELEASE), ' '); + +diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c +index 71c50751b5a6..1654064deea5 100644 +--- a/drivers/nvme/target/configfs.c ++++ b/drivers/nvme/target/configfs.c +@@ -919,12 +919,78 @@ static ssize_t nvmet_subsys_attr_cntlid_max_store(struct config_item *item, + } + CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_max); + ++static ssize_t nvmet_subsys_attr_model_show(struct config_item *item, ++ char *page) ++{ ++ struct nvmet_subsys *subsys = to_subsys(item); ++ struct nvmet_subsys_model *subsys_model; ++ char *model = NVMET_DEFAULT_CTRL_MODEL; ++ int ret; ++ ++ rcu_read_lock(); ++ subsys_model = rcu_dereference(subsys->model); ++ if (subsys_model) ++ model = subsys_model->number; ++ ret = snprintf(page, PAGE_SIZE, "%s\n", model); ++ rcu_read_unlock(); ++ ++ return ret; ++} ++ ++/* See Section 1.5 of NVMe 1.4 */ ++static bool nvmet_is_ascii(const char c) ++{ ++ return c >= 0x20 && c <= 0x7e; ++} ++ ++static ssize_t nvmet_subsys_attr_model_store(struct config_item *item, ++ const char *page, size_t count) ++{ ++ struct nvmet_subsys *subsys = to_subsys(item); ++ struct nvmet_subsys_model *new_model; ++ char *new_model_number; ++ int pos = 0, len; ++ ++ len = strcspn(page, "\n"); ++ if (!len) ++ return -EINVAL; ++ ++ for (pos = 0; pos < len; pos++) { ++ if (!nvmet_is_ascii(page[pos])) ++ return -EINVAL; ++ } ++ ++ new_model_number = kstrndup(page, len, GFP_KERNEL); ++ if (!new_model_number) ++ return -ENOMEM; ++ ++ new_model = kzalloc(sizeof(*new_model) + len + 1, GFP_KERNEL); ++ if (!new_model) { ++ kfree(new_model_number); ++ return -ENOMEM; ++ } ++ memcpy(new_model->number, new_model_number, len); ++ ++ down_write(&nvmet_config_sem); ++ mutex_lock(&subsys->lock); ++ new_model = rcu_replace_pointer(subsys->model, new_model, ++ mutex_is_locked(&subsys->lock)); ++ mutex_unlock(&subsys->lock); ++ up_write(&nvmet_config_sem); ++ ++ kfree_rcu(new_model, rcuhead); ++ ++ return count; ++} ++CONFIGFS_ATTR(nvmet_subsys_, attr_model); ++ + static struct configfs_attribute *nvmet_subsys_attrs[] = { + &nvmet_subsys_attr_attr_allow_any_host, + &nvmet_subsys_attr_attr_version, + &nvmet_subsys_attr_attr_serial, + &nvmet_subsys_attr_attr_cntlid_min, + &nvmet_subsys_attr_attr_cntlid_max, ++ &nvmet_subsys_attr_attr_model, + NULL, + }; + +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 48080c948692..b685f99d56a1 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -1461,6 +1461,7 @@ static void nvmet_subsys_free(struct kref *ref) + WARN_ON_ONCE(!list_empty(&subsys->namespaces)); + + kfree(subsys->subsysnqn); ++ kfree_rcu(subsys->model, rcuhead); + kfree(subsys); + } + +diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h +index c2d518fb1789..42ba2ddd9e96 100644 +--- a/drivers/nvme/target/nvmet.h ++++ b/drivers/nvme/target/nvmet.h +@@ -23,6 +23,7 @@ + #define NVMET_ASYNC_EVENTS 4 + #define NVMET_ERROR_LOG_SLOTS 128 + #define NVMET_NO_ERROR_LOC ((u16)-1) ++#define NVMET_DEFAULT_CTRL_MODEL "Linux" + + /* + * Supported optional AENs: +@@ -202,6 +203,11 @@ struct nvmet_ctrl { + struct nvme_error_slot slots[NVMET_ERROR_LOG_SLOTS]; + }; + ++struct nvmet_subsys_model { ++ struct rcu_head rcuhead; ++ char number[]; ++}; ++ + struct nvmet_subsys { + enum nvme_subsys_type type; + +@@ -229,6 +235,8 @@ struct nvmet_subsys { + + struct config_group namespaces_group; + struct config_group allowed_hosts_group; ++ ++ struct nvmet_subsys_model __rcu *model; + }; + + static inline struct nvmet_subsys *to_subsys(struct config_item *item) +-- +2.16.4 + diff --git a/patches.suse/nvmet-rdma-add-unlikely-check-at-nvmet_rdma_map_sgl_.patch b/patches.suse/nvmet-rdma-add-unlikely-check-at-nvmet_rdma_map_sgl_.patch new file mode 100644 index 0000000..cbec3f4 --- /dev/null +++ b/patches.suse/nvmet-rdma-add-unlikely-check-at-nvmet_rdma_map_sgl_.patch @@ -0,0 +1,43 @@ +From: Israel Rukshin +Date: Sun, 13 Oct 2019 19:57:34 +0300 +Subject: [PATCH] nvmet-rdma: add unlikely check at nvmet_rdma_map_sgl_keyed +Git-commit: 59534b9d606e7f566970a6f8621c6022f7c19ff1 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +The calls to nvmet_req_alloc_sgl and rdma_rw_ctx_init should usually +succeed, so add this simple optimization to the fast path. + +Signed-off-by: Israel Rukshin +Reviewed-by: Christoph Hellwig +Reviewed-by: Max Gurtovoy +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/rdma.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c +index 36d906a7f70d..ccf982164136 100644 +--- a/drivers/nvme/target/rdma.c ++++ b/drivers/nvme/target/rdma.c +@@ -672,13 +672,13 @@ static u16 nvmet_rdma_map_sgl_keyed(struct nvmet_rdma_rsp *rsp, + return 0; + + ret = nvmet_req_alloc_sgl(&rsp->req); +- if (ret < 0) ++ if (unlikely(ret < 0)) + goto error_out; + + ret = rdma_rw_ctx_init(&rsp->rw, cm_id->qp, cm_id->port_num, + rsp->req.sg, rsp->req.sg_cnt, 0, addr, key, + nvmet_data_dir(&rsp->req)); +- if (ret < 0) ++ if (unlikely(ret < 0)) + goto error_out; + rsp->n_rdma += ret; + +-- +2.16.4 + diff --git a/patches.suse/nvmet-rdma-fix-bonding-failover-possible-NULL-deref.patch b/patches.suse/nvmet-rdma-fix-bonding-failover-possible-NULL-deref.patch new file mode 100644 index 0000000..07aff76 --- /dev/null +++ b/patches.suse/nvmet-rdma-fix-bonding-failover-possible-NULL-deref.patch @@ -0,0 +1,317 @@ +From: Sagi Grimberg +Date: Thu, 2 Apr 2020 08:48:53 -0700 +Subject: [PATCH] nvmet-rdma: fix bonding failover possible NULL deref +Git-commit: a032e4f6d60d0aca4f6570d2ad33105a2b9ba385 +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +RDMA_CM_EVENT_ADDR_CHANGE event occur in the case of bonding failover +on normal as well as on listening cm_ids. Hence this event will +immediately trigger a NULL dereference trying to disconnect a queue +for a cm_id that actually belongs to the port. + +To fix this we provide a different handler for the listener cm_ids +that will defer a work to disable+(re)enable the port which essentially +destroys and setups another listener cm_id + +Reported-by: Alex Lyakas +Signed-off-by: Sagi Grimberg +Reviewed-by: Max Gurtovoy +Tested-by: Alex Lyakas +Signed-off-by: Christoph Hellwig +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/rdma.c | 175 ++++++++++++++++++++++++++++++--------------- + 1 file changed, 119 insertions(+), 56 deletions(-) + +diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c +index 9e1b8c61f54e..f78201421978 100644 +--- a/drivers/nvme/target/rdma.c ++++ b/drivers/nvme/target/rdma.c +@@ -105,6 +105,13 @@ struct nvmet_rdma_queue { + struct list_head queue_list; + }; + ++struct nvmet_rdma_port { ++ struct nvmet_port *nport; ++ struct sockaddr_storage addr; ++ struct rdma_cm_id *cm_id; ++ struct delayed_work repair_work; ++}; ++ + struct nvmet_rdma_device { + struct ib_device *device; + struct ib_pd *pd; +@@ -917,7 +924,8 @@ static void nvmet_rdma_free_dev(struct kref *ref) + static struct nvmet_rdma_device * + nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id) + { +- struct nvmet_port *port = cm_id->context; ++ struct nvmet_rdma_port *port = cm_id->context; ++ struct nvmet_port *nport = port->nport; + struct nvmet_rdma_device *ndev; + int inline_page_count; + int inline_sge_count; +@@ -934,17 +942,17 @@ nvmet_rdma_find_get_device(struct rdma_cm_id *cm_id) + if (!ndev) + goto out_err; + +- inline_page_count = num_pages(port->inline_data_size); ++ inline_page_count = num_pages(nport->inline_data_size); + inline_sge_count = max(cm_id->device->attrs.max_sge_rd, + cm_id->device->attrs.max_recv_sge) - 1; + if (inline_page_count > inline_sge_count) { + pr_warn("inline_data_size %d cannot be supported by device %s. Reducing to %lu.\n", +- port->inline_data_size, cm_id->device->name, ++ nport->inline_data_size, cm_id->device->name, + inline_sge_count * PAGE_SIZE); +- port->inline_data_size = inline_sge_count * PAGE_SIZE; ++ nport->inline_data_size = inline_sge_count * PAGE_SIZE; + inline_page_count = inline_sge_count; + } +- ndev->inline_data_size = port->inline_data_size; ++ ndev->inline_data_size = nport->inline_data_size; + ndev->inline_page_count = inline_page_count; + ndev->device = cm_id->device; + kref_init(&ndev->ref); +@@ -1272,6 +1280,7 @@ static int nvmet_rdma_cm_accept(struct rdma_cm_id *cm_id, + static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id, + struct rdma_cm_event *event) + { ++ struct nvmet_rdma_port *port = cm_id->context; + struct nvmet_rdma_device *ndev; + struct nvmet_rdma_queue *queue; + int ret = -EINVAL; +@@ -1287,7 +1296,7 @@ static int nvmet_rdma_queue_connect(struct rdma_cm_id *cm_id, + ret = -ENOMEM; + goto put_device; + } +- queue->port = cm_id->context; ++ queue->port = port->nport; + + if (queue->host_qid == 0) { + /* Let inflight controller teardown complete */ +@@ -1412,7 +1421,7 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id, + static int nvmet_rdma_device_removal(struct rdma_cm_id *cm_id, + struct nvmet_rdma_queue *queue) + { +- struct nvmet_port *port; ++ struct nvmet_rdma_port *port; + + if (queue) { + /* +@@ -1431,7 +1440,7 @@ static int nvmet_rdma_device_removal(struct rdma_cm_id *cm_id, + * cm_id destroy. use atomic xchg to make sure + * we don't compete with remove_port. + */ +- if (xchg(&port->priv, NULL) != cm_id) ++ if (xchg(&port->cm_id, NULL) != cm_id) + return 0; + + /* +@@ -1462,6 +1471,13 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id, + nvmet_rdma_queue_established(queue); + break; + case RDMA_CM_EVENT_ADDR_CHANGE: ++ if (!queue) { ++ struct nvmet_rdma_port *port = cm_id->context; ++ ++ schedule_delayed_work(&port->repair_work, 0); ++ break; ++ } ++ /* FALLTHROUGH */ + case RDMA_CM_EVENT_DISCONNECTED: + case RDMA_CM_EVENT_TIMEWAIT_EXIT: + nvmet_rdma_queue_disconnect(queue); +@@ -1504,42 +1520,19 @@ static void nvmet_rdma_delete_ctrl(struct nvmet_ctrl *ctrl) + mutex_unlock(&nvmet_rdma_queue_mutex); + } + +-static int nvmet_rdma_add_port(struct nvmet_port *port) ++static void nvmet_rdma_disable_port(struct nvmet_rdma_port *port) + { +- struct rdma_cm_id *cm_id; +- struct sockaddr_storage addr = { }; +- __kernel_sa_family_t af; +- int ret; +- +- switch (port->disc_addr.adrfam) { +- case NVMF_ADDR_FAMILY_IP4: +- af = AF_INET; +- break; +- case NVMF_ADDR_FAMILY_IP6: +- af = AF_INET6; +- break; +- default: +- pr_err("address family %d not supported\n", +- port->disc_addr.adrfam); +- return -EINVAL; +- } ++ struct rdma_cm_id *cm_id = xchg(&port->cm_id, NULL); + +- if (port->inline_data_size < 0) { +- port->inline_data_size = NVMET_RDMA_DEFAULT_INLINE_DATA_SIZE; +- } else if (port->inline_data_size > NVMET_RDMA_MAX_INLINE_DATA_SIZE) { +- pr_warn("inline_data_size %u is too large, reducing to %u\n", +- port->inline_data_size, +- NVMET_RDMA_MAX_INLINE_DATA_SIZE); +- port->inline_data_size = NVMET_RDMA_MAX_INLINE_DATA_SIZE; +- } ++ if (cm_id) ++ rdma_destroy_id(cm_id); ++} + +- ret = inet_pton_with_scope(&init_net, af, port->disc_addr.traddr, +- port->disc_addr.trsvcid, &addr); +- if (ret) { +- pr_err("malformed ip/port passed: %s:%s\n", +- port->disc_addr.traddr, port->disc_addr.trsvcid); +- return ret; +- } ++static int nvmet_rdma_enable_port(struct nvmet_rdma_port *port) ++{ ++ struct sockaddr *addr = (struct sockaddr *)&port->addr; ++ struct rdma_cm_id *cm_id; ++ int ret; + + cm_id = rdma_create_id(&init_net, nvmet_rdma_cm_handler, port, + RDMA_PS_TCP, IB_QPT_RC); +@@ -1558,23 +1551,19 @@ static int nvmet_rdma_add_port(struct nvmet_port *port) + goto out_destroy_id; + } + +- ret = rdma_bind_addr(cm_id, (struct sockaddr *)&addr); ++ ret = rdma_bind_addr(cm_id, addr); + if (ret) { +- pr_err("binding CM ID to %pISpcs failed (%d)\n", +- (struct sockaddr *)&addr, ret); ++ pr_err("binding CM ID to %pISpcs failed (%d)\n", addr, ret); + goto out_destroy_id; + } + + ret = rdma_listen(cm_id, 128); + if (ret) { +- pr_err("listening to %pISpcs failed (%d)\n", +- (struct sockaddr *)&addr, ret); ++ pr_err("listening to %pISpcs failed (%d)\n", addr, ret); + goto out_destroy_id; + } + +- pr_info("enabling port %d (%pISpcs)\n", +- le16_to_cpu(port->disc_addr.portid), (struct sockaddr *)&addr); +- port->priv = cm_id; ++ port->cm_id = cm_id; + return 0; + + out_destroy_id: +@@ -1582,18 +1571,92 @@ static int nvmet_rdma_add_port(struct nvmet_port *port) + return ret; + } + +-static void nvmet_rdma_remove_port(struct nvmet_port *port) ++static void nvmet_rdma_repair_port_work(struct work_struct *w) + { +- struct rdma_cm_id *cm_id = xchg(&port->priv, NULL); ++ struct nvmet_rdma_port *port = container_of(to_delayed_work(w), ++ struct nvmet_rdma_port, repair_work); ++ int ret; + +- if (cm_id) +- rdma_destroy_id(cm_id); ++ nvmet_rdma_disable_port(port); ++ ret = nvmet_rdma_enable_port(port); ++ if (ret) ++ schedule_delayed_work(&port->repair_work, 5 * HZ); ++} ++ ++static int nvmet_rdma_add_port(struct nvmet_port *nport) ++{ ++ struct nvmet_rdma_port *port; ++ __kernel_sa_family_t af; ++ int ret; ++ ++ port = kzalloc(sizeof(*port), GFP_KERNEL); ++ if (!port) ++ return -ENOMEM; ++ ++ nport->priv = port; ++ port->nport = nport; ++ INIT_DELAYED_WORK(&port->repair_work, nvmet_rdma_repair_port_work); ++ ++ switch (nport->disc_addr.adrfam) { ++ case NVMF_ADDR_FAMILY_IP4: ++ af = AF_INET; ++ break; ++ case NVMF_ADDR_FAMILY_IP6: ++ af = AF_INET6; ++ break; ++ default: ++ pr_err("address family %d not supported\n", ++ nport->disc_addr.adrfam); ++ ret = -EINVAL; ++ goto out_free_port; ++ } ++ ++ if (nport->inline_data_size < 0) { ++ nport->inline_data_size = NVMET_RDMA_DEFAULT_INLINE_DATA_SIZE; ++ } else if (nport->inline_data_size > NVMET_RDMA_MAX_INLINE_DATA_SIZE) { ++ pr_warn("inline_data_size %u is too large, reducing to %u\n", ++ nport->inline_data_size, ++ NVMET_RDMA_MAX_INLINE_DATA_SIZE); ++ nport->inline_data_size = NVMET_RDMA_MAX_INLINE_DATA_SIZE; ++ } ++ ++ ret = inet_pton_with_scope(&init_net, af, nport->disc_addr.traddr, ++ nport->disc_addr.trsvcid, &port->addr); ++ if (ret) { ++ pr_err("malformed ip/port passed: %s:%s\n", ++ nport->disc_addr.traddr, nport->disc_addr.trsvcid); ++ goto out_free_port; ++ } ++ ++ ret = nvmet_rdma_enable_port(port); ++ if (ret) ++ goto out_free_port; ++ ++ pr_info("enabling port %d (%pISpcs)\n", ++ le16_to_cpu(nport->disc_addr.portid), ++ (struct sockaddr *)&port->addr); ++ ++ return 0; ++ ++out_free_port: ++ kfree(port); ++ return ret; ++} ++ ++static void nvmet_rdma_remove_port(struct nvmet_port *nport) ++{ ++ struct nvmet_rdma_port *port = nport->priv; ++ ++ cancel_delayed_work_sync(&port->repair_work); ++ nvmet_rdma_disable_port(port); ++ kfree(port); + } + + static void nvmet_rdma_disc_port_addr(struct nvmet_req *req, +- struct nvmet_port *port, char *traddr) ++ struct nvmet_port *nport, char *traddr) + { +- struct rdma_cm_id *cm_id = port->priv; ++ struct nvmet_rdma_port *port = nport->priv; ++ struct rdma_cm_id *cm_id = port->cm_id; + + if (inet_addr_is_any((struct sockaddr *)&cm_id->route.addr.src_addr)) { + struct nvmet_rdma_rsp *rsp = +@@ -1603,7 +1666,7 @@ static void nvmet_rdma_disc_port_addr(struct nvmet_req *req, + + sprintf(traddr, "%pISc", addr); + } else { +- memcpy(traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE); ++ memcpy(traddr, nport->disc_addr.traddr, NVMF_TRADDR_SIZE); + } + } + +-- +2.16.4 + diff --git a/patches.suse/nvmet-stop-using-bio_set_op_attrs.patch b/patches.suse/nvmet-stop-using-bio_set_op_attrs.patch new file mode 100644 index 0000000..cbb96f0 --- /dev/null +++ b/patches.suse/nvmet-stop-using-bio_set_op_attrs.patch @@ -0,0 +1,74 @@ +From: Christoph Hellwig +Date: Tue, 29 Oct 2019 08:12:23 +0100 +Subject: [PATCH] nvmet: stop using bio_set_op_attrs +Git-commit: 716fd9c119a982c34af196fe9205d7a617f38e3e +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +bio_set_op_attrs has been long deprecated, replace it with a direct +assignment of the flags to bio->bi_opf. + +Reviewed-by: Chaitanya Kulkarni +Reviewed-by: Johannes Thumshirn +Signed-off-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/io-cmd-bdev.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c +index 07e4f8c579d3..b6fca0e421ef 100644 +--- a/drivers/nvme/target/io-cmd-bdev.c ++++ b/drivers/nvme/target/io-cmd-bdev.c +@@ -149,7 +149,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + struct scatterlist *sg; + struct blk_plug plug; + sector_t sector; +- int op, op_flags = 0, i; ++ int op, i; + + if (!nvmet_check_data_len(req, nvmet_rw_len(req))) + return; +@@ -160,16 +160,15 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + } + + if (req->cmd->rw.opcode == nvme_cmd_write) { +- op = REQ_OP_WRITE; +- op_flags = REQ_SYNC | REQ_IDLE; ++ op = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE; + if (req->cmd->rw.control & cpu_to_le16(NVME_RW_FUA)) +- op_flags |= REQ_FUA; ++ op |= REQ_FUA; + } else { + op = REQ_OP_READ; + } + + if (is_pci_p2pdma_page(sg_page(req->sg))) +- op_flags |= REQ_NOMERGE; ++ op |= REQ_NOMERGE; + + sector = le64_to_cpu(req->cmd->rw.slba); + sector <<= (req->ns->blksize_shift - 9); +@@ -184,7 +183,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + bio->bi_iter.bi_sector = sector; + bio->bi_private = req; + bio->bi_end_io = nvmet_bio_done; +- bio_set_op_attrs(bio, op, op_flags); ++ bio->bi_opf = op; + + blk_start_plug(&plug); + for_each_sg(req->sg, sg, req->sg_cnt, i) { +@@ -195,7 +194,7 @@ static void nvmet_bdev_execute_rw(struct nvmet_req *req) + bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES)); + bio_set_dev(bio, req->ns->bdev); + bio->bi_iter.bi_sector = sector; +- bio_set_op_attrs(bio, op, op_flags); ++ bio->bi_opf = op; + + bio_chain(bio, prev); + submit_bio(prev); +-- +2.16.4 + diff --git a/patches.suse/nvmet-tcp-Don-t-check-data_len-in-nvmet_tcp_map_data.patch b/patches.suse/nvmet-tcp-Don-t-check-data_len-in-nvmet_tcp_map_data.patch new file mode 100644 index 0000000..71d88fa --- /dev/null +++ b/patches.suse/nvmet-tcp-Don-t-check-data_len-in-nvmet_tcp_map_data.patch @@ -0,0 +1,37 @@ +From: Logan Gunthorpe +Date: Wed, 23 Oct 2019 10:35:39 -0600 +Subject: [PATCH] nvmet-tcp: Don't check data_len in nvmet_tcp_map_data() +Git-commit: e0bace71779d602e419a2f3b35f3bff2cfc638a3 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +None of the other transports check data_len which is verified +in core code. The function should instead check that the sgl length +is non-zero. + +Reviewed-by: Sagi Grimberg +Reviewed-by: Christoph Hellwig +Signed-off-by: Logan Gunthorpe +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/tcp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index d535080b781f..1e2d92f818ad 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -320,7 +320,7 @@ static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd) + struct nvme_sgl_desc *sgl = &cmd->req.cmd->common.dptr.sgl; + u32 len = le32_to_cpu(sgl->length); + +- if (!cmd->req.data_len) ++ if (!len) + return 0; + + if (sgl->type == ((NVME_SGL_FMT_DATA_DESC << 4) | +-- +2.16.4 + diff --git a/patches.suse/nvmet-tcp-Don-t-set-the-request-s-data_len.patch b/patches.suse/nvmet-tcp-Don-t-set-the-request-s-data_len.patch new file mode 100644 index 0000000..00df4c2 --- /dev/null +++ b/patches.suse/nvmet-tcp-Don-t-set-the-request-s-data_len.patch @@ -0,0 +1,45 @@ +From: Logan Gunthorpe +Date: Wed, 23 Oct 2019 10:35:40 -0600 +Subject: [PATCH] nvmet-tcp: Don't set the request's data_len +Git-commit: c73eebc07a0fc8f4ea0f69c65803595d6471bb47 +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +It's not apprporiate for the transports to set the data_len +field of the request which is only used by the core. + +In this case, just use a variable on the stack to store the +length of the sgl for comparison. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Logan Gunthorpe +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/tcp.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index 1e2d92f818ad..3378480c49f6 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -813,13 +813,11 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue) + static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue, + struct nvmet_tcp_cmd *cmd, struct nvmet_req *req) + { ++ size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); + int ret; + +- /* recover the expected data transfer length */ +- req->data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length); +- + if (!nvme_is_write(cmd->req.cmd) || +- req->data_len > cmd->req.port->inline_data_size) { ++ data_len > cmd->req.port->inline_data_size) { + nvmet_prepare_receive_pdu(queue); + return; + } +-- +2.16.4 + diff --git a/patches.suse/nvmet-tcp-set-MSG_MORE-only-if-we-actually-have-more.patch b/patches.suse/nvmet-tcp-set-MSG_MORE-only-if-we-actually-have-more.patch new file mode 100644 index 0000000..f9b448c --- /dev/null +++ b/patches.suse/nvmet-tcp-set-MSG_MORE-only-if-we-actually-have-more.patch @@ -0,0 +1,72 @@ +From: Sagi Grimberg +Date: Thu, 12 Mar 2020 16:06:38 -0700 +Subject: [PATCH] nvmet-tcp: set MSG_MORE only if we actually have more to send +Git-commit: 98fd5c723730f560e5bea919a64ac5b83d45eb72 +Patch-mainline: v5.6-rc7 +References: bsc#1161930 + +When we send PDU data, we want to optimize the tcp stack +operation if we have more data to send. So when we set MSG_MORE +when: +- We have more fragments coming in the batch, or +- We have a more data to send in this PDU +- We don't have a data digest trailer +- We optimize with the SUCCESS flag and omit the NVMe completion + (used if sq_head pointer update is disabled) + +This addresses a regression in QD=1 with SUCCESS flag optimization +as we unconditionally set MSG_MORE when we didn't actually have +more data to send. + +Fixes: 70583295388a ("nvmet-tcp: implement C2HData SUCCESS optimization") +Reported-by: Mark Wunderlich +Tested-by: Mark Wunderlich +Signed-off-by: Sagi Grimberg +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/tcp.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index af674fc0bb1e..5bb5342b8d0c 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -515,7 +515,7 @@ static int nvmet_try_send_data_pdu(struct nvmet_tcp_cmd *cmd) + return 1; + } + +-static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd) ++static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd, bool last_in_batch) + { + struct nvmet_tcp_queue *queue = cmd->queue; + int ret; +@@ -523,9 +523,15 @@ static int nvmet_try_send_data(struct nvmet_tcp_cmd *cmd) + while (cmd->cur_sg) { + struct page *page = sg_page(cmd->cur_sg); + u32 left = cmd->cur_sg->length - cmd->offset; ++ int flags = MSG_DONTWAIT; ++ ++ if ((!last_in_batch && cmd->queue->send_list_len) || ++ cmd->wbytes_done + left < cmd->req.transfer_len || ++ queue->data_digest || !queue->nvme_sq.sqhd_disabled) ++ flags |= MSG_MORE; + + ret = kernel_sendpage(cmd->queue->sock, page, cmd->offset, +- left, MSG_DONTWAIT | MSG_MORE); ++ left, flags); + if (ret <= 0) + return ret; + +@@ -660,7 +666,7 @@ static int nvmet_tcp_try_send_one(struct nvmet_tcp_queue *queue, + } + + if (cmd->state == NVMET_TCP_SEND_DATA) { +- ret = nvmet_try_send_data(cmd); ++ ret = nvmet_try_send_data(cmd, last_in_batch); + if (ret <= 0) + goto done_send; + } +-- +2.16.4 + diff --git a/patches.suse/nvmet-tcp-set-SO_PRIORITY-for-accepted-sockets.patch b/patches.suse/nvmet-tcp-set-SO_PRIORITY-for-accepted-sockets.patch new file mode 100644 index 0000000..ffd5614 --- /dev/null +++ b/patches.suse/nvmet-tcp-set-SO_PRIORITY-for-accepted-sockets.patch @@ -0,0 +1,75 @@ +From: "Wunderlich, Mark" +Date: Thu, 16 Jan 2020 00:46:16 +0000 +Subject: [PATCH] nvmet-tcp: set SO_PRIORITY for accepted sockets +Git-commit: 43cc66892e81bb05283159e489a19cec177e6f9d +Patch-mainline: v5.7-rc1 +References: bsc#1169045 + +Enable ability to associate all sockets related to NVMf TCP traffic +to a priority group that will perform optimized network processing for +this traffic class. Maintain initial default behavior of using priority +of zero. + +Signed-off-by: Kiran Patil +Signed-off-by: Mark Wunderlich +Reviewed-by: Sagi Grimberg +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/tcp.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c +index af674fc0bb1e..cbff1038bdb3 100644 +--- a/drivers/nvme/target/tcp.c ++++ b/drivers/nvme/target/tcp.c +@@ -19,6 +19,16 @@ + + #define NVMET_TCP_DEF_INLINE_DATA_SIZE (4 * PAGE_SIZE) + ++/* Define the socket priority to use for connections were it is desirable ++ * that the NIC consider performing optimized packet processing or filtering. ++ * A non-zero value being sufficient to indicate general consideration of any ++ * possible optimization. Making it a module param allows for alternative ++ * values that may be unique for some NIC implementations. ++ */ ++static int so_priority; ++module_param(so_priority, int, 0644); ++MODULE_PARM_DESC(so_priority, "nvmet tcp socket optimize priority"); ++ + #define NVMET_TCP_RECV_BUDGET 8 + #define NVMET_TCP_SEND_BUDGET 8 + #define NVMET_TCP_IO_WORK_BUDGET 64 +@@ -1433,6 +1443,13 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue) + if (ret) + return ret; + ++ if (so_priority > 0) { ++ ret = kernel_setsockopt(sock, SOL_SOCKET, SO_PRIORITY, ++ (char *)&so_priority, sizeof(so_priority)); ++ if (ret) ++ return ret; ++ } ++ + /* Set socket type of service */ + if (inet->rcv_tos > 0) { + int tos = inet->rcv_tos; +@@ -1622,6 +1639,15 @@ static int nvmet_tcp_add_port(struct nvmet_port *nport) + goto err_sock; + } + ++ if (so_priority > 0) { ++ ret = kernel_setsockopt(port->sock, SOL_SOCKET, SO_PRIORITY, ++ (char *)&so_priority, sizeof(so_priority)); ++ if (ret) { ++ pr_err("failed to set SO_PRIORITY sock opt %d\n", ret); ++ goto err_sock; ++ } ++ } ++ + ret = kernel_bind(port->sock, (struct sockaddr *)&port->addr, + sizeof(port->addr)); + if (ret) { +-- +2.16.4 + diff --git a/patches.suse/nvmet-update-AEN-list-and-array-at-one-place.patch b/patches.suse/nvmet-update-AEN-list-and-array-at-one-place.patch new file mode 100644 index 0000000..03d2927 --- /dev/null +++ b/patches.suse/nvmet-update-AEN-list-and-array-at-one-place.patch @@ -0,0 +1,152 @@ +From: Daniel Wagner +Date: Thu, 30 Jan 2020 10:29:34 -0800 +Subject: [PATCH] nvmet: update AEN list and array at one place +Git-commit: 0f5be6a4ff7b3f8bf3db15f904e3e76797a43d9a +Patch-mainline: v5.6-rc1 +References: bsc#1169045 + +All async events are enqueued via nvmet_add_async_event() which +updates the ctrl->async_event_cmds[] array and additionally an struct +nvmet_async_event is added to the ctrl->async_events list. + +Under normal operations the nvmet_async_event_work() updates again +the ctrl->async_event_cmds and removes the corresponding struct +nvmet_async_event from the list again. Though nvmet_sq_destroy() could +be called which calls nvmet_async_events_free() which only updates the +ctrl->async_event_cmds[] array. + +Add new functions nvmet_async_events_process() and +nvmet_async_events_free() to process async events, update an array and +the list. + +When we destroy submission queue after clearing the aen present on +the ctrl->async list we also loop over ctrl->async_event_cmds[] for +any requests posted by the host for which we don't have the AEN in +the ctrl->async_events list by calling nvmet_async_event_process() +and nvmet_async_events_free(). + +Reviewed-by: Christoph Hellwig +Signed-off-by: Daniel Wagner +[chaitanya.kulkarni@wdc.com + * Loop over and clear out outstanding requests + * Update changelog +] +Signed-off-by: Chaitanya Kulkarni +Signed-off-by: Keith Busch +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/core.c | 63 ++++++++++++++++++++++++++-------------------- + 1 file changed, 36 insertions(+), 27 deletions(-) + +diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c +index 461987f669c5..576de773b4db 100644 +--- a/drivers/nvme/target/core.c ++++ b/drivers/nvme/target/core.c +@@ -129,27 +129,8 @@ static u32 nvmet_async_event_result(struct nvmet_async_event *aen) + return aen->event_type | (aen->event_info << 8) | (aen->log_page << 16); + } + +-static void nvmet_async_events_free(struct nvmet_ctrl *ctrl) +-{ +- struct nvmet_req *req; +- +- while (1) { +- mutex_lock(&ctrl->lock); +- if (!ctrl->nr_async_event_cmds) { +- mutex_unlock(&ctrl->lock); +- return; +- } +- +- req = ctrl->async_event_cmds[--ctrl->nr_async_event_cmds]; +- mutex_unlock(&ctrl->lock); +- nvmet_req_complete(req, NVME_SC_INTERNAL | NVME_SC_DNR); +- } +-} +- +-static void nvmet_async_event_work(struct work_struct *work) ++static void nvmet_async_events_process(struct nvmet_ctrl *ctrl, u16 status) + { +- struct nvmet_ctrl *ctrl = +- container_of(work, struct nvmet_ctrl, async_event_work); + struct nvmet_async_event *aen; + struct nvmet_req *req; + +@@ -159,20 +140,43 @@ static void nvmet_async_event_work(struct work_struct *work) + struct nvmet_async_event, entry); + if (!aen || !ctrl->nr_async_event_cmds) { + mutex_unlock(&ctrl->lock); +- return; ++ break; + } + + req = ctrl->async_event_cmds[--ctrl->nr_async_event_cmds]; +- nvmet_set_result(req, nvmet_async_event_result(aen)); ++ if (status == 0) ++ nvmet_set_result(req, nvmet_async_event_result(aen)); + + list_del(&aen->entry); + kfree(aen); + + mutex_unlock(&ctrl->lock); +- nvmet_req_complete(req, 0); ++ nvmet_req_complete(req, status); + } + } + ++static void nvmet_async_events_free(struct nvmet_ctrl *ctrl) ++{ ++ struct nvmet_req *req; ++ ++ mutex_lock(&ctrl->lock); ++ while (ctrl->nr_async_event_cmds) { ++ req = ctrl->async_event_cmds[--ctrl->nr_async_event_cmds]; ++ mutex_unlock(&ctrl->lock); ++ nvmet_req_complete(req, NVME_SC_INTERNAL | NVME_SC_DNR); ++ mutex_lock(&ctrl->lock); ++ } ++ mutex_unlock(&ctrl->lock); ++} ++ ++static void nvmet_async_event_work(struct work_struct *work) ++{ ++ struct nvmet_ctrl *ctrl = ++ container_of(work, struct nvmet_ctrl, async_event_work); ++ ++ nvmet_async_events_process(ctrl, 0); ++} ++ + void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type, + u8 event_info, u8 log_page) + { +@@ -753,19 +757,24 @@ static void nvmet_confirm_sq(struct percpu_ref *ref) + + void nvmet_sq_destroy(struct nvmet_sq *sq) + { ++ u16 status = NVME_SC_INTERNAL | NVME_SC_DNR; ++ struct nvmet_ctrl *ctrl = sq->ctrl; ++ + /* + * If this is the admin queue, complete all AERs so that our + * queue doesn't have outstanding requests on it. + */ +- if (sq->ctrl && sq->ctrl->sqs && sq->ctrl->sqs[0] == sq) +- nvmet_async_events_free(sq->ctrl); ++ if (ctrl && ctrl->sqs && ctrl->sqs[0] == sq) { ++ nvmet_async_events_process(ctrl, status); ++ nvmet_async_events_free(ctrl); ++ } + percpu_ref_kill_and_confirm(&sq->ref, nvmet_confirm_sq); + wait_for_completion(&sq->confirm_done); + wait_for_completion(&sq->free_done); + percpu_ref_exit(&sq->ref); + +- if (sq->ctrl) { +- nvmet_ctrl_put(sq->ctrl); ++ if (ctrl) { ++ nvmet_ctrl_put(ctrl); + sq->ctrl = NULL; /* allows reusing the queue later */ + } + } +-- +2.16.4 + diff --git a/patches.suse/nvmet-use-bio_io_error-instead-of-duplicating-it.patch b/patches.suse/nvmet-use-bio_io_error-instead-of-duplicating-it.patch new file mode 100644 index 0000000..8498d56 --- /dev/null +++ b/patches.suse/nvmet-use-bio_io_error-instead-of-duplicating-it.patch @@ -0,0 +1,42 @@ +From: Israel Rukshin +Date: Sun, 13 Oct 2019 19:57:32 +0300 +Subject: [PATCH] nvmet: use bio_io_error instead of duplicating it +Git-commit: 4d764bb9a92bc63afc3befe36a0bedfddff1398a +Patch-mainline: v5.5-rc1 +References: bsc#1169045 + +This commit doesn't change any logic. + +Signed-off-by: Israel Rukshin +Reviewed-by: Max Gurtovoy +Reviewed-by: Christoph Hellwig +Signed-off-by: Keith Busch +Signed-off-by: Jens Axboe +Acked-by: Hannes Reinecke +--- + drivers/nvme/target/io-cmd-bdev.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c +index 32008d85172b..f2618dc2ef3a 100644 +--- a/drivers/nvme/target/io-cmd-bdev.c ++++ b/drivers/nvme/target/io-cmd-bdev.c +@@ -261,12 +261,10 @@ static void nvmet_bdev_execute_discard(struct nvmet_req *req) + if (bio) { + bio->bi_private = req; + bio->bi_end_io = nvmet_bio_done; +- if (status) { +- bio->bi_status = BLK_STS_IOERR; +- bio_endio(bio); +- } else { ++ if (status) ++ bio_io_error(bio); ++ else + submit_bio(bio); +- } + } else { + nvmet_req_complete(req, status); + } +-- +2.16.4 + diff --git a/series.conf b/series.conf index 4d50051..4ce84da 100644 --- a/series.conf +++ b/series.conf @@ -4217,6 +4217,13 @@ patches.suse/libata-ahci-Fix-PCS-quirk-application.patch patches.suse/md-raid0-fix-warning-message-for-parameter-default_l.patch patches.suse/io_uring-fix-up-O_NONBLOCK-handling-for-sockets.patch + patches.suse/nvme-fix-possible-deadlock-when-nvme_update_formats-.patch + patches.suse/nvme-retain-split-access-workaround-for-capability-r.patch + patches.suse/nvme-pci-Free-tagset-if-no-IO-queues.patch + patches.suse/nvme-Remove-ADMIN_ONLY-state.patch + patches.suse/nvme-Restart-request-timers-in-resetting-state.patch + patches.suse/nvme-Prevent-resets-during-paused-controller-state.patch + patches.suse/nvme-Wait-for-reset-state-when-required.patch patches.suse/nvme-tcp-Initialize-sk-sk_ll_usec-only-with-NET_RX_B.patch patches.suse/nvme-pci-Set-the-prp2-correctly-when-using-more-than.patch patches.suse/drivers-base-memory.c-don-t-access-uninitialized-mem.patch @@ -4579,6 +4586,7 @@ patches.suse/riscv-init-merge-split-string-literals-in-preprocess.patch patches.suse/riscv-fp-add-missing-__user-pointer-annotations.patch patches.suse/nvme-multipath-fix-possible-io-hang-after-ctrl-recon.patch + patches.suse/nvme-multipath-remove-unused-groups_only-mode-in-ana.patch patches.suse/um-ubd-Entrust-re-queue-to-the-upper-layers.patch patches.suse/io_uring-ensure-we-clear-io_kiocb-result-before-each.patch patches.suse/iocost-don-t-nest-spin_lock_irq-in-ioc_weight_write.patch @@ -5175,7 +5183,31 @@ patches.suse/md-improve-handling-of-bio-with-REQ_PREFLUSH-in-md_f.patch patches.suse/0013-md-no-longer-compare-spare-disk-superblock-events-in.patch patches.suse/loop-fix-no-unmap-write-zeroes-request-behavior.patch + patches.suse/nvme-fc-Sync-nvme-fc-header-to-FC-NVME-2.patch + patches.suse/nvme-fc-and-nvmet-fc-sync-with-FC-NVME-2-header-chan.patch + patches.suse/nvme-fc-Set-new-cmd-set-indicator-in-nvme-fc-cmnd-iu.patch + patches.suse/nvme-fc-clarify-error-messages.patch + patches.suse/nvme-fc-ensure-association_id-is-cleared-regardless-.patch + patches.suse/nvme-introduce-nvme_is_aen_req-function.patch + patches.suse/nvmet-use-bio_io_error-instead-of-duplicating-it.patch + patches.suse/nvmet-add-unlikely-check-at-nvmet_req_alloc_sgl.patch + patches.suse/nvmet-rdma-add-unlikely-check-at-nvmet_rdma_map_sgl_.patch + patches.suse/nvme-introduce-Command-Aborted-By-host-status-code.patch + patches.suse/nvme-move-common-call-to-nvme_cleanup_cmd-to-core-la.patch patches.suse/nvme-resync-include-linux-nvme.h-with-nvmecli.patch + patches.suse/nvme-Cleanup-and-rename-nvme_block_nr.patch + patches.suse/nvme-Introduce-nvme_lba_to_sect.patch + patches.suse/nvmet-tcp-Don-t-check-data_len-in-nvmet_tcp_map_data.patch + patches.suse/nvmet-tcp-Don-t-set-the-request-s-data_len.patch + patches.suse/nvmet-Introduce-common-execute-function-for-get_log_.patch + patches.suse/nvmet-Cleanup-discovery-execute-handlers.patch + patches.suse/nvmet-Introduce-nvmet_dsm_len-helper.patch + patches.suse/nvmet-Remove-the-data_len-field-from-the-nvmet_req-s.patch + patches.suse/nvmet-Open-code-nvmet_req_execute.patch + patches.suse/nvmet-fill-discovery-controller-sn-fr-and-mn-correct.patch + patches.suse/nvmet-clean-up-command-parsing-a-bit.patch + patches.suse/nvmet-add-plugging-for-read-write-when-ns-is-bdev.patch + patches.suse/nvmet-stop-using-bio_set_op_attrs.patch patches.suse/nvme-Fix-parsing-of-ANA-log-page.patch patches.suse/0014-md-raid1-avoid-soft-lockup-under-high-load.patch patches.suse/0015-md-avoid-invalid-memory-access-for-array-sb-dev_role.patch @@ -5192,6 +5224,10 @@ patches.suse/0012-bcache-remove-the-extra-cflags-for-request.o.patch patches.suse/0013-bcache-don-t-export-symbols.patch patches.suse/0016-drivers-md-raid5.c-use-the-new-spelling-of-RWH_WRITE.patch + patches.suse/nvme-Add-hardware-monitoring-support.patch + patches.suse/nvme-Discard-workaround-for-non-conformant-devices.patch + patches.suse/nvme-hwmon-provide-temperature-min-and-max-values-fo.patch + patches.suse/nvme-hwmon-add-quirk-to-avoid-changing-temperature-t.patch patches.suse/nbd-prevent-memory-leak.patch patches.suse/dm-writecache-handle-REQ_FUA.patch patches.suse/dm-zoned-reduce-overhead-of-backing-device-checks.patch @@ -7746,6 +7782,17 @@ patches.suse/0006-dm-thin-metadata-Add-support-for-a-pre-commit-callba.patch patches.suse/0007-dm-thin-Flush-data-device-before-committing-metadata.patch patches.suse/net-make-socket-read-write_iter-honor-IOCB_NOWAIT.patch + patches.suse/nvme-rdma-Avoid-preallocating-big-SGL-for-data.patch + patches.suse/nvme-fc-Avoid-preallocating-big-SGL-for-data.patch + patches.suse/nvme_fc-add-module-to-ops-template-to-allow-module-r.patch + patches.suse/nvme-add-error-message-on-mismatching-controller-ids.patch + patches.suse/nvme-else-following-return-is-not-needed.patch + patches.suse/nvme-fc-fix-double-free-scenarios-on-hw-queues.patch + patches.suse/nvme-Namepace-identification-descriptor-list-is-opti.patch + patches.suse/nvme-pci-Remove-last_cq_head.patch + patches.suse/nvme-pci-Fix-write-and-poll-queue-types.patch + patches.suse/nvme-pci-Limit-write-queue-sizes-to-possible-cpus.patch + patches.suse/nvme-pci-Fix-read-queue-count.patch patches.suse/block-fix-check-bi_size-overflow-before-merge.patch patches.suse/raid5-need-to-set-STRIPE_HANDLE-for-batch-head.patch patches.suse/0020-md-raid1-check-rdev-before-reference-in-raid1_sync_r.patch @@ -8282,6 +8329,7 @@ patches.suse/mtd-rawnand-stm32_fmc2-avoid-to-lock-the-CPU-bus.patch patches.suse/mtd-onenand-omap2-Pass-correct-flags-for-prep_dma_me.patch patches.suse/nvme-Translate-more-status-codes-to-blk_status_t.patch + patches.suse/nvmet-fix-per-feat-data-len-for-get_feature.patch patches.suse/tty-always-relink-the-port.patch patches.suse/serdev-Don-t-claim-unsupported-ACPI-serial-devices.patch patches.suse/staging-vt6656-Fix-non-zero-logical-return-of-usb_co.patch @@ -9728,6 +9776,11 @@ patches.suse/0025-bcache-check-return-value-of-prio_read.patch patches.suse/block-bfq-do-not-plug-I-O-for-bfq_queues-with-no-pro.patch patches.suse/block-bfq-get-a-ref-to-a-group-when-adding-it-to-a-s.patch + patches.suse/nvmet-fix-dsm-failure-when-payload-does-not-match-sg.patch + patches.suse/nvme-pci-remove-nvmeq-tags.patch + patches.suse/nvmet-Fix-error-print-message-at-nvmet_install_queue.patch + patches.suse/nvmet-Fix-controller-use-after-free.patch + patches.suse/nvmet-update-AEN-list-and-array-at-one-place.patch patches.suse/eventfd-track-eventfd_signal-recursion-depth.patch patches.suse/aio-prevent-potential-eventfd-recursion-on-poll.patch patches.suse/tracing-fix-very-unlikely-race-of-registering-two-stat-tracers.patch @@ -9992,6 +10045,9 @@ patches.suse/0026-bcache-ignore-pending-signals-when-creating-gc-and-a.patch patches.suse/0027-bcache-Revert-bcache-shrink-btree-node-cache-after-b.patch patches.suse/0028-bcache-remove-macro-nr_to_fifo_front.patch + patches.suse/nvme-tcp-fix-bug-on-double-requeue-when-send-fails.patch + patches.suse/nvme-prevent-warning-triggered-by-nvme_stop_keep_ali.patch + patches.suse/nvme-pci-move-cqe-check-after-device-shutdown.patch patches.suse/nvme-fix-the-parameter-order-for-nvme_get_log-in-nvm.patch patches.suse/edac-mc-fix-use-after-free-and-memleaks-during-device-removal.patch patches.suse/edac-sysfs-remove-csrow-objects-on-errors.patch @@ -10105,6 +10161,10 @@ patches.suse/watchdog-da9062-do-not-ping-the-hw-during-stop.patch patches.suse/powerpc-tm-Fix-clearing-MSR-TS-in-current-when-recla.patch patches.suse/0001-xen-Enable-interrupts-when-calling-_cond_resched.patch + patches.suse/nvme-pci-Add-sleep-quirk-for-Samsung-and-Toshiba-dri.patch + patches.suse/nvme-pci-Use-single-IRQ-vector-for-old-Apple-models.patch + patches.suse/nvme-Fix-uninitialized-variable-warning.patch + patches.suse/nvme-multipath-Fix-memory-leak-with-ana_log_buf.patch patches.suse/io_uring-prevent-sq_thread-from-spinning-when-it-sho.patch patches.suse/io_uring-fix-__io_iopoll_check-deadlock-in-io_sq_thr.patch patches.suse/x86-cpu-amd-enable-the-fixed-instructions-retired-counter-irperf.patch @@ -10159,6 +10219,7 @@ patches.suse/ACPI-watchdog-Fix-gas-access_width-usage.patch patches.suse/acpi-watchdog-set-default-timeout-in-probe.patch patches.suse/blktrace-Protect-q-blk_trace-with-RCU.patch + patches.suse/nvme-pci-Hold-cq_poll_lock-while-completing-CQEs.patch patches.suse/pci-brcmstb-fix-build-on-32bit-arm-platforms-with-older-compilers.patch patches.suse/i2c-altera-Fix-potential-integer-overflow.patch patches.suse/kvm-vmx-check-descriptor-table-exits-on-instruction-emulation @@ -10387,6 +10448,8 @@ patches.suse/iio-chemical-sps30-fix-missing-triggered-buffer-depe.patch patches.suse/intel_th-Fix-user-visible-error-codes.patch patches.suse/intel_th-pci-Add-Elkhart-Lake-CPU-support.patch + patches.suse/nvme-rdma-Avoid-double-freeing-of-async-event-data.patch + patches.suse/nvmet-tcp-set-MSG_MORE-only-if-we-actually-have-more.patch patches.suse/mm-slub-prevent-kmalloc_node-crashes-and-memory-leaks.patch patches.suse/x86-mm-split-vmalloc_sync_all.patch patches.suse/gpiolib-Fix-irq_disable-semantics.patch @@ -10459,6 +10522,18 @@ patches.suse/block-bfq-fix-use-after-free-in-bfq_idle_slice_timer.patch patches.suse/block-diskstats-more-accurate-approximation-of-io_ti.patch patches.suse/block-keep-bdi-io_pages-in-sync-with-max_sectors_kb-.patch + patches.suse/nvme-remove-unused-return-code-from-nvme_alloc_ns.patch + patches.suse/nvmet-configfs-code-cleanup.patch + patches.suse/nvmet-make-ctrl-id-configurable.patch + patches.suse/nvmet-make-ctrl-model-configurable.patch + patches.suse/nvmet-check-sscanf-value-for-subsys-serial-attr.patch + patches.suse/nvme-tcp-Set-SO_PRIORITY-for-all-host-sockets.patch + patches.suse/nvmet-tcp-set-SO_PRIORITY-for-accepted-sockets.patch + patches.suse/nvme-code-cleanup-nvme_identify_ns_desc.patch + patches.suse/nvme-log-additional-message-for-controller-status.patch + patches.suse/nvme-Check-for-readiness-more-quickly-to-speed-up-bo.patch + patches.suse/nvme-multipath-do-not-reset-on-unknown-status.patch + patches.suse/nvme-fabrics-Use-scnprintf-for-avoiding-potential-bu.patch patches.suse/seccomp-Add-missing-compat_ioctl-for-notify.patch patches.suse/pstore-pstore_ftrace_seq_next-should-increase-positi.patch patches.suse/edac-mc-change-mci-device-removal-to-use-put_device.patch @@ -10915,6 +10990,14 @@ patches.suse/powerpc-pseries-Fix-MCE-handling-on-pseries.patch patches.suse/powerpc-pseries-ddw-Extend-upper-limit-for-huge-DMA-.patch patches.suse/Revert-powerpc-64-irq_work-avoid-interrupt-when-call.patch + patches.suse/nvme-fcloop-fix-deallocation-of-working-context.patch + patches.suse/nvme-rdma-Replace-comma-with-a-semicolon.patch + patches.suse/nvmet-fc-fix-typo-in-comment.patch + patches.suse/nvme-inherit-stable-pages-constraint-in-the-mpath-st.patch + patches.suse/nvmet-fix-NULL-dereference-when-removing-a-referral.patch + patches.suse/nvmet-rdma-fix-bonding-failover-possible-NULL-deref.patch + patches.suse/nvme-fix-deadlock-caused-by-ANA-update-wrong-locking.patch + patches.suse/nvme-fc-Revert-add-module-to-ops-template-to-allow-m.patch patches.suse/scsi-lpfc-Fix-kasan-slab-out-of-bounds-error-in-lpfc.patch patches.suse/scsi-lpfc-Fix-lockdep-error-register-non-static-key.patch patches.suse/scsi-lpfc-Fix-lpfc-overwrite-of-sg_cnt-field-in-nvme.patch @@ -10963,6 +11046,34 @@ patches.suse/0033-lib-raid6-test-fix-build-on-distros-whose-bin-sh-is-.patch patches.suse/time-namespace-Add-max_time_namespaces-ucount.patch + # git://git.infradead.org/nvme.git nvme-5.8 + patches.suse/nvme-fc-Sync-header-to-FC-NVME-2-rev-1.08.patch + patches.suse/nvme-fc-and-nvmet-fc-revise-LLDD-api-for-LS-receptio.patch + patches.suse/nvme-fc-nvmet-fc-refactor-for-common-LS-definitions.patch + patches.suse/nvmet-fc-Better-size-LS-buffers.patch + patches.suse/nvme-fc-Ensure-private-pointers-are-NULL-if-no-data.patch + patches.suse/nvme-fc-convert-assoc_active-flag-to-bit-op.patch + patches.suse/nvme-fc-Update-header-and-host-for-common-definition.patch + patches.suse/nvmet-fc-Update-target-for-common-definitions-for-LS.patch + patches.suse/nvme-fc-Add-Disconnect-Association-Rcv-support.patch + patches.suse/nvmet-fc-add-LS-failure-messages.patch + patches.suse/nvmet-fc-perform-small-cleanups-on-unneeded-checks.patch + patches.suse/nvmet-fc-track-hostport-handle-for-associations.patch + patches.suse/nvmet-fc-rename-ls_list-to-ls_rcv_list.patch + patches.suse/nvmet-fc-Add-Disconnect-Association-Xmt-support.patch + patches.suse/nvme-fcloop-refactor-to-enable-target-to-host-LS.patch + patches.suse/nvme-fcloop-add-target-to-host-LS-request-support.patch + patches.suse/lpfc-Refactor-lpfc-nvme-headers.patch + patches.suse/lpfc-Refactor-nvmet_rcv_ctx-to-create-lpfc_async_xch.patch + patches.suse/lpfc-Commonize-lpfc_async_xchg_ctx-state-and-flag-de.patch + patches.suse/lpfc-Refactor-NVME-LS-receive-handling.patch + patches.suse/lpfc-Refactor-Send-LS-Request-support.patch + patches.suse/lpfc-Refactor-Send-LS-Abort-support.patch + patches.suse/lpfc-Refactor-Send-LS-Response-support.patch + patches.suse/lpfc-nvme-Add-Receive-LS-Request-and-Send-LS-Respons.patch + patches.suse/lpfc-nvmet-Add-support-for-NVME-LS-request-hosthandl.patch + patches.suse/lpfc-nvmet-Add-Send-LS-Request-and-Abort-LS-Request-.patch + ######################################################## # end of sorted patches ########################################################