Hello community,

here is the log from the commit of package ndctl for openSUSE:Factory checked 
in at 2020-08-23 09:19:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ndctl (Old)
 and      /work/SRC/openSUSE:Factory/.ndctl.new.3399 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ndctl"

Sun Aug 23 09:19:02 2020 rev:29 rq:827551 version:69

Changes:
--------
--- /work/SRC/openSUSE:Factory/ndctl/ndctl.changes      2020-05-20 
18:36:16.772081981 +0200
+++ /work/SRC/openSUSE:Factory/.ndctl.new.3399/ndctl.changes    2020-08-23 
09:19:05.510615719 +0200
@@ -1,0 +2,18 @@
+Mon Aug 10 09:25:52 UTC 2020 - Michal Suchanek <[email protected]>
+
+- Update to v69 (jsc#SLE-13824, jsc#SLE-12770, jsc#SLE-15065):
+  * infoblock: Set the default alignment to the platform alignment
+  * libndctl/papr_scm: Add support for reporting "life_used_percentage" metric
+  * Skip region filtering if numa_node attribute is not present
+  * libndctl,papr_scm: Implement support for PAPR_PDSM_HEALTH
+  * miscellaneous bugfixes
+
+- Removed ndctl-Documentation-use-includes-in-more-ndctl-command-pag.patch
+
+-------------------------------------------------------------------
+Tue Jul 14 08:24:42 UTC 2020 - Michal Suchanek <[email protected]>
+
+- Clarify documentation about filtering options (bsc#1173861)
+  + ndctl-Documentation-use-includes-in-more-ndctl-command-pag.patch
+
+-------------------------------------------------------------------

Old:
----
  ndctl-68.tar.gz

New:
----
  ndctl-69.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ndctl.spec ++++++
--- /var/tmp/diff_new_pack.1F24kP/_old  2020-08-23 09:19:06.170616085 +0200
+++ /var/tmp/diff_new_pack.1F24kP/_new  2020-08-23 09:19:06.174616086 +0200
@@ -20,14 +20,13 @@
 %define lname libndctl6
 %define dname libndctl-devel
 Name:           ndctl
-Version:        68
+Version:        69
 Release:        0
 Summary:        Manage "libnvdimm" subsystem devices (Non-volatile Memory)
 License:        GPL-2.0-only
 Group:          Hardware/Other
 URL:            https://github.com/pmem/ndctl
-# Snapshot tarball can be created using: ./make-git-shapshot.sh [gitcommit]
-Source0:        %{name}-%{version}.tar.gz
+Source0:        
https://github.com/pmem/ndctl/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz
 Patch9:         %{name}-namespace-skip-zero-namespaces-when-processing.patch
 BuildRequires:  autoconf
 BuildRequires:  automake

++++++ ndctl-68.tar.gz -> ndctl-69.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/.gitignore new/ndctl-69/.gitignore
--- old/ndctl-68/.gitignore     1970-01-01 01:00:00.000000000 +0100
+++ new/ndctl-69/.gitignore     2020-07-23 07:15:11.000000000 +0200
@@ -0,0 +1,61 @@
+*.o
+*.xml
+.deps/
+.libs/
+Makefile
+!contrib/Makefile
+Makefile.in
+/aclocal.m4
+/autom4te.cache
+/build-aux
+/config.*
+/configure
+/libtool
+/stamp-h1
+*.1
+Documentation/daxctl/asciidoc.conf
+Documentation/ndctl/asciidoc.conf
+Documentation/daxctl/asciidoctor-extensions.rb
+Documentation/ndctl/asciidoctor-extensions.rb
+.dirstamp
+daxctl/config.h
+daxctl/daxctl
+daxctl/lib/libdaxctl.la
+daxctl/lib/libdaxctl.lo
+daxctl/lib/libdaxctl.pc
+*.a
+ndctl/config.h
+ndctl/lib/libndctl.pc
+ndctl/ndctl
+rhel/
+sles/ndctl.spec
+util/log.lo
+util/sysfs.lo
+version.m4
+*.swp
+cscope.files
+cscope*.out
+tags
+test/*.log
+test/*.trs
+test/blk-ns
+test/dax-dev
+test/dax-errors
+test/dax-pmd
+test/daxdev-errors
+test/device-dax
+test/dpa-alloc
+test/dsm-fail
+test/hugetlb
+test/image
+test/libndctl
+test/mmap
+test/multi-pmem
+test/parent-uuid
+test/pmem-ns
+test/smart-listen
+test/smart-notify
+test/fio.job
+test/local-write-0-verify.state
+test/ack-shutdown-count-set
+test/list-smart-dimm
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/Documentation/daxctl/movable-options.txt 
new/ndctl-69/Documentation/daxctl/movable-options.txt
--- old/ndctl-68/Documentation/daxctl/movable-options.txt       2020-03-24 
05:54:05.000000000 +0100
+++ new/ndctl-69/Documentation/daxctl/movable-options.txt       2020-07-23 
07:15:11.000000000 +0200
@@ -2,7 +2,7 @@
 
 --no-movable::
        '--movable' is the default. This can be overridden to online new
-       memory such that is is not 'movable'. This allows any allocation
+       memory such that it is not 'movable'. This allows any allocation
        to potentially be served from this memory. This may preclude subsequent
        removal. With the '--movable' behavior (which is default), kernel
        allocations will not consider this memory, and it will be reserved
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/Documentation/ndctl/labels-options.txt 
new/ndctl-69/Documentation/ndctl/labels-options.txt
--- old/ndctl-68/Documentation/ndctl/labels-options.txt 2020-03-24 
05:54:05.000000000 +0100
+++ new/ndctl-69/Documentation/ndctl/labels-options.txt 2020-07-23 
07:15:11.000000000 +0200
@@ -1,9 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 
 <memory device(s)>::
-       One or more 'nmemX' device names. The keyword 'all' can be specified to
-       operate on every dimm in the system, optionally filtered by bus id (see
-        --bus= option).
+include::xable-dimm-options.txt[]
 
 -s::
 --size=::
@@ -16,8 +14,7 @@
 
 -b::
 --bus=::
-       Limit operation to memory devices (dimms) that are on the given bus.
-       Where 'bus' can be a provider name or a bus id number.
+include::xable-bus-options.txt[]
 
 -v::
        Turn on verbose debug messages in the library (if ndctl was built with
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/Documentation/ndctl/ndctl-inject-smart.txt 
new/ndctl-69/Documentation/ndctl/ndctl-inject-smart.txt
--- old/ndctl-68/Documentation/ndctl/ndctl-inject-smart.txt     2020-03-24 
05:54:05.000000000 +0100
+++ new/ndctl-69/Documentation/ndctl/ndctl-inject-smart.txt     2020-07-23 
07:15:11.000000000 +0200
@@ -38,9 +38,7 @@
 -------
 -b::
 --bus=::
-       Enforce that the operation only be carried on devices that are
-       attached to the given bus. Where 'bus' can be a provider name or a bus
-       id number.
+include::xable-bus-options.txt[]
 
 -m::
 --media-temperature=::
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/Documentation/ndctl/ndctl-monitor.txt 
new/ndctl-69/Documentation/ndctl/ndctl-monitor.txt
--- old/ndctl-68/Documentation/ndctl/ndctl-monitor.txt  2020-03-24 
05:54:05.000000000 +0100
+++ new/ndctl-69/Documentation/ndctl/ndctl-monitor.txt  2020-07-23 
07:15:11.000000000 +0200
@@ -49,20 +49,15 @@
 -------
 -b::
 --bus=::
-       Enforce that the operation only be carried on devices that are
-       attached to the given bus. Where 'bus' can be a provider name
-       or a bus id number.
+include::xable-bus-options.txt[]
 
 -d::
 --dimm=::
-       A 'nmemX' device name, or dimm id number. Select the devices to
-       monitor reference the given dimm.
+include::xable-dimm-options.txt[]
 
 -r::
 --region=::
-       A 'regionX' device name, or a region id number. The keyword 'all'
-       can be specified to carry out the operation on every region in
-       the system, optionally filtered by bus id (see --bus= option).
+include::xable-region-options.txt[]
 
 -n::
 --namespace=::
@@ -108,6 +103,10 @@
 The monitor will attempt to enable the alarm control bits for all
 specified events.
 
+-p::
+--poll=::
+       Poll and report status/event every <n> seconds.
+
 -u::
 --human::
        Output monitor notification as human friendly json format instead
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/Makefile.am.in new/ndctl-69/Makefile.am.in
--- old/ndctl-68/Makefile.am.in 2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/Makefile.am.in 2020-07-23 07:15:11.000000000 +0200
@@ -35,9 +35,9 @@
        -e 's,@includedir\@,$(includedir),g' \
        < $< > $@ || rm $@
 
-LIBNDCTL_CURRENT=23
+LIBNDCTL_CURRENT=24
 LIBNDCTL_REVISION=0
-LIBNDCTL_AGE=17
+LIBNDCTL_AGE=18
 
 LIBDAXCTL_CURRENT=5
 LIBDAXCTL_REVISION=0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/README.md new/ndctl-69/README.md
--- old/ndctl-68/README.md      2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/README.md      2020-07-23 07:15:11.000000000 +0200
@@ -65,6 +65,7 @@
    CONFIG_NVDIMM_PFN=y
    CONFIG_NVDIMM_DAX=y
    CONFIG_DEV_DAX_PMEM=m
+   CONFIG_ENCRYPTED_KEYS=y
    ```
 
 1. Build and install the unit test enabled libnvdimm modules in the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/git-version new/ndctl-69/git-version
--- old/ndctl-68/git-version    2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/git-version    2020-07-23 07:15:11.000000000 +0200
@@ -19,7 +19,7 @@
        fi
 }
 
-DEF_VER=68
+DEF_VER=69
 
 LF='
 '
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/m4/.gitignore new/ndctl-69/m4/.gitignore
--- old/ndctl-68/m4/.gitignore  1970-01-01 01:00:00.000000000 +0100
+++ new/ndctl-69/m4/.gitignore  2020-07-23 07:15:11.000000000 +0200
@@ -0,0 +1,6 @@
+libtool.m4
+ltoptions.m4
+ltsugar.m4
+ltversion.m4
+lt~obsolete.m4
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/.gitignore 
new/ndctl-69/ndctl/lib/.gitignore
--- old/ndctl-68/ndctl/lib/.gitignore   1970-01-01 01:00:00.000000000 +0100
+++ new/ndctl-69/ndctl/lib/.gitignore   2020-07-23 07:15:11.000000000 +0200
@@ -0,0 +1,7 @@
+.dirstamp
+.deps/
+.libs/
+*.la
+*.lo
+libabc.pc
+test-libabc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/Makefile.am 
new/ndctl-69/ndctl/lib/Makefile.am
--- old/ndctl-68/ndctl/lib/Makefile.am  2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/lib/Makefile.am  2020-07-23 07:15:11.000000000 +0200
@@ -23,6 +23,7 @@
        hpe1.c \
        msft.c \
        hyperv.c \
+       papr.c \
        ars.c \
        firmware.c \
        libndctl.c \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/hpe1.h 
new/ndctl-69/ndctl/lib/hpe1.h
--- old/ndctl-68/ndctl/lib/hpe1.h       2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/lib/hpe1.h       2020-07-23 07:15:11.000000000 +0200
@@ -111,7 +111,7 @@
        __u32 status;
        union {
                __u8 buf[124];
-               struct ndn_hpe1_smart_data data[0];
+               struct ndn_hpe1_smart_data data[1];
        };
 } __attribute__((packed));
 
@@ -136,7 +136,7 @@
        __u32 status;
        union {
                __u8 buf[32];
-               struct ndn_hpe1_smart_threshold_data data[0];
+               struct ndn_hpe1_smart_threshold_data data[1];
        };
 } __attribute__((packed));
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/libndctl.c 
new/ndctl-69/ndctl/lib/libndctl.c
--- old/ndctl-68/ndctl/lib/libndctl.c   2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/lib/libndctl.c   2020-07-23 07:15:11.000000000 +0200
@@ -799,6 +799,28 @@
                                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 @@
                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 @@
        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,82 +1486,49 @@
 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_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base)
 {
-       int formats, i;
-       struct ndctl_dimm *dimm;
+       int rc = -ENODEV;
        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);
+       const char * const devname = ndctl_dimm_get_devname(dimm);
 
-       if (!path)
-               return NULL;
+       dbg(ctx, "%s: Probing of_pmem dimm at %s\n", devname, dimm_base);
 
-       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;
+       if (!path)
+               return -ENOMEM;
 
-       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;
+       /* construct path to the papr compatible dimm flags file */
+       sprintf(path, "%s/papr/flags", dimm_base);
 
-       sprintf(path, "%s/commands", dimm_base);
-       if (sysfs_read_attr(ctx, path, buf) < 0)
-               goto err_read;
-       dimm->cmd_mask = parse_commands(buf, 1);
+       if (ndctl_bus_is_papr_scm(dimm->bus) &&
+           sysfs_read_attr(ctx, path, buf) == 0) {
 
-       dimm->dimm_buf = calloc(1, strlen(dimm_base) + 50);
-       if (!dimm->dimm_buf)
-               goto err_read;
-       dimm->buf_len = strlen(dimm_base) + 50;
+               dbg(ctx, "%s: Adding papr-scm dimm flags:\"%s\"\n", devname, 
buf);
+               dimm->cmd_family = NVDIMM_FAMILY_PAPR;
 
-       dimm->dimm_path = strdup(dimm_base);
-       if (!dimm->dimm_path)
-               goto err_read;
+               /* Parse dimm flags */
+               parse_papr_flags(dimm, buf);
 
-       sprintf(path, "%s/modalias", dimm_base);
-       if (sysfs_read_attr(ctx, path, buf) < 0)
-               goto err_read;
-       dimm->module = to_module(ctx, buf);
+               /* Allocate monitor mode fd */
+               dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC);
+               rc = 0;
+       }
 
-       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;
+       free(path);
+       return rc;
+}
 
-       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);
+static int add_nfit_dimm(struct ndctl_dimm *dimm, const char *dimm_base)
+{
+       int i, rc = -1;
+       char buf[SYSFS_ATTR_SIZE];
+       struct ndctl_ctx *ctx = dimm->bus->ctx;
+       char *path = calloc(1, strlen(dimm_base) + 100);
 
-       if (!ndctl_bus_has_nfit(bus))
-               goto out;
+       if (!path)
+               return -ENOMEM;
 
        /*
         * 'unique_id' may not be available on older kernels, so don't
@@ -1582,24 +1594,15 @@
        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 +1613,120 @@
                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);
+       } else if (ndctl_bus_has_of_node(bus)) {
+               rc = add_papr_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;
+       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),
+                   strerror(-rc));
+               goto err_read;
+       }
+
        list_add(&bus->dimms, &dimm->list);
        free(path);
 
@@ -2136,7 +2252,7 @@
        struct ndctl_bus *bus = parent;
        struct ndctl_ctx *ctx = bus->ctx;
        char *path = calloc(1, strlen(region_base) + 100);
-       int perm;
+       int perm, rc;
 
        if (!path)
                return NULL;
@@ -2186,10 +2302,12 @@
        region->module = to_module(ctx, buf);
 
        sprintf(path, "%s/numa_node", region_base);
-       if (sysfs_read_attr(ctx, path, buf) == 0)
+       if ((rc = sysfs_read_attr(ctx, path, buf)) == 0)
                region->numa_node = strtol(buf, NULL, 0);
+       else if (rc == -ENOENT)
+               region->numa_node = NUMA_NO_ATTR;
        else
-               region->numa_node = -1;
+               region->numa_node = NUMA_NO_NODE;
 
        sprintf(path, "%s/target_node", region_base);
        if (sysfs_read_attr(ctx, path, buf) == 0)
@@ -2471,6 +2589,11 @@
        return NULL;
 }
 
+NDCTL_EXPORT int ndctl_region_has_numa(struct ndctl_region *region)
+{
+       return (region->numa_node != NUMA_NO_ATTR);
+}
+
 NDCTL_EXPORT int ndctl_region_get_numa_node(struct ndctl_region *region)
 {
        return region->numa_node;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/libndctl.sym 
new/ndctl-69/ndctl/lib/libndctl.sym
--- old/ndctl-68/ndctl/lib/libndctl.sym 2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/lib/libndctl.sym 2020-07-23 07:15:11.000000000 +0200
@@ -431,3 +431,9 @@
        ndctl_region_get_align;
        ndctl_region_set_align;
 } LIBNDCTL_22;
+
+LIBNDCTL_24 {
+       ndctl_bus_has_of_node;
+       ndctl_bus_is_papr_scm;
+       ndctl_region_has_numa;
+} LIBNDCTL_23;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/msft.h 
new/ndctl-69/ndctl/lib/msft.h
--- old/ndctl-68/ndctl/lib/msft.h       2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/lib/msft.h       2020-07-23 07:15:11.000000000 +0200
@@ -46,7 +46,7 @@
        __u32   status;
        union {
                __u8 buf[9];
-               struct ndn_msft_smart_data data[0];
+               struct ndn_msft_smart_data data[1];
        };
 } __attribute__((packed));
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/papr.c 
new/ndctl-69/ndctl/lib/papr.c
--- old/ndctl-68/ndctl/lib/papr.c       1970-01-01 01:00:00.000000000 +0100
+++ new/ndctl-69/ndctl/lib/papr.c       2020-07-23 07:15:11.000000000 +0200
@@ -0,0 +1,248 @@
+// 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>
+#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 */
+       if (cmd == ND_CMD_SMART)
+               return true;
+
+       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)
+{
+       return (cmd->type == ND_CMD_CALL) ? to_pdsm(cmd)->cmd_status : 0;
+}
+
+/* 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;
+}
+
+/* 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;
+       unsigned int flags;
+
+       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;
+       }
+
+       /*
+        * 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);
+               flags = ND_SMART_HEALTH_VALID | ND_SMART_SHUTDOWN_VALID;
+
+               /* check for extension flags */
+               if (health.extension_flags & PDSM_DIMM_HEALTH_RUN_GAUGE_VALID)
+                       flags |= ND_SMART_USED_VALID;
+
+               return flags;
+       }
+
+       /* 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;
+}
+
+static unsigned int papr_smart_get_life_used(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 dimm life remaining from the health payload */
+       return (health.extension_flags & PDSM_DIMM_HEALTH_RUN_GAUGE_VALID) ?
+               (100 - health.dimm_fuel_gauge) : 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,
+       .new_smart = papr_new_smart_health,
+       .smart_get_health = papr_smart_get_health,
+       .smart_get_shutdown_state = papr_smart_get_shutdown_state,
+       .smart_get_life_used = papr_smart_get_life_used,
+};
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/papr.h 
new/ndctl-69/ndctl/lib/papr.h
--- old/ndctl-68/ndctl/lib/papr.h       1970-01-01 01:00:00.000000000 +0100
+++ new/ndctl-69/ndctl/lib/papr.h       2020-07-23 07:15:11.000000000 +0200
@@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/papr_pdsm.h 
new/ndctl-69/ndctl/lib/papr_pdsm.h
--- old/ndctl-68/ndctl/lib/papr_pdsm.h  1970-01-01 01:00:00.000000000 +0100
+++ new/ndctl-69/ndctl/lib/papr_pdsm.h  2020-07-23 07:15:11.000000000 +0200
@@ -0,0 +1,139 @@
+/* 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
+
+/* Indicate that the 'dimm_fuel_gauge' field is valid */
+#define PDSM_DIMM_HEALTH_RUN_GAUGE_VALID 1
+
+/*
+ * 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
+ * dimm_fuel_gauge     : Life remaining of DIMM as a percentage from 0-100
+ */
+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;
+
+                       /* Extension flag PDSM_DIMM_HEALTH_RUN_GAUGE_VALID */
+                       __u16 dimm_fuel_gauge;
+               };
+               __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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/lib/private.h 
new/ndctl-69/ndctl/lib/private.h
--- old/ndctl-68/ndctl/lib/private.h    2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/lib/private.h    2020-07-23 07:15:11.000000000 +0200
@@ -32,6 +32,7 @@
 #include "hpe1.h"
 #include "msft.h"
 #include "hyperv.h"
+#include "papr.h"
 #include "libndctl-nfit.h"
 
 struct nvdimm_data {
@@ -167,6 +168,7 @@
        int dimms_init;
        int regions_init;
        int has_nfit;
+       int has_of_node;
        char *bus_path;
        char *bus_buf;
        size_t buf_len;
@@ -276,6 +278,7 @@
                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];
@@ -352,6 +355,7 @@
 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/libndctl.h 
new/ndctl-69/ndctl/libndctl.h
--- old/ndctl-68/ndctl/libndctl.h       2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/libndctl.h       2020-07-23 07:15:11.000000000 +0200
@@ -119,6 +119,8 @@
              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);
@@ -385,6 +387,7 @@
 struct ndctl_dimm *ndctl_region_get_next_dimm(struct ndctl_region *region,
                struct ndctl_dimm *dimm);
 int ndctl_region_get_numa_node(struct ndctl_region *region);
+int ndctl_region_has_numa(struct ndctl_region *region);
 int ndctl_region_get_target_node(struct ndctl_region *region);
 struct ndctl_region *ndctl_bus_get_region_by_physical_address(struct ndctl_bus 
*bus,
                unsigned long long address);
@@ -734,6 +737,9 @@
 #define ND_KEY_DESC_SIZE       128
 #define ND_KEY_CMD_SIZE                128
 
+#define NUMA_NO_NODE    (-1)
+#define NUMA_NO_ATTR    (-2)
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/monitor.c new/ndctl-69/ndctl/monitor.c
--- old/ndctl-68/ndctl/monitor.c        2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/monitor.c        2020-07-23 07:15:11.000000000 +0200
@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <json-c/json.h>
 #include <libgen.h>
+#include <time.h>
 #include <dirent.h>
 #include <util/json.h>
 #include <util/filter.h>
@@ -33,6 +34,7 @@
        bool daemon;
        bool human;
        bool verbose;
+       unsigned int poll_timeout;
        unsigned int event_flags;
        struct log_ctx ctx;
 } monitor;
@@ -322,9 +324,14 @@
                struct monitor_filter_arg *mfa)
 {
        struct epoll_event ev, *events;
-       int nfds, epollfd, i, rc = 0;
+       int nfds, epollfd, i, rc = 0, polltimeout = -1;
        struct monitor_dimm *mdimm;
        char buf;
+       /* last time a full poll happened */
+       struct timespec fullpoll_ts, ts;
+
+       if (monitor.poll_timeout)
+               polltimeout = monitor.poll_timeout * 1000;
 
        events = calloc(mfa->num_dimm, sizeof(struct epoll_event));
        if (!events) {
@@ -354,14 +361,30 @@
                }
        }
 
+       clock_gettime(CLOCK_BOOTTIME, &fullpoll_ts);
        while (1) {
                did_fail = 0;
-               nfds = epoll_wait(epollfd, events, mfa->num_dimm, -1);
-               if (nfds <= 0 && errno != EINTR) {
+               nfds = epoll_wait(epollfd, events, mfa->num_dimm, polltimeout);
+               if (nfds < 0 && errno != EINTR) {
                        err(&monitor, "epoll_wait error: (%s)\n", 
strerror(errno));
                        rc = -errno;
                        goto out;
                }
+
+               /* If needed force a full poll of dimm health */
+               clock_gettime(CLOCK_BOOTTIME, &ts);
+               if ((fullpoll_ts.tv_sec - ts.tv_sec) > monitor.poll_timeout) {
+                       nfds = 0;
+                       dbg(&monitor, "forcing a full poll\n");
+               }
+
+               /* If we timed out then fill events array with all dimms */
+               if (nfds == 0) {
+                       list_for_each(&mfa->dimms, mdimm, list)
+                               events[nfds++].data.ptr = mdimm;
+                       fullpoll_ts = ts;
+               }
+
                for (i = 0; i < nfds; i++) {
                        mdimm = events[i].data.ptr;
                        if (util_dimm_event_filter(mdimm, monitor.event_flags)) 
{
@@ -570,6 +593,8 @@
                                "use human friendly output formats"),
                OPT_BOOLEAN('v', "verbose", &monitor.verbose,
                                "emit extra debug messages to log"),
+               OPT_UINTEGER('p', "poll", &monitor.poll_timeout,
+                            "poll and report events/status every <n> seconds"),
                OPT_END(),
        };
        const char * const u[] = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/namespace.c 
new/ndctl-69/ndctl/namespace.c
--- old/ndctl-68/ndctl/namespace.c      2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/namespace.c      2020-07-23 07:15:11.000000000 +0200
@@ -175,7 +175,7 @@
 OPT_STRING('s', "size", &param.size, "size", \
        "override the image size to instantiate the infoblock"), \
 OPT_STRING('a', "align", &param.align, "align", \
-       "specify the expected physical alignment (default: 2M)"), \
+       "specify the expected physical alignment"), \
 OPT_STRING('u', "uuid", &param.uuid, "uuid", \
        "specify the uuid for the infoblock (default: autogenerate)"), \
 OPT_STRING('M', "map", &param.map, "memmap-location", \
@@ -325,23 +325,15 @@
                                        sysconf(_SC_PAGE_SIZE));
                        rc = -EINVAL;
                }
-       } else if (action == ACTION_WRITE_INFOBLOCK)
-               param.align = "2M";
+       }
 
        if (param.size) {
                unsigned long long size = parse_size64(param.size);
-               unsigned long long align = parse_size64(param.align);
 
                if (size == ULLONG_MAX) {
                        error("failed to parse namespace size '%s'\n",
                                        param.size);
                        rc = -EINVAL;
-               } else if (action == ACTION_WRITE_INFOBLOCK
-                               && align < ULLONG_MAX
-                               && !IS_ALIGNED(size, align)) {
-                       error("--size=%s not aligned to %s\n", param.size,
-                                       param.align);
-                       rc = -EINVAL;
                }
        }
 
@@ -1977,11 +1969,28 @@
 
        free(buf);
 out:
-       if (fd > 0 && fd != STDOUT_FILENO)
+       if (fd >= 0 && fd != STDOUT_FILENO)
                close(fd);
        return rc;
 }
 
+static unsigned long ndctl_get_default_alignment(struct ndctl_namespace *ndns)
+{
+       unsigned long long align = 0;
+       struct ndctl_dax *dax = ndctl_namespace_get_dax(ndns);
+       struct ndctl_pfn *pfn = ndctl_namespace_get_pfn(ndns);
+
+       if (ndctl_namespace_get_mode(ndns) == NDCTL_NS_MODE_FSDAX && pfn)
+               align = ndctl_pfn_get_supported_alignment(pfn, 1);
+       else if (ndctl_namespace_get_mode(ndns) == NDCTL_NS_MODE_DEVDAX && dax)
+               align = ndctl_dax_get_supported_alignment(dax, 1);
+
+       if (!align)
+               align =  sysconf(_SC_PAGE_SIZE);
+
+       return align;
+}
+
 static int namespace_rw_infoblock(struct ndctl_namespace *ndns,
                struct read_infoblock_ctx *ri_ctx, int write)
 {
@@ -2013,9 +2022,40 @@
        }
 
        sprintf(path, "/dev/%s", ndctl_namespace_get_block_device(ndns));
-       if (write)
-               rc = file_write_infoblock(path);
-       else
+       if (write) {
+               unsigned long long align;
+               bool align_provided = true;
+
+               if (!param.align) {
+                       align = ndctl_get_default_alignment(ndns);
+
+                       if (asprintf((char **)&param.align, "%llu", align) < 0) 
{
+                               rc = -EINVAL;
+                               goto out;
+                       }
+                       align_provided = false;
+               }
+
+               if (param.size) {
+                       unsigned long long size = parse_size64(param.size);
+                       align = parse_size64(param.align);
+
+                       if (align < ULLONG_MAX && !IS_ALIGNED(size, align)) {
+                               error("--size=%s not aligned to %s\n", 
param.size,
+                                       param.align);
+
+                               rc = -EINVAL;
+                       }
+               }
+
+               if (!rc)
+                       rc = file_write_infoblock(path);
+
+               if (!align_provided) {
+                       free((char *)param.align);
+                       param.align = NULL;
+               }
+       } else
                rc = file_read_infoblock(path, ndns, ri_ctx);
        param.parent_uuid = save;
 out:
@@ -2060,6 +2100,9 @@
        }
 
        if (action == ACTION_WRITE_INFOBLOCK && !namespace) {
+               if (!param.align)
+                       param.align = "2M";
+
                rc = file_write_infoblock(param.outfile);
                if (rc >= 0)
                        (*processed)++;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/ndctl/ndctl.h new/ndctl-69/ndctl/ndctl.h
--- old/ndctl-68/ndctl/ndctl.h  2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/ndctl/ndctl.h  2020-07-23 07:15:11.000000000 +0200
@@ -91,7 +91,7 @@
                __u32 reserved;
                __u64 err_address;
                __u64 length;
-       } __attribute__((packed)) records[0];
+       } __attribute__((packed)) records[];
 } __attribute__((packed));
 
 struct nd_cmd_clear_error {
@@ -263,6 +263,7 @@
 #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)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/test/align.sh new/ndctl-69/test/align.sh
--- old/ndctl-68/test/align.sh  2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/test/align.sh  2020-07-23 07:15:11.000000000 +0200
@@ -34,8 +34,19 @@
 set -e
 trap 'err $LINENO cleanup' ERR
 
-region=$($NDCTL list -R -b ACPI.NFIT | jq -r '.[] | [select(.available_size == 
.size)] | .[0].dev')
+find_region()
+{
+       $NDCTL list -R -b ACPI.NFIT | jq -r '[.[] | select(.available_size == 
.size)][0] | .dev'
+}
 
+region=$(find_region)
+if [ "x$region" = "xnull"  ]; then
+       # this is destructive
+       $NDCTL disable-region -b ACPI.NFIT all
+       $NDCTL init-labels -f -b ACPI.NFIT all
+       $NDCTL enable-region -b ACPI.NFIT all
+fi
+region=$(find_region)
 if [ "x$region" = "xnull"  ]; then
        unset $region
        echo "unable to find empty region"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ndctl-68/util/filter.c new/ndctl-69/util/filter.c
--- old/ndctl-68/util/filter.c  2020-03-24 05:54:05.000000000 +0100
+++ new/ndctl-69/util/filter.c  2020-07-23 07:15:11.000000000 +0200
@@ -23,8 +23,6 @@
 #include <ndctl/libndctl.h>
 #include <daxctl/libdaxctl.h>
 
-#define NUMA_NO_NODE    (-1)
-
 struct ndctl_bus *util_bus_filter(struct ndctl_bus *bus, const char *__ident)
 {
        char *end = NULL, *ident, *save;
@@ -467,7 +465,22 @@
                                                param->namespace))
                                continue;
 
+                       /*
+                        * if numa_node attribute is not available for regions
+                        * (which is true for pre 5.4 kernels), don't skip the
+                        * region if namespace is also requested, let the
+                        * namespace filter handle the NUMA node filtering.
+                        */
                        if (numa_node != NUMA_NO_NODE &&
+                           !ndctl_region_has_numa(region) &&
+                           !fctx->filter_namespace) {
+                               fprintf(stderr,
+                                       "This kernel does not provide NUMA node 
information per-region\n");
+                               continue;
+                       }
+
+                       if (ndctl_region_has_numa(region) &&
+                           numa_node != NUMA_NO_NODE &&
                            ndctl_region_get_numa_node(region) != numa_node)
                                continue;
 
@@ -489,6 +502,10 @@
                                if (param->mode && util_nsmode(param->mode) != 
mode)
                                        continue;
 
+                               if (numa_node != NUMA_NO_NODE &&
+                                   ndctl_namespace_get_numa_node(ndns) != 
numa_node)
+                                       continue;
+
                                fctx->filter_namespace(ndns, fctx);
                        }
                }


Reply via email to