linux-nvdimm.lists.01.org archive mirror
 help / color / mirror / Atom feed
* [ndctl PATCH v7 0/5] Add support for reporting papr nvdimm health
@ 2020-06-18  7:00 Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 1/5] libndctl: Refactor out add_dimm() to handle NFIT specific init Vaibhav Jain
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Vaibhav Jain @ 2020-06-18  7:00 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Changes since v6 [1]:
* Removed a stale comment and assignment from 'add_dimm()'.
* Updated patch description for Patch-1,2 based on review comments on
  v6 patch-series.
* Updated links to kernel patch series in patch-2.

[1] https://lore.kernel.org/linux-nvdimm/20200616053029.84731-1-vaibhav@linux.ibm.com
---
This patch-set proposes changes to libndctl to add support for reporting
health for nvdimms that support the PAPR standard[2]. The standard defines
machenism (HCALL) through which a guest kernel can query and fetch health
and performance stats of an nvdimm attached to the hypervisor[3]. Until
now 'ndctl' was unable to report these stats for papr_scm dimms on PPC64
guests due to absence of ACPI/NFIT, a limitation which this patch-set tries
to address.

The patch-set introduces support for the new PAPR PDSM family
defined at [4] & [5] via a new dimm-ops named
'papr_dimm_ops'. Infrastructure to probe and distinguish papr-scm
dimms from other dimm families that may support ACPI/NFIT is
implemented by updating the 'struct ndctl_dimm' initialization
routines to bifurcate based on the nvdimm type. We also introduce two
new dimm-ops member for handling initialization of dimm specific data
for specific DSM families.

These changes coupled with proposed kernel changes located at Ref[1] should
provide a way for the user to retrieve NVDIMM health status using ndtcl for
pseries guests. Below is a sample output using proposed kernel + ndctl
changes:

 # ndctl list -DH
[
  {
    "dev":"nmem0",
    "flag_smart_event":true,
    "health":{
      "health_state":"fatal",
      "shutdown_state":"dirty"
    }
  }
]

Structure of the patchset
=========================

We start with a re-factoring patch that splits the 'add_dimm()' function
into two functions one that take care of allocating and initializing
'struct ndctl_dimm' and another that takes care of initializing nfit
specific dimm attributes.

Patch-2 introduces probe function of papr nvdimms and assigning
'papr_dimm_ops' defined in 'papr.c' to 'dimm->ops' if
needed. The patch also code to parse the dimm flags specific to
papr nvdimms

Patches-3,4 implements scaffolding to add support for PAPR PDSM
requests and pull in their definitions from the kernel.

Finally Patch-6 add support for issuing and handling the result of
'struct ndctl_cmd' to request dimm health stats from papr_scm kernel module
and returning appropriate health status to libndctl for reporting.

References
==========
[2] "Power Architecture Platform Reference"
https://en.wikipedia.org/wiki/Power_Architecture_Platform_Reference

[3] "Hypercall Op-codes (hcalls)"
https://github.com/torvalds/linux/blob/master/Documentation/powerpc/papr_hcalls.rst

[4] "powerpc/papr_scm: Add support for reporting nvdimm health"
https://lore.kernel.org/linux-nvdimm/20200615124407.32596-1-vaibhav@linux.ibm.com/

[5] "ndctl/papr_scm,uapi: Add support for PAPR nvdimm specific methods"
https://lore.kernel.org/linux-nvdimm/20200615124407.32596-6-vaibhav@linux.ibm.com/

Vaibhav Jain (5):
  libndctl: Refactor out add_dimm() to handle NFIT specific init
  libncdtl: Add initial support for NVDIMM_FAMILY_PAPR nvdimm family
  libndctl,papr_scm: Add definitions for PAPR nvdimm specific methods
  papr: Add scaffolding to issue and handle PDSM requests
  libndctl,papr_scm: Implement support for PAPR_PDSM_HEALTH

 ndctl/lib/Makefile.am  |   1 +
 ndctl/lib/libndctl.c   | 262 +++++++++++++++++++++++++++++------------
 ndctl/lib/libndctl.sym |   5 +
 ndctl/lib/papr.c       | 224 +++++++++++++++++++++++++++++++++++
 ndctl/lib/papr.h       |  15 +++
 ndctl/lib/papr_pdsm.h  | 132 +++++++++++++++++++++
 ndctl/lib/private.h    |   4 +
 ndctl/libndctl.h       |   2 +
 ndctl/ndctl.h          |   1 +
 9 files changed, 573 insertions(+), 73 deletions(-)
 create mode 100644 ndctl/lib/papr.c
 create mode 100644 ndctl/lib/papr.h
 create mode 100644 ndctl/lib/papr_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	[flat|nested] 6+ messages in thread

* [ndctl PATCH v7 1/5] libndctl: Refactor out add_dimm() to handle NFIT specific init
  2020-06-18  7:00 [ndctl PATCH v7 0/5] Add support for reporting papr nvdimm health Vaibhav Jain
@ 2020-06-18  7:01 ` Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 2/5] libncdtl: Add initial support for NVDIMM_FAMILY_PAPR nvdimm family Vaibhav Jain
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Vaibhav Jain @ 2020-06-18  7:01 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Presently add_dimm() only probes dimms that support ACPI. Thus
refactor this functionality into two functions namely add_dimm() and
add_nfit_dimm(). Function add_dimm() performs allocation and common
'struct ndctl_dimm' initialization and depending on whether the
dimm-bus supports ACPI, calls add_nfit_dimm(). Once the probe is
completed based on the value of 'ndctl_dimm.cmd_family' appropriate
dimm-ops are assigned to the dimm.

In case dimm-bus is of unknown type or doesn't support ACPI the
initialization still continues, with no dimm-ops assigned to the
'struct ndctl_dimm' there by limiting the functionality available.

This patch shouldn't introduce any behavioral change.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
Changelog:

v6..v7:
* Updated the patch description. [ Vishal ]
* Removed a stale comment and assignment from add_dimm(). [ Vishal ]

v5..v6:
* Changed a return code for add_nfit_dimm() in case a allocation
  failed. [ Vishal ]
* Updated an error message in error path of add_dimm() [ Vishal ]

v4..v5:
* None

v3..v4:
* None

v2..v3:
* None

v1..v2:
* None
---
 ndctl/lib/libndctl.c | 194 +++++++++++++++++++++++++------------------
 1 file changed, 113 insertions(+), 81 deletions(-)

diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index ee737cbbfe3e..5f6dad71975b 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1441,82 +1441,15 @@ static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,
 static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath);
 static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias);
 
-static void *add_dimm(void *parent, int id, const char *dimm_base)
+static int add_nfit_dimm(struct ndctl_dimm *dimm, const char *dimm_base)
 {
-	int formats, i;
-	struct ndctl_dimm *dimm;
+	int i, rc = -1;
 	char buf[SYSFS_ATTR_SIZE];
-	struct ndctl_bus *bus = parent;
-	struct ndctl_ctx *ctx = bus->ctx;
+	struct ndctl_ctx *ctx = dimm->bus->ctx;
 	char *path = calloc(1, strlen(dimm_base) + 100);
 
 	if (!path)
-		return NULL;
-
-	sprintf(path, "%s/nfit/formats", dimm_base);
-	if (sysfs_read_attr(ctx, path, buf) < 0)
-		formats = 1;
-	else
-		formats = clamp(strtoul(buf, NULL, 0), 1UL, 2UL);
-
-	dimm = calloc(1, sizeof(*dimm) + sizeof(int) * formats);
-	if (!dimm)
-		goto err_dimm;
-	dimm->bus = bus;
-	dimm->id = id;
-
-	sprintf(path, "%s/dev", dimm_base);
-	if (sysfs_read_attr(ctx, path, buf) < 0)
-		goto err_read;
-	if (sscanf(buf, "%d:%d", &dimm->major, &dimm->minor) != 2)
-		goto err_read;
-
-	sprintf(path, "%s/commands", dimm_base);
-	if (sysfs_read_attr(ctx, path, buf) < 0)
-		goto err_read;
-	dimm->cmd_mask = parse_commands(buf, 1);
-
-	dimm->dimm_buf = calloc(1, strlen(dimm_base) + 50);
-	if (!dimm->dimm_buf)
-		goto err_read;
-	dimm->buf_len = strlen(dimm_base) + 50;
-
-	dimm->dimm_path = strdup(dimm_base);
-	if (!dimm->dimm_path)
-		goto err_read;
-
-	sprintf(path, "%s/modalias", dimm_base);
-	if (sysfs_read_attr(ctx, path, buf) < 0)
-		goto err_read;
-	dimm->module = to_module(ctx, buf);
-
-	dimm->handle = -1;
-	dimm->phys_id = -1;
-	dimm->serial = -1;
-	dimm->vendor_id = -1;
-	dimm->device_id = -1;
-	dimm->revision_id = -1;
-	dimm->health_eventfd = -1;
-	dimm->dirty_shutdown = -ENOENT;
-	dimm->subsystem_vendor_id = -1;
-	dimm->subsystem_device_id = -1;
-	dimm->subsystem_revision_id = -1;
-	dimm->manufacturing_date = -1;
-	dimm->manufacturing_location = -1;
-	dimm->cmd_family = -1;
-	dimm->nfit_dsm_mask = ULONG_MAX;
-	for (i = 0; i < formats; i++)
-		dimm->format[i] = -1;
-
-	sprintf(path, "%s/flags", dimm_base);
-	if (sysfs_read_attr(ctx, path, buf) < 0) {
-		dimm->locked = -1;
-		dimm->aliased = -1;
-	} else
-		parse_dimm_flags(dimm, buf);
-
-	if (!ndctl_bus_has_nfit(bus))
-		goto out;
+		return -ENOMEM;
 
 	/*
 	 * 'unique_id' may not be available on older kernels, so don't
@@ -1582,24 +1515,15 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)
 	sprintf(path, "%s/nfit/family", dimm_base);
 	if (sysfs_read_attr(ctx, path, buf) == 0)
 		dimm->cmd_family = strtoul(buf, NULL, 0);
-	if (dimm->cmd_family == NVDIMM_FAMILY_INTEL)
-		dimm->ops = intel_dimm_ops;
-	if (dimm->cmd_family == NVDIMM_FAMILY_HPE1)
-		dimm->ops = hpe1_dimm_ops;
-	if (dimm->cmd_family == NVDIMM_FAMILY_MSFT)
-		dimm->ops = msft_dimm_ops;
-	if (dimm->cmd_family == NVDIMM_FAMILY_HYPERV)
-		dimm->ops = hyperv_dimm_ops;
 
 	sprintf(path, "%s/nfit/dsm_mask", dimm_base);
 	if (sysfs_read_attr(ctx, path, buf) == 0)
 		dimm->nfit_dsm_mask = strtoul(buf, NULL, 0);
 
-	dimm->formats = formats;
 	sprintf(path, "%s/nfit/format", dimm_base);
 	if (sysfs_read_attr(ctx, path, buf) == 0)
 		dimm->format[0] = strtoul(buf, NULL, 0);
-	for (i = 1; i < formats; i++) {
+	for (i = 1; i < dimm->formats; i++) {
 		sprintf(path, "%s/nfit/format%d", dimm_base, i);
 		if (sysfs_read_attr(ctx, path, buf) == 0)
 			dimm->format[i] = strtoul(buf, NULL, 0);
@@ -1610,7 +1534,115 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)
 		parse_nfit_mem_flags(dimm, buf);
 
 	dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);
+	rc = 0;
+ err_read:
+
+	free(path);
+	return rc;
+}
+
+static void *add_dimm(void *parent, int id, const char *dimm_base)
+{
+	int formats, i, rc = -ENODEV;
+	struct ndctl_dimm *dimm = NULL;
+	char buf[SYSFS_ATTR_SIZE];
+	struct ndctl_bus *bus = parent;
+	struct ndctl_ctx *ctx = bus->ctx;
+	char *path = calloc(1, strlen(dimm_base) + 100);
+
+	if (!path)
+		return NULL;
+
+	sprintf(path, "%s/nfit/formats", dimm_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		formats = 1;
+	else
+		formats = clamp(strtoul(buf, NULL, 0), 1UL, 2UL);
+
+	dimm = calloc(1, sizeof(*dimm) + sizeof(int) * formats);
+	if (!dimm)
+		goto err_dimm;
+	dimm->bus = bus;
+	dimm->id = id;
+
+	sprintf(path, "%s/dev", dimm_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		goto err_read;
+	if (sscanf(buf, "%d:%d", &dimm->major, &dimm->minor) != 2)
+		goto err_read;
+
+	sprintf(path, "%s/commands", dimm_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		goto err_read;
+	dimm->cmd_mask = parse_commands(buf, 1);
+
+	dimm->dimm_buf = calloc(1, strlen(dimm_base) + 50);
+	if (!dimm->dimm_buf)
+		goto err_read;
+	dimm->buf_len = strlen(dimm_base) + 50;
+
+	dimm->dimm_path = strdup(dimm_base);
+	if (!dimm->dimm_path)
+		goto err_read;
+
+	sprintf(path, "%s/modalias", dimm_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		goto err_read;
+	dimm->module = to_module(ctx, buf);
+
+	dimm->handle = -1;
+	dimm->phys_id = -1;
+	dimm->serial = -1;
+	dimm->vendor_id = -1;
+	dimm->device_id = -1;
+	dimm->revision_id = -1;
+	dimm->health_eventfd = -1;
+	dimm->dirty_shutdown = -ENOENT;
+	dimm->subsystem_vendor_id = -1;
+	dimm->subsystem_device_id = -1;
+	dimm->subsystem_revision_id = -1;
+	dimm->manufacturing_date = -1;
+	dimm->manufacturing_location = -1;
+	dimm->cmd_family = -1;
+	dimm->nfit_dsm_mask = ULONG_MAX;
+	for (i = 0; i < formats; i++)
+		dimm->format[i] = -1;
+
+	sprintf(path, "%s/flags", dimm_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0) {
+		dimm->locked = -1;
+		dimm->aliased = -1;
+	} else
+		parse_dimm_flags(dimm, buf);
+
+	/* Check if the given dimm supports nfit */
+	if (ndctl_bus_has_nfit(bus)) {
+		dimm->formats = formats;
+		rc = add_nfit_dimm(dimm, dimm_base);
+	}
+
+	if (rc == -ENODEV) {
+		/* Unprobed dimm with no family */
+		rc = 0;
+		goto out;
+	}
+
+	/* Assign dimm-ops based on command family */
+	if (dimm->cmd_family == NVDIMM_FAMILY_INTEL)
+		dimm->ops = intel_dimm_ops;
+	if (dimm->cmd_family == NVDIMM_FAMILY_HPE1)
+		dimm->ops = hpe1_dimm_ops;
+	if (dimm->cmd_family == NVDIMM_FAMILY_MSFT)
+		dimm->ops = msft_dimm_ops;
+	if (dimm->cmd_family == NVDIMM_FAMILY_HYPERV)
+		dimm->ops = hyperv_dimm_ops;
  out:
+	if (rc) {
+		err(ctx, "%s: probe failed: %s\n", ndctl_dimm_get_devname(dimm),
+		    strerror(-rc));
+		goto err_read;
+	}
+
 	list_add(&bus->dimms, &dimm->list);
 	free(path);
 
-- 
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] 6+ messages in thread

* [ndctl PATCH v7 2/5] libncdtl: Add initial support for NVDIMM_FAMILY_PAPR nvdimm family
  2020-06-18  7:00 [ndctl PATCH v7 0/5] Add support for reporting papr nvdimm health Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 1/5] libndctl: Refactor out add_dimm() to handle NFIT specific init Vaibhav Jain
@ 2020-06-18  7:01 ` Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 3/5] libndctl,papr_scm: Add definitions for PAPR nvdimm specific methods Vaibhav Jain
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Vaibhav Jain @ 2020-06-18  7:01 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Add necessary scaffolding in libndctl for dimms that support the
papr_scm specification[1]. Since there can be platforms that support
Open-Firmware[2] but not the papr_scm specification, the changes
proposed first add support for probing if the dimm bus supports
Open-Firmware. This is done by querying for the sysfs attribute
'of_node' in dimm device sysfs directory. If available newly
introduced member 'struct ndctl_bus.has_of_node' is set. During
'add_dimm()', the newly introduced add_papr_dimm() is called if dimm
bus reports supports Open-Firmware.

Function add_papr_dimm() queries the 'compatible' device tree
attribute via newly introduced ndctl_bus_is_papr_scm() and based on
its value assigns NVDIMM_FAMILY_PAPR to the dimm command family. In
the future, based on the contents of 'compatible' attribute more
of_pmem dimm families can be queried.

Additionally add support for parsing the dimm flags for
NVDIMM_FAMILY_PAPR supporting nvdimms as described at [3]. A newly
introduced function parse_papr_flags() reads the contents of this
flag file and sets appropriate flag bits in 'struct
ndctl_dimm.flags'.

Also, advertise support for monitor mode.

References:
[1] Documentation/powerpc/papr_hcalls.rst
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/powerpc/papr_hcalls.rst

[2] https://en.wikipedia.org/wiki/Open_Firmware

[3] Documentation/ABI/testing/sysfs-bus-papr-pmem
https://git.kernel.org/nvdimm/nvdimm/c/b791abf3201d724ac372c2ba1fa6e90d192e1dbf

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
Changelog:

v6..v7:
* Updated patch description based of review comments on v6 [ Vishal ]
* Updated links in patch description to current version. [ Vishal ]
* Added the missing copyright text in 'papr.c'

v5..v6:
* Updated various dbg messages to use consistent dimm device name
  rather than dimm-id. [Vishal]
* Minor changes to log messages in add_papr_dimm() [ Vishal ]
* Minor change in parse_papr_flags() to aid in code readability [Vishal]
* Added ndctl_bus_has_of_node() to library ld version script. [Vishal]
* Added new library function ndctl_bus_is_papr_scm() that checks the
  device tree compatible field [Vishal]
* Updated add_papr_dimm() to use ndctl_bus_is_papr_scm() [Vishal]
* Updated the license header of 'papr.c' to LGPL 2.1

v4..v5:
* Renamed file 'papr_scm.c' to 'papr.c'
* s/NVDIMM_FAMILY_PAPR_SCM/NVDIMM_FAMILY_PAPR/g
* s/papr_scm_dimm_ops/papr_dimm_ops/g
* s/parse_papr_scm_flags()/parse_papr_flags()/g
* Updated patch description & title to reflect new command family name
  and file-names.

v3..v4:
* None

v2..v3:
* Renamed add_of_pmem() to add_papr_dimm() [ Aneesh ]

v1..v2:
* Squashed the patch to parse dimm flags
* Updated the dimm flags parsing to add case for 'restore_fail' and
  'flush_fail'.
* Renamed parse_of_pmem_flags() to parse_papr_scm_flags().
* Updated the path to dimm flags file to 'papr/flags'.
* Introduced 'papr_scm.c' file in this patch rather than later in the
  patch series.
* Update add_of_pmem_dimm() to parse dimm flags and enable monitoring
  only if 'ibm,pmemory' compatible nvdimm is found.
---
 ndctl/lib/Makefile.am  |  1 +
 ndctl/lib/libndctl.c   | 84 ++++++++++++++++++++++++++++++++++++++++++
 ndctl/lib/libndctl.sym |  5 +++
 ndctl/lib/papr.c       | 28 ++++++++++++++
 ndctl/lib/private.h    |  2 +
 ndctl/libndctl.h       |  2 +
 ndctl/ndctl.h          |  1 +
 7 files changed, 123 insertions(+)
 create mode 100644 ndctl/lib/papr.c

diff --git a/ndctl/lib/Makefile.am b/ndctl/lib/Makefile.am
index d6be5c3acd26..e15bb2288575 100644
--- a/ndctl/lib/Makefile.am
+++ b/ndctl/lib/Makefile.am
@@ -23,6 +23,7 @@ libndctl_la_SOURCES =\
 	hpe1.c \
 	msft.c \
 	hyperv.c \
+	papr.c \
 	ars.c \
 	firmware.c \
 	libndctl.c \
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index 5f6dad71975b..24ae27d5979e 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -799,6 +799,28 @@ static void parse_nfit_mem_flags(struct ndctl_dimm *dimm, char *flags)
 				ndctl_dimm_get_devname(dimm), flags);
 }
 
+static void parse_papr_flags(struct ndctl_dimm *dimm, char *flags)
+{
+	struct ndctl_ctx *ctx = ndctl_dimm_get_ctx(dimm);
+	char *start, *end;
+
+	start = flags;
+	while ((end = strchr(start, ' '))) {
+		*end = '\0';
+		if (strcmp(start, "not_armed") == 0)
+			dimm->flags.f_arm = 1;
+		else if (strcmp(start, "flush_fail") == 0)
+			dimm->flags.f_flush = 1;
+		else if (strcmp(start, "restore_fail") == 0)
+			dimm->flags.f_restore = 1;
+		else if (strcmp(start, "smart_notify") == 0)
+			dimm->flags.f_smart = 1;
+		start = end + 1;
+	}
+	if (end != start)
+		dbg(ctx, "%s: Flags:%s\n", ndctl_dimm_get_devname(dimm), flags);
+}
+
 static void parse_dimm_flags(struct ndctl_dimm *dimm, char *flags)
 {
 	char *start, *end;
@@ -856,6 +878,12 @@ static void *add_bus(void *parent, int id, const char *ctl_base)
 		bus->revision = strtoul(buf, NULL, 0);
 	}
 
+	sprintf(path, "%s/device/of_node/compatible", ctl_base);
+	if (sysfs_read_attr(ctx, path, buf) < 0)
+		bus->has_of_node = 0;
+	else
+		bus->has_of_node = 1;
+
 	sprintf(path, "%s/device/nfit/dsm_mask", ctl_base);
 	if (sysfs_read_attr(ctx, path, buf) < 0)
 		bus->nfit_dsm_mask = 0;
@@ -964,6 +992,23 @@ NDCTL_EXPORT int ndctl_bus_has_nfit(struct ndctl_bus *bus)
 	return bus->has_nfit;
 }
 
+NDCTL_EXPORT int ndctl_bus_has_of_node(struct ndctl_bus *bus)
+{
+	return bus->has_of_node;
+}
+
+NDCTL_EXPORT int ndctl_bus_is_papr_scm(struct ndctl_bus *bus)
+{
+	char buf[SYSFS_ATTR_SIZE];
+
+	snprintf(bus->bus_buf, bus->buf_len,
+		 "%s/of_node/compatible", bus->bus_path);
+	if (sysfs_read_attr(bus->ctx, bus->bus_buf, buf) < 0)
+		return 0;
+
+	return (strcmp(buf, "ibm,pmemory") == 0);
+}
+
 /**
  * ndctl_bus_get_major - nd bus character device major number
  * @bus: ndctl_bus instance returned from ndctl_bus_get_{first|next}
@@ -1441,6 +1486,40 @@ static int ndctl_bind(struct ndctl_ctx *ctx, struct kmod_module *module,
 static int ndctl_unbind(struct ndctl_ctx *ctx, const char *devpath);
 static struct kmod_module *to_module(struct ndctl_ctx *ctx, const char *alias);
 
+static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base)
+{
+	int rc = -ENODEV;
+	char buf[SYSFS_ATTR_SIZE];
+	struct ndctl_ctx *ctx = dimm->bus->ctx;
+	char *path = calloc(1, strlen(dimm_base) + 100);
+	const char * const devname = ndctl_dimm_get_devname(dimm);
+
+	dbg(ctx, "%s: Probing of_pmem dimm at %s\n", devname, dimm_base);
+
+	if (!path)
+		return -ENOMEM;
+
+	/* construct path to the papr compatible dimm flags file */
+	sprintf(path, "%s/papr/flags", dimm_base);
+
+	if (ndctl_bus_is_papr_scm(dimm->bus) &&
+	    sysfs_read_attr(ctx, path, buf) == 0) {
+
+		dbg(ctx, "%s: Adding papr-scm dimm flags:\"%s\"\n", devname, buf);
+		dimm->cmd_family = NVDIMM_FAMILY_PAPR;
+
+		/* Parse dimm flags */
+		parse_papr_flags(dimm, buf);
+
+		/* Allocate monitor mode fd */
+		dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);
+		rc = 0;
+	}
+
+	free(path);
+	return rc;
+}
+
 static int add_nfit_dimm(struct ndctl_dimm *dimm, const char *dimm_base)
 {
 	int i, rc = -1;
@@ -1619,6 +1698,8 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)
 	if (ndctl_bus_has_nfit(bus)) {
 		dimm->formats = formats;
 		rc = add_nfit_dimm(dimm, dimm_base);
+	} else if (ndctl_bus_has_of_node(bus)) {
+		rc = add_papr_dimm(dimm, dimm_base);
 	}
 
 	if (rc == -ENODEV) {
@@ -1636,6 +1717,9 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)
 		dimm->ops = msft_dimm_ops;
 	if (dimm->cmd_family == NVDIMM_FAMILY_HYPERV)
 		dimm->ops = hyperv_dimm_ops;
+	if (dimm->cmd_family == NVDIMM_FAMILY_PAPR)
+		dimm->ops = papr_dimm_ops;
+
  out:
 	if (rc) {
 		err(ctx, "%s: probe failed: %s\n", ndctl_dimm_get_devname(dimm),
diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym
index ac575a23d035..9cfaccf5d3b7 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_bus_has_of_node;
+	ndctl_bus_is_papr_scm;
+} LIBNDCTL_23;
diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c
new file mode 100644
index 000000000000..2d1be73e455f
--- /dev/null
+++ b/ndctl/lib/papr.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: LGPL-2.1
+/*
+ * libndctl support for PAPR-SCM based NVDIMMs
+ *
+ * (C) Copyright IBM 2020
+ *
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <util/log.h>
+#include <ndctl.h>
+#include <ndctl/libndctl.h>
+#include <lib/private.h>
+
+static bool papr_cmd_is_supported(struct ndctl_dimm *dimm, int cmd)
+{
+	/* Handle this separately to support monitor mode */
+	if (cmd == ND_CMD_SMART)
+		return true;
+
+	return !!(dimm->cmd_mask & (1ULL << cmd));
+}
+
+struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) {
+	.cmd_is_supported = papr_cmd_is_supported,
+};
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index 2e537f0a8649..d90236b1f98b 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -167,6 +167,7 @@ struct ndctl_bus {
 	int dimms_init;
 	int regions_init;
 	int has_nfit;
+	int has_of_node;
 	char *bus_path;
 	char *bus_buf;
 	size_t buf_len;
@@ -352,6 +353,7 @@ extern struct ndctl_dimm_ops * const intel_dimm_ops;
 extern struct ndctl_dimm_ops * const hpe1_dimm_ops;
 extern struct ndctl_dimm_ops * const msft_dimm_ops;
 extern struct ndctl_dimm_ops * const hyperv_dimm_ops;
+extern struct ndctl_dimm_ops * const papr_dimm_ops;
 
 static inline struct ndctl_bus *cmd_to_bus(struct ndctl_cmd *cmd)
 {
diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h
index 2580f433ade8..e16fb7eaf34b 100644
--- a/ndctl/libndctl.h
+++ b/ndctl/libndctl.h
@@ -119,6 +119,8 @@ struct ndctl_bus *ndctl_bus_get_next(struct ndctl_bus *bus);
              bus = ndctl_bus_get_next(bus))
 struct ndctl_ctx *ndctl_bus_get_ctx(struct ndctl_bus *bus);
 int ndctl_bus_has_nfit(struct ndctl_bus *bus);
+int ndctl_bus_has_of_node(struct ndctl_bus *bus);
+int ndctl_bus_is_papr_scm(struct ndctl_bus *bus);
 unsigned int ndctl_bus_get_major(struct ndctl_bus *bus);
 unsigned int ndctl_bus_get_minor(struct ndctl_bus *bus);
 const char *ndctl_bus_get_devname(struct ndctl_bus *bus);
diff --git a/ndctl/ndctl.h b/ndctl/ndctl.h
index 008f81cdeb9f..3b64f66d58cc 100644
--- a/ndctl/ndctl.h
+++ b/ndctl/ndctl.h
@@ -263,6 +263,7 @@ struct nd_cmd_pkg {
 #define NVDIMM_FAMILY_HPE2 2
 #define NVDIMM_FAMILY_MSFT 3
 #define NVDIMM_FAMILY_HYPERV 4
+#define NVDIMM_FAMILY_PAPR 5
 
 #define ND_IOCTL_CALL			_IOWR(ND_IOCTL, ND_CMD_CALL,\
 					struct nd_cmd_pkg)
-- 
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] 6+ messages in thread

* [ndctl PATCH v7 3/5] libndctl,papr_scm: Add definitions for PAPR nvdimm specific methods
  2020-06-18  7:00 [ndctl PATCH v7 0/5] Add support for reporting papr nvdimm health Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 1/5] libndctl: Refactor out add_dimm() to handle NFIT specific init Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 2/5] libncdtl: Add initial support for NVDIMM_FAMILY_PAPR nvdimm family Vaibhav Jain
@ 2020-06-18  7:01 ` Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 4/5] papr: Add scaffolding to issue and handle PDSM requests Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 5/5] libndctl,papr_scm: Implement support for PAPR_PDSM_HEALTH Vaibhav Jain
  4 siblings, 0 replies; 6+ messages in thread
From: Vaibhav Jain @ 2020-06-18  7:01 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Pull the kernel definition of PAPR nvdimm specific methods which is
located in the proposed kernel tree patches at Ref[1] & [2].

Add a new header file 'papr.h' that introduces defines 'struct
nd_pkg_papr' that holds an instance of 'struct nd_cmd_pkg' and 'struct
nd_pkg_pdsm' together. Also add an instance of 'struct nd_pkg_pdsm' to
'struct ndctl_cmd' named as 'papr'.

References:
[1] "powerpc/papr_scm: Add support for reporting nvdimm health"
https://lore.kernel.org/linux-nvdimm/20200615124407.32596-1-vaibhav@linux.ibm.com/

[2] "ndctl/papr_scm,uapi: Add support for PAPR nvdimm specific methods"
https://lore.kernel.org/linux-nvdimm/20200615124407.32596-6-vaibhav@linux.ibm.com/

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
Changelog:

v6..v7:
* None

v5..v6:
* Updated 'papr_pdsm.h' to recent kernel-uapi version.
* Introduced a new header 'papr.h' and 'struct nd_pkg_papr'.
* Updated patch description.

v4..v5:
* Renamed 'papr_scm_pdsm.h' to 'papr_pdsm.h'
* Updated 'papr_pdsm.h' to recent kernel-uapi version.

v3..v4:
* Updated the definition of 'struct nd_pdsm_cmd_pkg' and
  pdsm_cmd_to_payload() to remove 'payload_offset' field. [ Aneesh ]

v2..v3:
* Added instance of 'struct nd_pdsm_cmd_pkg' to 'struct ndctl_cmd'
* Updated commit description.
* Updated the papr_scm_pdsm.h header to recently proposed kernel
  version.

v1..v2:
* Switched from obsolete papr_scm_dsm.h to recent papr_scm_pdsm.h that
  describes the ND_CMD_CALL interface between libndctl and papr_scm
  module.
---
 ndctl/lib/papr.c      |   1 +
 ndctl/lib/papr.h      |  15 +++++
 ndctl/lib/papr_pdsm.h | 132 ++++++++++++++++++++++++++++++++++++++++++
 ndctl/lib/private.h   |   2 +
 4 files changed, 150 insertions(+)
 create mode 100644 ndctl/lib/papr.h
 create mode 100644 ndctl/lib/papr_pdsm.h

diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c
index 2d1be73e455f..42372c3e2f7f 100644
--- a/ndctl/lib/papr.c
+++ b/ndctl/lib/papr.c
@@ -13,6 +13,7 @@
 #include <ndctl.h>
 #include <ndctl/libndctl.h>
 #include <lib/private.h>
+#include "papr.h"
 
 static bool papr_cmd_is_supported(struct ndctl_dimm *dimm, int cmd)
 {
diff --git a/ndctl/lib/papr.h b/ndctl/lib/papr.h
new file mode 100644
index 000000000000..77579396a7bd
--- /dev/null
+++ b/ndctl/lib/papr.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/* (C) Copyright IBM 2020 */
+
+#ifndef __PAPR_H__
+#define __PAPR_H__
+
+#include <papr_pdsm.h>
+
+/* Wraps a nd_cmd generic header with pdsm header */
+struct nd_pkg_papr {
+	struct nd_cmd_pkg gen;
+	struct nd_pkg_pdsm pdsm;
+};
+
+#endif /* __PAPR_H__ */
diff --git a/ndctl/lib/papr_pdsm.h b/ndctl/lib/papr_pdsm.h
new file mode 100644
index 000000000000..4c7c06757053
--- /dev/null
+++ b/ndctl/lib/papr_pdsm.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * PAPR nvDimm Specific Methods (PDSM) and structs for libndctl
+ *
+ * (C) Copyright IBM 2020
+ *
+ * Author: Vaibhav Jain <vaibhav at linux.ibm.com>
+ */
+
+#ifndef _UAPI_ASM_POWERPC_PAPR_PDSM_H_
+#define _UAPI_ASM_POWERPC_PAPR_PDSM_H_
+
+#include <linux/types.h>
+#include <linux/ndctl.h>
+
+/*
+ * PDSM Envelope:
+ *
+ * The ioctl ND_CMD_CALL exchange data between user-space and kernel via
+ * envelope which consists of 2 headers sections and payload sections as
+ * illustrated below:
+ *  +-----------------+---------------+---------------------------+
+ *  |   64-Bytes      |   8-Bytes     |       Max 184-Bytes       |
+ *  +-----------------+---------------+---------------------------+
+ *  | ND-HEADER       |  PDSM-HEADER  |      PDSM-PAYLOAD         |
+ *  +-----------------+---------------+---------------------------+
+ *  | nd_family       |               |                           |
+ *  | nd_size_out     | cmd_status    |                           |
+ *  | nd_size_in      | reserved      |     nd_pdsm_payload       |
+ *  | nd_command      | payload   --> |                           |
+ *  | nd_fw_size      |               |                           |
+ *  | nd_payload ---> |               |                           |
+ *  +---------------+-----------------+---------------------------+
+ *
+ * ND Header:
+ * This is the generic libnvdimm header described as 'struct nd_cmd_pkg'
+ * which is interpreted by libnvdimm before passed on to papr_scm. Important
+ * member fields used are:
+ * 'nd_family'		: (In) NVDIMM_FAMILY_PAPR_SCM
+ * 'nd_size_in'		: (In) PDSM-HEADER + PDSM-IN-PAYLOAD (usually 0)
+ * 'nd_size_out'        : (In) PDSM-HEADER + PDSM-RETURN-PAYLOAD
+ * 'nd_command'         : (In) One of PAPR_PDSM_XXX
+ * 'nd_fw_size'         : (Out) PDSM-HEADER + size of actual payload returned
+ *
+ * PDSM Header:
+ * This is papr-scm specific header that precedes the payload. This is defined
+ * as nd_cmd_pdsm_pkg.  Following fields aare available in this header:
+ *
+ * 'cmd_status'		: (Out) Errors if any encountered while servicing PDSM.
+ * 'reserved'		: Not used, reserved for future and should be set to 0.
+ * 'payload'            : A union of all the possible payload structs
+ *
+ * PDSM Payload:
+ *
+ * The layout of the PDSM Payload is defined by various structs shared between
+ * papr_scm and libndctl so that contents of payload can be interpreted. As such
+ * its defined as a union of all possible payload structs as
+ * 'union nd_pdsm_payload'. Based on the value of 'nd_cmd_pkg.nd_command'
+ * appropriate member of the union is accessed.
+ */
+
+/* Max payload size that we can handle */
+#define ND_PDSM_PAYLOAD_MAX_SIZE 184
+
+/* Max payload size that we can handle */
+#define ND_PDSM_HDR_SIZE \
+	(sizeof(struct nd_pkg_pdsm) - ND_PDSM_PAYLOAD_MAX_SIZE)
+
+/* Various nvdimm health indicators */
+#define PAPR_PDSM_DIMM_HEALTHY       0
+#define PAPR_PDSM_DIMM_UNHEALTHY     1
+#define PAPR_PDSM_DIMM_CRITICAL      2
+#define PAPR_PDSM_DIMM_FATAL         3
+
+/*
+ * Struct exchanged between kernel & ndctl in for PAPR_PDSM_HEALTH
+ * Various flags indicate the health status of the dimm.
+ *
+ * extension_flags	: Any extension fields present in the struct.
+ * dimm_unarmed		: Dimm not armed. So contents wont persist.
+ * dimm_bad_shutdown	: Previous shutdown did not persist contents.
+ * dimm_bad_restore	: Contents from previous shutdown werent restored.
+ * dimm_scrubbed	: Contents of the dimm have been scrubbed.
+ * dimm_locked		: Contents of the dimm cant be modified until CEC reboot
+ * dimm_encrypted	: Contents of dimm are encrypted.
+ * dimm_health		: Dimm health indicator. One of PAPR_PDSM_DIMM_XXXX
+ */
+struct nd_papr_pdsm_health {
+	union {
+		struct {
+			__u32 extension_flags;
+			__u8 dimm_unarmed;
+			__u8 dimm_bad_shutdown;
+			__u8 dimm_bad_restore;
+			__u8 dimm_scrubbed;
+			__u8 dimm_locked;
+			__u8 dimm_encrypted;
+			__u16 dimm_health;
+		};
+		__u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE];
+	};
+};
+
+/*
+ * Methods to be embedded in ND_CMD_CALL request. These are sent to the kernel
+ * via 'nd_cmd_pkg.nd_command' member of the ioctl struct
+ */
+enum papr_pdsm {
+	PAPR_PDSM_MIN = 0x0,
+	PAPR_PDSM_HEALTH,
+	PAPR_PDSM_MAX,
+};
+
+/* Maximal union that can hold all possible payload types */
+union nd_pdsm_payload {
+	struct nd_papr_pdsm_health health;
+	__u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE];
+} __attribute__((packed));
+
+/*
+ * PDSM-header + payload expected with ND_CMD_CALL ioctl from libnvdimm
+ * Valid member of union 'payload' is identified via 'nd_cmd_pkg.nd_command'
+ * that should always precede this struct when sent to papr_scm via CMD_CALL
+ * interface.
+ */
+struct nd_pkg_pdsm {
+	__s32 cmd_status;	/* Out: Sub-cmd status returned back */
+	__u16 reserved[2];	/* Ignored and to be set as '0' */
+	union nd_pdsm_payload payload;
+} __attribute__((packed));
+
+#endif /* _UAPI_ASM_POWERPC_PAPR_PDSM_H_ */
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index d90236b1f98b..c3d5fd7ac9a9 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -32,6 +32,7 @@
 #include "hpe1.h"
 #include "msft.h"
 #include "hyperv.h"
+#include "papr.h"
 #include "libndctl-nfit.h"
 
 struct nvdimm_data {
@@ -277,6 +278,7 @@ struct ndctl_cmd {
 		struct ndn_pkg_msft msft[0];
 		struct nd_pkg_hyperv hyperv[0];
 		struct nd_pkg_intel intel[0];
+		struct nd_pkg_papr papr[0];
 		struct nd_cmd_get_config_size get_size[0];
 		struct nd_cmd_get_config_data_hdr get_data[0];
 		struct nd_cmd_set_config_hdr set_data[0];
-- 
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] 6+ messages in thread

* [ndctl PATCH v7 4/5] papr: Add scaffolding to issue and handle PDSM requests
  2020-06-18  7:00 [ndctl PATCH v7 0/5] Add support for reporting papr nvdimm health Vaibhav Jain
                   ` (2 preceding siblings ...)
  2020-06-18  7:01 ` [ndctl PATCH v7 3/5] libndctl,papr_scm: Add definitions for PAPR nvdimm specific methods Vaibhav Jain
@ 2020-06-18  7:01 ` Vaibhav Jain
  2020-06-18  7:01 ` [ndctl PATCH v7 5/5] libndctl,papr_scm: Implement support for PAPR_PDSM_HEALTH Vaibhav Jain
  4 siblings, 0 replies; 6+ messages in thread
From: Vaibhav Jain @ 2020-06-18  7:01 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

This patch implement necessary infrastructure inside 'papr.c' to
issue and handle PDSM requests. Changes implemented are:

* New helper function allocate_cmd() to allocate command packages for
  a specific PDSM command and payload size.

* Provide a skeleton implementation of 'dimm_ops->smart_get_flags' to
  check the submitted command for any errors. Presently no flags are
  returned from this callback and future patch will update this
  callback function to check submitted ndctl_cmd instance and return
  appropriate flags.

* cmd_is_valid() to validate submitted 'struct ndctl_cmd' instance for
  correct command family and PDSM command id.

* Implement callbacks for 'dimm_ops->get_firmware_status' and
  'dimm_ops->get_xlat_firmware_status' to return translated firmware
  command status from 'struct ndctl_cmd'.

* Logging helpers for papr_scm that use the underlying libndctl
  provided logging.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
Changelog:

v6..v7:
* None

v5..v6:
* Reworked the patch based on recent changes introduced for layout
  changes to  'struct nd_cmd_pkg'.
* Removed function update_dimm_stats() and papr_dimm_init/uninit() as
  they depended on an now a defunct patch "libndctl: Introduce new
  dimm-ops dimm_init() & dimm_uninit()"
* Introduced various helper macros to_pdsm(), to_ndcmd(), to_payload()
  and to_pdsm_cmd().

v4..v5:
* Updated papr_dbg/err macros to remove the 'scm' suffix.
* s/NVDIMM_FAMILY_PAPR_SCM/NVDIMM_FAMILY_PAPR/g
* s/PAPR_SCM_PDSM_*/PAPR_PDSM_*/g
* Minor changes to various comments and patch-description to remove
  usage of term 'scm'.

v3..v4:
* Remove the initialization of 'nd_pdsm_cmd_pkg.payload_offset' field
  from allocate_cmd(). [ Aneesh ]

v2..v3:
* None

v1..v2:
* Added new dimm callback 'papr_get_firmware_status'
* Switched to new papr_scm interface as described by papr_scm_dsm.h
* Changed the case of logging functions [ Santosh Sivaraj ]
* Removed redundant logging functions.
* Minor updates to patch description to s/DSM/PDSM/
---
 ndctl/lib/papr.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)

diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c
index 42372c3e2f7f..ebf31bac9a23 100644
--- a/ndctl/lib/papr.c
+++ b/ndctl/lib/papr.c
@@ -15,6 +15,29 @@
 #include <lib/private.h>
 #include "papr.h"
 
+/* Utility logging maros for simplify logging */
+#define papr_dbg(_dimm, _format_str, ...) dbg(_dimm->bus->ctx,		\
+					      "%s:" _format_str,	\
+					      ndctl_dimm_get_devname(_dimm), \
+					      ##__VA_ARGS__)
+
+#define papr_err(_dimm, _format_str, ...) err(_dimm->bus->ctx,		\
+					      "%s:" _format_str,	\
+					      ndctl_dimm_get_devname(_dimm), \
+					      ##__VA_ARGS__)
+
+/* Convert a ndctl_cmd to pdsm package */
+#define to_pdsm(C)  (&(C)->papr[0].pdsm)
+
+/* Convert a ndctl_cmd to nd_cmd_pkg */
+#define to_ndcmd(C)  (&(C)->papr[0].gen)
+
+/* Return payload from a ndctl_cmd */
+#define to_payload(C) (&(C)->papr[0].pdsm.payload)
+
+/* return the pdsm command */
+#define to_pdsm_cmd(C) ((enum papr_pdsm)to_ndcmd(C)->nd_command)
+
 static bool papr_cmd_is_supported(struct ndctl_dimm *dimm, int cmd)
 {
 	/* Handle this separately to support monitor mode */
@@ -24,6 +47,107 @@ static bool papr_cmd_is_supported(struct ndctl_dimm *dimm, int cmd)
 	return !!(dimm->cmd_mask & (1ULL << cmd));
 }
 
+static u32 papr_get_firmware_status(struct ndctl_cmd *cmd)
+{
+	const struct nd_pkg_pdsm *pcmd = to_pdsm(cmd);
+
+	return (u32) pcmd->cmd_status;
+}
+
+static int papr_xlat_firmware_status(struct ndctl_cmd *cmd)
+{
+	const struct nd_pkg_pdsm *pcmd = to_pdsm(cmd);
+
+	return pcmd->cmd_status;
+}
+
+/* Verify if the given command is supported and valid */
+static bool cmd_is_valid(struct ndctl_cmd *cmd)
+{
+	const struct nd_cmd_pkg  *ncmd = NULL;
+
+	if (cmd == NULL)
+		return false;
+
+	ncmd = to_ndcmd(cmd);
+
+	/* Verify the command family */
+	if (ncmd->nd_family != NVDIMM_FAMILY_PAPR) {
+		papr_err(cmd->dimm, "Invalid command family:0x%016llx\n",
+			 ncmd->nd_family);
+		return false;
+	}
+
+	/* Verify the PDSM */
+	if (ncmd->nd_command <= PAPR_PDSM_MIN ||
+	    ncmd->nd_command >= PAPR_PDSM_MAX) {
+		papr_err(cmd->dimm, "Invalid command :0x%016llx\n",
+			 ncmd->nd_command);
+		return false;
+	}
+
+	return true;
+}
+
+/* Allocate a struct ndctl_cmd for given pdsm request with payload size */
+static struct ndctl_cmd *allocate_cmd(struct ndctl_dimm *dimm,
+				      enum papr_pdsm pdsm_cmd,
+				      size_t payload_size)
+{
+	struct ndctl_cmd *cmd;
+
+	/* Verify that payload size is within acceptable range */
+	if (payload_size > ND_PDSM_PAYLOAD_MAX_SIZE) {
+		papr_err(dimm, "Requested payload size too large %lu bytes\n",
+			 payload_size);
+		return NULL;
+	}
+
+	cmd = calloc(1, sizeof(struct ndctl_cmd) + sizeof(struct nd_pkg_papr));
+	if (!cmd)
+		return NULL;
+
+	ndctl_cmd_ref(cmd);
+	cmd->dimm = dimm;
+	cmd->type = ND_CMD_CALL;
+	cmd->status = 0;
+	cmd->get_firmware_status = &papr_get_firmware_status;
+
+	/* Populate the nd_cmd_pkg contained in nd_pkg_pdsm */
+	*to_ndcmd(cmd) =  (struct nd_cmd_pkg) {
+		.nd_family = NVDIMM_FAMILY_PAPR,
+		.nd_command = pdsm_cmd,
+		.nd_size_in = 0,
+		.nd_size_out = ND_PDSM_HDR_SIZE + payload_size,
+		.nd_fw_size = 0,
+	};
+	return cmd;
+}
+
+/* Validate the ndctl_cmd and return applicable flags */
+static unsigned int papr_smart_get_flags(struct ndctl_cmd *cmd)
+{
+	struct nd_pkg_pdsm *pcmd;
+
+	if (!cmd_is_valid(cmd))
+		return 0;
+
+	pcmd = to_pdsm(cmd);
+	/* If error reported then return empty flags */
+	if (pcmd->cmd_status) {
+		papr_err(cmd->dimm, "PDSM(0x%x) reported error:%d\n",
+			 to_pdsm_cmd(cmd), pcmd->cmd_status);
+		return 0;
+	}
+
+	/* return empty flags for now */
+	return 0;
+}
+
+
 struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) {
 	.cmd_is_supported = papr_cmd_is_supported,
+	.smart_get_flags = papr_smart_get_flags,
+	.get_firmware_status =  papr_get_firmware_status,
+	.xlat_firmware_status = papr_xlat_firmware_status,
 };
-- 
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] 6+ messages in thread

* [ndctl PATCH v7 5/5] libndctl,papr_scm: Implement support for PAPR_PDSM_HEALTH
  2020-06-18  7:00 [ndctl PATCH v7 0/5] Add support for reporting papr nvdimm health Vaibhav Jain
                   ` (3 preceding siblings ...)
  2020-06-18  7:01 ` [ndctl PATCH v7 4/5] papr: Add scaffolding to issue and handle PDSM requests Vaibhav Jain
@ 2020-06-18  7:01 ` Vaibhav Jain
  4 siblings, 0 replies; 6+ messages in thread
From: Vaibhav Jain @ 2020-06-18  7:01 UTC (permalink / raw)
  To: linux-nvdimm; +Cc: Vaibhav Jain, Aneesh Kumar K . V

Add support for reporting DIMM health and shutdown state by issuing
PAPR_PDSM_HEALTH request to papr_scm module. It returns an
instance of 'struct nd_papr_pdsm_health' as defined in
'papr_pdsm.h'. The patch provides support for dimm-ops
'new_smart', 'smart_get_health' & 'smart_get_shutdown_state' as newly
introduced functions papr_new_smart_health(), papr_smart_get_health()
& papr_smart_get_shutdown_state() respectively. These callbacks should
enable ndctl to report DIMM health.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
---
Changelog:

v6..v7:
* None

v5..v6:
* Updated patch description to reflect removal of
  update_dimm_health().
* Update papr_smart_get_flags() to parse the 'struct ndctl_cmd'
  instance and return appropriate ND_SMART_XXX flags.
* Callbacks papr_smart_get_health() , papr_smart_get_shutdown_state()
  callbacks to use 'struct ndctl_cmd' instead of 'dimm_priv'.
* Added update_dimm_flags() to update 'struct ndctl_dimm' with the
  flags returned in 'struct nd_papr_psdm_health'.

v4..v5:
* Updated patch description to reflect updated names of struct and
  defines that have the term 'scm' removed.

v3..v4:
* None

v2..v3:
* None

v1..v2:
* Squashed patch to report nvdimm bad shutdown state with this patch.
* Switched to new structs/enums as defined in papr_scm_pdsm.h
---
 ndctl/lib/papr.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 72 insertions(+), 1 deletion(-)

diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c
index ebf31bac9a23..d9ce253369b3 100644
--- a/ndctl/lib/papr.c
+++ b/ndctl/lib/papr.c
@@ -124,10 +124,23 @@ static struct ndctl_cmd *allocate_cmd(struct ndctl_dimm *dimm,
 	return cmd;
 }
 
+/* Parse the nd_papr_pdsm_health and update dimm flags */
+static int update_dimm_flags(struct ndctl_dimm *dimm, struct nd_papr_pdsm_health *health)
+{
+	/* Update the dimm flags */
+	dimm->flags.f_arm = health->dimm_unarmed;
+	dimm->flags.f_flush = health->dimm_bad_shutdown;
+	dimm->flags.f_restore = health->dimm_bad_restore;
+	dimm->flags.f_smart = (health->dimm_health != 0);
+
+	return 0;
+}
+
 /* Validate the ndctl_cmd and return applicable flags */
 static unsigned int papr_smart_get_flags(struct ndctl_cmd *cmd)
 {
 	struct nd_pkg_pdsm *pcmd;
+	struct nd_papr_pdsm_health health;
 
 	if (!cmd_is_valid(cmd))
 		return 0;
@@ -140,14 +153,72 @@ static unsigned int papr_smart_get_flags(struct ndctl_cmd *cmd)
 		return 0;
 	}
 
-	/* return empty flags for now */
+	/*
+	 * In case of nvdimm health PDSM, update dimm flags
+	 * and  return possible flags.
+	 */
+	if (to_pdsm_cmd(cmd) == PAPR_PDSM_HEALTH) {
+		health = pcmd->payload.health;
+		update_dimm_flags(cmd->dimm, &health);
+		return ND_SMART_HEALTH_VALID | ND_SMART_SHUTDOWN_VALID;
+	}
+
+	/* Else return empty flags */
 	return 0;
 }
 
+static struct ndctl_cmd *papr_new_smart_health(struct ndctl_dimm *dimm)
+{
+	struct ndctl_cmd *cmd;
+
+	cmd = allocate_cmd(dimm, PAPR_PDSM_HEALTH,
+			       sizeof(struct nd_papr_pdsm_health));
+	if (!cmd)
+		papr_err(dimm, "Unable to allocate smart_health command\n");
+
+	return cmd;
+}
+
+static unsigned int papr_smart_get_health(struct ndctl_cmd *cmd)
+{
+	struct nd_papr_pdsm_health health;
+
+	/* Ignore in case of error or invalid pdsm */
+	if (!cmd_is_valid(cmd) ||
+	    to_pdsm(cmd)->cmd_status != 0 ||
+	    to_pdsm_cmd(cmd) != PAPR_PDSM_HEALTH)
+		return 0;
+
+	/* get the payload from command */
+	health = to_payload(cmd)->health;
+
+	/* Use some math to return one of defined ND_SMART_*_HEALTH values */
+	return  !health.dimm_health ? 0 : 1 << (health.dimm_health - 1);
+}
+
+static unsigned int papr_smart_get_shutdown_state(struct ndctl_cmd *cmd)
+{
+	struct nd_papr_pdsm_health health;
+
+	/* Ignore in case of error or invalid pdsm */
+	if (!cmd_is_valid(cmd) ||
+	    to_pdsm(cmd)->cmd_status != 0 ||
+	    to_pdsm_cmd(cmd) != PAPR_PDSM_HEALTH)
+		return 0;
+
+	/* get the payload from command */
+	health = to_payload(cmd)->health;
+
+	/* return the bad shutdown flag returned from papr_scm */
+	return health.dimm_bad_shutdown;
+}
 
 struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) {
 	.cmd_is_supported = papr_cmd_is_supported,
 	.smart_get_flags = papr_smart_get_flags,
 	.get_firmware_status =  papr_get_firmware_status,
 	.xlat_firmware_status = papr_xlat_firmware_status,
+	.new_smart = papr_new_smart_health,
+	.smart_get_health = papr_smart_get_health,
+	.smart_get_shutdown_state = papr_smart_get_shutdown_state,
 };
-- 
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] 6+ messages in thread

end of thread, other threads:[~2020-06-18  7:02 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-06-18  7:00 [ndctl PATCH v7 0/5] Add support for reporting papr nvdimm health Vaibhav Jain
2020-06-18  7:01 ` [ndctl PATCH v7 1/5] libndctl: Refactor out add_dimm() to handle NFIT specific init Vaibhav Jain
2020-06-18  7:01 ` [ndctl PATCH v7 2/5] libncdtl: Add initial support for NVDIMM_FAMILY_PAPR nvdimm family Vaibhav Jain
2020-06-18  7:01 ` [ndctl PATCH v7 3/5] libndctl,papr_scm: Add definitions for PAPR nvdimm specific methods Vaibhav Jain
2020-06-18  7:01 ` [ndctl PATCH v7 4/5] papr: Add scaffolding to issue and handle PDSM requests Vaibhav Jain
2020-06-18  7:01 ` [ndctl PATCH v7 5/5] libndctl,papr_scm: Implement support for PAPR_PDSM_HEALTH 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).