]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
mi: add nvme_mi_admin_admin_passthru
authorJinliang Wang <jinliangw@google.com>
Fri, 28 Oct 2022 15:42:10 +0000 (08:42 -0700)
committerDaniel Wagner <dwagner@suse.de>
Mon, 7 Nov 2022 10:37:45 +0000 (11:37 +0100)
Similar to nvme_admin_passthru, send a customized NVMe Admin command
request message and get the corresponding response message.
Currently, it only supports data xfer size <= 4096.

Signed-off-by: Jinliang Wang <jinliangw@google.com>
[dwagner: refactored has_*_data checks]
Signed-off-by: Daniel Wagner <dwagner@suse.de>
src/libnvme-mi.map
src/nvme/mi.c
src/nvme/mi.h

index fad10c9cba5ea55fbf7b86387a7f62f3f8fc77c7..739f135e59f9629c2681f264d9fc7ded0793f28e 100644 (file)
@@ -1,6 +1,7 @@
 LIBNVME_MI_1_3 {
        global:
                nvme_mi_set_probe_enabled;
+               nvme_mi_admin_admin_passthru;
 };
 
 LIBNVME_MI_1_2 {
index 34bfa42ce2aaa31da8c907c051a678b2f498c126..20f5117c65446aabc543fa3d4503ac1c5303ac59 100644 (file)
@@ -624,6 +624,93 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl,
        return 0;
 }
 
+int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags,
+                                __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3,
+                                __u32 cdw10, __u32 cdw11, __u32 cdw12,
+                                __u32 cdw13, __u32 cdw14, __u32 cdw15,
+                                __u32 data_len, void *data, __u32 metadata_len,
+                                void *metadata, __u32 timeout_ms, __u32 *result)
+{
+       /* Input parameters flags, rsvd, metadata, metadata_len are not used */
+       struct nvme_mi_admin_resp_hdr resp_hdr;
+       struct nvme_mi_admin_req_hdr req_hdr;
+       struct nvme_mi_resp resp;
+       struct nvme_mi_req req;
+       int rc;
+       int direction = opcode & 0x3;
+       bool has_write_data = false;
+       bool has_read_data = false;
+
+       if (direction == NVME_DATA_TFR_BIDIRECTIONAL) {
+               nvme_msg(ctrl->ep->root, LOG_ERR,
+                       "nvme_mi_admin_admin_passthru doesn't support bidirectional commands\n");
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (data_len > 4096) {
+               nvme_msg(ctrl->ep->root, LOG_ERR,
+                       "nvme_mi_admin_admin_passthru doesn't support data_len over 4096 bytes.\n");
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (data != NULL && data_len != 0) {
+               if (direction == NVME_DATA_TFR_HOST_TO_CTRL)
+                       has_write_data = true;
+               if (direction == NVME_DATA_TFR_CTRL_TO_HOST)
+                       has_read_data = true;
+       }
+
+       if (timeout_ms > nvme_mi_ep_get_timeout(ctrl->ep)) {
+               /* Set timeout if user needs a bigger timeout */
+               nvme_mi_ep_set_timeout(ctrl->ep, timeout_ms);
+       }
+
+       nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id, opcode);
+       req_hdr.cdw1 = cpu_to_le32(nsid);
+       req_hdr.cdw2 = cpu_to_le32(cdw2);
+       req_hdr.cdw3 = cpu_to_le32(cdw3);
+       req_hdr.cdw10 = cpu_to_le32(cdw10);
+       req_hdr.cdw11 = cpu_to_le32(cdw11);
+       req_hdr.cdw12 = cpu_to_le32(cdw12);
+       req_hdr.cdw13 = cpu_to_le32(cdw13);
+       req_hdr.cdw14 = cpu_to_le32(cdw14);
+       req_hdr.cdw15 = cpu_to_le32(cdw15);
+       req_hdr.doff = 0;
+       if (data_len != 0) {
+               req_hdr.dlen = cpu_to_le32(data_len);
+               /* Bit 0 set to 1 means DLEN contains a value */
+               req_hdr.flags = 0x1;
+       }
+
+       if (has_write_data) {
+               req.data = data;
+               req.data_len = data_len;
+       }
+
+       nvme_mi_calc_req_mic(&req);
+
+       nvme_mi_admin_init_resp(&resp, &resp_hdr);
+
+       if (has_read_data) {
+               resp.data = data;
+               resp.data_len = data_len;
+       }
+
+       rc = nvme_mi_submit(ctrl->ep, &req, &resp);
+       if (rc)
+               return rc;
+
+       rc = nvme_mi_admin_parse_status(&resp, result);
+       if (has_read_data && (resp.data_len != data_len)) {
+               errno = EPROTO;
+               return -1;
+       }
+
+       return 0;
+}
+
 int nvme_mi_admin_identify_partial(nvme_mi_ctrl_t ctrl,
                                   struct nvme_identify_args *args,
                                   off_t offset, size_t size)
index be37d67fb8fbd16ef04d8d7a5ce73cf06c8da92a..565915956b9408c55bf98d586ec97856b6e8e26c 100644 (file)
@@ -966,6 +966,46 @@ int nvme_mi_admin_xfer(nvme_mi_ctrl_t ctrl,
                       off_t resp_data_offset,
                       size_t *resp_data_size);
 
+/**
+ * nvme_mi_admin_admin_passthru() - Submit an nvme admin passthrough command
+ * @ctrl: Controller to send command to
+ * @opcode:    The nvme admin command to send
+ * @flags:     NVMe command flags (not used)
+ * @rsvd:      Reserved for future use
+ * @nsid:      Namespace identifier
+ * @cdw2:      Command dword 2
+ * @cdw3:      Command dword 3
+ * @cdw10:     Command dword 10
+ * @cdw11:     Command dword 11
+ * @cdw12:     Command dword 12
+ * @cdw13:     Command dword 13
+ * @cdw14:     Command dword 14
+ * @cdw15:     Command dword 15
+ * @data_len:  Length of the data transferred in this command in bytes
+ * @data:      Pointer to user address of the data buffer
+ * @metadata_len:Length of metadata transferred in this command(not used)
+ * @metadata:  Pointer to user address of the metadata buffer(not used)
+ * @timeout_ms:        How long to wait for the command to complete
+ * @result:    Optional field to return the result from the CQE dword 0
+ *
+ * Send a customized NVMe Admin command request message and get the corresponding
+ * response message.
+ *
+ * This interface supports no data, host to controller and controller to
+ * host but it doesn't support bidirectional data transfer.
+ * Also this interface only supports data transfer size range [0, 4096] (bytes)
+ * so the & data_len parameter must be less than 4097.
+ *
+ * Return: The nvme command status if a response was received (see
+ * &enum nvme_status_field) or -1 with errno set otherwise.
+ */
+int nvme_mi_admin_admin_passthru(nvme_mi_ctrl_t ctrl, __u8 opcode, __u8 flags,
+                                __u16 rsvd, __u32 nsid, __u32 cdw2, __u32 cdw3,
+                                __u32 cdw10, __u32 cdw11, __u32 cdw12,
+                                __u32 cdw13, __u32 cdw14, __u32 cdw15,
+                                __u32 data_len, void *data, __u32 metadata_len,
+                                void *metadata, __u32 timeout_ms, __u32 *result);
+
 /**
  * nvme_mi_admin_identify_partial() - Perform an Admin identify command,
  * and retrieve partial response data.