diff options
author | Dan Williams <dan.j.williams@intel.com> | 2016-03-03 16:08:54 -0800 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2016-03-05 18:06:14 -0800 |
commit | d4f323672aa63713b7ca26da418f66cc30d3a41a (patch) | |
tree | c073dd799eab97ed7b6e7e04a94c16e793361285 /drivers | |
parent | 07accfa9d1a8bac8262f6d24a94a54d2d1f35149 (diff) | |
download | blackbird-op-linux-d4f323672aa63713b7ca26da418f66cc30d3a41a.tar.gz blackbird-op-linux-d4f323672aa63713b7ca26da418f66cc30d3a41a.zip |
nfit, libnvdimm: clear poison command support
Add the boiler-plate for a 'clear error' command based on section
9.20.7.6 "Function Index 4 - Clear Uncorrectable Error" from the ACPI
6.1 specification, and add a reference implementation in nfit_test.
Reviewed-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/nfit.c | 12 | ||||
-rw-r--r-- | drivers/nvdimm/bus.c | 19 |
2 files changed, 30 insertions, 1 deletions
diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 0def4ebf5d43..c067d7414007 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -87,6 +87,7 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc) static int xlat_status(void *buf, unsigned int cmd) { + struct nd_cmd_clear_error *clear_err; struct nd_cmd_ars_status *ars_status; struct nd_cmd_ars_start *ars_start; struct nd_cmd_ars_cap *ars_cap; @@ -149,6 +150,15 @@ static int xlat_status(void *buf, unsigned int cmd) if (ars_status->status >> 16) return -EIO; break; + case ND_CMD_CLEAR_ERROR: + clear_err = buf; + if (clear_err->status & 0xffff) + return -EIO; + if (!clear_err->cleared) + return -EIO; + if (clear_err->length > clear_err->cleared) + return clear_err->cleared; + break; default: break; } @@ -1002,7 +1012,7 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc) if (!adev) return; - for (i = ND_CMD_ARS_CAP; i <= ND_CMD_ARS_STATUS; i++) + for (i = ND_CMD_ARS_CAP; i <= ND_CMD_CLEAR_ERROR; i++) if (acpi_check_dsm(adev->handle, uuid, 1, 1ULL << i)) set_bit(i, &nd_desc->dsm_mask); } diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index 2e9ac22595ec..cb6fd64b13e3 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c @@ -421,6 +421,12 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = { .out_num = 3, .out_sizes = { 4, 4, UINT_MAX, }, }, + [ND_CMD_CLEAR_ERROR] = { + .in_num = 2, + .in_sizes = { 8, 8, }, + .out_num = 3, + .out_sizes = { 4, 4, 8, }, + }, }; const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd) @@ -489,6 +495,13 @@ void wait_nvdimm_bus_probe_idle(struct device *dev) } while (true); } +static int pmem_active(struct device *dev, void *data) +{ + if (is_nd_pmem(dev) && dev->driver) + return -EBUSY; + return 0; +} + /* set_config requires an idle interleave set */ static int nd_cmd_clear_to_send(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, unsigned int cmd) @@ -503,6 +516,11 @@ static int nd_cmd_clear_to_send(struct nvdimm_bus *nvdimm_bus, return rc; } + /* require clear error to go through the pmem driver */ + if (!nvdimm && cmd == ND_CMD_CLEAR_ERROR) + return device_for_each_child(&nvdimm_bus->dev, NULL, + pmem_active); + if (!nvdimm || cmd != ND_CMD_SET_CONFIG_DATA) return 0; @@ -551,6 +569,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, case ND_CMD_VENDOR: case ND_CMD_SET_CONFIG_DATA: case ND_CMD_ARS_START: + case ND_CMD_CLEAR_ERROR: dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n", nvdimm ? nvdimm_cmd_name(cmd) : nvdimm_bus_cmd_name(cmd)); |