Validate vendor specific ACPI-defined command implementations against
the published dsm_mask.

Cc: Lijun Pan <[email protected]>
Cc: Jerry Hoemann <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
---
 ndctl/lib/hpe1.c     |   12 ++++++++++++
 ndctl/lib/libndctl.c |    5 +++++
 ndctl/lib/msft.c     |    5 +++++
 ndctl/lib/private.h  |   16 ++++++++++++++++
 4 files changed, 38 insertions(+)

diff --git a/ndctl/lib/hpe1.c b/ndctl/lib/hpe1.c
index 45cb5cc6db73..addebe952ce6 100644
--- a/ndctl/lib/hpe1.c
+++ b/ndctl/lib/hpe1.c
@@ -36,6 +36,12 @@ static struct ndctl_cmd *hpe1_dimm_cmd_new_smart(struct 
ndctl_dimm *dimm)
                return NULL;
        }
 
+       if (test_dimm_dsm(dimm, NDN_HPE1_CMD_SMART)
+                       == DIMM_DSM_UNSUPPORTED) {
+               dbg(ctx, "unsupported function\n");
+               return NULL;
+       }
+
        size = sizeof(*cmd) + sizeof(struct ndn_pkg_hpe1);
        cmd = calloc(1, size);
        if (!cmd)
@@ -214,6 +220,12 @@ static struct ndctl_cmd 
*hpe1_dimm_cmd_new_smart_threshold(struct ndctl_dimm *di
                return NULL;
        }
 
+       if (test_dimm_dsm(dimm, NDN_HPE1_CMD_SMART_THRESHOLD)
+                       == DIMM_DSM_UNSUPPORTED) {
+               dbg(ctx, "unsupported function\n");
+               return NULL;
+       }
+
        size = sizeof(*cmd) + sizeof(struct ndn_pkg_hpe1);
        cmd = calloc(1, size);
        if (!cmd)
diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c
index bb47c9d1f522..0473b482ad23 100644
--- a/ndctl/lib/libndctl.c
+++ b/ndctl/lib/libndctl.c
@@ -1232,6 +1232,7 @@ static void *add_dimm(void *parent, int id, const char 
*dimm_base)
        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;
 
@@ -1310,6 +1311,10 @@ static void *add_dimm(void *parent, int id, const char 
*dimm_base)
        if (dimm->cmd_family == NVDIMM_FAMILY_MSFT)
                dimm->smart_ops = msft_smart_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)
diff --git a/ndctl/lib/msft.c b/ndctl/lib/msft.c
index 8c226f5602f1..1c4c8913714f 100644
--- a/ndctl/lib/msft.c
+++ b/ndctl/lib/msft.c
@@ -35,6 +35,11 @@ static struct ndctl_cmd *msft_dimm_cmd_new_smart(struct 
ndctl_dimm *dimm)
                return NULL;
        }
 
+       if (test_dimm_dsm(dimm, NDN_MSFT_CMD_SMART) == DIMM_DSM_UNSUPPORTED) {
+               dbg(ctx, "unsupported function\n");
+               return NULL;
+       }
+
        size = sizeof(*cmd) + sizeof(struct ndn_pkg_msft);
        cmd = calloc(1, size);
        if (!cmd)
diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h
index 64bc5aee1134..685d65d89a06 100644
--- a/ndctl/lib/private.h
+++ b/ndctl/lib/private.h
@@ -77,6 +77,7 @@ struct ndctl_dimm {
        unsigned char manufacturing_location;
        unsigned long cmd_family;
        unsigned long cmd_mask;
+       unsigned long nfit_dsm_mask;
        char *unique_id;
        char *dimm_path;
        char *dimm_buf;
@@ -102,6 +103,21 @@ struct ndctl_dimm {
        int format[0];
 };
 
+enum dsm_support {
+       DIMM_DSM_UNSUPPORTED, /* don't attempt command */
+       DIMM_DSM_SUPPORTED, /* good to go */
+       DIMM_DSM_UNKNOWN, /* try ND_CMD_CALL on older kernels */
+};
+
+static inline enum dsm_support test_dimm_dsm(struct ndctl_dimm *dimm, int fn)
+{
+       if (dimm->nfit_dsm_mask == ULONG_MAX) {
+               return DIMM_DSM_UNKNOWN;
+       } else if (dimm->nfit_dsm_mask & (1 << fn))
+               return DIMM_DSM_SUPPORTED;
+       return DIMM_DSM_UNSUPPORTED;
+}
+
 void region_flag_refresh(struct ndctl_region *region);
 
 /**

_______________________________________________
Linux-nvdimm mailing list
[email protected]
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to