lpfc: nvme: Add Receive LS Request and Send LS Response support to nvme
authorJames Smart <jsmart2021@gmail.com>
Tue, 31 Mar 2020 16:50:09 +0000 (09:50 -0700)
committerJens Axboe <axboe@kernel.dk>
Sat, 9 May 2020 22:18:34 +0000 (16:18 -0600)
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 <paul.ely@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/scsi/lpfc/lpfc_nvme.c

index 406f71b327a1e0397e39989de189d59d7a2e92e4..21bbccf0dc313b4624119d3fddb1d7f9b1403c6f 100644 (file)
@@ -402,6 +402,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
  */
@@ -409,6 +413,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;
 }
 
@@ -860,6 +898,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.
@@ -2005,6 +2074,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,
@@ -2200,6 +2270,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);
        }