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
