@@ -1322,6 +1322,7 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)
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;
@@ -1387,6 +1388,10 @@ static void *add_dimm(void *parent, int id, const char *dimm_base)
if (sysfs_read_attr(ctx, path, buf) == 0)
dimm->revision_id = strtoul(buf, NULL, 0);
+ sprintf(path, "%s/nfit/dirty_shutdown", dimm_base);
+ if (sysfs_read_attr(ctx, path, buf) == 0)
+ dimm->dirty_shutdown = strtoll(buf, NULL, 0);
+
sprintf(path, "%s/nfit/subsystem_vendor", dimm_base);
if (sysfs_read_attr(ctx, path, buf) == 0)
dimm->subsystem_vendor_id = strtoul(buf, NULL, 0);
@@ -1489,6 +1494,11 @@ NDCTL_EXPORT unsigned short ndctl_dimm_get_revision(struct ndctl_dimm *dimm)
return dimm->revision_id;
}
+NDCTL_EXPORT long long ndctl_dimm_get_dirty_shutdown(struct ndctl_dimm *dimm)
+{
+ return dimm->dirty_shutdown;
+}
+
NDCTL_EXPORT unsigned short ndctl_dimm_get_subsystem_vendor(
struct ndctl_dimm *dimm)
{
@@ -378,3 +378,8 @@ global:
ndctl_region_get_max_available_extent;
ndctl_cmd_smart_inject_ctrl_temperature;
} LIBNDCTL_16;
+
+LIBNDCTL_18 {
+global:
+ ndctl_dimm_get_dirty_shutdown;
+} LIBNDCTL_17;
@@ -76,6 +76,7 @@ struct ndctl_dimm {
unsigned long cmd_family;
unsigned long cmd_mask;
unsigned long nfit_dsm_mask;
+ long long dirty_shutdown;
char *unique_id;
char *dimm_path;
char *dimm_buf;
@@ -150,6 +150,7 @@ unsigned short ndctl_dimm_get_phys_id(struct ndctl_dimm *dimm);
unsigned short ndctl_dimm_get_vendor(struct ndctl_dimm *dimm);
unsigned short ndctl_dimm_get_device(struct ndctl_dimm *dimm);
unsigned short ndctl_dimm_get_revision(struct ndctl_dimm *dimm);
+long long ndctl_dimm_get_dirty_shutdown(struct ndctl_dimm *dimm);
unsigned short ndctl_dimm_get_subsystem_vendor(struct ndctl_dimm *dimm);
unsigned short ndctl_dimm_get_subsystem_device(struct ndctl_dimm *dimm);
unsigned short ndctl_dimm_get_manufacturing_date(struct ndctl_dimm *dimm);
@@ -118,6 +118,7 @@ struct dimm {
unsigned int subsystem_vendor;
unsigned short manufacturing_date;
unsigned char manufacturing_location;
+ long long dirty_shutdown;
union {
unsigned long flags;
struct {
@@ -136,15 +137,15 @@ struct dimm {
(((n & 0xfff) << 16) | ((s & 0xf) << 12) | ((i & 0xf) << 8) \
| ((c & 0xf) << 4) | (d & 0xf))
static struct dimm dimms0[] = {
- { DIMM_HANDLE(0, 0, 0, 0, 0), 0, 0, 2016, 10, { 0 }, 2, { 0x201, 0x301, }, },
- { DIMM_HANDLE(0, 0, 0, 0, 1), 1, 0, 2016, 10, { 0 }, 2, { 0x201, 0x301, }, },
- { DIMM_HANDLE(0, 0, 1, 0, 0), 2, 0, 2016, 10, { 0 }, 2, { 0x201, 0x301, }, },
- { DIMM_HANDLE(0, 0, 1, 0, 1), 3, 0, 2016, 10, { 0 }, 2, { 0x201, 0x301, }, },
+ { DIMM_HANDLE(0, 0, 0, 0, 0), 0, 0, 2016, 10, 42, { 0 }, 2, { 0x201, 0x301, }, },
+ { DIMM_HANDLE(0, 0, 0, 0, 1), 1, 0, 2016, 10, 42, { 0 }, 2, { 0x201, 0x301, }, },
+ { DIMM_HANDLE(0, 0, 1, 0, 0), 2, 0, 2016, 10, 42, { 0 }, 2, { 0x201, 0x301, }, },
+ { DIMM_HANDLE(0, 0, 1, 0, 1), 3, 0, 2016, 10, 42, { 0 }, 2, { 0x201, 0x301, }, },
};
static struct dimm dimms1[] = {
{
- DIMM_HANDLE(0, 0, 0, 0, 0), 0, 0, 2016, 10, {
+ DIMM_HANDLE(0, 0, 0, 0, 0), 0, 0, 2016, 10, 42, {
.f_arm = 1,
.f_save = 1,
.f_flush = 1,
@@ -2195,7 +2196,7 @@ static int check_set_config_data(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
*/
struct smart {
unsigned int flags, health, temperature, spares, alarm_flags,
- life_used, shutdown_state, vendor_size;
+ life_used, shutdown_state, shutdown_count, vendor_size;
};
static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
@@ -2211,6 +2212,7 @@ static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
.alarm_flags = ND_SMART_SPARE_TRIP | ND_SMART_TEMP_TRIP,
.life_used = 5,
.shutdown_state = 0,
+ .shutdown_count = 42,
.vendor_size = 0,
};
struct ndctl_cmd *cmd = ndctl_dimm_cmd_new_smart(dimm);
@@ -2230,7 +2232,8 @@ static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
return rc;
}
- __check_smart(dimm, cmd, flags, ~ND_SMART_CTEMP_VALID);
+ __check_smart(dimm, cmd, flags, ~(ND_SMART_CTEMP_VALID
+ | ND_SMART_SHUTDOWN_COUNT_VALID));
__check_smart(dimm, cmd, health, -1);
__check_smart(dimm, cmd, temperature, -1);
__check_smart(dimm, cmd, spares, -1);
@@ -2238,6 +2241,8 @@ static int check_smart(struct ndctl_bus *bus, struct ndctl_dimm *dimm,
__check_smart(dimm, cmd, life_used, -1);
__check_smart(dimm, cmd, shutdown_state, -1);
__check_smart(dimm, cmd, vendor_size, -1);
+ if (ndctl_cmd_smart_get_flags(cmd) & ND_SMART_SHUTDOWN_COUNT_VALID)
+ __check_smart(dimm, cmd, shutdown_count, -1);
check->cmd = cmd;
return 0;
@@ -2468,6 +2473,7 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
unsigned long bus_commands, unsigned long dimm_commands,
struct ndctl_test *test)
{
+ long long dsc;
int i, j, rc;
for (i = 0; i < n; i++) {
@@ -2552,6 +2558,15 @@ static int check_dimms(struct ndctl_bus *bus, struct dimm *dimms, int n,
}
}
+ dsc = ndctl_dimm_get_dirty_shutdown(dimm);
+ if (dsc != -ENOENT && dsc != dimms[i].dirty_shutdown) {
+ fprintf(stderr,
+ "dimm%d expected dirty shutdown: %lld got: %lld\n",
+ i, dimms[i].dirty_shutdown,
+ ndctl_dimm_get_dirty_shutdown(dimm));
+ return -ENXIO;
+ }
+
rc = check_commands(bus, dimm, bus_commands, dimm_commands, test);
if (rc)
return rc;
The kernel now exports nmemX/nfit/dirty_shutdown for DIMMs/platforms that provide a free running dirty-shutdown-counter. Signed-off-by: Dan Williams <dan.j.williams@intel.com> --- ndctl/lib/libndctl.c | 10 ++++++++++ ndctl/lib/libndctl.sym | 5 +++++ ndctl/lib/private.h | 1 + ndctl/libndctl.h | 1 + test/libndctl.c | 29 ++++++++++++++++++++++------- 5 files changed, 39 insertions(+), 7 deletions(-)