]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
mi: Implement Format NVM command
authorJeremy Kerr <jk@codeconstruct.com.au>
Tue, 19 Jul 2022 09:47:04 +0000 (17:47 +0800)
committerJeremy Kerr <jk@codeconstruct.com.au>
Sun, 14 Aug 2022 02:54:25 +0000 (10:54 +0800)
Add support for the Format NVM command, using the existing
struct nvme_format_nvm_args, plus a small test.

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 d20766a080d7941fd4dfcdf7cb581ff10fa7bf7b..42b7ada884d5e4994fb77090e95c5ab8d9dbf937 100644 (file)
@@ -18,6 +18,7 @@ LIBNVME_MI_1_1 {
                nvme_mi_admin_set_features;
                nvme_mi_admin_ns_mgmt;
                nvme_mi_admin_ns_attach;
+               nvme_mi_admin_format_nvm;
                nvme_mi_admin_xfer;
                nvme_mi_admin_security_send;
                nvme_mi_admin_security_recv;
index 5440f7e58e59aa6cd06a2be6b3da6f103c120766..7a3fd85278326118539c67ad5aa0f1a2b9d0f4d9 100644 (file)
@@ -810,6 +810,46 @@ int nvme_mi_admin_ns_attach(nvme_mi_ctrl_t ctrl,
        return 0;
 }
 
+int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl,
+                            struct nvme_format_nvm_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_format_nvm);
+
+       req_hdr.cdw1 = cpu_to_le32(args->nsid);
+       req_hdr.cdw10 = cpu_to_le32(((args->lbafu & 0x3) << 12)
+                                   | ((args->ses & 0x7) << 9)
+                                   | ((args->pil & 0x1) << 8)
+                                   | ((args->pi & 0x7) << 5)
+                                   | ((args->mset & 0x1) << 4)
+                                   | ((args->lbaf & 0xf) << 0));
+
+       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 a0e63942a57432706b618526b5c24bfe85b1005c..9a2b68e1584f0965a26c9c638c3b12b46ecfd7d3 100644 (file)
@@ -1496,4 +1496,17 @@ static inline int nvme_mi_admin_ns_detach_ctrls(nvme_mi_ctrl_t ctrl, __u32 nsid,
        return nvme_mi_admin_ns_attach(ctrl, &args);
 }
 
+/**
+ * nvme_mi_admin_format_nvm() - Format NVMe namespace
+ * @ctrl: Controller to send command to
+ * @args: Format NVM command arguments
+ *
+ * Perform a low-level format to set the LBA data & metadata size. May destroy
+ * data & metadata on the specified namespaces
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+int nvme_mi_admin_format_nvm(nvme_mi_ctrl_t ctrl,
+                            struct nvme_format_nvm_args *args);
+
 #endif /* _LIBNVME_MI_MI_H */
index aecbb566c0bb030a4bfd3c296e0fb8f23047e01d..bf4fb07ea6ae2d3418afba178a8908c437646bda 100644 (file)
--- a/test/mi.c
+++ b/test/mi.c
@@ -1350,6 +1350,83 @@ static void test_admin_ns_detach(struct nvme_mi_ep *ep)
        assert(!rc);
 }
 
+struct format_data {
+       __u32 nsid;
+       __u8 lbafu;
+       __u8 ses;
+       __u8 pil;
+       __u8 pi;
+       __u8 mset;
+       __u8 lbafl;
+};
+
+static int test_admin_format_nvm_cb(struct nvme_mi_ep *ep,
+                                   struct nvme_mi_req *req,
+                                   struct nvme_mi_resp *resp,
+                                   void *data)
+{
+       struct nvme_format_nvm_args *args = data;
+       __u8 *rq_hdr;
+       __u32 nsid;
+
+       assert(req->data_len == 0);
+
+       rq_hdr = (__u8 *)req->hdr;
+
+       assert(rq_hdr[4] == nvme_admin_format_nvm);
+
+       nsid = rq_hdr[11] << 24 | rq_hdr[10] << 16 | rq_hdr[9] << 8 | rq_hdr[8];
+       assert(nsid == args->nsid);
+
+       assert(((rq_hdr[44] >> 0) & 0xf) == args->lbaf);
+       assert(((rq_hdr[44] >> 4) & 0x1) == args->mset);
+       assert(((rq_hdr[44] >> 5) & 0x7) == args->pi);
+
+       assert(((rq_hdr[45] >> 0) & 0x1) == args->pil);
+       assert(((rq_hdr[45] >> 1) & 0x7) == args->ses);
+       assert(((rq_hdr[45] >> 4) & 0x3) == args->lbafu);
+
+       test_transport_resp_calc_mic(resp);
+
+       return 0;
+}
+
+static void test_admin_format_nvm(struct nvme_mi_ep *ep)
+{
+       struct nvme_format_nvm_args args = { 0 };
+       nvme_mi_ctrl_t ctrl;
+       int rc;
+
+       ctrl = nvme_mi_init_ctrl(ep, 5);
+       assert(ctrl);
+
+       test_set_transport_callback(ep, test_admin_format_nvm_cb, &args);
+
+       /* ensure we have the cdw0 bit field encoding correct, by testing twice
+        * with inverted bit values */
+       args.args_size = sizeof(args);
+       args.nsid = 0x04030201;
+       args.lbafu = 0x3;
+       args.ses = 0x0;
+       args.pil = 0x1;
+       args.pi = 0x0;
+       args.mset = 0x1;
+       args.lbaf = 0x0;
+
+       rc = nvme_mi_admin_format_nvm(ctrl, &args);
+       assert(!rc);
+
+       args.nsid = ~args.nsid;
+       args.lbafu = 0;
+       args.ses = 0x7;
+       args.pil = 0x0;
+       args.pi = 0x7;
+       args.mset = 0x0;
+       args.lbaf = 0xf;
+
+       rc = nvme_mi_admin_format_nvm(ctrl, &args);
+       assert(!rc);
+}
 
 #define DEFINE_TEST(name) { #name, test_ ## name }
 struct test {
@@ -1385,6 +1462,7 @@ struct test {
        DEFINE_TEST(admin_ns_mgmt_delete),
        DEFINE_TEST(admin_ns_attach),
        DEFINE_TEST(admin_ns_detach),
+       DEFINE_TEST(admin_format_nvm),
 };
 
 static void run_test(struct test *test, FILE *logfd, nvme_mi_ep_t ep)