linux-nvdimm.lists.01.org archive mirror
 help / color / mirror / Atom feed
* [ndctl RFC-PATCH 0/4] Add support for reporting PAPR NVDIMM Statistics
@ 2020-05-18 11:20 Vaibhav Jain
  2020-05-18 11:20 ` [ndctl RFC-PATCH 1/4] ndctl,libndctl: Implement new dimm-ops 'new_stats' and 'get_stat' Vaibhav Jain
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Vaibhav Jain @ 2020-05-18 11:20 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

This patch-set proposes addition of new functionality to ndctl and
libndctl enabling them to report vendor specific NVDIMM Statistics
(dimm-stats) like "Cache Read/Write Hit Count" which arent S.M.A.R.T
attributes but still indicate important NVDIMM performance metrics.

Until now these statistics were exposed via vendor specific tools
like ipmictl[1] in case of Intel Optane-DC memory. These patch-set
however tries to implement a generic abstraction within libndctl to
report such statistics from the ndctl tool.

The patch-set proposes to add a new command line arg '--stats' / '-S'
that reports vendor specific dimm-stats for a NVDIMM. Below is an
example invocation and output of the proposed changes:

 # ndctl list -D --stats
[
  {
    "dev":"nmem0",
    "stats":{
      "Controller Reset Count":2,
      "Controller Reset Elapsed Time":603331,
      "Power-on Seconds":603931,
      "Life Remaining":"100%",
      "Critical Resource Utilization":"0%",
      "Host Load Count":5781028,
      "Host Store Count":8966800,
      "Host Load Duration":975895365,
      "Host Store Duration":716230690,
      "Media Read Count":0,
      "Media Write Count":6313,
      "Media Read Duration":0,
      "Media Write Duration":9679615,
      "Cache Read Hit Count":5781028,
      "Cache Write Hit Count":8442479,
      "Fast Write Count":8969912
    }
  }
]

As a proof of concept the patch-set implements reporting dimm-stats for
PAPR compatible NVDIMMs. The output above is from a PPC64 PSeries
Guest LPAR with an NVDIMM, running on a PowerVM Hyper-visor.

The patch-set is dependent on existing patch-set "[ndctl PATCH v3 0/6]
Add support for reporting papr-scm nvdimm health" available at
Ref[2] and [3]. That patch-set implemented the base infrastructure
needed to support PAPR complaint NVDIMMs in ndctl and libndctl.

For PAPR compliant NVDIMMs we also depend on kernel side changes
published at [4] that add support for necessary pdsms to expose
dimm-stats to libndctl via CMD_CALL ioctl interface.

Structure of the patch-set
==========================

First patch in the series starts with implementing necessary
infrastructure in libndctl to introduce two new dimm_ops namely
'new_stats' and 'get_stat' that can be implemented by dimm-providers
to provide libndctl access to vendor specific dimm-stats. The patch
also implements necessary changes in ndctl ndctl/util/json-smart.c to
call these new dimm-ops and generate json-c objects to generate an
output as mentioned above.

Next three patches deal with implementing support for these new
dimm-ops for papr_scm in libndctl. Patch-2 implements dimm-op
'new_stats' that returns a 'struct ndctl_cmd' that can be submitted to
libnvdimm for fetching dimm-stats and copy them to papr_scm managed
buffer.

Patch-2 implements parsing and clean-up of the fetched dimm-stats from
kernel.

Finally Patch-3 implements dimm_ops 'get_stat' that provides ndctl
access to dimm-stat which then constructs a json object aggregating
them and then generating a text output from it.


References
==========
[1] https://docs.pmem.io/ipmctl-user-guide/instrumentation/show-device-performance

[2] https://github.com/vaibhav92/ndctl/tree/papr_scm_health_v7

[3] https://lore.kernel.org/linux-nvdimm/20200420075556.272174-1-vaibhav@linux.ibm.com/

[4] https://lore.kernel.org/linux-nvdimm/20200518110814.145644-1-vaibhav@linux.ibm.com

Vaibhav Jain (4):
  ndctl,libndctl: Implement new dimm-ops 'new_stats' and 'get_stat'
  papr_scm: Add support for fetching dimm-stats
  papr_scm: Implement parsing and clean-up for fetched dimm stats
  papr_scm: Implement dimm op 'get_stat'

 Documentation/ndctl/ndctl-list.txt |  24 +++
 ndctl/lib/libndctl.sym             |   5 +
 ndctl/lib/papr_scm.c               | 300 ++++++++++++++++++++++++++++-
 ndctl/lib/papr_scm_pdsm.h          |  48 +++++
 ndctl/lib/private.h                |   6 +
 ndctl/lib/smart.c                  |  26 +++
 ndctl/libndctl.h                   |  23 +++
 ndctl/list.c                       |   9 +
 ndctl/util/json-smart.c            |  73 +++++++
 util/json.h                        |   1 +
 10 files changed, 514 insertions(+), 1 deletion(-)

-- 
2.26.2
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [ndctl RFC-PATCH 1/4] ndctl,libndctl: Implement new dimm-ops 'new_stats' and 'get_stat'
  2020-05-18 11:20 [ndctl RFC-PATCH 0/4] Add support for reporting PAPR NVDIMM Statistics Vaibhav Jain
@ 2020-05-18 11:20 ` Vaibhav Jain
  2020-05-18 11:20 ` [ndctl RFC-PATCH 2/4] papr_scm: Add support for fetching dimm-stats Vaibhav Jain
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Vaibhav Jain @ 2020-05-18 11:20 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Do necessary ndctl, libndctl changes to add support for two new dimm-ops
namely 'new_stats' and 'get_stat' that can be implemented by dimm
providers to expose dimm statistics for e.g "Controller Reset Count"
etc, to ndctl. These dimm-ops are called when newly introduced command
line argument '-S' or '--stats' is provided on with ndctl-list
command.

Following are the semantics of these new dimm-ops:

* struct ndctl_cmd *(*new_stats)(struct ndctl_dimm *):

  Return a ndctl command that can be sent to libnvdimm to fetch
  dimm-stats from kernel. On successful submission
  'dimm_ops->smart_get_flags' is called to check if ND_SMART_STATS_VALID
  flag is set which indicates dimm-stats successfully fetched from
  libnvdimm.

* int (*get_stat)(struct ndctl_cmd *, struct ndctl_dimm_stat *):

  If ND_SMART_STATS_VALID flag was returned for a command from
  'dimm-ops->smart_get_flags' then this dimm-op is called to
  incrementally retrieve dimm-stats. For each call the dimm-op
  implementer is expected to populate the provided instance of 'struct
  ndctl_dimm_stat *' with a info on name, type and value of a
  dimm-stat. In case no more dimm-stats are available the dimm-op
  should return an error.

The newly introduced 'struct ndctl_dimm_stat' holds Name, type and
value information of a single dimm-stat. The ndctl_dimm_stat.type
information is used to appropriately format the dimm-stat value in the
json output.

The patch also updates 'util/json-smart.c' introducing new function
util_dimm_stats_to_json() thats called when '--stats' command line arg
is provided, and it drives the calls to dimm-ops 'new_stats' and
'get_stat'. The function does follows this sequence:

1. Generates a new json-object named 'stats' in the json output
2. Use 'dimm_ops->new_stats' to get a ndctl_cmd instance.
3. Submit the command to libndctl.
4. In case of successful submission, retrieve flags associated with the
   command.
4. In case flag ND_SMART_STATS_VALID use dimm-op 'get_stat' to retrieve
   available dimm-stats.
5. Creates new json-object for each 'struct ndctl_dimm_stat' returned
   from dimm-op 'get_stat' based on the type of dimm-stat.
6. Adds the above create json-object as child node of the 'stats'
   json-object.
7. Return the 'stats' json object from the function.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
 Documentation/ndctl/ndctl-list.txt | 24 ++++++++++
 ndctl/lib/libndctl.sym             |  5 ++
 ndctl/lib/private.h                |  6 +++
 ndctl/lib/smart.c                  | 26 +++++++++++
 ndctl/libndctl.h                   | 23 ++++++++++
 ndctl/list.c                       |  9 ++++
 ndctl/util/json-smart.c            | 73 ++++++++++++++++++++++++++++++
 util/json.h                        |  1 +
 8 files changed, 167 insertions(+)

diff --git a/Documentation/ndctl/ndctl-list.txt b/Documentation/ndctl/ndctl-list.txt
index 7c7e3ac9d05c..4ba58b96fb74 100644
--- a/Documentation/ndctl/ndctl-list.txt
+++ b/Documentation/ndctl/ndctl-list.txt
@@ -129,6 +129,30 @@ include::xable-bus-options.txt[]
     "shutdown_state":"clean"
   }
 }
+-S::
+--stats::
+	Include dimm statistics in the listing. For example:
+[verse]
+{
+  "dev":"nmem0"
+  "stats":{
+    "Controller Reset Count":2,
+    "Controller Reset Elapsed Time":50800,
+    "Power-on Seconds":51400,
+    "Critical Resource Utilization":"0%",
+    "Host Load Count":4056485,
+    "Host Store Count":8956850,
+    "Host Load Duration":765053890,
+    "Host Store Duration":715390700,
+    "Media Read Count":0,
+    "Media Write Count":6178,
+    "Media Read Duration":0,
+    "Media Write Duration":9468375,
+    "Cache Read Hit Count":4056485,
+    "Cache Write Hit Count":8432554,
+    "Fast Write Count":8959962
+  }
+}
 
 -F::
 --firmware::
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index ac575a23d035..5b8eabc1b9d5 100644
--- a/ndctl/lib/libndctl.sym
+++ b/ndctl/lib/libndctl.sym
@@ -431,3 +431,8 @@ LIBNDCTL_23 {
 	ndctl_region_get_align;
 	ndctl_region_set_align;
 } LIBNDCTL_22;
+
+LIBNDCTL_24 {
+	ndctl_dimm_cmd_new_stats;
+	ndctl_dimm_get_stat;
+} LIBNDCTL_23;
\ No newline at end of file
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index 679e359a1070..c4d1f42f7ac2 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -238,6 +238,7 @@ struct ndctl_namespace {
  * @status: negative if failed, 0 if success, > 0 if never submitted
  * @get_firmware_status: per command firmware status field retrieval
  * @iter: iterator for multi-xfer commands
+ * @private_data: Used by dimm-provider to store private data
  * @source: source cmd of an inherited iter.total_buf
  *
  * For dynamically sized commands like 'get_config', 'set_config', or
@@ -266,6 +267,7 @@ struct ndctl_cmd {
 		u32 total_xfer;
 		int dir;
 	} iter;
+	void *private_data;
 	struct ndctl_cmd *source;
 	union {
 		struct nd_cmd_ars_cap ars_cap[0];
@@ -352,6 +354,10 @@ struct ndctl_dimm_ops {
 	int (*dimm_init)(struct ndctl_dimm *);
 	/* Called just before struct ndctl_dimm is de-allocated */
 	void (*dimm_uninit)(struct ndctl_dimm *);
+	/* Return a command to fetch dimm stats */
+	struct ndctl_cmd *(*new_stats)(struct ndctl_dimm *);
+	/* Return a single dimm-stat from the command until error */
+	int (*get_stat)(struct ndctl_cmd *, struct ndctl_dimm_stat *);
 };
 
 extern struct ndctl_dimm_ops * const intel_dimm_ops;
diff --git a/ndctl/lib/smart.c b/ndctl/lib/smart.c
index 0e180cff5a3e..fbb1248c08a9 100644
--- a/ndctl/lib/smart.c
+++ b/ndctl/lib/smart.c
@@ -31,6 +31,32 @@ NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart(
 		return NULL;
 }
 
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_stats(
+		struct ndctl_dimm *dimm)
+{
+	struct ndctl_dimm_ops *ops = dimm->ops;
+
+	if (ops && ops->new_stats)
+		return ops->new_stats(dimm);
+	else
+		return NULL;
+}
+
+NDCTL_EXPORT int ndctl_dimm_get_stat(struct ndctl_cmd *cmd,
+				      struct ndctl_dimm_stat * stat)
+{
+	struct ndctl_dimm_ops *ops;
+
+	if (!cmd || !cmd->dimm)
+		return -EINVAL;
+	ops = cmd->dimm->ops;
+
+	if (ops && ops->get_stat)
+		return ops->get_stat(cmd, stat);
+	else
+		return -ENOENT;
+}
+
 NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(
 		struct ndctl_dimm *dimm)
 {
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index daf11b8ce4ea..9fab2097a920 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -247,6 +247,7 @@ int ndctl_cmd_ars_stat_get_flag_overflow(struct ndctl_cmd *ars_stat);
 #define ND_SMART_ALARM_VALID	(1 << 9)
 #define ND_SMART_SHUTDOWN_VALID	(1 << 10)
 #define ND_SMART_VENDOR_VALID	(1 << 11)
+#define ND_SMART_STATS_VALID	(1 << 12)
 #define ND_SMART_SPARE_TRIP	(1 << 0)
 #define ND_SMART_MTEMP_TRIP	(1 << 1)
 #define ND_SMART_TEMP_TRIP	ND_SMART_MTEMP_TRIP
@@ -341,6 +342,28 @@ int ndctl_cmd_get_status(struct ndctl_cmd *cmd);
 unsigned int ndctl_cmd_get_firmware_status(struct ndctl_cmd *cmd);
 int ndctl_cmd_submit(struct ndctl_cmd *cmd);
 
+/* Holds a single dimm stat which can be retrived */
+struct ndctl_dimm_stat {
+        const char *name;
+        enum {
+		STAT_TYPE_BOOL,
+		STAT_TYPE_INT,
+		STAT_TYPE_INT64,
+		STAT_TYPE_DOUBLE,
+		STAT_TYPE_STR,
+		STAT_TYPE_PERCENT,
+	} type;
+	union {
+		bool bool_val;
+		int int_val;
+		long long int64_val;
+		double double_val;
+		char str_val[32];
+	} val;
+};
+
+struct ndctl_cmd *ndctl_dimm_cmd_new_stats(struct ndctl_dimm *dimm);
+int ndctl_dimm_get_stat(struct ndctl_cmd *cmd, struct ndctl_dimm_stat *stat);
 struct badblock {
 	unsigned long long offset;
 	unsigned int len;
diff --git a/ndctl/list.c b/ndctl/list.c
index 31fb1b9593a2..cda3493c2ffc 100644
--- a/ndctl/list.c
+++ b/ndctl/list.c
@@ -32,6 +32,7 @@ static struct {
 	bool namespaces;
 	bool idle;
 	bool health;
+	bool stats;
 	bool dax;
 	bool media_errors;
 	bool human;
@@ -367,6 +368,13 @@ static void filter_dimm(struct ndctl_dimm *dimm, struct util_filter_ctx *ctx)
 		}
 	}
 
+	if (list.stats) {
+		struct json_object *jstats;
+
+		jstats = util_dimm_stats_to_json(dimm);
+		json_object_object_add(jdimm, "stats", jstats);
+	}
+
 	if (list.firmware) {
 		struct json_object *jfirmware;
 
@@ -479,6 +487,7 @@ int cmd_list(int argc, const char **argv, struct ndctl_ctx *ctx)
 		OPT_BOOLEAN('D', "dimms", &list.dimms, "include dimm info"),
 		OPT_BOOLEAN('F', "firmware", &list.firmware, "include firmware info"),
 		OPT_BOOLEAN('H', "health", &list.health, "include dimm health"),
+		OPT_BOOLEAN('S', "stats", &list.stats, "include dimm stats"),
 		OPT_BOOLEAN('R', "regions", &list.regions,
 				"include region info"),
 		OPT_BOOLEAN('N', "namespaces", &list.namespaces,
diff --git a/ndctl/util/json-smart.c b/ndctl/util/json-smart.c
index a9bd17b37b4e..1312439453ee 100644
--- a/ndctl/util/json-smart.c
+++ b/ndctl/util/json-smart.c
@@ -221,3 +221,76 @@ struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm)
 		ndctl_cmd_unref(cmd);
 	return jhealth;
 }
+
+struct json_object *util_dimm_stats_to_json(struct ndctl_dimm *dimm)
+{
+	struct json_object *jstat = json_object_new_object();
+	struct json_object *jobj;
+	struct ndctl_cmd *cmd;
+	struct ndctl_dimm_stat stat = { 0 };
+	char format_buffer[32] = { 0 };
+	int rc;
+	unsigned int flags;
+
+	if (!jstat)
+		return NULL;
+
+	cmd = ndctl_dimm_cmd_new_stats(dimm);
+	if (!cmd)
+		goto err;
+
+	rc = ndctl_cmd_submit_xlat(cmd);
+	if (rc < 0) {
+		jobj = json_object_new_string("unknown");
+		if (jobj)
+			json_object_object_add(jstat, "stats", jobj);
+		goto out;
+	}
+
+	/* Check if any stats are reported */
+	flags = ndctl_cmd_smart_get_flags(cmd);
+	if (!(flags & ND_SMART_STATS_VALID))
+		goto out;
+
+	/* Iterate through the reported stats list */
+	while (ndctl_dimm_get_stat(cmd, &stat) == 0) {
+		switch(stat.type) {
+		case STAT_TYPE_BOOL:
+			jobj = json_object_new_boolean(stat.val.bool_val);
+			break;
+		case STAT_TYPE_INT:
+			jobj = json_object_new_int(stat.val.int_val);
+			break;
+		case STAT_TYPE_INT64:
+			jobj = json_object_new_int64(stat.val.int64_val);
+			break;
+		case STAT_TYPE_DOUBLE:
+			jobj = json_object_new_double(stat.val.double_val);
+			break;
+		case STAT_TYPE_STR:
+			jobj = json_object_new_string(stat.val.str_val);
+			break;
+		case STAT_TYPE_PERCENT:
+			snprintf(format_buffer, sizeof(format_buffer) - 1,
+				 "%u%%",stat.val.int_val);
+			format_buffer[sizeof(format_buffer) - 1] = '\0';
+			jobj = json_object_new_string(format_buffer);
+			break;
+		default:
+			jobj = json_object_new_string("unknown-type");
+			break;
+		};
+
+		if (jobj)
+			json_object_object_add(jstat, stat.name, jobj);
+	}
+	ndctl_cmd_unref(cmd);
+	return jstat;
+ err:
+	json_object_put(jstat);
+	jstat = NULL;
+ out:
+	if (cmd)
+		ndctl_cmd_unref(cmd);
+	return jstat;
+}
diff --git a/util/json.h b/util/json.h
index 6d39d3aa4693..e678596e1aab 100644
--- a/util/json.h
+++ b/util/json.h
@@ -56,6 +56,7 @@ struct json_object *util_json_object_size(unsigned long long size,
 struct json_object *util_json_object_hex(unsigned long long val,
 		unsigned long flags);
 struct json_object *util_dimm_health_to_json(struct ndctl_dimm *dimm);
+struct json_object *util_dimm_stats_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);
-- 
2.26.2
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [ndctl RFC-PATCH 2/4] papr_scm: Add support for fetching dimm-stats
  2020-05-18 11:20 [ndctl RFC-PATCH 0/4] Add support for reporting PAPR NVDIMM Statistics Vaibhav Jain
  2020-05-18 11:20 ` [ndctl RFC-PATCH 1/4] ndctl,libndctl: Implement new dimm-ops 'new_stats' and 'get_stat' Vaibhav Jain
@ 2020-05-18 11:20 ` Vaibhav Jain
  2020-05-18 11:20 ` [ndctl RFC-PATCH 3/4] papr_scm: Implement parsing and clean-up for fetched dimm stats Vaibhav Jain
  2020-05-18 11:20 ` [ndctl RFC-PATCH 4/4] papr_scm: Implement dimm op 'get_stat' Vaibhav Jain
  3 siblings, 0 replies; 5+ messages in thread
From: Vaibhav Jain @ 2020-05-18 11:20 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Add support for fetching dimm-stats from 'papr_scm' module by
implementing newly introduced dimm-op 'new_stats' as
papr_new_stats(). The function uses two pdsm to fetch dimm-stats.

* PAPR_SCM_PDSM_FETCH_PERF_STATS:
  Asks 'papr_scm' module to request fresh values of all dimm-stats
  from PHYP and store then in its perf-stats buffer. It returns the
  size of the perf-stats buffer as bytes in command package 'struct
  nd_pdsm_fetch_perf_stats'.

* PAPR_SCM_PDSM_READ_PERF_STATS:
  Once dimm-stats are placed in 'papr_scm' perf-stats buffer, this
  pdsm is issued to read it contents and copy then to libndctl
  user-space memory using 'struct nd_pdsm_read_perf_stats'
  payload. Since libnvdimm enforces a envelope size limit of 256
  bytes, this pdsm uses libndctl command iterator functionality to
  incrementally copy the entire perf-stat buffer content from
  'papr_scm' module.

The patch introduces new members in 'struct dimm_priv' to hold the
dimm-stat information fetched from 'papr_scm' module. A new function
update_perf_stat_size() is introduced that handles response to pdsm
FETCH_PERF_STATS and allocate enough memory to 'dimm_priv.perf_stats'
to hold all dimm-stats.

When papr_new_stats() is called by libndctl in response to '--stats'
arg being given to ndctl-list command, following sequence is executed:

1. Allocate and submit ndctl_cmd to issue pdsm FETCH_PERF_STATS.
2. On success call update_dimm_stats() that in return calls
   update_perf_stat_size() to allocate buffer 'dimm_priv.perf_stats'
   needed to store dimm-stats.
3. Allocate ndctl_cmd to issue pdsm READ_PERF_STATS.
4. Setup the command iterator pointing to dimm_priv.perf_stats to hold
   the entire data and setting the total length of the read operation.
5. Setup the various get/set callback functions for command 'xfer' and
   'offset' access.
6. Return this command back to libndctl that will then submit the
   command to libnvdimm.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
 ndctl/lib/papr_scm.c      | 169 ++++++++++++++++++++++++++++++++++++++
 ndctl/lib/papr_scm_pdsm.h |  48 +++++++++++
 2 files changed, 217 insertions(+)

diff --git a/ndctl/lib/papr_scm.c b/ndctl/lib/papr_scm.c
index 562262111c91..14fb6d48c12a 100644
--- a/ndctl/lib/papr_scm.c
+++ b/ndctl/lib/papr_scm.c
@@ -14,6 +14,7 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <util/log.h>
+#include <util/util.h>
 #include <ndctl.h>
 #include <ndctl/libndctl.h>
 #include <lib/private.h>
@@ -40,11 +41,19 @@
 #define CMD_PKG_SUBMITTED 1
 #define CMD_PKG_PARSED 2
 
+/* Number of bytes to transffer in each ioctl for pdsm READ_PERF_STATS */
+#define GET_PERF_STAT_XFER_SIZE 16
+
 /* Per dimm data. Holds per-dimm data parsed from the cmd_pkgs */
 struct dimm_priv {
 
 	/* Cache the dimm health status */
 	struct nd_papr_pdsm_health health;
+
+	/* Cache the dimm perf-stats buffer, length in bytes, count */
+	ssize_t len_perf_stats;
+	ssize_t count_perf_stats;
+	struct nd_pdsm_perf_stat *perf_stats;
 };
 
 static bool papr_cmd_is_supported(struct ndctl_dimm *dimm, int cmd)
@@ -136,6 +145,45 @@ static int update_dimm_health(struct ndctl_dimm *dimm, struct ndctl_cmd *cmd)
 	return -EINVAL;
 }
 
+/* Parse the PAPR_SCM_PDSM_FETCH_PERF_STATS command package */
+static int update_perf_stat_size(struct ndctl_dimm *dimm, struct ndctl_cmd *cmd)
+{
+	struct nd_pdsm_cmd_pkg *pcmd = nd_to_pdsm_cmd_pkg(cmd->pkg);
+	struct dimm_priv *p = dimm->dimm_user_data;
+	const struct nd_pdsm_fetch_perf_stats * psize =
+		pdsm_cmd_to_payload(pcmd);
+
+	/* is it an unknown version */
+	if (pcmd->payload_version != 1) {
+		papr_err(dimm, "Unknown payload version for perf stat size\n");
+		return -EBADE;
+	}
+
+	/* Update the perf_size and reallocate the buffer if needed */
+	if (p->len_perf_stats < psize->max_stats_size) {
+		struct nd_pdsm_perf_stat *new_stats, *old_stats;
+		old_stats = p->perf_stats;
+
+		new_stats = (struct nd_pdsm_perf_stat *)
+			calloc(1, psize->max_stats_size);
+		if (!new_stats) {
+			papr_err(dimm, "Unable to allocate new perf_stats buffer\n");
+			return -ENOMEM;
+		}
+		if (old_stats) {
+			/* Copy the old buffer contents to new */
+			memcpy(new_stats, old_stats, p->len_perf_stats);
+			free(old_stats);
+		}
+		p->perf_stats = new_stats;
+	}
+
+	p->len_perf_stats = psize->max_stats_size;
+	papr_dbg(dimm, "dimm perf stats size =%lu\n",
+		 p->len_perf_stats);
+	return 0;
+}
+
 /* Parse a command payload and update dimm flags/private data */
 static int update_dimm_stats(struct ndctl_dimm *dimm, struct ndctl_cmd *cmd)
 {
@@ -163,6 +211,8 @@ static int update_dimm_stats(struct ndctl_dimm *dimm, struct ndctl_cmd *cmd)
 	switch (pcmd_to_pdsm(pcmd)) {
 	case PAPR_SCM_PDSM_HEALTH:
 		return update_dimm_health(dimm, cmd);
+	case PAPR_SCM_PDSM_FETCH_PERF_STATS:
+		return update_perf_stat_size(dimm, cmd);
 	default:
 		papr_err(dimm, "Unhandled pdsm-request 0x%016llx\n",
 			 pcmd_to_pdsm(pcmd));
@@ -286,10 +336,128 @@ static void papr_dimm_uninit(struct ndctl_dimm *dimm)
 		return;
 	}
 
+	if (p->perf_stats)
+		free(p->perf_stats);
+
 	dimm->dimm_user_data = NULL;
 	free(p);
 }
 
+/*
+ * Check if the given command is of type PDSM_READ_PERF_STATS and return
+ * 'struct nd_pdsm_read_perf_stats *' otherwise return NULL.
+ */
+static struct nd_pdsm_read_perf_stats *cmd_to_read_perf(struct ndctl_cmd *cmd)
+{
+	struct nd_pdsm_cmd_pkg *pcmd = nd_to_pdsm_cmd_pkg(cmd->pkg);
+
+	if (cmd && cmd_is_valid(cmd->dimm, cmd) &&
+	    pcmd_to_pdsm(pcmd) == PAPR_SCM_PDSM_READ_PERF_STATS)
+		return (struct nd_pdsm_read_perf_stats *)
+			(pdsm_cmd_to_payload(pcmd));
+	else
+		return NULL;
+}
+
+/* Callbacks from libndctl core to handle iterable read_perf_stats command */
+static u32 papr_get_xfer(struct ndctl_cmd *cmd)
+{
+	struct nd_pdsm_read_perf_stats *stats = cmd_to_read_perf(cmd);
+	if (stats == NULL)
+		papr_err(cmd->dimm, "Invalid command\n");
+	return stats ? stats->in_length : 0;
+}
+
+static u32 papr_get_offset(struct ndctl_cmd *cmd)
+{
+	struct nd_pdsm_read_perf_stats *stats = cmd_to_read_perf(cmd);
+	if (stats == NULL)
+		papr_err(cmd->dimm, "Invalid command\n");
+	return stats ? stats->in_offset : 0;
+}
+
+static void papr_set_xfer(struct ndctl_cmd *cmd, u32 xfer)
+{
+	struct nd_pdsm_read_perf_stats *stats = cmd_to_read_perf(cmd);
+	if (stats == NULL)
+		papr_err(cmd->dimm, "Invalid command\n");
+	stats->in_length = xfer;
+}
+
+static void papr_set_offset(struct ndctl_cmd *cmd, u32 offset)
+{
+	struct nd_pdsm_read_perf_stats *stats = cmd_to_read_perf(cmd);
+	if (stats == NULL)
+		papr_err(cmd->dimm, "Invalid command\n");
+	stats->in_offset = offset;
+}
+
+/* Fetch dimm stats and return a command to read them */
+static struct ndctl_cmd * papr_new_stats(struct ndctl_dimm * dimm)
+{
+	struct dimm_priv * p = dimm->dimm_user_data;
+	struct ndctl_cmd * cmd = NULL;
+	int rc;
+
+	/*
+	 * Submit a pdsm FETCH_PERF_STATS to get the latest stats fetched from
+	 * PHYP and have their length returned to libndctl. Next allocate
+	 * suitable size buffer in dimm private buffer 'perf_stats' and create
+	 * an iterable command for pdsm READ_PERF_STATS to read these stats
+	 * from kernel to 'perf_stats'
+	 */
+	cmd = allocate_cmd(dimm, PAPR_SCM_PDSM_FETCH_PERF_STATS,
+			   sizeof (struct nd_pdsm_fetch_perf_stats),
+			   ND_PDSM_FETCH_PERF_STATS_VERSION);
+	if (!cmd) {
+		papr_err(dimm, "Unable to allocate cmd for perf_stats size\n");
+		return NULL;
+	}
+
+	papr_dbg(dimm, "Fetching dimm stats from papr_scm\n");
+	cmd->pkg[0].nd_size_out = ND_PDSM_ENVELOPE_CONTENT_SIZE(
+		struct nd_pdsm_fetch_perf_stats);
+
+	/* If successful update the dimm data with length of dimm stats */
+	rc = ndctl_cmd_submit_xlat(cmd);
+	rc = rc ? rc : update_dimm_stats(dimm, cmd);
+
+	ndctl_cmd_unref(cmd);
+	if (rc) {
+		papr_err(dimm, "Error fetching perf stats. Err=%d\n", rc);
+		return NULL;
+	}
+
+	/* allocate pdsm READ_PERF_STATS command having tail xfer buffer */
+	cmd = allocate_cmd(dimm, PAPR_SCM_PDSM_READ_PERF_STATS,
+			   sizeof(struct nd_pdsm_read_perf_stats) + GET_PERF_STAT_XFER_SIZE,
+			   ND_PDSM_READ_PERF_STATS_VERSION);
+	if (!cmd) {
+		papr_err(dimm, "Unable to allocated read_perf_stats cmd\n");
+		return NULL;
+	}	/* Update the expected out size from the papr_scm module */
+
+        cmd->pkg[0].nd_size_out =
+		ND_PDSM_ENVELOPE_CONTENT_SIZE(struct nd_pdsm_read_perf_stats) +
+		GET_PERF_STAT_XFER_SIZE;
+
+        /* Setup the iterators */
+	cmd->iter.total_buf = (char *) p->perf_stats;
+	cmd->iter.init_offset = 0;
+	cmd->iter.max_xfer = GET_PERF_STAT_XFER_SIZE;
+	cmd->iter.total_xfer = p->len_perf_stats;
+	cmd->iter.dir = READ;
+	cmd->iter.data = (u8*)cmd_to_read_perf(cmd)->stats_data;
+
+	/* setup the callbacks */
+	cmd->get_xfer = papr_get_xfer;
+	cmd->get_offset = papr_get_offset;
+	cmd->set_xfer = papr_set_xfer;
+	cmd->set_offset = papr_set_offset;
+
+	return cmd;
+}
+
 struct ndctl_dimm_ops * const papr_scm_dimm_ops = &(struct ndctl_dimm_ops) {
 	.cmd_is_supported = papr_cmd_is_supported,
 	.dimm_init = papr_dimm_init,
@@ -299,4 +467,5 @@ struct ndctl_dimm_ops * const papr_scm_dimm_ops = &(struct ndctl_dimm_ops) {
 	.new_smart = papr_new_smart_health,
 	.smart_get_health = papr_smart_get_health,
 	.smart_get_shutdown_state = papr_smart_get_shutdown_state,
+	.new_stats = papr_new_stats,
 };
diff --git a/ndctl/lib/papr_scm_pdsm.h b/ndctl/lib/papr_scm_pdsm.h
index 9b1fdd894a6e..f9f463e6b7dd 100644
--- a/ndctl/lib/papr_scm_pdsm.h
+++ b/ndctl/lib/papr_scm_pdsm.h
@@ -114,6 +114,8 @@ struct nd_pdsm_cmd_pkg {
 enum papr_scm_pdsm {
 	PAPR_SCM_PDSM_MIN = 0x0,
 	PAPR_SCM_PDSM_HEALTH,
+	PAPR_SCM_PDSM_FETCH_PERF_STATS,
+	PAPR_SCM_PDSM_READ_PERF_STATS,
 	PAPR_SCM_PDSM_MAX,
 };
 
@@ -170,4 +172,50 @@ struct nd_papr_pdsm_health_v1 {
 /* Current version number for the dimm health struct */
 #define ND_PAPR_PDSM_HEALTH_VERSION 1
 
+/*
+ * Return the maximum buffer size needed to hold all performance state.
+ * max_stats_size: The buffer size needed to hold all stat entries
+ */
+struct nd_pdsm_fetch_perf_stats_v1 {
+	__u32 max_stats_size;
+	__u8 reserved[4];
+} __attribute__((packed));
+
+#define nd_pdsm_fetch_perf_stats nd_pdsm_fetch_perf_stats_v1
+#define ND_PDSM_FETCH_PERF_STATS_VERSION 1
+
+/*
+ * Holds a single performance stat. papr_scm owns a buffer that holds an array
+ * of all the available stats and their values. Access to the buffer is provided
+ * via PERF_STAT_SIZE and READ_PERF_STATS psdm.
+ * id : id of the performance stat. Usually acsii encode stat name.
+ * val : Non normalized value of the id.
+ */
+
+struct nd_pdsm_perf_stat {
+	__u64 id;
+	__u64 val;
+};
+
+/*
+ * Returns a chunk of performance stats buffer data to libndctl.
+ * This is needed to overcome the 256 byte envelope size limit enforced by
+ * libnvdimm.
+ * in_offset: The starting offset to perf stats data buffer.
+ * in_length: Length of data to be copied to 'stats_data'
+ * stats_data: Holds the chunk of requested perf stats data buffer.
+ *
+ * Note: To prevent races in reading performance stats, in_offset and in_length
+ * should multiple of 16-Bytes. If they are not then papr_scm will return an
+ * -EINVAL error.
+ */
+struct nd_pdsm_read_perf_stats_v1 {
+	__u32 in_offset;
+	__u32 in_length;
+ 	struct nd_pdsm_perf_stat stats_data[];
+} __attribute__((packed));
+
+#define nd_pdsm_read_perf_stats nd_pdsm_read_perf_stats_v1
+#define ND_PDSM_READ_PERF_STATS_VERSION 1
+
 #endif /* _UAPI_ASM_POWERPC_PAPR_SCM_PDSM_H_ */
-- 
2.26.2
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [ndctl RFC-PATCH 3/4] papr_scm: Implement parsing and clean-up for fetched dimm stats
  2020-05-18 11:20 [ndctl RFC-PATCH 0/4] Add support for reporting PAPR NVDIMM Statistics Vaibhav Jain
  2020-05-18 11:20 ` [ndctl RFC-PATCH 1/4] ndctl,libndctl: Implement new dimm-ops 'new_stats' and 'get_stat' Vaibhav Jain
  2020-05-18 11:20 ` [ndctl RFC-PATCH 2/4] papr_scm: Add support for fetching dimm-stats Vaibhav Jain
@ 2020-05-18 11:20 ` Vaibhav Jain
  2020-05-18 11:20 ` [ndctl RFC-PATCH 4/4] papr_scm: Implement dimm op 'get_stat' Vaibhav Jain
  3 siblings, 0 replies; 5+ messages in thread
From: Vaibhav Jain @ 2020-05-18 11:20 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Previous commit added functionality to fetch the dimm stats from
kernel 'papr_scm' module and store them into dimm private
struct. However these fetched values may contain stats which are
currently unknown to libndctl.

Hence this patch implements mechanism to parse and clean-up these
fetched dimm stats in a new function update_read_perf_stats(). Also a
new array of known stat-ids and their corresponding names and types is
introduced with a lookup function get_dimm_stat_desc().

Also since libndctl tends to deallocate the cmd->iter.total_buf on its
own when ndctl_cmd is freed, update_read_perf_stats() set it to NULL
to prevent this from happening.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
 ndctl/lib/papr_scm.c | 95 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 94 insertions(+), 1 deletion(-)

diff --git a/ndctl/lib/papr_scm.c b/ndctl/lib/papr_scm.c
index 14fb6d48c12a..d27bacaa7d2c 100644
--- a/ndctl/lib/papr_scm.c
+++ b/ndctl/lib/papr_scm.c
@@ -44,6 +44,13 @@
 /* Number of bytes to transffer in each ioctl for pdsm READ_PERF_STATS */
 #define GET_PERF_STAT_XFER_SIZE 16
 
+/* Structure that holds single dimm stat retrived from kernel */
+struct dimm_stat {
+	u64 id;
+	const char *name;
+	int type;
+};
+
 /* Per dimm data. Holds per-dimm data parsed from the cmd_pkgs */
 struct dimm_priv {
 
@@ -56,6 +63,40 @@ struct dimm_priv {
 	struct nd_pdsm_perf_stat *perf_stats;
 };
 
+/* List of all known dimm_stat descriptors */
+static const struct dimm_stat dimm_stats[] = {
+	{ 0x74437365526c7443ULL, "Controller Reset Count", STAT_TYPE_INT },
+	{ 0x6D547365526C7443ULL, "Controller Reset Elapsed Time", STAT_TYPE_INT},
+	{ 0x20736365536e6f50ULL, "Power-on Seconds", STAT_TYPE_INT64 },
+	{ 0x206566694c6d654dULL, "Life Remaining", STAT_TYPE_PERCENT },
+	{ 0x5563735274697243ULL, "Critical Resource Utilization", STAT_TYPE_PERCENT },
+	{ 0x746e434c74736f48ULL, "Host Load Count", STAT_TYPE_INT64 },
+	{ 0x746e435374736f48ULL, "Host Store Count", STAT_TYPE_INT64 },
+	{ 0x7275444c74736f48ULL, "Host Load Duration", STAT_TYPE_INT64 },
+	{ 0x7275445374736f48ULL, "Host Store Duration", STAT_TYPE_INT64 },
+	{ 0x20746e435264654dULL, "Media Read Count", STAT_TYPE_INT64 },
+	{ 0x20746e435764654dULL, "Media Write Count", STAT_TYPE_INT64 },
+	{ 0x207275445264654dULL, "Media Read Duration", STAT_TYPE_INT64 },
+	{ 0x207275445764654dULL, "Media Write Duration", STAT_TYPE_INT64 },
+	{ 0x746e434852686343ULL, "Cache Read Hit Count", STAT_TYPE_INT64 },
+	{ 0x746e434857686343ULL, "Cache Write Hit Count", STAT_TYPE_INT64 },
+	{ 0x746e435774736146ULL, "Fast Write Count", STAT_TYPE_INT64 },
+};
+
+/* Given a stat-id find the corrosponding descriptor */
+static const struct dimm_stat *get_dimm_stat_desc(u64 id)
+{
+	unsigned index;
+	if (id) {
+		for (index = 0; index < ARRAY_SIZE(dimm_stats); ++index) {
+			if (dimm_stats[index].id == id)
+				return &dimm_stats[index];
+		}
+	}
+
+	return NULL;
+}
+
 static bool papr_cmd_is_supported(struct ndctl_dimm *dimm, int cmd)
 {
 	/* Handle this separately to support monitor mode */
@@ -184,6 +225,47 @@ static int update_perf_stat_size(struct ndctl_dimm *dimm, struct ndctl_cmd *cmd)
 	return 0;
 }
 
+/* Parse the pdsm READ_PERF_STATS command package */
+static int update_read_perf_stats(struct ndctl_dimm *dimm, struct ndctl_cmd *cmd)
+{
+	struct nd_pdsm_cmd_pkg *pcmd = nd_to_pdsm_cmd_pkg(cmd->pkg);
+	struct dimm_priv *p = dimm->dimm_user_data;
+	struct nd_pdsm_perf_stat *stat_src, *stat_dest;
+
+	/* Prevent libndctl from freeing pointer to cmd->iter.total_buf */
+	cmd->iter.total_buf = NULL;
+
+	if (pcmd->cmd_status) {
+		/* Indicate no stats are available */
+		p->count_perf_stats = 0;
+		return pcmd->cmd_status;
+	}
+
+	/* is it an unknown version ? */
+	if (pcmd->payload_version != 1) {
+		papr_err(dimm, "Unknown payload version for perf stats\n");
+		return -EBADE;
+	}
+
+	/* count number of stats available and remove any unknown stats */
+	for(stat_dest = stat_src = p->perf_stats;
+	    (void *)stat_src < (void *)p->perf_stats + p->len_perf_stats;
+	    stat_src++) {
+
+		if (stat_src != stat_dest)
+			*stat_dest = *stat_src;
+
+		/* Skip unknown dimm stats */
+		if (get_dimm_stat_desc(stat_dest->id) != NULL)
+			stat_dest++;
+	}
+
+	/* Update the stats count that we received */
+	p->count_perf_stats = (stat_dest - p->perf_stats);
+
+	return 0;
+}
+
 /* Parse a command payload and update dimm flags/private data */
 static int update_dimm_stats(struct ndctl_dimm *dimm, struct ndctl_cmd *cmd)
 {
@@ -213,6 +295,8 @@ static int update_dimm_stats(struct ndctl_dimm *dimm, struct ndctl_cmd *cmd)
 		return update_dimm_health(dimm, cmd);
 	case PAPR_SCM_PDSM_FETCH_PERF_STATS:
 		return update_perf_stat_size(dimm, cmd);
+	case PAPR_SCM_PDSM_READ_PERF_STATS:
+		return update_read_perf_stats(dimm, cmd);
 	default:
 		papr_err(dimm, "Unhandled pdsm-request 0x%016llx\n",
 			 pcmd_to_pdsm(pcmd));
@@ -301,11 +385,20 @@ static unsigned int papr_smart_get_shutdown_state(struct ndctl_cmd *cmd)
 
 static unsigned int papr_smart_get_flags(struct ndctl_cmd *cmd)
 {
+	struct nd_pdsm_cmd_pkg *pcmd = nd_to_pdsm_cmd_pkg(cmd->pkg);
+
 	/* In case of error return empty flags * */
 	if (update_dimm_stats(cmd->dimm, cmd))
 		return 0;
 
-	return ND_SMART_HEALTH_VALID | ND_SMART_SHUTDOWN_VALID;
+	switch (pcmd_to_pdsm(pcmd)) {
+	case PAPR_SCM_PDSM_HEALTH:
+		return ND_SMART_HEALTH_VALID | ND_SMART_SHUTDOWN_VALID;
+	case PAPR_SCM_PDSM_READ_PERF_STATS:
+		return ND_SMART_STATS_VALID;
+	default:
+		return 0;
+	}
 }
 
 static int papr_dimm_init(struct ndctl_dimm *dimm)
-- 
2.26.2
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [ndctl RFC-PATCH 4/4] papr_scm: Implement dimm op 'get_stat'
  2020-05-18 11:20 [ndctl RFC-PATCH 0/4] Add support for reporting PAPR NVDIMM Statistics Vaibhav Jain
                   ` (2 preceding siblings ...)
  2020-05-18 11:20 ` [ndctl RFC-PATCH 3/4] papr_scm: Implement parsing and clean-up for fetched dimm stats Vaibhav Jain
@ 2020-05-18 11:20 ` Vaibhav Jain
  3 siblings, 0 replies; 5+ messages in thread
From: Vaibhav Jain @ 2020-05-18 11:20 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Previous patches implemented functionality to fetch the dimm-stats
from kernel by implementing dimm-op 'new_stats'. However in absence of
dimm-op 'get_stat' the fetched dimm-stats are never passed on to ndctl
json presentation layer.

This patch implements dimm-op 'get_stat' as function papr_get_stat()
that incremently returns populated 'struct ndctl_dimm_stat' instances
back to ndctl json util function util_dimm_stats_to_json() which then
creates a json-object out of them.

In order to keep track of last returned dimm-stat, papr_get_stat()
utilizes ndctl_cmd.private_data to store the next index of 'struct
nd_pdsm_perf_stat' to be returned from array dimm_priv.perf_stats.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
 ndctl/lib/papr_scm.c | 36 ++++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/ndctl/lib/papr_scm.c b/ndctl/lib/papr_scm.c
index d27bacaa7d2c..46f8992508b2 100644
--- a/ndctl/lib/papr_scm.c
+++ b/ndctl/lib/papr_scm.c
@@ -551,6 +551,41 @@ static struct ndctl_cmd * papr_new_stats(struct ndctl_dimm * dimm)
 	return cmd;
 }
 
+/* Return a single dimm-stat from the command until ret */
+static int papr_get_stat(struct ndctl_cmd *cmd, struct ndctl_dimm_stat * stat)
+{
+	/* Store the next stat index in stat->provider_private */
+	int next_index;
+	struct dimm_priv * p = cmd->dimm->dimm_user_data;
+	struct nd_pdsm_cmd_pkg *pcmd;
+	const struct dimm_stat *stat_desc;
+
+	if (!stat || !cmd)
+		return -EINVAL;
+
+	pcmd = nd_to_pdsm_cmd_pkg(cmd->pkg);
+	if (pcmd_to_pdsm(pcmd) != PAPR_SCM_PDSM_READ_PERF_STATS)
+		return -EINVAL;
+
+	/* Fetch the next_index from cmd and check bounds */
+	next_index = (cmd->private_data - (void*)0);
+	if (next_index >= p->count_perf_stats)
+		return -ENOENT;
+
+	stat_desc = get_dimm_stat_desc(p->perf_stats[next_index].id);
+	if (!stat_desc)
+		return -EINVAL;
+
+	/* populate theprovided struct */
+	stat->name = stat_desc->name;
+	stat->type = stat_desc->type;
+	stat->val.int64_val = p->perf_stats[next_index].val;
+
+	/* update the stored next index in the struct ndctl_cmd */
+	cmd->private_data = (void*)0 + next_index + 1;
+	return 0;
+}
+
 struct ndctl_dimm_ops * const papr_scm_dimm_ops = &(struct ndctl_dimm_ops) {
 	.cmd_is_supported = papr_cmd_is_supported,
 	.dimm_init = papr_dimm_init,
@@ -561,4 +596,5 @@ struct ndctl_dimm_ops * const papr_scm_dimm_ops = &(struct ndctl_dimm_ops) {
 	.smart_get_health = papr_smart_get_health,
 	.smart_get_shutdown_state = papr_smart_get_shutdown_state,
 	.new_stats = papr_new_stats,
+	.get_stat = papr_get_stat,
 };
-- 
2.26.2
_______________________________________________
Linux-nvdimm mailing list -- linux-nvdimm@lists.01.org
To unsubscribe send an email to linux-nvdimm-leave@lists.01.org

^ permalink raw reply related	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2020-05-18 11:20 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-18 11:20 [ndctl RFC-PATCH 0/4] Add support for reporting PAPR NVDIMM Statistics Vaibhav Jain
2020-05-18 11:20 ` [ndctl RFC-PATCH 1/4] ndctl,libndctl: Implement new dimm-ops 'new_stats' and 'get_stat' Vaibhav Jain
2020-05-18 11:20 ` [ndctl RFC-PATCH 2/4] papr_scm: Add support for fetching dimm-stats Vaibhav Jain
2020-05-18 11:20 ` [ndctl RFC-PATCH 3/4] papr_scm: Implement parsing and clean-up for fetched dimm stats Vaibhav Jain
2020-05-18 11:20 ` [ndctl RFC-PATCH 4/4] papr_scm: Implement dimm op 'get_stat' Vaibhav Jain

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).