From: Jeremy Kerr Date: Wed, 8 Jun 2022 08:40:20 +0000 (+0800) Subject: mi: Implement Namespace Management command and create/delete helpers X-Git-Tag: v1.2~41^2~4 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=4dac7f0b37b42d94d7ee8891042488d9245afe5c;p=users%2Fsagi%2Flibnvme.git mi: Implement Namespace Management command and create/delete helpers 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 --- diff --git a/src/libnvme-mi.map b/src/libnvme-mi.map index b6007b22..289ef56c 100644 --- a/src/libnvme-mi.map +++ b/src/libnvme-mi.map @@ -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; diff --git a/src/nvme/mi.c b/src/nvme/mi.c index cb3a0bc9..68e88ace 100644 --- a/src/nvme/mi.c +++ b/src/nvme/mi.c @@ -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) { diff --git a/src/nvme/mi.h b/src/nvme/mi.h index c21598e2..137b4277 100644 --- a/src/nvme/mi.h +++ b/src/nvme/mi.h @@ -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 */ diff --git a/test/mi.c b/test/mi.c index 183f634d..4058b5df 100644 --- 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)