]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
mi: Implement NS attach command and helpers
authorJeremy Kerr <jk@codeconstruct.com.au>
Tue, 19 Jul 2022 08:55:40 +0000 (16:55 +0800)
committerJeremy Kerr <jk@codeconstruct.com.au>
Sun, 14 Aug 2022 02:54:11 +0000 (10:54 +0800)
This change adds support for the NVMe Namespace Attach Admin command:

    nvme_mi_admin_ns_attach

plus a couple of helpers for constructing the attach and detach args:

    nvme_mi_admin_ns_attach_ctrls
    nvme_mi_admin_ns_detach_ctrls

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 289ef56c20febb6d73d187eb2c73373f079cdead..d20766a080d7941fd4dfcdf7cb581ff10fa7bf7b 100644 (file)
@@ -17,6 +17,7 @@ LIBNVME_MI_1_1 {
                nvme_mi_admin_get_features;
                nvme_mi_admin_set_features;
                nvme_mi_admin_ns_mgmt;
+               nvme_mi_admin_ns_attach;
                nvme_mi_admin_xfer;
                nvme_mi_admin_security_send;
                nvme_mi_admin_security_recv;
index 68e88acec2f2ea5e69601ea9baf5106e53ef454b..5440f7e58e59aa6cd06a2be6b3da6f103c120766 100644 (file)
@@ -771,6 +771,45 @@ int nvme_mi_admin_ns_mgmt(nvme_mi_ctrl_t ctrl,
        return 0;
 }
 
+int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl,
+                           struct nvme_ns_attach_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_attach);
+
+       req_hdr.cdw1 = cpu_to_le32(args->nsid);
+       req_hdr.cdw10 = cpu_to_le32(args->sel & 0xf);
+       req.data = args->ctrlist;
+       req.data_len = sizeof(*args->ctrlist);
+       req_hdr.dlen = cpu_to_le32(sizeof(*args->ctrlist));
+       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 137b4277679321c080d56ff236c3f052ceda0a4f..a0e63942a57432706b618526b5c24bfe85b1005c 100644 (file)
@@ -1442,4 +1442,58 @@ static inline int nvme_mi_admin_ns_mgmt_delete(nvme_mi_ctrl_t ctrl, __u32 nsid)
        return nvme_mi_admin_ns_mgmt(ctrl, &args);
 }
 
+/**
+ * nvme_mi_admin_ns_attach() - Attach or detach namespace to controller(s)
+ * @ctrl: Controller to send command to
+ * @args: Namespace Attach command arguments
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl,
+                           struct nvme_ns_attach_args *args);
+
+/**
+ * nvme_mi_admin_ns_attach_ctrls() - Attach namespace to controllers
+ * @ctrl: Controller to send command to
+ * @nsid: Namespace ID to attach
+ * @ctrlist: Controller list to modify attachment state of nsid
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static inline int nvme_mi_admin_ns_attach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid,
+                                               struct nvme_ctrl_list *ctrlist)
+{
+       struct nvme_ns_attach_args args = {
+               .result = NULL,
+               .ctrlist = ctrlist,
+               .args_size = sizeof(args),
+               .nsid = nsid,
+               .sel = NVME_NS_ATTACH_SEL_CTRL_ATTACH,
+       };
+
+       return nvme_mi_admin_ns_attach(ctrl, &args);
+}
+
+/**
+ * nvme_mi_admin_ns_detach_ctrls() - Detach namespace from controllers
+ * @ctrl: Controller to send command to
+ * @nsid: Namespace ID to detach
+ * @ctrlist: Controller list to modify attachment state of nsid
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static inline int nvme_mi_admin_ns_detach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid,
+                                               struct nvme_ctrl_list *ctrlist)
+{
+       struct nvme_ns_attach_args args = {
+               .result = NULL,
+               .ctrlist = ctrlist,
+               .args_size = sizeof(args),
+               .nsid = nsid,
+               .sel = NVME_NS_ATTACH_SEL_CTRL_DEATTACH,
+       };
+
+       return nvme_mi_admin_ns_attach(ctrl, &args);
+}
+
 #endif /* _LIBNVME_MI_MI_H */
index 4058b5df411402296b428158cc081fc833a865a5..aecbb566c0bb030a4bfd3c296e0fb8f23047e01d 100644 (file)
--- a/test/mi.c
+++ b/test/mi.c
@@ -1260,6 +1260,97 @@ static void test_admin_ns_mgmt_delete(struct nvme_mi_ep *ep)
        assert(!rc);
 }
 
+struct attach_op {
+       enum {
+               NS_ATTACH,
+               NS_DETACH,
+       } op;
+       struct nvme_ctrl_list *list;
+};
+
+static int test_admin_ns_attach_cb(struct nvme_mi_ep *ep,
+                                  struct nvme_mi_req *req,
+                                  struct nvme_mi_resp *resp,
+                                  void *data)
+{
+       struct attach_op *op = data;
+       __u8 *rq_hdr, sel;
+       __u32 nsid;
+
+       rq_hdr = (__u8 *)req->hdr;
+       assert(rq_hdr[4] == nvme_admin_ns_attach);
+
+       sel = rq_hdr[44];
+       nsid = rq_hdr[11] << 24 | rq_hdr[10] << 16 | rq_hdr[9] << 8 | rq_hdr[8];
+
+       assert(req->data_len == sizeof(*op->list));
+
+       assert(nsid == 0x02030405);
+       switch (op->op) {
+       case NS_ATTACH:
+               assert(sel == NVME_NS_ATTACH_SEL_CTRL_ATTACH);
+               break;
+       case NS_DETACH:
+               assert(sel == NVME_NS_ATTACH_SEL_CTRL_DEATTACH);
+               break;
+       default:
+               assert(0);
+       }
+
+       assert(!memcmp(req->data, op->list, sizeof(*op->list)));
+
+       test_transport_resp_calc_mic(resp);
+
+       return 0;
+}
+
+static void test_admin_ns_attach(struct nvme_mi_ep *ep)
+{
+       struct nvme_ctrl_list list = { 0 };
+       struct attach_op aop;
+       nvme_mi_ctrl_t ctrl;
+       int rc;
+
+       list.num = cpu_to_le16(2);
+       list.identifier[0] = 4;
+       list.identifier[1] = 5;
+
+       aop.op = NS_ATTACH;
+       aop.list = &list;
+
+       test_set_transport_callback(ep, test_admin_ns_attach_cb, &aop);
+
+       ctrl = nvme_mi_init_ctrl(ep, 5);
+       assert(ctrl);
+
+       rc = nvme_mi_admin_ns_attach_ctrls(ctrl, 0x02030405, &list);
+       assert(!rc);
+}
+
+static void test_admin_ns_detach(struct nvme_mi_ep *ep)
+{
+       struct nvme_ctrl_list list = { 0 };
+       struct attach_op aop;
+       nvme_mi_ctrl_t ctrl;
+       int rc;
+
+       list.num = cpu_to_le16(2);
+       list.identifier[0] = 6;
+       list.identifier[1] = 7;
+
+       aop.op = NS_DETACH;
+       aop.list = &list;
+
+       test_set_transport_callback(ep, test_admin_ns_attach_cb, &aop);
+
+       ctrl = nvme_mi_init_ctrl(ep, 5);
+       assert(ctrl);
+
+       rc = nvme_mi_admin_ns_detach_ctrls(ctrl, 0x02030405, &list);
+       assert(!rc);
+}
+
+
 #define DEFINE_TEST(name) { #name, test_ ## name }
 struct test {
        const char *name;
@@ -1292,6 +1383,8 @@ struct test {
        DEFINE_TEST(admin_id_nsid_ctrl_list),
        DEFINE_TEST(admin_ns_mgmt_create),
        DEFINE_TEST(admin_ns_mgmt_delete),
+       DEFINE_TEST(admin_ns_attach),
+       DEFINE_TEST(admin_ns_detach),
 };
 
 static void run_test(struct test *test, FILE *logfd, nvme_mi_ep_t ep)