@@ -143,6 +143,7 @@ static unsigned int intel_cmd_smart_get_health(struct ndctl_cmd *cmd)
}
intel_smart_get_field(cmd, media_temperature)
+intel_smart_get_field(cmd, ctrl_temperature)
intel_smart_get_field(cmd, spares)
intel_smart_get_field(cmd, alarm_flags)
intel_smart_get_field(cmd, life_used)
@@ -198,6 +199,7 @@ static unsigned int intel_cmd_smart_threshold_get_alarm_control(
}
intel_smart_threshold_get_field(cmd, media_temperature)
+intel_smart_threshold_get_field(cmd, ctrl_temperature)
intel_smart_threshold_get_field(cmd, spares)
static struct ndctl_cmd *intel_dimm_cmd_new_smart_threshold(
@@ -216,11 +218,77 @@ static struct ndctl_cmd *intel_dimm_cmd_new_smart_threshold(
return cmd;
}
+static struct ndctl_cmd *intel_dimm_cmd_new_smart_set_threshold(
+ struct ndctl_cmd *cmd_thresh)
+{
+ struct ndctl_cmd *cmd;
+ struct nd_intel_smart_threshold *thresh;
+ struct nd_intel_smart_set_threshold *set_thresh;
+
+ BUILD_ASSERT(sizeof(struct nd_intel_smart_set_threshold) == 11);
+
+ if (intel_smart_threshold_valid(cmd_thresh) < 0)
+ return NULL;
+
+ cmd = alloc_intel_cmd(cmd_thresh->dimm, ND_INTEL_SMART_SET_THRESHOLD,
+ offsetof(typeof(*set_thresh), status), 4);
+ if (!cmd)
+ return NULL;
+
+ cmd->source = cmd_thresh;
+ ndctl_cmd_ref(cmd_thresh);
+ set_thresh = &cmd->intel->set_thresh;
+ thresh = &cmd_thresh->intel->thresh;
+ set_thresh->alarm_control = thresh->alarm_control;
+ set_thresh->spares = thresh->spares;
+ set_thresh->media_temperature = thresh->media_temperature;
+ set_thresh->ctrl_temperature = thresh->ctrl_temperature;
+ cmd->firmware_status = &set_thresh->status;
+
+ return cmd;
+}
+
+static int intel_smart_set_threshold_valid(struct ndctl_cmd *cmd)
+{
+ struct nd_pkg_intel *pkg = cmd->intel;
+
+ if (cmd->type != ND_CMD_CALL || cmd->status != 1
+ || pkg->gen.nd_family != NVDIMM_FAMILY_INTEL
+ || pkg->gen.nd_command != ND_INTEL_SMART_SET_THRESHOLD)
+ return -EINVAL;
+ return 0;
+}
+
+#define intel_smart_set_threshold_field(field) \
+static int intel_cmd_smart_threshold_set_##field( \
+ struct ndctl_cmd *cmd, unsigned int val) \
+{ \
+ if (intel_smart_set_threshold_valid(cmd) < 0) \
+ return -EINVAL; \
+ cmd->intel->set_thresh.field = val; \
+ return 0; \
+}
+
+static unsigned int intel_cmd_smart_threshold_get_supported_alarms(
+ struct ndctl_cmd *cmd)
+{
+ if (intel_smart_set_threshold_valid(cmd) < 0)
+ return 0;
+ return ND_SMART_SPARE_TRIP | ND_SMART_MTEMP_TRIP
+ | ND_SMART_CTEMP_TRIP;
+}
+
+intel_smart_set_threshold_field(alarm_control)
+intel_smart_set_threshold_field(spares)
+intel_smart_set_threshold_field(media_temperature)
+intel_smart_set_threshold_field(ctrl_temperature)
+
struct ndctl_smart_ops * const intel_smart_ops = &(struct ndctl_smart_ops) {
.new_smart = intel_dimm_cmd_new_smart,
.smart_get_flags = intel_cmd_smart_get_flags,
.smart_get_health = intel_cmd_smart_get_health,
.smart_get_media_temperature = intel_cmd_smart_get_media_temperature,
+ .smart_get_ctrl_temperature = intel_cmd_smart_get_ctrl_temperature,
.smart_get_spares = intel_cmd_smart_get_spares,
.smart_get_alarm_flags = intel_cmd_smart_get_alarm_flags,
.smart_get_life_used = intel_cmd_smart_get_life_used,
@@ -229,8 +297,21 @@ struct ndctl_smart_ops * const intel_smart_ops = &(struct ndctl_smart_ops) {
.smart_get_vendor_size = intel_cmd_smart_get_vendor_size,
.smart_get_vendor_data = intel_cmd_smart_get_vendor_data,
.new_smart_threshold = intel_dimm_cmd_new_smart_threshold,
- .smart_threshold_get_alarm_control = intel_cmd_smart_threshold_get_alarm_control,
+ .smart_threshold_get_alarm_control
+ = intel_cmd_smart_threshold_get_alarm_control,
.smart_threshold_get_media_temperature
= intel_cmd_smart_threshold_get_media_temperature,
+ .smart_threshold_get_ctrl_temperature
+ = intel_cmd_smart_threshold_get_ctrl_temperature,
.smart_threshold_get_spares = intel_cmd_smart_threshold_get_spares,
+ .new_smart_set_threshold = intel_dimm_cmd_new_smart_set_threshold,
+ .smart_threshold_get_supported_alarms
+ = intel_cmd_smart_threshold_get_supported_alarms,
+ .smart_threshold_set_alarm_control
+ = intel_cmd_smart_threshold_set_alarm_control,
+ .smart_threshold_set_media_temperature
+ = intel_cmd_smart_threshold_set_media_temperature,
+ .smart_threshold_set_ctrl_temperature
+ = intel_cmd_smart_threshold_set_ctrl_temperature,
+ .smart_threshold_set_spares = intel_cmd_smart_threshold_set_spares,
};
@@ -5,6 +5,7 @@
#define __INTEL_H__
#define ND_INTEL_SMART 1
#define ND_INTEL_SMART_THRESHOLD 2
+#define ND_INTEL_SMART_SET_THRESHOLD 17
#define ND_INTEL_SMART_HEALTH_VALID (1 << 0)
#define ND_INTEL_SMART_SPARES_VALID (1 << 1)
@@ -62,11 +63,20 @@ struct nd_intel_smart_threshold {
};
} __attribute__((packed));
+struct nd_intel_smart_set_threshold {
+ __u16 alarm_control;
+ __u8 spares;
+ __u16 media_temperature;
+ __u16 ctrl_temperature;
+ __u32 status;
+} __attribute__((packed));
+
struct nd_pkg_intel {
struct nd_cmd_pkg gen;
union {
struct nd_intel_smart smart;
struct nd_intel_smart_threshold thresh;
+ struct nd_intel_smart_set_threshold set_thresh;
};
};
#endif /* __INTEL_H__ */
@@ -312,4 +312,13 @@ global:
ndctl_bb_get_count;
ndctl_cmd_smart_get_media_temperature;
ndctl_cmd_smart_threshold_get_media_temperature;
+ ndctl_cmd_smart_get_ctrl_temperature;
+ ndctl_cmd_smart_threshold_get_ctrl_temperature;
+ ndctl_dimm_cmd_new_smart_set_threshold;
+ ndctl_cmd_smart_threshold_get_supported_alarms;
+ ndctl_cmd_smart_threshold_set_alarm_control;
+ ndctl_cmd_smart_threshold_set_temperature;
+ ndctl_cmd_smart_threshold_set_media_temperature;
+ ndctl_cmd_smart_threshold_set_ctrl_temperature;
+ ndctl_cmd_smart_threshold_set_spares;
} LIBNDCTL_13;
@@ -282,6 +282,7 @@ struct ndctl_smart_ops {
unsigned int (*smart_get_flags)(struct ndctl_cmd *);
unsigned int (*smart_get_health)(struct ndctl_cmd *);
unsigned int (*smart_get_media_temperature)(struct ndctl_cmd *);
+ unsigned int (*smart_get_ctrl_temperature)(struct ndctl_cmd *);
unsigned int (*smart_get_spares)(struct ndctl_cmd *);
unsigned int (*smart_get_alarm_flags)(struct ndctl_cmd *);
unsigned int (*smart_get_life_used)(struct ndctl_cmd *);
@@ -292,7 +293,14 @@ struct ndctl_smart_ops {
struct ndctl_cmd *(*new_smart_threshold)(struct ndctl_dimm *);
unsigned int (*smart_threshold_get_alarm_control)(struct ndctl_cmd *);
unsigned int (*smart_threshold_get_media_temperature)(struct ndctl_cmd *);
+ unsigned int (*smart_threshold_get_ctrl_temperature)(struct ndctl_cmd *);
unsigned int (*smart_threshold_get_spares)(struct ndctl_cmd *);
+ struct ndctl_cmd *(*new_smart_set_threshold)(struct ndctl_cmd *);
+ unsigned int (*smart_threshold_get_supported_alarms)(struct ndctl_cmd *);
+ int (*smart_threshold_set_alarm_control)(struct ndctl_cmd *, unsigned int);
+ int (*smart_threshold_set_media_temperature)(struct ndctl_cmd *, unsigned int);
+ int (*smart_threshold_set_ctrl_temperature)(struct ndctl_cmd *, unsigned int);
+ int (*smart_threshold_set_spares)(struct ndctl_cmd *, unsigned int);
};
struct ndctl_smart_ops * const intel_smart_ops;
@@ -40,6 +40,25 @@ NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(
return NULL;
}
+/*
+ * smart_set_threshold is a read-modify-write command it depends on a
+ * successfully completed smart_threshold command for its defaults.
+ */
+NDCTL_EXPORT struct ndctl_cmd *ndctl_dimm_cmd_new_smart_set_threshold(
+ struct ndctl_cmd *cmd)
+{
+ struct ndctl_smart_ops *ops;
+
+ if (!cmd || !cmd->dimm)
+ return NULL;
+ ops = ndctl_dimm_get_smart_ops(cmd->dimm);
+
+ if (ops && ops->new_smart_set_threshold)
+ return ops->new_smart_set_threshold(cmd);
+ else
+ return NULL;
+}
+
#define smart_cmd_op(op, rettype, defretvalue) \
NDCTL_EXPORT rettype ndctl_cmd_##op(struct ndctl_cmd *cmd) \
{ \
@@ -54,6 +73,7 @@ NDCTL_EXPORT rettype ndctl_cmd_##op(struct ndctl_cmd *cmd) \
smart_cmd_op(smart_get_flags, unsigned int, 0)
smart_cmd_op(smart_get_health, unsigned int, 0)
smart_cmd_op(smart_get_media_temperature, unsigned int, 0)
+smart_cmd_op(smart_get_ctrl_temperature, unsigned int, 0)
smart_cmd_op(smart_get_spares, unsigned int, 0)
smart_cmd_op(smart_get_alarm_flags, unsigned int, 0)
smart_cmd_op(smart_get_life_used, unsigned int, 0)
@@ -63,6 +83,7 @@ smart_cmd_op(smart_get_vendor_size, unsigned int, 0)
smart_cmd_op(smart_get_vendor_data, unsigned char *, NULL)
smart_cmd_op(smart_threshold_get_alarm_control, unsigned int, 0)
smart_cmd_op(smart_threshold_get_media_temperature, unsigned int, 0)
+smart_cmd_op(smart_threshold_get_ctrl_temperature, unsigned int, 0)
smart_cmd_op(smart_threshold_get_spares, unsigned int, 0)
NDCTL_EXPORT unsigned int ndctl_cmd_smart_get_temperature(struct ndctl_cmd *cmd)
@@ -75,3 +96,21 @@ NDCTL_EXPORT unsigned int ndctl_cmd_smart_threshold_get_temperature(
{
return ndctl_cmd_smart_threshold_get_media_temperature(cmd);
}
+
+smart_cmd_op(smart_threshold_get_supported_alarms, unsigned int, 0);
+
+#define smart_cmd_set_op(op) \
+NDCTL_EXPORT int ndctl_cmd_##op(struct ndctl_cmd *cmd, unsigned int val) \
+{ \
+ if (cmd->dimm) { \
+ struct ndctl_smart_ops *ops = ndctl_dimm_get_smart_ops(cmd->dimm); \
+ if (ops && ops->op) \
+ return ops->op(cmd, val); \
+ } \
+ return -ENXIO; \
+}
+
+smart_cmd_set_op(smart_threshold_set_alarm_control)
+smart_cmd_set_op(smart_threshold_set_media_temperature)
+smart_cmd_set_op(smart_threshold_set_ctrl_temperature)
+smart_cmd_set_op(smart_threshold_set_spares)
@@ -230,6 +230,7 @@ unsigned int ndctl_cmd_smart_get_flags(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_get_health(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_get_temperature(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_get_media_temperature(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_get_ctrl_temperature(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_get_spares(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_get_alarm_flags(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_get_life_used(struct ndctl_cmd *cmd);
@@ -241,7 +242,20 @@ struct ndctl_cmd *ndctl_dimm_cmd_new_smart_threshold(struct ndctl_dimm *dimm);
unsigned int ndctl_cmd_smart_threshold_get_alarm_control(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_threshold_get_temperature(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_threshold_get_media_temperature(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_threshold_get_ctrl_temperature(struct ndctl_cmd *cmd);
unsigned int ndctl_cmd_smart_threshold_get_spares(struct ndctl_cmd *cmd);
+struct ndctl_cmd *ndctl_dimm_cmd_new_smart_set_threshold(struct ndctl_cmd *cmd);
+unsigned int ndctl_cmd_smart_threshold_get_supported_alarms(struct ndctl_cmd *cmd);
+int ndctl_cmd_smart_threshold_set_alarm_control(struct ndctl_cmd *cmd,
+ unsigned int val);
+int ndctl_cmd_smart_threshold_set_temperature(struct ndctl_cmd *cmd,
+ unsigned int val);
+int ndctl_cmd_smart_threshold_set_media_temperature(struct ndctl_cmd *cmd,
+ unsigned int val);
+int ndctl_cmd_smart_threshold_set_ctrl_temperature(struct ndctl_cmd *cmd,
+ unsigned int val);
+int ndctl_cmd_smart_threshold_set_spares(struct ndctl_cmd *cmd,
+ unsigned int val);
struct ndctl_cmd *ndctl_dimm_cmd_new_vendor_specific(struct ndctl_dimm *dimm,
unsigned int opcode, size_t input_size, size_t output_size);
@@ -2182,7 +2182,7 @@ static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
__check_smart(dimm, cmd, shutdown_state);
__check_smart(dimm, cmd, vendor_size);
- ndctl_cmd_unref(cmd);
+ check->cmd = cmd;
return 0;
}
@@ -2203,7 +2203,7 @@ static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
* smart_threshold parameters.
*/
struct smart_threshold {
- unsigned int alarm_control, temperature, spares;
+ unsigned int alarm_control, media_temperature, ctrl_temperature, spares;
};
static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
@@ -2211,10 +2211,13 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
{
static const struct smart_threshold smart_t_data = {
.alarm_control = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP,
- .temperature = 40 * 16,
+ .media_temperature = 40 * 16,
+ .ctrl_temperature = 30 * 16,
.spares = 5,
};
struct ndctl_cmd *cmd = ndctl_dimm_cmd_new_smart_threshold(dimm);
+ struct ndctl_cmd *cmd_smart = check_cmds[ND_CMD_SMART].cmd;
+ struct ndctl_cmd *cmd_set;
struct timeval tm;
char buf[4096];
fd_set fds;
@@ -2249,7 +2252,7 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
if (pid == 0) {
FD_ZERO(&fds);
FD_SET(fd, &fds);
- tm.tv_sec = 1;
+ tm.tv_sec = 5;
tm.tv_usec = 0;
rc = select(fd + 1, NULL, NULL, &fds, &tm);
if (rc != 1 || !FD_ISSET(fd, &fds))
@@ -2267,6 +2270,50 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
return rc;
}
+ __check_smart_threshold(dimm, cmd, alarm_control);
+ __check_smart_threshold(dimm, cmd, media_temperature);
+ __check_smart_threshold(dimm, cmd, ctrl_temperature);
+ __check_smart_threshold(dimm, cmd, spares);
+
+ /*
+ * The same kernel change that adds nfit_test support for this
+ * command is the same change that moves notifications to
+ * require set_threshold. If we fail to get a command, but the
+ * notification fires then we are on an old kernel, otherwise
+ * whether old kernel or new kernel the notification should
+ * fire.
+ */
+ cmd_set = ndctl_dimm_cmd_new_smart_set_threshold(cmd);
+ if (cmd_set) {
+ /*
+ * Set all thresholds to match current values and set
+ * all alarms.
+ */
+ rc = ndctl_cmd_smart_threshold_set_alarm_control(cmd_set,
+ ndctl_cmd_smart_threshold_get_supported_alarms(cmd_set));
+ rc |= ndctl_cmd_smart_threshold_set_media_temperature(cmd_set,
+ ndctl_cmd_smart_get_media_temperature(cmd_smart));
+ rc |= ndctl_cmd_smart_threshold_set_ctrl_temperature(cmd_set,
+ ndctl_cmd_smart_get_ctrl_temperature(cmd_smart));
+ rc |= ndctl_cmd_smart_threshold_set_spares(cmd_set,
+ ndctl_cmd_smart_get_spares(cmd_smart));
+ if (rc) {
+ fprintf(stderr, "%s: failed set threshold parameters\n",
+ __func__);
+ ndctl_cmd_unref(cmd_set);
+ return -ENXIO;
+ }
+
+ rc = ndctl_cmd_submit(cmd_set);
+ if (rc) {
+ fprintf(stderr, "%s: dimm: %#x failed to submit cmd_set: %d\n",
+ __func__, ndctl_dimm_get_handle(dimm), rc);
+ ndctl_cmd_unref(cmd_set);
+ return rc;
+ }
+ ndctl_cmd_unref(cmd_set);
+ }
+
if (ndctl_test_attempt(check->test, KERNEL_VERSION(4, 9, 0))) {
wait(&rc);
if (WEXITSTATUS(rc) == EXIT_FAILURE) {
@@ -2276,10 +2323,6 @@ static int check_smart_threshold(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
}
}
- __check_smart_threshold(dimm, cmd, alarm_control);
- __check_smart_threshold(dimm, cmd, temperature);
- __check_smart_threshold(dimm, cmd, spares);
-
ndctl_cmd_unref(cmd);
return 0;
}
libndctl and test support for the ND_INTEL_SMART_SET_THRESHOLD command. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- ndctl/lib/intel.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++- ndctl/lib/intel.h | 10 ++++++ ndctl/lib/libndctl.sym | 9 +++++ ndctl/lib/private.h | 8 +++++ ndctl/lib/smart.c | 39 +++++++++++++++++++++++ ndctl/libndctl.h | 14 ++++++++ test/libndctl.c | 59 +++++++++++++++++++++++++++++----- 7 files changed, 213 insertions(+), 9 deletions(-)