From da2820a80483791498b50bd5b5932076b7c17b1a Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Wed, 6 Mar 2019 23:19:45 -0800
Subject: [PATCH] ndctl/list: Introduce region capability objects

For common capabilities that a region can create provide a json object
of the following form:

    "capabilities":[
      {
        "mode":"sector",
        "sector_sizes":[
          512,
          520,
          528,
          4096,
          4104,
          4160,
          4224
        ]
      },
      {
        "mode":"fsdax",
        "alignments":[
          4096,
          2097152,
          1073741824
        ]
      },
      {
        "mode":"devdax",
        "alignments":[
          4096,
          2097152,
          1073741824
        ]
      }
    ]

This replaces the "supported_alignments" and "supported sector sizes"
fields which ended up being too repetitive at the namespace level.

Cc: Oliver O'Halloran <oohall@gmail.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
---
 Documentation/ndctl/ndctl-list.txt |  9 ++-
 ndctl/list.c                       | 12 ++++
 util/json.c                        | 89 ++++++++++++++++++++++++------
 util/json.h                        |  2 +
 4 files changed, 93 insertions(+), 19 deletions(-)

diff --git a/Documentation/ndctl/ndctl-list.txt b/Documentation/ndctl/ndctl-list.txt
index bdd69ad..80ad610 100644
--- a/Documentation/ndctl/ndctl-list.txt
+++ b/Documentation/ndctl/ndctl-list.txt
@@ -175,6 +175,12 @@ include::xable-region-options.txt[]
 --idle::
 	Include idle (not enabled) devices in the listing
 
+-C::
+--capabilities::
+	Include region capabilities in the listing, i.e. supported
+	namespace modes and variable properties like sector sizes and
+	alignments.
+
 -M::
 --media-errors::
 	Include media errors (badblocks) in the listing. Note that the
@@ -222,7 +228,8 @@ include::xable-region-options.txt[]
 	  Everything '-v' provides, plus automatically enable --dimms,
 	  --buses, and --regions. +
 	- *-vvv*
-	  Everything '-vv' provides, plus --health, --idle, and --firmware.
+	  Everything '-vv' provides, plus --health, --capabilities,
+	  --idle, and --firmware.
 
 include::human-option.txt[]
 
diff --git a/ndctl/list.c b/ndctl/list.c
index 506404d..1c3e34d 100644
--- a/ndctl/list.c
+++ b/ndctl/list.c
@@ -36,6 +36,7 @@ static struct {
 	bool media_errors;
 	bool human;
 	bool firmware;
+	bool capabilities;
 	int verbose;
 } list;
 
@@ -53,6 +54,8 @@ static unsigned long listopts_to_flags(void)
 		flags |= UTIL_JSON_HUMAN;
 	if (list.verbose)
 		flags |= UTIL_JSON_VERBOSE;
+	if (list.capabilities)
+		flags |= UTIL_JSON_CAPABILITIES;
 	return flags;
 }
 
@@ -186,6 +189,12 @@ static struct json_object *region_to_json(struct ndctl_region *region,
 	if ((flags & UTIL_JSON_MEDIA_ERRORS) && jbbs)
 		json_object_object_add(jregion, "badblocks", jbbs);
 
+	if (flags & UTIL_JSON_CAPABILITIES) {
+		jobj = util_region_capabilities_to_json(region);
+		if (jobj)
+			json_object_object_add(jregion, "capabilities", jobj);
+	}
+
 	pd = ndctl_region_get_persistence_domain(region);
 	switch (pd) {
 	case PERSISTENCE_CPU_CACHE:
@@ -450,6 +459,8 @@ int cmd_list(int argc, const char **argv, struct ndctl_ctx *ctx)
 				"include namespace info (default)"),
 		OPT_BOOLEAN('X', "device-dax", &list.dax,
 				"include device-dax info"),
+		OPT_BOOLEAN('C', "capabilities", &list.capabilities,
+				"include region capability info"),
 		OPT_BOOLEAN('i', "idle", &list.idle, "include idle devices"),
 		OPT_BOOLEAN('M', "media-errors", &list.media_errors,
 				"include media errors"),
@@ -487,6 +498,7 @@ int cmd_list(int argc, const char **argv, struct ndctl_ctx *ctx)
 		list.idle = true;
 		list.firmware = true;
 		list.health = true;
+		list.capabilities = true;
 	case 2:
 		list.dimms = true;
 		list.buses = true;
diff --git a/util/json.c b/util/json.c
index c732f1b..babdc8c 100644
--- a/util/json.c
+++ b/util/json.c
@@ -321,7 +321,7 @@ struct json_object *util_daxctl_devs_to_list(struct daxctl_region *region,
 }
 
 #define _SZ(get_max, get_elem, type) \
-static struct json_object *type##_build_size_array(struct type *arg)	\
+static struct json_object *util_##type##_build_size_array(struct ndctl_##type *arg)	\
 {								\
 	struct json_object *arr = json_object_new_array();	\
 	int i;							\
@@ -346,11 +346,78 @@ err:								\
 	return NULL;						\
 }
 #define SZ(type, kind) _SZ(ndctl_##type##_get_num_##kind##s, \
-			   ndctl_##type##_get_supported_##kind, ndctl_##type)
+			   ndctl_##type##_get_supported_##kind, type)
 SZ(pfn, alignment)
 SZ(dax, alignment)
 SZ(btt, sector_size)
-//SZ(namespace, sector_size)
+
+struct json_object *util_region_capabilities_to_json(struct ndctl_region *region)
+{
+	struct json_object *jcaps, *jcap, *jobj;
+	struct ndctl_btt *btt = ndctl_region_get_btt_seed(region);
+	struct ndctl_pfn *pfn = ndctl_region_get_pfn_seed(region);
+	struct ndctl_dax *dax = ndctl_region_get_dax_seed(region);
+
+	if (!btt || !pfn || !dax)
+		return NULL;
+
+	jcaps = json_object_new_array();
+	if (!jcaps)
+		return NULL;
+
+	if (btt) {
+		jcap = json_object_new_object();
+		if (!jcap)
+			goto err;
+		json_object_array_add(jcaps, jcap);
+
+		jobj = json_object_new_string("sector");
+		if (!jobj)
+			goto err;
+		json_object_object_add(jcap, "mode", jobj);
+		jobj = util_btt_build_size_array(btt);
+		if (!jobj)
+			goto err;
+		json_object_object_add(jcap, "sector_sizes", jobj);
+	}
+
+	if (pfn) {
+		jcap = json_object_new_object();
+		if (!jcap)
+			goto err;
+		json_object_array_add(jcaps, jcap);
+
+		jobj = json_object_new_string("fsdax");
+		if (!jobj)
+			goto err;
+		json_object_object_add(jcap, "mode", jobj);
+		jobj = util_pfn_build_size_array(pfn);
+		if (!jobj)
+			goto err;
+		json_object_object_add(jcap, "alignments", jobj);
+	}
+
+	if (dax) {
+		jcap = json_object_new_object();
+		if (!jcap)
+			goto err;
+		json_object_array_add(jcaps, jcap);
+
+		jobj = json_object_new_string("devdax");
+		if (!jobj)
+			goto err;
+		json_object_object_add(jcap, "mode", jobj);
+		jobj = util_dax_build_size_array(dax);
+		if (!jobj)
+			goto err;
+		json_object_object_add(jcap, "alignments", jobj);
+	}
+
+	return jcaps;
+err:
+	json_object_put(jcaps);
+	return NULL;
+}
 
 struct json_object *util_daxctl_region_to_json(struct daxctl_region *region,
 		const char *ident, unsigned long flags)
@@ -788,7 +855,7 @@ struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns,
 {
 	struct json_object *jndns = json_object_new_object();
 	enum ndctl_pfn_loc loc = NDCTL_PFN_LOC_NONE;
-	struct json_object *jobj, *jbbs = NULL, *size_array = NULL;
+	struct json_object *jobj, *jbbs = NULL;
 	const char *locations[] = {
 		[NDCTL_PFN_LOC_NONE] = "none",
 		[NDCTL_PFN_LOC_RAM] = "mem",
@@ -798,7 +865,6 @@ struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns,
 	unsigned int sector_size = UINT_MAX;
 	enum ndctl_namespace_mode mode;
 	const char *bdev = NULL, *name;
-	const char *size_array_name;
 	unsigned int bb_count = 0;
 	struct ndctl_btt *btt;
 	struct ndctl_pfn *pfn;
@@ -986,19 +1052,6 @@ struct json_object *util_namespace_to_json(struct ndctl_namespace *ndns,
 			json_object_object_add(jndns, "numa_node", jobj);
 	}
 
-	if (pfn) {
-		size_array_name = "supported_alignments";
-		size_array = ndctl_pfn_build_size_array(pfn);
-	} else if (dax) {
-		size_array_name = "supported_alignments";
-		size_array = ndctl_dax_build_size_array(dax);
-	} else if (btt) {
-		size_array_name = "supported sector sizes";
-		size_array = ndctl_btt_build_size_array(btt);
-	}
-	if (size_array && flags & UTIL_JSON_VERBOSE)
-		json_object_object_add(jndns, size_array_name, size_array);
-
 	if (pfn)
 		jbbs = util_pfn_badblocks_to_json(pfn, &bb_count, flags);
 	else if (dax)
diff --git a/util/json.h b/util/json.h
index e292973..7c3f649 100644
--- a/util/json.h
+++ b/util/json.h
@@ -24,6 +24,7 @@ enum util_json_flags {
 	UTIL_JSON_DAX_DEVS = (1 << 3),
 	UTIL_JSON_HUMAN = (1 << 4),
 	UTIL_JSON_VERBOSE = (1 << 5),
+	UTIL_JSON_CAPABILITIES = (1 << 6),
 };
 
 struct json_object;
@@ -56,4 +57,5 @@ struct json_object *util_json_object_hex(unsigned long long val,
 struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm);
 struct json_object *util_dimm_firmware_to_json(struct ndctl_dimm *dimm,
 		unsigned long flags);
+struct json_object *util_region_capabilities_to_json(struct ndctl_region *region);
 #endif /* __NDCTL_JSON_H__ */
-- 
2.22.0

