The "smart_get_shutdown_count" dimm-op is expected to return a shutdown
count, but for the Hyper-V family this is only available from a separate
DSM. Perform a command submission in the "hyperv_cmd_get_shutdown_count"
dimm-op and the "hyperv_cmd_get_flags" dimm-op to retrieve this info, so
that a smart health listing can display this info.

Now "ndctl list --dimms --health" can show a line of "shutdown_count"
for Hyper-V NVDIMM, e.g.

{
    "dev":"nmem0",
    "id":"04d5-01-1701-00000000",
    "handle":0,
    "phys_id":0,
    "health":{
      "health_state":"ok",
      "shutdown_count":2
    }
}

Signed-off-by: Dexuan Cui <[email protected]>
---
 ndctl/lib/hyperv.c | 43 +++++++++++++++++++++++++++++++++++++++++++
 ndctl/lib/hyperv.h |  8 ++++++++
 2 files changed, 51 insertions(+)

diff --git a/ndctl/lib/hyperv.c b/ndctl/lib/hyperv.c
index 6ed2125..efd8b03 100644
--- a/ndctl/lib/hyperv.c
+++ b/ndctl/lib/hyperv.c
@@ -72,9 +72,33 @@ static int hyperv_valid_health_info(struct ndctl_cmd *cmd)
        return hyperv_cmd_valid(cmd, ND_HYPERV_CMD_GET_HEALTH_INFO);
 }
 
+static int hyperv_get_shutdown_count(struct ndctl_cmd *cmd, unsigned int 
*count)
+{
+       unsigned int command = ND_HYPERV_CMD_GET_SHUTDOWN_INFO;
+       struct ndctl_cmd *cmd_get_shutdown_info;
+       int rc;
+
+       cmd_get_shutdown_info = alloc_hyperv_cmd(cmd->dimm, command);
+       if (!cmd_get_shutdown_info)
+               return -EINVAL;
+
+       if (ndctl_cmd_submit_xlat(cmd_get_shutdown_info) < 0 ||
+           hyperv_cmd_valid(cmd_get_shutdown_info, command) < 0) {
+               rc = -EINVAL;
+               goto out;
+       }
+
+       *count = cmd_get_shutdown_info->hyperv->u.shutdown_info.count;
+       rc = 0;
+out:
+       ndctl_cmd_unref(cmd_get_shutdown_info);
+       return rc;
+}
+
 static unsigned int hyperv_cmd_get_flags(struct ndctl_cmd *cmd)
 {
        unsigned int flags = 0;
+       unsigned int count;
        int rc;
 
        rc = hyperv_valid_health_info(cmd);
@@ -84,6 +108,9 @@ static unsigned int hyperv_cmd_get_flags(struct ndctl_cmd 
*cmd)
        }
        flags |= ND_SMART_HEALTH_VALID;
 
+       if (hyperv_get_shutdown_count(cmd, &count) == 0)
+               flags |= ND_SMART_SHUTDOWN_COUNT_VALID;
+
        return flags;
 }
 
@@ -113,6 +140,21 @@ static unsigned int hyperv_cmd_get_health(struct ndctl_cmd 
*cmd)
        return health;
 }
 
+static unsigned int hyperv_cmd_get_shutdown_count(struct ndctl_cmd *cmd)
+{
+       unsigned int count;
+       int rc;;
+
+       rc = hyperv_get_shutdown_count(cmd, &count);
+
+       if (rc < 0) {
+               errno = -rc;
+               return UINT_MAX;
+       }
+
+       return count;
+}
+
 static int hyperv_cmd_xlat_firmware_status(struct ndctl_cmd *cmd)
 {
        return cmd->hyperv->u.status == 0 ? 0 : -EINVAL;
@@ -122,5 +164,6 @@ struct ndctl_dimm_ops * const hyperv_dimm_ops = &(struct 
ndctl_dimm_ops) {
        .new_smart = hyperv_dimm_cmd_new_smart,
        .smart_get_flags = hyperv_cmd_get_flags,
        .smart_get_health = hyperv_cmd_get_health,
+       .smart_get_shutdown_count = hyperv_cmd_get_shutdown_count,
        .xlat_firmware_status = hyperv_cmd_xlat_firmware_status,
 };
diff --git a/ndctl/lib/hyperv.h b/ndctl/lib/hyperv.h
index 45bbc12..0c1677f 100644
--- a/ndctl/lib/hyperv.h
+++ b/ndctl/lib/hyperv.h
@@ -9,6 +9,7 @@
 enum {
        ND_HYPERV_CMD_QUERY_SUPPORTED_FUNCTIONS = 0,
        ND_HYPERV_CMD_GET_HEALTH_INFO           = 1,
+       ND_HYPERV_CMD_GET_SHUTDOWN_INFO         = 2,
 };
 
 /* Get Health Information (Function Index 1) */
@@ -17,9 +18,16 @@ struct nd_hyperv_health_info {
        __u32   health;
 } __attribute__((packed));
 
+/* Get Unsafe Shutdown Count (Function Index 2) */
+struct nd_hyperv_shutdown_info {
+        __u32   status;
+        __u32   count;
+} __attribute__((packed));
+
 union nd_hyperv_cmd {
        __u32                           status;
        struct nd_hyperv_health_info    health_info;
+       struct nd_hyperv_shutdown_info  shutdown_info;
 } __attribute__((packed));
 
 struct nd_pkg_hyperv {
-- 
2.19.1

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

Reply via email to