The branch stable/12 has been updated by rpokala:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=49318a0aac641813d971806667b734feefefbb03

commit 49318a0aac641813d971806667b734feefefbb03
Author:     Ravi Pokala <[email protected]>
AuthorDate: 2021-02-16 08:03:32 +0000
Commit:     Ravi Pokala <[email protected]>
CommitDate: 2021-02-21 01:47:34 +0000

    nvdimm(4): Export NVDIMM health flags via sysctl
    
    The ACPI NFIT specification defines a set of "NVDIMM State Flags". These
    flags are already reported by `acpidump -t', but this change makes them
    available on a per-device basis, in a format that is more easily parsed.
    
    To simplify this, introduce acpi_nfit_get_memory_maps_by_dimm(), which
    locates the (ACPI_NFIT_MEMORY_MAP)s associated with a given
    (nfit_handle_t).
    
    Reviewed by:    mav, cem
    Tested by:      mav, rpokala (version for stable/12)
    MFC after:      3 days
    Sponsored by:   Panasas
    Differential Revision:  https://reviews.freebsd.org/D28700
    
    (cherry picked from commit bdde49b7c7232c6936525f84ffb90856a7cd8e74)
---
 sys/dev/nvdimm/nvdimm.c      | 65 +++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/nvdimm/nvdimm_nfit.c | 10 +++++++
 sys/dev/nvdimm/nvdimm_var.h  |  3 ++
 3 files changed, 77 insertions(+), 1 deletion(-)

diff --git a/sys/dev/nvdimm/nvdimm.c b/sys/dev/nvdimm/nvdimm.c
index b2c716044d5d..afa926955498 100644
--- a/sys/dev/nvdimm/nvdimm.c
+++ b/sys/dev/nvdimm/nvdimm.c
@@ -43,6 +43,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/lock.h>
 #include <sys/malloc.h>
 #include <sys/module.h>
+#include <sys/sbuf.h>
+#include <sys/sysctl.h>
 #include <sys/uuid.h>
 #include <contrib/dev/acpica/include/acpi.h>
 #include <contrib/dev/acpica/include/accommon.h>
@@ -319,12 +321,21 @@ static int
 nvdimm_attach(device_t dev)
 {
        struct nvdimm_dev *nv;
+       struct sysctl_ctx_list *ctx;
+       struct sysctl_oid *oid;
+       struct sysctl_oid_list *children;
+       struct sbuf *sb;
        ACPI_TABLE_NFIT *nfitbl;
        ACPI_HANDLE handle;
        ACPI_STATUS status;
-       int error;
+       ACPI_NFIT_MEMORY_MAP **maps;
+       int error, i, num_maps;
+       uint16_t flags;
 
        nv = device_get_softc(dev);
+       ctx = device_get_sysctl_ctx(dev);
+       oid = device_get_sysctl_tree(dev);
+       children = SYSCTL_CHILDREN(oid);
        handle = nvdimm_root_get_acpi_handle(dev);
        if (handle == NULL)
                return (EINVAL);
@@ -339,6 +350,57 @@ nvdimm_attach(device_t dev)
        }
        acpi_nfit_get_flush_addrs(nfitbl, nv->nv_handle, &nv->nv_flush_addr,
            &nv->nv_flush_addr_cnt);
+
+       /*
+        * Each NVDIMM should have at least one memory map associated with it.
+        * If any of the maps have one of the error flags set, reflect that in
+        * the overall status.
+        */
+       acpi_nfit_get_memory_maps_by_dimm(nfitbl, nv->nv_handle, &maps,
+           &num_maps);
+       if (num_maps == 0) {
+               free(nv->nv_flush_addr, M_NVDIMM);
+               free(maps, M_NVDIMM);
+               device_printf(dev, "cannot find memory map\n");
+               return (ENXIO);
+       }
+       flags = 0;
+       for (i = 0; i < num_maps; i++) {
+               flags |= maps[i]->Flags;
+       }
+       free(maps, M_NVDIMM);
+
+       /* sbuf_new_auto(9) is M_WAITOK; no need to check for NULL. */
+       sb = sbuf_new_auto();
+       (void) sbuf_printf(sb, "0x%b", flags,
+           "\20"
+           "\001SAVE_FAILED"
+           "\002RESTORE_FAILED"
+           "\003FLUSH_FAILED"
+           "\004NOT_ARMED"
+           "\005HEALTH_OBSERVED"
+           "\006HEALTH_ENABLED"
+           "\007MAP_FAILED");
+       error = sbuf_finish(sb);
+       if (error != 0) {
+               sbuf_delete(sb);
+               free(nv->nv_flush_addr, M_NVDIMM);
+               device_printf(dev, "cannot convert flags to string\n");
+               return (error);
+       }
+       /* strdup(9) is M_WAITOK; no need to check for NULL. */
+       nv->nv_flags_str = strdup(sbuf_data(sb), M_NVDIMM);
+       sbuf_delete(sb);
+       SYSCTL_ADD_STRING(ctx, children, OID_AUTO, "flags",
+           CTLFLAG_RD | CTLFLAG_MPSAFE, nv->nv_flags_str, 0,
+           "NVDIMM State Flags");
+       /*
+        * Anything other than HEALTH_ENABLED indicates a fault condition of
+        * some kind, so log if that's seen.
+        */
+       if ((flags & ~ACPI_NFIT_MEM_HEALTH_ENABLED) != 0)
+               device_printf(dev, "flags: %s\n", nv->nv_flags_str);
+
        AcpiPutTable(&nfitbl->Header);
        error = read_label_area_size(nv);
        if (error == 0) {
@@ -358,6 +420,7 @@ nvdimm_detach(device_t dev)
        struct nvdimm_label_entry *label, *next;
 
        nv = device_get_softc(dev);
+       free(nv->nv_flags_str, M_NVDIMM);
        free(nv->nv_flush_addr, M_NVDIMM);
        free(nv->label_index, M_NVDIMM);
        SLIST_FOREACH_SAFE(label, &nv->labels, link, next) {
diff --git a/sys/dev/nvdimm/nvdimm_nfit.c b/sys/dev/nvdimm/nvdimm_nfit.c
index ae00b88f8018..7396393a3a2c 100644
--- a/sys/dev/nvdimm/nvdimm_nfit.c
+++ b/sys/dev/nvdimm/nvdimm_nfit.c
@@ -201,3 +201,13 @@ acpi_nfit_get_flush_addrs(ACPI_TABLE_NFIT *nfitbl, 
nfit_handle_t dimm,
        for (i = 0; i < subtable->HintCount; i++)
                (*listp)[i] = (uint64_t *)(intptr_t)subtable->HintAddress[i];
 }
+
+void
+acpi_nfit_get_memory_maps_by_dimm(ACPI_TABLE_NFIT *nfitbl, nfit_handle_t dimm,
+    ACPI_NFIT_MEMORY_MAP ***listp, int *countp)
+{
+
+       malloc_find_matches(nfitbl, ACPI_NFIT_TYPE_MEMORY_MAP,
+           offsetof(ACPI_NFIT_MEMORY_MAP, DeviceHandle), UINT32_MAX, dimm,
+           (void ***)listp, countp);
+}
diff --git a/sys/dev/nvdimm/nvdimm_var.h b/sys/dev/nvdimm/nvdimm_var.h
index 7d1621512a42..e30d6b407293 100644
--- a/sys/dev/nvdimm/nvdimm_var.h
+++ b/sys/dev/nvdimm/nvdimm_var.h
@@ -97,6 +97,7 @@ struct nvdimm_dev {
        device_t        nv_dev;
        nfit_handle_t   nv_handle;
        uint64_t        **nv_flush_addr;
+       char            *nv_flags_str;
        int             nv_flush_addr_cnt;
        uint32_t        label_area_size;
        uint32_t        max_label_xfer;
@@ -167,6 +168,8 @@ void acpi_nfit_get_control_region(ACPI_TABLE_NFIT *nfitbl,
     uint16_t control_region_index, ACPI_NFIT_CONTROL_REGION **out);
 void acpi_nfit_get_flush_addrs(ACPI_TABLE_NFIT *nfitbl, nfit_handle_t dimm,
     uint64_t ***listp, int *countp);
+void acpi_nfit_get_memory_maps_by_dimm(ACPI_TABLE_NFIT *nfitbl,
+    nfit_handle_t dimm, ACPI_NFIT_MEMORY_MAP ***listp, int *countp);
 enum SPA_mapping_type nvdimm_spa_type_from_uuid(struct uuid *);
 struct nvdimm_dev *nvdimm_find_by_handle(nfit_handle_t nv_handle);
 int nvdimm_spa_init(struct SPA_mapping *spa, ACPI_NFIT_SYSTEM_ADDRESS 
*nfitaddr,
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to