]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
mi: Implement Namespace Management command and create/delete helpers
authorJeremy Kerr <jk@codeconstruct.com.au>
Wed, 8 Jun 2022 08:40:20 +0000 (16:40 +0800)
committerJeremy Kerr <jk@codeconstruct.com.au>
Sun, 14 Aug 2022 02:53:57 +0000 (10:53 +0800)
This change adds a function for the base Namespace Management command:

    nvme_mi_admin_ns_mgmt(...)

And helpers for the create and delete actions.

Signed-off-by: Jeremy Kerr <jk@codeconstruct.com.au>
src/libnvme-mi.map
src/nvme/mi.c
src/nvme/mi.h
test/mi.c

index b6007b22d3aadcd2947100a609706be9522937f5..289ef56c20febb6d73d187eb2c73373f079cdead 100644 (file)
@@ -16,6 +16,7 @@ LIBNVME_MI_1_1 {
                nvme_mi_admin_get_log;
                nvme_mi_admin_get_features;
                nvme_mi_admin_set_features;
+               nvme_mi_admin_ns_mgmt;
                nvme_mi_admin_xfer;
                nvme_mi_admin_security_send;
                nvme_mi_admin_security_recv;
index cb3a0bc93fc3528f70060a12cacca703e7239017..68e88acec2f2ea5e69601ea9baf5106e53ef454b 100644 (file)
@@ -729,6 +729,48 @@ int nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl,
        return 0;
 }
 
+int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl,
+                         struct nvme_ns_mgmt_args *args)
+{
+       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;
+
+       if (args->args_size < sizeof(*args))
+               return -EINVAL;
+
+       nvme_mi_admin_init_req(&req, &req_hdr, ctrl->id,
+                              nvme_admin_ns_mgmt);
+
+       req_hdr.cdw1 = cpu_to_le32(args->nsid);
+       req_hdr.cdw10 = cpu_to_le32(args->sel & 0xf);
+       req_hdr.cdw11 = cpu_to_le32(args->csi << 24);
+       if (args->ns) {
+               req.data = args->ns;
+               req.data_len = sizeof(*args->ns);
+               req_hdr.dlen = cpu_to_le32(sizeof(*args->ns));
+               req_hdr.flags = 0x1;
+       }
+
+       nvme_mi_calc_req_mic(&req);
+
+       nvme_mi_admin_init_resp(&resp, &resp_hdr);
+
+       rc = nvme_mi_submit(ctrl->ep, &req, &resp);
+       if (rc)
+               return rc;
+
+       if (resp_hdr.status)
+               return resp_hdr.status;
+
+       if (args->result)
+               *args->result = le32_to_cpu(resp_hdr.cdw0);
+
+       return 0;
+}
+
 static int nvme_mi_read_data(nvme_mi_ep_t ep, __u32 cdw0,
                             void *data, size_t *data_len)
 {
index c21598e2e548da8c5437136f6cc738eb81660531..137b4277679321c080d56ff236c3f052ceda0a4f 100644 (file)
@@ -1379,4 +1379,67 @@ static inline int nvme_mi_admin_get_features_simple(nvme_mi_ctrl_t ctrl,
 int nvme_mi_admin_set_features(nvme_mi_ctrl_t ctrl,
                               struct nvme_set_features_args *args);
 
+/**
+ * nvme_mi_admin_ns_mgmt - Issue a Namespace Management command
+ * @ctrl: Controller to send command to
+ * @args: Namespace management command arguments
+ *
+ * Issues a Namespace Management command to @ctrl, with arguments specified
+ * from @args.
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl,
+                         struct nvme_ns_mgmt_args *args);
+
+/**
+ * nvme_mi_admin_ns_mgmt_create - Helper for Namespace Management Create command
+ * @ctrl: Controller to send command to
+ * @ns: New namespace parameters
+ * @csi: Command Set Identifier for new NS
+ * @nsid: Set to new namespace ID on create
+ *
+ * Issues a Namespace Management (Create) command to @ctrl, to create a
+ * new namespace specified by @ns, using command set @csi. On success,
+ * the new namespace ID will be written to @nsid.
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static inline int nvme_mi_admin_ns_mgmt_create(nvme_mi_ctrl_t ctrl,
+                                              struct nvme_id_ns *ns,
+                                              __u8 csi, __u32 *nsid)
+{
+       struct nvme_ns_mgmt_args args = {
+               .args_size = sizeof(args),
+               .csi = csi,
+               .nsid = NVME_NSID_NONE,
+               .sel = NVME_NS_MGMT_SEL_CREATE,
+               .ns = ns,
+               .result = nsid,
+       };
+
+       return nvme_mi_admin_ns_mgmt(ctrl, &args);
+}
+
+/**
+ * nvme_mi_admin_ns_mgmt_delete - Helper for Namespace Management Delete command
+ * @ctrl: Controller to send command to
+ * @nsid: Namespace ID to delete
+ *
+ * Issues a Namespace Management (Delete) command to @ctrl, to delete the
+ * namespace with id @nsid.
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static inline int nvme_mi_admin_ns_mgmt_delete(nvme_mi_ctrl_t ctrl, __u32 nsid)
+{
+       struct nvme_ns_mgmt_args args = {
+               .args_size = sizeof(args),
+               .nsid = nsid,
+               .sel = NVME_NS_MGMT_SEL_DELETE,
+       };
+
+       return nvme_mi_admin_ns_mgmt(ctrl, &args);
+}
+
 #endif /* _LIBNVME_MI_MI_H */
index 183f634d2773c16f39b2fe92629b016bc7f55aec..4058b5df411402296b428158cc081fc833a865a5 100644 (file)
--- a/test/mi.c
+++ b/test/mi.c
@@ -1170,6 +1170,96 @@ static void test_admin_id_nsid_ctrl_list(struct nvme_mi_ep *ep)
        assert(!rc);
 }
 
+static int test_admin_ns_mgmt_cb(struct nvme_mi_ep *ep,
+                                struct nvme_mi_req *req,
+                                struct nvme_mi_resp *resp,
+                                void *data)
+{
+       __u8 *rq_hdr, *rs_hdr, sel, csi;
+       struct nvme_id_ns *id;
+       __u32 nsid;
+
+       rq_hdr = (__u8 *)req->hdr;
+       assert(rq_hdr[4] == nvme_admin_ns_mgmt);
+
+       sel = rq_hdr[44];
+       csi = rq_hdr[45];
+       nsid = rq_hdr[11] << 24 | rq_hdr[10] << 16 | rq_hdr[9] << 8 | rq_hdr[8];
+
+       rs_hdr = (__u8 *)resp->hdr;
+
+       switch (sel) {
+       case NVME_NS_MGMT_SEL_CREATE:
+               assert(req->data_len == sizeof(struct nvme_id_ns));
+               id = req->data;
+
+               /* No NSID on created namespaces */
+               assert(nsid == 0);
+               assert(csi == 0);
+
+               /* allow operations on nsze == 42, reject others */
+               if (le64_to_cpu(id->nsze) != 42) {
+                       rs_hdr[4] = 0;
+                       /* response cdw0 is created NSID */
+                       rs_hdr[8] = 0x04;
+                       rs_hdr[9] = 0x03;
+                       rs_hdr[10] = 0x02;
+                       rs_hdr[11] = 0x01;
+               } else {
+                       rs_hdr[4] = NVME_MI_RESP_INVALID_PARAM;
+               }
+               break;
+
+       case NVME_NS_MGMT_SEL_DELETE:
+               assert(req->data_len == 0);
+               /* NSID required on delete */
+               assert(nsid == 0x05060708);
+               break;
+
+       default:
+               assert(0);
+       }
+
+       test_transport_resp_calc_mic(resp);
+
+       return 0;
+}
+
+static void test_admin_ns_mgmt_create(struct nvme_mi_ep *ep)
+{
+       struct nvme_id_ns nsid;
+       nvme_mi_ctrl_t ctrl;
+       __u32 ns;
+       int rc;
+
+       test_set_transport_callback(ep, test_admin_ns_mgmt_cb, NULL);
+
+       ctrl = nvme_mi_init_ctrl(ep, 5);
+       assert(ctrl);
+
+       rc = nvme_mi_admin_ns_mgmt_create(ctrl, &nsid, 0, &ns);
+       assert(!rc);
+       assert(ns == 0x01020304);
+
+       nsid.nsze = 42;
+       rc = nvme_mi_admin_ns_mgmt_create(ctrl, &nsid, 0, &ns);
+       assert(rc);
+}
+
+static void test_admin_ns_mgmt_delete(struct nvme_mi_ep *ep)
+{
+       nvme_mi_ctrl_t ctrl;
+       int rc;
+
+       test_set_transport_callback(ep, test_admin_ns_mgmt_cb, NULL);
+
+       ctrl = nvme_mi_init_ctrl(ep, 5);
+       assert(ctrl);
+
+       rc = nvme_mi_admin_ns_mgmt_delete(ctrl, 0x05060708);
+       assert(!rc);
+}
+
 #define DEFINE_TEST(name) { #name, test_ ## name }
 struct test {
        const char *name;
@@ -1200,6 +1290,8 @@ struct test {
        DEFINE_TEST(admin_id_alloc_ns),
        DEFINE_TEST(admin_id_active_ns),
        DEFINE_TEST(admin_id_nsid_ctrl_list),
+       DEFINE_TEST(admin_ns_mgmt_create),
+       DEFINE_TEST(admin_ns_mgmt_delete),
 };
 
 static void run_test(struct test *test, FILE *logfd, nvme_mi_ep_t ep)