Index: sys/dev/nvdimm/nvdimm.c =================================================================== --- sys/dev/nvdimm/nvdimm.c +++ sys/dev/nvdimm/nvdimm.c @@ -49,6 +49,7 @@ #include #include +#include #include #define _COMPONENT ACPI_OEM @@ -359,16 +360,36 @@ */ read_labels(nv); } + status = AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, + nvdimm_acpi_notify, dev); + if (ACPI_FAILURE(status)) { + device_printf(dev, "Couldn't install health notify handler: " + "0x%08x\n", status); + } else + nv->have_handler = true; return (0); } static int nvdimm_detach(device_t dev) { + ACPI_STATUS status; struct nvdimm_dev *nv; struct nvdimm_label_entry *label, *next; nv = device_get_softc(dev); + + if (nv->have_handler) { + status = AcpiRemoveNotifyHandler( + nvdimm_root_get_acpi_handle(dev), ACPI_DEVICE_NOTIFY, + nvdimm_acpi_notify); + if (ACPI_FAILURE(status)) { + device_printf(dev, "Couldn't remove health notify " + "handler: 0x%08x\n", status); + } + nv->have_handler = false; + } + free(nv->nv_flush_addr, M_NVDIMM); free(nv->label_index, M_NVDIMM); SLIST_FOREACH_SAFE(label, &nv->labels, link, next) { Index: sys/dev/nvdimm/nvdimm_dsm.h =================================================================== --- /dev/null +++ sys/dev/nvdimm/nvdimm_dsm.h @@ -0,0 +1,177 @@ +/** + * Copyright 2020 Conrad Meyer . All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * Be Gay + * Do Crimes + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * $FreeBSD$ + */ +#pragma once + +/* + * Define the child device _DSM function index per the Microsoft model. Ref. + * + */ +#define MS_DSM_QUERY_IMPLEMENTED_FUNCTIONS 0x00 +#define MS_DSM_GET_NVDIMM_N_IDENTIFICATION 0x01 +#define MS_DSM_GET_SAVE_OPERATIONS_REQUIREMENTS 0x02 +#define MS_DSM_GET_ENERGY_SOURCE_IDENTIFICATION 0x03 +#define MS_DSM_GET_LAST_BACKUP_INFORMATION 0x04 +#define MS_DSM_GET_NVM_THRESHOLD 0x05 +#define MS_DSM_SET_NVM_LIFETIME_PERCENTAGE_WARNING_THRESHOLD 0x06 +#define MS_DSM_GET_ENERGY_SOURCE_THRESHOLD 0x07 +#define MS_DSM_SET_ENERGY_SOURCE_LIFETIME_WARNING 0x08 +#define MS_DSM_SET_ENERGY_SOURCE_TEMPERATURE_WARNING_THRESHOLD 0x09 +#define MS_DSM_GET_CRITICAL_HEALTH_INFO 0x0a +#define MS_DSM_GET_NVDIMM_N_HEALTH_INFO 0x0b +#define MS_DSM_GET_ENERGY_SOURCE_HEALTH_INFO 0x0c +#define MS_DSM_GET_OPERATIONAL_STATISTICS 0x0d +#define MS_DSM_GET_VENDOR_LOG_PAGE_SIZE 0x0e +#define MS_DSM_GET_VENDOR_LOG_PAGE 0x0f +#define MS_DSM_QUERY_ERROR_INJECTION_STATUS 0x10 +#define MS_DSM_INJECT_ERROR 0x11 +#define MS_DSM_GET_INJECTED_ERRORS 0x12 +#define MS_DSM_ERASE_NVM_IMAGE 0x13 +#define MS_DSM_ARM_NVDIMM_N 0x14 +#define MS_DSM_RESET_TO_FACTORY_DEFAULT 0x15 +#define MS_DSM_START_FIRMWARE_UPDATE 0x16 +#define MS_DSM_SEND_FIRMWARE_UPDATE_DATA 0x17 +#define MS_DSM_FINISH_FIRMWARE_UPDATE 0x18 +#define MS_DSM_SELECT_FIRMWARE_IMAGE_SLOT 0x19 +#define MS_DSM_GET_FIRMWARE_INFO 0x1a +#define MS_DSM_I2C_READ 0x1b +#define MS_DSM_I2C_WRITE 0x1c +#define MS_DSM_READ_TYPED_DATA 0x1d +#define MS_DSM_WRITE_TYPED_DATA 0x1e +#define MS_DSM_SET_MEMORY_ERROR_COUNTERS 0x1f + +/* + * Ref. BABEI (JESD245B.01, Sept. 2017) + * 8.1.8.1 MODULE_HEALTH -- Offset 0xA0 + * Define MODULE_HEALTH flags. + */ +#define NVDIMM_MODULE_HEALTH_NO_EVENT (0x00 << 0) +#define NVDIMM_MODULE_HEALTH_PERSISTENCY_LOST_ERROR (0x01 << 0) +#define NVDIMM_MODULE_HEALTH_WARNING_THRESHOLD_EXCEEDED (0x01 << 1) +#define NVDIMM_MODULE_HEALTH_PERSISTENCY_RESTORED (0x01 << 2) +#define NVDIMM_MODULE_HEALTH_BELOW_WARNING_THRESHOLD (0x01 << 3) +#define NVDIMM_MODULE_HEALTH_PERMANENT_HARDWARE_FAILURE (0x01 << 4) +#define NVDIMM_MODULE_HEALTH_EVENT_N_LOW (0x01 << 5) +#define NVDIMM_MODULE_HEALTH_EVENT_MASK 0x3F + +/* + * Ref. BABEI (JESD245B.01, Sept. 2017) + * 8.1.8.2 MODULE_HEALTH_STATUS0 -- Offset 0xA1 + * Define MODULE_HEALTH_STATUS0 flags. + */ +#define NVDIMM_MODULE_HEALTH_STATUS0_VOLTAGE_REGULATOR_FAILED (0x01 << 0) +#define NVDIMM_MODULE_HEALTH_STATUS0_VDD_LOST (0x01 << 1) +#define NVDIMM_MODULE_HEALTH_STATUS0_VPP_LOST (0x01 << 2) +#define NVDIMM_MODULE_HEALTH_STATUS0_VTT_LOST (0x01 << 3) +#define NVDIMM_MODULE_HEALTH_STATUS0_DRAM_NOT_SELF_REFRESH (0x01 << 4) +#define NVDIMM_MODULE_HEALTH_STATUS0_CONTROLLER_HARDWARE_ERROR (0x01 << 5) +#define NVDIMM_MODULE_HEALTH_STATUS0_NVM_CONTROLLER_ERROR (0x01 << 6) +#define NVDIMM_MODULE_HEALTH_STATUS0_NVM_LIFETIME_ERROR (0x01 << 7) +#define NVDIMM_MODULE_HEALTH_STATUS0_OFFSET 0xA1 + +/* + * Ref. BABEI (JESD245B.01, Sept. 2017) + * 8.1.8.3 MODULE_HEALTH_STATUS1 -- Offset 0xA2 + * Define MODULE_HEALTH_STATUS1 flags. + */ +#define NVDIMM_MODULE_HEALTH_STATUS1_NOT_ENOUGH_ENERGY_FOR_CSAVE (0x01 << 0) +#define NVDIMM_MODULE_HEALTH_STATUS1_INVALID_FIRMWARE_ERROR (0X01 << 1) +#define NVDIMM_MODULE_HEALTH_STATUS1_CONFIG_DATA_ERROR (0x01 << 2) +#define NVDIMM_MODULE_HEALTH_STATUS1_NO_ES_PRESENT (0x01 << 3) +#define NVDIMM_MODULE_HEALTH_STATUS1_POLICY_NOT_SET (0x01 << 4) +#define NVDIMM_MODULE_HEALTH_STATUS1_ES_HARDWARE_FAILURE (0x01 << 5) +#define NVDIMM_MODULE_HEALTH_STATUS1_HEALTH_ASSESS_ERROR (0X01 << 6) +#define NVDIMM_MODULE_HEALTH_STATUS1_OFFSET 0xA2 + +#define NVDIMM_MODULE_HEALTH_STATUS0_SHIFT (NBBY * 0) +#define NVDIMM_MODULE_HEALTH_STATUS1_SHIFT (NBBY * 1) + +/* + * Ref. BABEI (JESD245B.01, Sept. 2017) + * 8.1.8.4 ERROR_THRESHOLD_STATUS -- Offset 0xA5 + * Define ERROR_THRESHOLD_STATUS flags. + */ +#define NVDIMM_ERROR_THRESHOLD_STATUS_NVM_LIFETIME_ERROR (0x01 << 0) +#define NVDIMM_ERROR_THRESHOLD_STATUS_ES_LIFETIME_ERROR (0x01 << 1) +#define NVDIMM_ERROR_THRESHOLD_STATUS_ES_TEMP_ERROR (0x01 << 2) +#define NVDIMM_ERROR_THRESHOLD_OFFSET 0xA5 + +/* + * Ref. BABEI (JESD245B.01, Sept. 2017) + * 8.1.8.5 WARNING_THRESHOLD_STATUS -- Offset 0xA7 + * Define WARNING_THRESHOLD_STATUS flags. + */ +#define NVDIMM_WARNING_THRESHOLD_STATUS_NVM_LIFETIME_WARNING (0x01 << 0) +#define NVDIMM_WARNING_THRESHOLD_STATUS_ES_LIFETIME_WARNING (0x01 << 1) +#define NVDIMM_WARNING_THRESHOLD_STATUS_ES_TEMP_WARNING (0x01 << 2) +#define NVDIMM_WARNING_THRESHOLD_OFFSET 0xA7 + +struct nvdimm_critical_health_info { + /* + * These fields are defined according to Microsoft DSM Function Index + * 10 (Get Critical Health Info). + */ + uint32_t status; + + /* Byte 0 – MODULE_HEALTH (0, 0xA0) */ + uint8_t critical_health_info; +} __packed; + +struct nvdimm_health_info { + /* + * These fields are defined according to Microsoft DSM Function Index + * 11 (Get NVDIMM-N Health Info). + */ + uint32_t status; + + /* Byte 0 – MODULE_HEALTH_STATUS0 (0, 0xA1) */ + /* Byte 1 – MODULE_HEALTH_STATUS1 (0, 0xA2) */ + uint16_t module_health; + + uint16_t module_current_temp; + + /* Byte 0 – ERROR_THRESHOLD_STATUS (0, 0xA5) */ + uint8_t error_threshold_status; + + /* Byte 0 – WARNING_THRESHOLD_STATUS (0, 0xA7) */ + uint8_t warning_threshold_status; + + /* Byte 0 – NVM_LIFETIME (0, 0xC0) */ + uint8_t nvm_lifetime; + + /* Byte 0 – DRAM_ECC_ERROR_COUNT (2, 0x80) */ + uint8_t uncorrectable_ecc_count; + + /* Byte 0 – DRAM_THRESHOLD_ECC_COUNT (2, 0x81) */ + uint8_t correctable_ecc_count; +} __packed; + +void nvdimm_acpi_notify(ACPI_HANDLE h, UINT32 notify, void *context); + +int nvdimm_get_critical_health_info(device_t dev, + struct nvdimm_critical_health_info *chi_out); +int nvdimm_get_health_info(device_t dev, struct nvdimm_health_info *hi_out); Index: sys/dev/nvdimm/nvdimm_dsm.c =================================================================== --- /dev/null +++ sys/dev/nvdimm/nvdimm_dsm.c @@ -0,0 +1,334 @@ +/** + * Copyright 2017, 2019, 2020 Dell Inc. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * Be Gay + * Do Crimes + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define ASSERT(cond, ...) \ + KASSERT((cond), ("ASSERT " #cond ":" __VA_ARGS__)) + +/* + * Probably not performance sensitive enough to bother with a separate lock per + * nvdimm_dev. + */ +static struct sx nvdimm_dsm_lock; +SX_SYSINIT(nvdimm_dsm, &nvdimm_dsm_lock, "NVDIMM _DSM lock"); + +#define NVDIMM_LEAF_HEALTH_EVENT 0x81 +void +nvdimm_acpi_notify(ACPI_HANDLE h, UINT32 notify, void *context) +{ + struct nvdimm_dev *sc; + device_t dev; + + dev = context; + sc = device_get_softc(dev); + + if (notify != NVDIMM_LEAF_HEALTH_EVENT) { + device_printf(dev, "Unknown event %u for NVDIMM-N Leaf\n", + notify); + return; + } + + if (bootverbose) + device_printf(dev, "NFIT Health Event Notification for NVDIMM-N" + " Leaf\n"); + + /* Raise a health event notification for userspace. */ + devctl_notify("ACPI", "nvdimm", "", "notify=health_event"); +} + +/* + * Microsoft GUID "1EE68B36-D4BD-4a1a-9A16-4F8E53D46E05" from + * "_DSM Interface for Byte Addressable Energy Backed Function Class" + * at microsoft.com for NVDIMM leaf devices. + * + * The NVDIMM-N DSMs in Dell 14G nodes belong to the Microsoft family. + */ +/* XXXCEM: struct uuid? */ +static const uint8_t ms_dsm_guid[] = { + 0x36, 0x8B, 0xE6, 0x1E, + 0xBD, 0xD4, + 0x1A, 0x4A, + 0x9A, 0x16, /* Big Endian */ + 0x4F, 0x8E, 0x53, 0xD4, 0x6E, 0x05 /* Big Endian */ +}; +#define NVDIMM_LEAF_MS_DSM_REVISION_ID 1 + +#if 0 +/* Some unused/untested GUIDS. */ +/* 4309AC30-0D11-11E4-9191-0800200C9A66 */ +static const uint8_t nvdimm_leaf_dsm_guid[] = { + 0x30, 0xAC, 0x09, 0x43, + 0x11, 0x0D, + 0xE4, 0x11, + 0x91, 0x91, /* Big Endian */ + 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66 /* Big Endian */ +}; +#define NVDIMM_LEAF_INTEL_DSM_REVISION_ID 1 + +/* + * ACPI NVDIMM Root Device GUID "2f10e7a4-9e91-11e4-89d3-123b93f75cba" + * from ACPI Version 6.2 Errata A September 2017 + */ +static const uint8_t nvdimm_root_dsm_guid[] = { + 0xA4, 0xE7, 0x10, 0x2F, + 0x91, 0x9E, + 0xE4, 0x11, + 0x89, 0xd3, /* Big Endian */ + 0x12, 0x3B, 0x93, 0xF7, 0x5C, 0xBA, /* Big Endian */ +}; +#define NVDIMM_ROOT_DSM_REVISION_ID 1 +#endif + +#define MINIMUM_BUFFER_LENGTH 4 +static ACPI_STATUS +nvdimm_child_dsm(device_t dev, const uint8_t guidp[static 16], size_t guidlen, + int revid, int funcndx, uint8_t *inpbfrp, size_t inpbfrlen, + ACPI_BUFFER *output) +{ + ACPI_OBJECT_LIST input; + ACPI_OBJECT params[4]; + ACPI_OBJECT arg3; + ACPI_OBJECT *obj; + ACPI_STATUS status; + ACPI_HANDLE handle; + uint32_t result; + + MPASS(guidlen == sizeof(struct uuid)); + + handle = nvdimm_root_get_acpi_handle(dev); + + sx_assert(&nvdimm_dsm_lock, SX_XLOCKED); + + input.Count = 4; + input.Pointer = params; + + params[0].Type = ACPI_TYPE_BUFFER; + params[0].Buffer.Length = guidlen; + params[0].Buffer.Pointer = __DECONST(void *, guidp); + + params[1].Type = ACPI_TYPE_INTEGER; + params[1].Integer.Value = revid; + + params[2].Type = ACPI_TYPE_INTEGER; + params[2].Integer.Value = funcndx; /* Function Index */ + + params[3].Type = ACPI_TYPE_PACKAGE; + if (inpbfrlen != 0 && inpbfrp != NULL) { + arg3.Type = ACPI_TYPE_BUFFER; + arg3.Buffer.Length = inpbfrlen; + arg3.Buffer.Pointer = inpbfrp; + params[3].Package.Count = 1; /* 0 length ACPI Package */ + params[3].Package.Elements = &arg3; + } else { + params[3].Package.Count = 0; /* 0 length ACPI Package */ + params[3].Package.Elements = NULL; + } + + status = AcpiEvaluateObject(handle, "_DSM", &input, output); + if (ACPI_FAILURE(status)) { + device_printf(dev, "%s: Failed to evaluate _DSM: funcndx %d, " + "slot %s, status 0x%08X\n", __func__, funcndx, + acpi_name(handle), status); + goto cleanup; + } + + obj = (ACPI_OBJECT *)output->Pointer; + if (obj->Type != ACPI_TYPE_BUFFER) { + device_printf(dev, "%s: Type mismatch: funcndx %d, slot %s, " + "status 0x%08X, expected %d, received %d\n", __func__, + funcndx, acpi_name(handle), status, ACPI_TYPE_BUFFER, + obj->Type); + status = AE_TYPE; + goto cleanup; + } + + if (bootverbose) { + struct sbuf *sb; + + sb = sbuf_new_auto(); + sbuf_printf(sb, "%s: funcndx %d, slot %s, status 0x%08X, " + "received a buffer of length %u: {\n", __func__, funcndx, + acpi_name(handle), status, obj->Buffer.Length); +#define ROW_WIDTH 8 +#define COL_WIDTH 2 + for (uint32_t i = 0; i < obj->Buffer.Length; i++) { + sbuf_printf(sb, "%02x", obj->Buffer.Pointer[i]); + + if (((i + 1) % ROW_WIDTH) == 0) { + sbuf_putc(sb, '\n'); + continue; + } + + if (((i + 1) % COL_WIDTH) == 0) + sbuf_putc(sb, ' '); + } + if ((obj->Buffer.Length % ROW_WIDTH) == 0) + sbuf_putc(sb, '}'); + else + sbuf_cat(sb, "\n}"); +#undef COL_WIDTH +#undef ROW_WIDTH + sbuf_finish(sb); + device_printf(dev, "%s", sbuf_data(sb)); + sbuf_delete(sb); + } + + if (obj->Buffer.Length < MINIMUM_BUFFER_LENGTH) { + device_printf(dev, "%s: Buffer length < MINIMUM_BUFFER_LENGTH " + "(%u): funcndx %d, slot %s, status 0x%08X, length %u\n", + __func__, MINIMUM_BUFFER_LENGTH, funcndx, acpi_name(handle), + status, obj->Buffer.Length); + status = AE_BAD_DATA; + goto cleanup; + } + + /* Print the status stored in the first four bytes. */ + MPASS(obj && obj->Type == ACPI_TYPE_BUFFER && + obj->Buffer.Length >= sizeof(result)); + result = le32dec(obj->Buffer.Pointer); + + if (bootverbose) + device_printf(dev, "%s: funcndx %d, slot %s, status 0x%08X, " + "buffer length %u, returned 0x%08X", __func__, funcndx, + acpi_name(handle), status, obj->Buffer.Length, result); + + return (status); + +cleanup: + AcpiOsFree(output->Pointer); + output->Pointer = NULL; + output->Length = ACPI_ALLOCATE_BUFFER; + return (status); +} + +/* + * Retrieve the module health registers by calling the Microsoft-based child + * device _DSM functions (indices 10 and 11) for the NVDIMM corresponding to + * the input index into the driver's internal NVDIMM vector. + */ +int +nvdimm_get_critical_health_info(device_t dev, + struct nvdimm_critical_health_info *chi) +{ + struct nvdimm_dev *nv; + int rc = 0; + ACPI_BUFFER critical_out = { ACPI_ALLOCATE_BUFFER, NULL }; + ACPI_OBJECT *obj; + ACPI_STATUS status; + + nv = device_get_softc(dev); + sx_xlock(&nvdimm_dsm_lock); + + /* MS-based DSM Function Index 10 - Get Critical Health Info */ + status = nvdimm_child_dsm(dev, ms_dsm_guid, sizeof(ms_dsm_guid), + NVDIMM_LEAF_MS_DSM_REVISION_ID, MS_DSM_GET_CRITICAL_HEALTH_INFO, + NULL, 0, &critical_out); + + if (ACPI_FAILURE(status)) { + device_printf(dev, "%s: Failed to execute " + "MS_DSM_GET_CRITICAL_HEALTH_INFO (%d) for NVDIMM element " + "%u, status 0x%08x\n", __func__, + MS_DSM_GET_CRITICAL_HEALTH_INFO, nv->nv_handle, status); + rc = EINVAL; + goto out; + } + + obj = critical_out.Pointer; + MPASS(obj && obj->Type == ACPI_TYPE_BUFFER && + obj->Buffer.Length >= sizeof(*chi)); + + memcpy(chi, obj->Buffer.Pointer, sizeof(*chi)); + chi->status = le32toh(chi->status); + /* chi->critical_health_info is a single byte. */ + +out: + AcpiOsFree(critical_out.Pointer); + + sx_unlock(&nvdimm_dsm_lock); + return (rc); +} + +int +nvdimm_get_health_info(device_t dev, struct nvdimm_health_info *hi) +{ + struct nvdimm_dev *nv; + int rc = 0; + ACPI_BUFFER health_out = { ACPI_ALLOCATE_BUFFER, NULL }; + ACPI_OBJECT *obj; + ACPI_STATUS status; + + nv = device_get_softc(dev); + sx_xlock(&nvdimm_dsm_lock); + + /* MS-based DSM Function Index 11 - Get NVDIMM-N Health Info */ + status = nvdimm_child_dsm(dev, ms_dsm_guid, sizeof(ms_dsm_guid), + NVDIMM_LEAF_MS_DSM_REVISION_ID, MS_DSM_GET_NVDIMM_N_HEALTH_INFO, + NULL, 0, &health_out); + + if (ACPI_FAILURE(status)) { + device_printf(dev, "%s: Failed to execute " + "MS_DSM_GET_NVDIMM_N_HEALTH_INFO (%d) for NVDIMM element " + "%u, status 0x%08X\n", __func__, + MS_DSM_GET_NVDIMM_N_HEALTH_INFO, nv->nv_handle, status); + rc = EINVAL; + goto out; + } + + obj = health_out.Pointer; + MPASS(obj && obj->Type == ACPI_TYPE_BUFFER && + obj->Buffer.Length >= sizeof(*hi)); + + memcpy(hi, obj->Buffer.Pointer, sizeof(*hi)); + + hi->status = le32toh(hi->status); + hi->module_health = le16toh(hi->module_health); + hi->module_current_temp = le16toh(hi->module_current_temp); + /* Remaining fields are all single byte. */ + +out: + AcpiOsFree(health_out.Pointer); + + sx_unlock(&nvdimm_dsm_lock); + return (rc); +} Index: sys/dev/nvdimm/nvdimm_var.h =================================================================== --- sys/dev/nvdimm/nvdimm_var.h +++ sys/dev/nvdimm/nvdimm_var.h @@ -98,6 +98,7 @@ uint32_t max_label_xfer; struct nvdimm_label_index *label_index; SLIST_HEAD(, nvdimm_label_entry) labels; + bool have_handler; }; enum SPA_mapping_type { Index: sys/modules/nvdimm/Makefile =================================================================== --- sys/modules/nvdimm/Makefile +++ sys/modules/nvdimm/Makefile @@ -5,6 +5,7 @@ KMOD= nvdimm SRCS= nvdimm.c \ nvdimm_acpi.c \ + nvdimm_dsm.c \ nvdimm_e820.c \ nvdimm_nfit.c \ nvdimm_ns.c \