diff options
author | Vishal Verma <vishal.l.verma@intel.com> | 2022-02-23 15:02:44 -0700 |
---|---|---|
committer | Vishal Verma <vishal.l.verma@intel.com> | 2022-02-23 15:02:44 -0700 |
commit | 989351bccb314206b84533dc0b137af79e75972a (patch) | |
tree | 800d51934f5d01dd8291bd3e7a637cec8c8fb0f9 | |
parent | fca9f6c354d055c1cea11d2f8cd163097b675360 (diff) | |
parent | c5ccbf29c54b5a3d9cb1c138c06c8d5ac3ee80c2 (diff) |
Merge branch 'for-73/vj/papr' into pending
-rw-r--r-- | ndctl/inject-smart.c | 35 | ||||
-rw-r--r-- | ndctl/lib/intel.c | 7 | ||||
-rw-r--r-- | ndctl/lib/libndctl.c | 61 | ||||
-rw-r--r-- | ndctl/lib/libndctl.sym | 4 | ||||
-rw-r--r-- | ndctl/lib/papr.c | 84 | ||||
-rw-r--r-- | ndctl/lib/papr_pdsm.h | 23 | ||||
-rw-r--r-- | ndctl/lib/private.h | 1 | ||||
-rw-r--r-- | ndctl/libndctl.h | 9 | ||||
-rw-r--r-- | test/ack-shutdown-count-set.c | 4 |
9 files changed, 205 insertions, 23 deletions
diff --git a/ndctl/inject-smart.c b/ndctl/inject-smart.c index 2b9d7e85..d7da5ad8 100644 --- a/ndctl/inject-smart.c +++ b/ndctl/inject-smart.c @@ -395,18 +395,26 @@ out: } \ } -static int smart_inject(struct ndctl_dimm *dimm) +static int smart_inject(struct ndctl_dimm *dimm, unsigned int inject_types) { const char *name = ndctl_dimm_get_devname(dimm); struct ndctl_cmd *si_cmd = NULL; int rc = -EOPNOTSUPP; - send_inject_val(media_temperature) - send_inject_val(ctrl_temperature) - send_inject_val(spares) - send_inject_bool(fatal) - send_inject_bool(unsafe_shutdown) + if (inject_types & ND_SMART_INJECT_MEDIA_TEMPERATURE) + send_inject_val(media_temperature); + if (inject_types & ND_SMART_INJECT_CTRL_TEMPERATURE) + send_inject_val(ctrl_temperature); + + if (inject_types & ND_SMART_INJECT_SPARES_REMAINING) + send_inject_val(spares); + + if (inject_types & ND_SMART_INJECT_HEALTH_STATE) + send_inject_bool(fatal); + + if (inject_types & ND_SMART_INJECT_UNCLEAN_SHUTDOWN) + send_inject_bool(unsafe_shutdown); out: ndctl_cmd_unref(si_cmd); return rc; @@ -417,6 +425,7 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm) struct json_object *jhealth; struct json_object *jdimms; struct json_object *jdimm; + unsigned int supported_types; int rc; rc = ndctl_dimm_smart_inject_supported(dimm); @@ -433,6 +442,14 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm) error("%s: smart injection not supported by either platform firmware or the kernel.", ndctl_dimm_get_devname(dimm)); return rc; + default: + if (rc < 0) { + error("%s: Unknown error %d while checking for smart injection support", + ndctl_dimm_get_devname(dimm), rc); + return rc; + } + supported_types = rc; + break; } if (sctx.op_mask & (1 << OP_SET)) { @@ -441,7 +458,7 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm) goto out; } if (sctx.op_mask & (1 << OP_INJECT)) { - rc = smart_inject(dimm); + rc = smart_inject(dimm, supported_types); if (rc) goto out; } @@ -450,6 +467,10 @@ static int dimm_inject_smart(struct ndctl_dimm *dimm) jdimms = json_object_new_array(); if (!jdimms) goto out; + + /* Ensure the dimm flags are upto date before reporting them */ + ndctl_dimm_refresh_flags(dimm); + jdimm = util_dimm_to_json(dimm, sctx.flags); if (!jdimm) goto out; diff --git a/ndctl/lib/intel.c b/ndctl/lib/intel.c index a3df26e6..13148545 100644 --- a/ndctl/lib/intel.c +++ b/ndctl/lib/intel.c @@ -455,7 +455,12 @@ static int intel_dimm_smart_inject_supported(struct ndctl_dimm *dimm) return -EIO; } - return 0; + /* Indicate all smart injection types are supported */ + return ND_SMART_INJECT_SPARES_REMAINING | + ND_SMART_INJECT_MEDIA_TEMPERATURE | + ND_SMART_INJECT_CTRL_TEMPERATURE | + ND_SMART_INJECT_HEALTH_STATE | + ND_SMART_INJECT_UNCLEAN_SHUTDOWN; } static const char *intel_cmd_desc(int fn) diff --git a/ndctl/lib/libndctl.c b/ndctl/lib/libndctl.c index 98d184ba..ccca8b57 100644 --- a/ndctl/lib/libndctl.c +++ b/ndctl/lib/libndctl.c @@ -608,6 +608,7 @@ static void free_dimm(struct ndctl_dimm *dimm) free(dimm->unique_id); free(dimm->dimm_buf); free(dimm->dimm_path); + free(dimm->bus_prefix); if (dimm->module) kmod_module_unref(dimm->module); if (dimm->health_eventfd > -1) @@ -1665,14 +1666,34 @@ static enum ndctl_fwa_result fwa_result_to_result(const char *result) return NDCTL_FWA_RESULT_INVALID; } +NDCTL_EXPORT void ndctl_dimm_refresh_flags(struct ndctl_dimm *dimm) +{ + struct ndctl_ctx *ctx = dimm->bus->ctx; + char *path = dimm->dimm_buf; + char buf[SYSFS_ATTR_SIZE]; + + /* Construct path to dimm flags sysfs file */ + sprintf(path, "%s/%s/flags", dimm->dimm_path, dimm->bus_prefix); + + if (sysfs_read_attr(ctx, path, buf) < 0) + return; + + /* Reset the flags */ + dimm->flags.flags = 0; + if (ndctl_bus_has_nfit(dimm->bus)) + parse_nfit_mem_flags(dimm, buf); + else if (ndctl_bus_is_papr_scm(dimm->bus)) + parse_papr_flags(dimm, buf); +} + static int populate_dimm_attributes(struct ndctl_dimm *dimm, - const char *dimm_base, - const char *bus_prefix) + 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); + const char *bus_prefix = dimm->bus_prefix; if (!path) return -ENOMEM; @@ -1756,16 +1777,10 @@ static int populate_dimm_attributes(struct ndctl_dimm *dimm, } sprintf(path, "%s/%s/flags", dimm_base, bus_prefix); - if (sysfs_read_attr(ctx, path, buf) == 0) { - if (ndctl_bus_has_nfit(dimm->bus)) - parse_nfit_mem_flags(dimm, buf); - else if (ndctl_bus_is_papr_scm(dimm->bus)) { - dimm->cmd_family = NVDIMM_FAMILY_PAPR; - parse_papr_flags(dimm, buf); - } - } - dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC); + + ndctl_dimm_refresh_flags(dimm); + rc = 0; err_read: @@ -1814,11 +1829,16 @@ static int add_papr_dimm(struct ndctl_dimm *dimm, const char *dimm_base) /* Allocate monitor mode fd */ dimm->health_eventfd = open(path, O_RDONLY|O_CLOEXEC); - rc = 0; + /* Get the dirty shutdown counter value */ + sprintf(path, "%s/papr/dirty_shutdown", dimm_base); + if (sysfs_read_attr(ctx, path, buf) == 0) + dimm->dirty_shutdown = strtoll(buf, NULL, 0); + rc = 0; } else if (strcmp(buf, "nvdimm_test") == 0) { + dimm->cmd_family = NVDIMM_FAMILY_PAPR; /* probe via common populate_dimm_attributes() */ - rc = populate_dimm_attributes(dimm, dimm_base, "papr"); + rc = populate_dimm_attributes(dimm, dimm_base); } out: free(path); @@ -1915,9 +1935,20 @@ static void *add_dimm(void *parent, int id, const char *dimm_base) dimm->formats = formats; /* Check if the given dimm supports nfit */ if (ndctl_bus_has_nfit(bus)) { - rc = populate_dimm_attributes(dimm, dimm_base, "nfit"); + dimm->bus_prefix = strdup("nfit"); + if (!dimm->bus_prefix) { + rc = -ENOMEM; + goto out; + } + rc = populate_dimm_attributes(dimm, dimm_base); + } else if (ndctl_bus_has_of_node(bus)) { - rc = add_papr_dimm(dimm, dimm_base); + dimm->bus_prefix = strdup("papr"); + if (!dimm->bus_prefix) { + rc = -ENOMEM; + goto out; + } + rc = add_papr_dimm(dimm, dimm_base); } if (rc == -ENODEV) { diff --git a/ndctl/lib/libndctl.sym b/ndctl/lib/libndctl.sym index 3557b32c..f1f9edd4 100644 --- a/ndctl/lib/libndctl.sym +++ b/ndctl/lib/libndctl.sym @@ -458,3 +458,7 @@ LIBNDCTL_26 { ndctl_set_config_path; ndctl_get_config_path; } LIBNDCTL_25; + +LIBNDCTL_27 { + ndctl_dimm_refresh_flags; +} LIBNDCTL_26; diff --git a/ndctl/lib/papr.c b/ndctl/lib/papr.c index 43b8412b..7a1d5595 100644 --- a/ndctl/lib/papr.c +++ b/ndctl/lib/papr.c @@ -165,6 +165,9 @@ static unsigned int papr_smart_get_flags(struct ndctl_cmd *cmd) if (health.extension_flags & PDSM_DIMM_HEALTH_RUN_GAUGE_VALID) flags |= ND_SMART_USED_VALID; + if (health.extension_flags & PDSM_DIMM_DSC_VALID) + flags |= ND_SMART_SHUTDOWN_COUNT_VALID; + return flags; } @@ -218,6 +221,41 @@ static unsigned int papr_smart_get_shutdown_state(struct ndctl_cmd *cmd) return health.dimm_bad_shutdown; } +static int papr_smart_inject_supported(struct ndctl_dimm *dimm) +{ + if (!ndctl_dimm_is_cmd_supported(dimm, ND_CMD_CALL)) + return -EOPNOTSUPP; + + if (!test_dimm_dsm(dimm, PAPR_PDSM_SMART_INJECT)) + return -EIO; + + return ND_SMART_INJECT_HEALTH_STATE | ND_SMART_INJECT_UNCLEAN_SHUTDOWN; +} + +static int papr_smart_inject_valid(struct ndctl_cmd *cmd) +{ + if (cmd->type != ND_CMD_CALL || + to_pdsm(cmd)->cmd_status != 0 || + to_pdsm_cmd(cmd) != PAPR_PDSM_SMART_INJECT) + return -EINVAL; + + return 0; +} + +static struct ndctl_cmd *papr_new_smart_inject(struct ndctl_dimm *dimm) +{ + struct ndctl_cmd *cmd; + + cmd = allocate_cmd(dimm, PAPR_PDSM_SMART_INJECT, + sizeof(struct nd_papr_pdsm_smart_inject)); + if (!cmd) + return NULL; + /* Set the input payload size */ + to_ndcmd(cmd)->nd_size_in = ND_PDSM_HDR_SIZE + + sizeof(struct nd_papr_pdsm_smart_inject); + return cmd; +} + static unsigned int papr_smart_get_life_used(struct ndctl_cmd *cmd) { struct nd_papr_pdsm_health health; @@ -236,8 +274,53 @@ static unsigned int papr_smart_get_life_used(struct ndctl_cmd *cmd) (100 - health.dimm_fuel_gauge) : 0; } +static unsigned int papr_smart_get_shutdown_count(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 (health.extension_flags & PDSM_DIMM_DSC_VALID) ? + (health.dimm_dsc) : 0; +} + +static int papr_cmd_smart_inject_fatal(struct ndctl_cmd *cmd, bool enable) +{ + if (papr_smart_inject_valid(cmd) < 0) + return -EINVAL; + + to_payload(cmd)->inject.flags |= PDSM_SMART_INJECT_HEALTH_FATAL; + to_payload(cmd)->inject.fatal_enable = enable; + + return 0; +} + +static int papr_cmd_smart_inject_unsafe_shutdown(struct ndctl_cmd *cmd, + bool enable) +{ + if (papr_smart_inject_valid(cmd) < 0) + return -EINVAL; + + to_payload(cmd)->inject.flags |= PDSM_SMART_INJECT_BAD_SHUTDOWN; + to_payload(cmd)->inject.unsafe_shutdown_enable = enable; + + return 0; +} + struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) { .cmd_is_supported = papr_cmd_is_supported, + .new_smart_inject = papr_new_smart_inject, + .smart_inject_supported = papr_smart_inject_supported, + .smart_inject_fatal = papr_cmd_smart_inject_fatal, + .smart_inject_unsafe_shutdown = papr_cmd_smart_inject_unsafe_shutdown, .smart_get_flags = papr_smart_get_flags, .get_firmware_status = papr_get_firmware_status, .xlat_firmware_status = papr_xlat_firmware_status, @@ -245,4 +328,5 @@ struct ndctl_dimm_ops * const papr_dimm_ops = &(struct ndctl_dimm_ops) { .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, + .smart_get_shutdown_count = papr_smart_get_shutdown_count, }; diff --git a/ndctl/lib/papr_pdsm.h b/ndctl/lib/papr_pdsm.h index 1bac8a7f..20ac20f8 100644 --- a/ndctl/lib/papr_pdsm.h +++ b/ndctl/lib/papr_pdsm.h @@ -75,6 +75,9 @@ /* Indicate that the 'dimm_fuel_gauge' field is valid */ #define PDSM_DIMM_HEALTH_RUN_GAUGE_VALID 1 +/* Indicate that the 'dimm_dsc' field is valid */ +#define PDSM_DIMM_DSC_VALID 2 + /* * Struct exchanged between kernel & ndctl in for PAPR_PDSM_HEALTH * Various flags indicate the health status of the dimm. @@ -103,6 +106,9 @@ struct nd_papr_pdsm_health { /* Extension flag PDSM_DIMM_HEALTH_RUN_GAUGE_VALID */ __u16 dimm_fuel_gauge; + + /* Extension flag PDSM_DIMM_DSC_VALID */ + __u64 dimm_dsc; }; __u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE]; }; @@ -115,12 +121,29 @@ struct nd_papr_pdsm_health { enum papr_pdsm { PAPR_PDSM_MIN = 0x0, PAPR_PDSM_HEALTH, + PAPR_PDSM_SMART_INJECT, PAPR_PDSM_MAX, }; +/* Flags for injecting specific smart errors */ +#define PDSM_SMART_INJECT_HEALTH_FATAL (1 << 0) +#define PDSM_SMART_INJECT_BAD_SHUTDOWN (1 << 1) + +struct nd_papr_pdsm_smart_inject { + union { + struct { + /* One or more of PDSM_SMART_INJECT_ */ + __u32 flags; + __u8 fatal_enable; + __u8 unsafe_shutdown_enable; + }; + __u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE]; + }; +}; /* Maximal union that can hold all possible payload types */ union nd_pdsm_payload { struct nd_papr_pdsm_health health; + struct nd_papr_pdsm_smart_inject inject; __u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE]; } __attribute__((packed)); diff --git a/ndctl/lib/private.h b/ndctl/lib/private.h index 4d862297..e5c56295 100644 --- a/ndctl/lib/private.h +++ b/ndctl/lib/private.h @@ -75,6 +75,7 @@ struct ndctl_dimm { char *unique_id; char *dimm_path; char *dimm_buf; + char *bus_prefix; int health_eventfd; int buf_len; int id; diff --git a/ndctl/libndctl.h b/ndctl/libndctl.h index b59026c1..57cf93d8 100644 --- a/ndctl/libndctl.h +++ b/ndctl/libndctl.h @@ -69,6 +69,13 @@ extern "C" { #define ND_EVENT_HEALTH_STATE (1 << 3) #define ND_EVENT_UNCLEAN_SHUTDOWN (1 << 4) +/* Flags indicating support for various smart injection types */ +#define ND_SMART_INJECT_SPARES_REMAINING (1 << 0) +#define ND_SMART_INJECT_MEDIA_TEMPERATURE (1 << 1) +#define ND_SMART_INJECT_CTRL_TEMPERATURE (1 << 2) +#define ND_SMART_INJECT_HEALTH_STATE (1 << 3) +#define ND_SMART_INJECT_UNCLEAN_SHUTDOWN (1 << 4) + size_t ndctl_min_namespace_size(void); size_t ndctl_sizeof_namespace_index(void); size_t ndctl_sizeof_namespace_label(void); @@ -216,6 +223,7 @@ int ndctl_dimm_is_active(struct ndctl_dimm *dimm); int ndctl_dimm_is_enabled(struct ndctl_dimm *dimm); int ndctl_dimm_disable(struct ndctl_dimm *dimm); int ndctl_dimm_enable(struct ndctl_dimm *dimm); +void ndctl_dimm_refresh_flags(struct ndctl_dimm *dimm); struct ndctl_cmd; struct ndctl_cmd *ndctl_bus_cmd_new_ars_cap(struct ndctl_bus *bus, @@ -311,6 +319,7 @@ int ndctl_cmd_smart_inject_spares(struct ndctl_cmd *cmd, bool enable, unsigned int spares); int ndctl_cmd_smart_inject_fatal(struct ndctl_cmd *cmd, bool enable); int ndctl_cmd_smart_inject_unsafe_shutdown(struct ndctl_cmd *cmd, bool enable); +/* Returns a bitmap of ND_SMART_INJECT_* supported */ int ndctl_dimm_smart_inject_supported(struct ndctl_dimm *dimm); struct ndctl_cmd *ndctl_dimm_cmd_new_vendor_specific(struct ndctl_dimm *dimm, diff --git a/test/ack-shutdown-count-set.c b/test/ack-shutdown-count-set.c index a9e95c63..f091a404 100644 --- a/test/ack-shutdown-count-set.c +++ b/test/ack-shutdown-count-set.c @@ -117,6 +117,7 @@ static int test_ack_shutdown_count_set(int loglevel, struct ndctl_test *test, int main(int argc, char *argv[]) { + char *test_env = getenv("NDCTL_TEST_FAMILY"); struct ndctl_test *test = ndctl_test_new(0); struct ndctl_ctx *ctx; int rc; @@ -126,6 +127,9 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } + if (test_env && strcmp(test_env, "PAPR") == 0) + return ndctl_test_result(test, 77); + rc = ndctl_new(&ctx); if (rc) return ndctl_test_result(test, rc); |