powerpc/papr_scm: Implement support for PAPR_PDSM_HEALTH
authorVaibhav Jain <vaibhav@linux.ibm.com>
Mon, 15 Jun 2020 12:44:07 +0000 (18:14 +0530)
committerDan Williams <dan.j.williams@intel.com>
Tue, 16 Jun 2020 01:22:44 +0000 (18:22 -0700)
This patch implements support for PDSM request 'PAPR_PDSM_HEALTH'
that returns a newly introduced 'struct nd_papr_pdsm_health' instance
containing dimm health information back to user space in response to
ND_CMD_CALL. This functionality is implemented in newly introduced
papr_pdsm_health() that queries the nvdimm health information and
then copies this information to the package payload whose layout is
defined by 'struct nd_papr_pdsm_health'.

Signed-off-by: Vaibhav Jain <vaibhav@linux.ibm.com>
Cc: "Aneesh Kumar K . V" <aneesh.kumar@linux.ibm.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Ira Weiny <ira.weiny@intel.com>
Link: https://lore.kernel.org/r/20200615124407.32596-7-vaibhav@linux.ibm.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
arch/powerpc/include/uapi/asm/papr_pdsm.h
arch/powerpc/platforms/pseries/papr_scm.c

index 2811515..9ccecc1 100644 (file)
 #define ND_PDSM_HDR_SIZE \
        (sizeof(struct nd_pkg_pdsm) - ND_PDSM_PAYLOAD_MAX_SIZE)
 
+/* Various nvdimm health indicators */
+#define PAPR_PDSM_DIMM_HEALTHY       0
+#define PAPR_PDSM_DIMM_UNHEALTHY     1
+#define PAPR_PDSM_DIMM_CRITICAL      2
+#define PAPR_PDSM_DIMM_FATAL         3
+
+/*
+ * Struct exchanged between kernel & ndctl in for PAPR_PDSM_HEALTH
+ * Various flags indicate the health status of the dimm.
+ *
+ * extension_flags     : Any extension fields present in the struct.
+ * dimm_unarmed                : Dimm not armed. So contents wont persist.
+ * dimm_bad_shutdown   : Previous shutdown did not persist contents.
+ * dimm_bad_restore    : Contents from previous shutdown werent restored.
+ * dimm_scrubbed       : Contents of the dimm have been scrubbed.
+ * dimm_locked         : Contents of the dimm cant be modified until CEC reboot
+ * dimm_encrypted      : Contents of dimm are encrypted.
+ * dimm_health         : Dimm health indicator. One of PAPR_PDSM_DIMM_XXXX
+ */
+struct nd_papr_pdsm_health {
+       union {
+               struct {
+                       __u32 extension_flags;
+                       __u8 dimm_unarmed;
+                       __u8 dimm_bad_shutdown;
+                       __u8 dimm_bad_restore;
+                       __u8 dimm_scrubbed;
+                       __u8 dimm_locked;
+                       __u8 dimm_encrypted;
+                       __u16 dimm_health;
+               };
+               __u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE];
+       };
+};
+
 /*
  * Methods to be embedded in ND_CMD_CALL request. These are sent to the kernel
  * via 'nd_cmd_pkg.nd_command' member of the ioctl struct
  */
 enum papr_pdsm {
        PAPR_PDSM_MIN = 0x0,
+       PAPR_PDSM_HEALTH,
        PAPR_PDSM_MAX,
 };
 
 /* Maximal union that can hold all possible payload types */
 union nd_pdsm_payload {
+       struct nd_papr_pdsm_health health;
        __u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE];
 } __packed;
 
index d3bbf99..9c56907 100644 (file)
@@ -416,6 +416,52 @@ static int is_cmd_valid(struct nvdimm *nvdimm, unsigned int cmd, void *buf,
        return 0;
 }
 
+/* Fetch the DIMM health info and populate it in provided package. */
+static int papr_pdsm_health(struct papr_scm_priv *p,
+                           union nd_pdsm_payload *payload)
+{
+       int rc;
+
+       /* Ensure dimm health mutex is taken preventing concurrent access */
+       rc = mutex_lock_interruptible(&p->health_mutex);
+       if (rc)
+               goto out;
+
+       /* Always fetch upto date dimm health data ignoring cached values */
+       rc = __drc_pmem_query_health(p);
+       if (rc) {
+               mutex_unlock(&p->health_mutex);
+               goto out;
+       }
+
+       /* update health struct with various flags derived from health bitmap */
+       payload->health = (struct nd_papr_pdsm_health) {
+               .extension_flags = 0,
+               .dimm_unarmed = !!(p->health_bitmap & PAPR_PMEM_UNARMED_MASK),
+               .dimm_bad_shutdown = !!(p->health_bitmap & PAPR_PMEM_BAD_SHUTDOWN_MASK),
+               .dimm_bad_restore = !!(p->health_bitmap & PAPR_PMEM_BAD_RESTORE_MASK),
+               .dimm_scrubbed = !!(p->health_bitmap & PAPR_PMEM_SCRUBBED_AND_LOCKED),
+               .dimm_locked = !!(p->health_bitmap & PAPR_PMEM_SCRUBBED_AND_LOCKED),
+               .dimm_encrypted = !!(p->health_bitmap & PAPR_PMEM_ENCRYPTED),
+               .dimm_health = PAPR_PDSM_DIMM_HEALTHY,
+       };
+
+       /* Update field dimm_health based on health_bitmap flags */
+       if (p->health_bitmap & PAPR_PMEM_HEALTH_FATAL)
+               payload->health.dimm_health = PAPR_PDSM_DIMM_FATAL;
+       else if (p->health_bitmap & PAPR_PMEM_HEALTH_CRITICAL)
+               payload->health.dimm_health = PAPR_PDSM_DIMM_CRITICAL;
+       else if (p->health_bitmap & PAPR_PMEM_HEALTH_UNHEALTHY)
+               payload->health.dimm_health = PAPR_PDSM_DIMM_UNHEALTHY;
+
+       /* struct populated hence can release the mutex now */
+       mutex_unlock(&p->health_mutex);
+       rc = sizeof(struct nd_papr_pdsm_health);
+
+out:
+       return rc;
+}
+
 /*
  * 'struct pdsm_cmd_desc'
  * Identifies supported PDSMs' expected length of in/out payloads
@@ -444,6 +490,11 @@ static const struct pdsm_cmd_desc __pdsm_cmd_descriptors[] = {
        },
        /* New PDSM command descriptors to be added below */
 
+       [PAPR_PDSM_HEALTH] = {
+               .size_in = 0,
+               .size_out = sizeof(struct nd_papr_pdsm_health),
+               .service = papr_pdsm_health,
+       },
        /* Empty */
        [PAPR_PDSM_MAX] = {
                .size_in = 0,