]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
mi: Add identify helpers for namespace lists
authorJeremy Kerr <jk@codeconstruct.com.au>
Wed, 8 Jun 2022 07:20:38 +0000 (15:20 +0800)
committerJeremy Kerr <jk@codeconstruct.com.au>
Fri, 12 Aug 2022 09:44:24 +0000 (17:44 +0800)
This change implements the Identify command helper for the active
and allocated namespace lists.

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

index e51ec4ca4fdc995c9b6e93c828739f1b23b114e8..4ff22606e5f3c527cad6ed39d2a58b775827df63 100644 (file)
@@ -1078,6 +1078,80 @@ static inline int nvme_mi_admin_identify_ctrl_list(nvme_mi_ctrl_t ctrl,
        return nvme_mi_admin_identify(ctrl, &args);
 }
 
+/**
+ * nvme_mi_admin_identify_allocated_ns_list() - Perform an Admin identify for
+ * an allocated namespace list
+ * @ctrl: Controller to process identify command
+ * @nsid: Namespace ID to specify list start
+ * @list: List data to populate
+ *
+ * Perform an Identify command, for the allocated namespace list starting with
+ * IDs greater than or equal to @nsid. Specify &NVME_NSID_NONE for the start
+ * of the list.
+ *
+ * Will return an error if the length of the response data (from the
+ * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @list will be
+ * be fully populated on success.
+ *
+ * Return: 0 on success, non-zero on failure
+ *
+ * See: &struct nvme_ns_list
+ */
+static inline int nvme_mi_admin_identify_allocated_ns_list(nvme_mi_ctrl_t ctrl,
+                                                          __u32 nsid,
+                                                          struct nvme_ns_list *list)
+{
+       struct nvme_identify_args args = {
+               .result = NULL,
+               .data = list,
+               .args_size = sizeof(args),
+               .cns = NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST,
+               .csi = NVME_CSI_NVM,
+               .nsid = nsid,
+               .cns_specific_id = NVME_CNSSPECID_NONE,
+               .uuidx = NVME_UUID_NONE,
+       };
+
+       return nvme_mi_admin_identify(ctrl, &args);
+}
+
+/**
+ * nvme_mi_admin_identify_active_ns_list() - Perform an Admin identify for an
+ * active namespace list
+ * @ctrl: Controller to process identify command
+ * @nsid: Namespace ID to specify list start
+ * @list: List data to populate
+ *
+ * Perform an Identify command, for the active namespace list starting with
+ * IDs greater than or equal to @nsid. Specify &NVME_NSID_NONE for the start
+ * of the list.
+ *
+ * Will return an error if the length of the response data (from the
+ * controller) is not a full &NVME_IDENTIFY_DATA_SIZE, so @list will be
+ * be fully populated on success.
+ *
+ * Return: 0 on success, non-zero on failure
+ *
+ * See: &struct nvme_ns_list
+ */
+static inline int nvme_mi_admin_identify_active_ns_list(nvme_mi_ctrl_t ctrl,
+                                                       __u32 nsid,
+                                                       struct nvme_ns_list *list)
+{
+       struct nvme_identify_args args = {
+               .result = NULL,
+               .data = list,
+               .args_size = sizeof(args),
+               .cns = NVME_IDENTIFY_CNS_NS_ACTIVE_LIST,
+               .csi = NVME_CSI_NVM,
+               .nsid = nsid,
+               .cns_specific_id = NVME_CNSSPECID_NONE,
+               .uuidx = NVME_UUID_NONE,
+       };
+
+       return nvme_mi_admin_identify(ctrl, &args);
+}
+
 /**
  * nvme_mi_admin_get_log() - Retrieve log page data from controller
  * @ctrl: Controller to query
index 8267397389e72ad875cf81a0be70373c5e1a31d1..579508f7d44c40957121286a2239addbb4b78ce1 100644 (file)
--- a/test/mi.c
+++ b/test/mi.c
@@ -11,6 +11,7 @@
 #include <unistd.h>
 
 #include <ccan/array_size/array_size.h>
+#include <ccan/endian/endian.h>
 
 /* we define a custom transport, so need the internal headers */
 #include "nvme/private.h"
@@ -954,6 +955,99 @@ static void test_set_features(nvme_mi_ep_t ep)
        assert(args.data_len == 0);
 }
 
+enum ns_type {
+       NS_ACTIVE,
+       NS_ALLOC,
+};
+
+static int test_admin_id_ns_list_cb(struct nvme_mi_ep *ep,
+                                   struct nvme_mi_req *req,
+                                   struct nvme_mi_resp *resp,
+                                   void *data)
+{
+       struct nvme_ns_list *list;
+       enum ns_type type;
+       int offset;
+       __u8 *hdr;
+       __u16 cns;
+
+       hdr = (__u8 *)req->hdr;
+       assert(hdr[4] == nvme_admin_identify);
+
+       assert(req->data_len == 0);
+
+       cns = hdr[45] << 8 | hdr[44];
+
+       /* NSID */
+       assert(hdr[8] == 1 && !hdr[9] && !hdr[10] && !hdr[11]);
+
+       type = *(enum ns_type *)data;
+       resp->data_len = sizeof(*list);
+       list = resp->data;
+
+       switch (type) {
+       case NS_ALLOC:
+               assert(cns == NVME_IDENTIFY_CNS_ALLOCATED_NS_LIST);
+               offset = 2;
+               break;
+       case NS_ACTIVE:
+               assert(cns == NVME_IDENTIFY_CNS_NS_ACTIVE_LIST);
+               offset = 4;
+               break;
+       default:
+               assert(0);
+       }
+
+       list->ns[0] = cpu_to_le32(offset);
+       list->ns[1] = cpu_to_le32(offset + 1);
+
+       test_transport_resp_calc_mic(resp);
+
+       return 0;
+}
+
+static void test_admin_id_alloc_ns_list(struct nvme_mi_ep *ep)
+{
+       struct nvme_ns_list list;
+       nvme_mi_ctrl_t ctrl;
+       enum ns_type type;
+       int rc;
+
+       type = NS_ALLOC;
+       test_set_transport_callback(ep, test_admin_id_ns_list_cb, &type);
+
+       ctrl = nvme_mi_init_ctrl(ep, 5);
+       assert(ctrl);
+
+       rc = nvme_mi_admin_identify_allocated_ns_list(ctrl, 1, &list);
+       assert(!rc);
+
+       assert(le32_to_cpu(list.ns[0]) == 2);
+       assert(le32_to_cpu(list.ns[1]) == 3);
+       assert(le32_to_cpu(list.ns[2]) == 0);
+}
+
+static void test_admin_id_active_ns_list(struct nvme_mi_ep *ep)
+{
+       struct nvme_ns_list list;
+       nvme_mi_ctrl_t ctrl;
+       enum ns_type type;
+       int rc;
+
+       type = NS_ACTIVE;
+       test_set_transport_callback(ep, test_admin_id_ns_list_cb, &type);
+
+       ctrl = nvme_mi_init_ctrl(ep, 5);
+       assert(ctrl);
+
+       rc = nvme_mi_admin_identify_active_ns_list(ctrl, 1, &list);
+       assert(!rc);
+
+       assert(le32_to_cpu(list.ns[0]) == 4);
+       assert(le32_to_cpu(list.ns[1]) == 5);
+       assert(le32_to_cpu(list.ns[2]) == 0);
+}
+
 #define DEFINE_TEST(name) { #name, test_ ## name }
 struct test {
        const char *name;
@@ -979,6 +1073,8 @@ struct test {
        DEFINE_TEST(get_features_nodata),
        DEFINE_TEST(get_features_data),
        DEFINE_TEST(set_features),
+       DEFINE_TEST(admin_id_alloc_ns_list),
+       DEFINE_TEST(admin_id_active_ns_list),
 };
 
 static void run_test(struct test *test, FILE *logfd, nvme_mi_ep_t ep)