Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/papr_scm: Implement support for PAPR_PDSM_HEALTH

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>

authored by

Vaibhav Jain and committed by
Dan Williams
d35f18b5 f517f792

+88
+37
arch/powerpc/include/uapi/asm/papr_pdsm.h
··· 66 66 #define ND_PDSM_HDR_SIZE \ 67 67 (sizeof(struct nd_pkg_pdsm) - ND_PDSM_PAYLOAD_MAX_SIZE) 68 68 69 + /* Various nvdimm health indicators */ 70 + #define PAPR_PDSM_DIMM_HEALTHY 0 71 + #define PAPR_PDSM_DIMM_UNHEALTHY 1 72 + #define PAPR_PDSM_DIMM_CRITICAL 2 73 + #define PAPR_PDSM_DIMM_FATAL 3 74 + 75 + /* 76 + * Struct exchanged between kernel & ndctl in for PAPR_PDSM_HEALTH 77 + * Various flags indicate the health status of the dimm. 78 + * 79 + * extension_flags : Any extension fields present in the struct. 80 + * dimm_unarmed : Dimm not armed. So contents wont persist. 81 + * dimm_bad_shutdown : Previous shutdown did not persist contents. 82 + * dimm_bad_restore : Contents from previous shutdown werent restored. 83 + * dimm_scrubbed : Contents of the dimm have been scrubbed. 84 + * dimm_locked : Contents of the dimm cant be modified until CEC reboot 85 + * dimm_encrypted : Contents of dimm are encrypted. 86 + * dimm_health : Dimm health indicator. One of PAPR_PDSM_DIMM_XXXX 87 + */ 88 + struct nd_papr_pdsm_health { 89 + union { 90 + struct { 91 + __u32 extension_flags; 92 + __u8 dimm_unarmed; 93 + __u8 dimm_bad_shutdown; 94 + __u8 dimm_bad_restore; 95 + __u8 dimm_scrubbed; 96 + __u8 dimm_locked; 97 + __u8 dimm_encrypted; 98 + __u16 dimm_health; 99 + }; 100 + __u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE]; 101 + }; 102 + }; 103 + 69 104 /* 70 105 * Methods to be embedded in ND_CMD_CALL request. These are sent to the kernel 71 106 * via 'nd_cmd_pkg.nd_command' member of the ioctl struct 72 107 */ 73 108 enum papr_pdsm { 74 109 PAPR_PDSM_MIN = 0x0, 110 + PAPR_PDSM_HEALTH, 75 111 PAPR_PDSM_MAX, 76 112 }; 77 113 78 114 /* Maximal union that can hold all possible payload types */ 79 115 union nd_pdsm_payload { 116 + struct nd_papr_pdsm_health health; 80 117 __u8 buf[ND_PDSM_PAYLOAD_MAX_SIZE]; 81 118 } __packed; 82 119
+51
arch/powerpc/platforms/pseries/papr_scm.c
··· 416 416 return 0; 417 417 } 418 418 419 + /* Fetch the DIMM health info and populate it in provided package. */ 420 + static int papr_pdsm_health(struct papr_scm_priv *p, 421 + union nd_pdsm_payload *payload) 422 + { 423 + int rc; 424 + 425 + /* Ensure dimm health mutex is taken preventing concurrent access */ 426 + rc = mutex_lock_interruptible(&p->health_mutex); 427 + if (rc) 428 + goto out; 429 + 430 + /* Always fetch upto date dimm health data ignoring cached values */ 431 + rc = __drc_pmem_query_health(p); 432 + if (rc) { 433 + mutex_unlock(&p->health_mutex); 434 + goto out; 435 + } 436 + 437 + /* update health struct with various flags derived from health bitmap */ 438 + payload->health = (struct nd_papr_pdsm_health) { 439 + .extension_flags = 0, 440 + .dimm_unarmed = !!(p->health_bitmap & PAPR_PMEM_UNARMED_MASK), 441 + .dimm_bad_shutdown = !!(p->health_bitmap & PAPR_PMEM_BAD_SHUTDOWN_MASK), 442 + .dimm_bad_restore = !!(p->health_bitmap & PAPR_PMEM_BAD_RESTORE_MASK), 443 + .dimm_scrubbed = !!(p->health_bitmap & PAPR_PMEM_SCRUBBED_AND_LOCKED), 444 + .dimm_locked = !!(p->health_bitmap & PAPR_PMEM_SCRUBBED_AND_LOCKED), 445 + .dimm_encrypted = !!(p->health_bitmap & PAPR_PMEM_ENCRYPTED), 446 + .dimm_health = PAPR_PDSM_DIMM_HEALTHY, 447 + }; 448 + 449 + /* Update field dimm_health based on health_bitmap flags */ 450 + if (p->health_bitmap & PAPR_PMEM_HEALTH_FATAL) 451 + payload->health.dimm_health = PAPR_PDSM_DIMM_FATAL; 452 + else if (p->health_bitmap & PAPR_PMEM_HEALTH_CRITICAL) 453 + payload->health.dimm_health = PAPR_PDSM_DIMM_CRITICAL; 454 + else if (p->health_bitmap & PAPR_PMEM_HEALTH_UNHEALTHY) 455 + payload->health.dimm_health = PAPR_PDSM_DIMM_UNHEALTHY; 456 + 457 + /* struct populated hence can release the mutex now */ 458 + mutex_unlock(&p->health_mutex); 459 + rc = sizeof(struct nd_papr_pdsm_health); 460 + 461 + out: 462 + return rc; 463 + } 464 + 419 465 /* 420 466 * 'struct pdsm_cmd_desc' 421 467 * Identifies supported PDSMs' expected length of in/out payloads ··· 490 444 }, 491 445 /* New PDSM command descriptors to be added below */ 492 446 447 + [PAPR_PDSM_HEALTH] = { 448 + .size_in = 0, 449 + .size_out = sizeof(struct nd_papr_pdsm_health), 450 + .service = papr_pdsm_health, 451 + }, 493 452 /* Empty */ 494 453 [PAPR_PDSM_MAX] = { 495 454 .size_in = 0,