Commit 11294d63 authored by Dan Williams's avatar Dan Williams

nfit: fail DSMs that return non-zero status by default

For the DSMs where the kernel knows the format of the output buffer and
originates those DSMs from within the kernel, return -EIO for any
non-zero status.  If the BIOS is indicating a status that we do not know
how to handle, fail the DSM.

Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarDan Williams <dan.j.williams@intel.com>
parent ecfb6d8a
...@@ -94,54 +94,50 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc) ...@@ -94,54 +94,50 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
return to_acpi_device(acpi_desc->dev); return to_acpi_device(acpi_desc->dev);
} }
static int xlat_status(void *buf, unsigned int cmd) static int xlat_status(void *buf, unsigned int cmd, u32 status)
{ {
struct nd_cmd_clear_error *clear_err; struct nd_cmd_clear_error *clear_err;
struct nd_cmd_ars_status *ars_status; struct nd_cmd_ars_status *ars_status;
struct nd_cmd_ars_start *ars_start;
struct nd_cmd_ars_cap *ars_cap;
u16 flags; u16 flags;
switch (cmd) { switch (cmd) {
case ND_CMD_ARS_CAP: case ND_CMD_ARS_CAP:
ars_cap = buf; if ((status & 0xffff) == NFIT_ARS_CAP_NONE)
if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
return -ENOTTY; return -ENOTTY;
/* Command failed */ /* Command failed */
if (ars_cap->status & 0xffff) if (status & 0xffff)
return -EIO; return -EIO;
/* No supported scan types for this range */ /* No supported scan types for this range */
flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE; flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
if ((ars_cap->status >> 16 & flags) == 0) if ((status >> 16 & flags) == 0)
return -ENOTTY; return -ENOTTY;
break; break;
case ND_CMD_ARS_START: case ND_CMD_ARS_START:
ars_start = buf;
/* ARS is in progress */ /* ARS is in progress */
if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY) if ((status & 0xffff) == NFIT_ARS_START_BUSY)
return -EBUSY; return -EBUSY;
/* Command failed */ /* Command failed */
if (ars_start->status & 0xffff) if (status & 0xffff)
return -EIO; return -EIO;
break; break;
case ND_CMD_ARS_STATUS: case ND_CMD_ARS_STATUS:
ars_status = buf; ars_status = buf;
/* Command failed */ /* Command failed */
if (ars_status->status & 0xffff) if (status & 0xffff)
return -EIO; return -EIO;
/* Check extended status (Upper two bytes) */ /* Check extended status (Upper two bytes) */
if (ars_status->status == NFIT_ARS_STATUS_DONE) if (status == NFIT_ARS_STATUS_DONE)
return 0; return 0;
/* ARS is in progress */ /* ARS is in progress */
if (ars_status->status == NFIT_ARS_STATUS_BUSY) if (status == NFIT_ARS_STATUS_BUSY)
return -EBUSY; return -EBUSY;
/* No ARS performed for the current boot */ /* No ARS performed for the current boot */
if (ars_status->status == NFIT_ARS_STATUS_NONE) if (status == NFIT_ARS_STATUS_NONE)
return -EAGAIN; return -EAGAIN;
/* /*
...@@ -149,19 +145,19 @@ static int xlat_status(void *buf, unsigned int cmd) ...@@ -149,19 +145,19 @@ static int xlat_status(void *buf, unsigned int cmd)
* agent wants the scan to stop. If we didn't overflow * agent wants the scan to stop. If we didn't overflow
* then just continue with the returned results. * then just continue with the returned results.
*/ */
if (ars_status->status == NFIT_ARS_STATUS_INTR) { if (status == NFIT_ARS_STATUS_INTR) {
if (ars_status->flags & NFIT_ARS_F_OVERFLOW) if (ars_status->flags & NFIT_ARS_F_OVERFLOW)
return -ENOSPC; return -ENOSPC;
return 0; return 0;
} }
/* Unknown status */ /* Unknown status */
if (ars_status->status >> 16) if (status >> 16)
return -EIO; return -EIO;
break; break;
case ND_CMD_CLEAR_ERROR: case ND_CMD_CLEAR_ERROR:
clear_err = buf; clear_err = buf;
if (clear_err->status & 0xffff) if (status & 0xffff)
return -EIO; return -EIO;
if (!clear_err->cleared) if (!clear_err->cleared)
return -EIO; return -EIO;
...@@ -172,6 +168,9 @@ static int xlat_status(void *buf, unsigned int cmd) ...@@ -172,6 +168,9 @@ static int xlat_status(void *buf, unsigned int cmd)
break; break;
} }
/* all other non-zero status results in an error */
if (status)
return -EIO;
return 0; return 0;
} }
...@@ -186,10 +185,10 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, ...@@ -186,10 +185,10 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
struct nd_cmd_pkg *call_pkg = NULL; struct nd_cmd_pkg *call_pkg = NULL;
const char *cmd_name, *dimm_name; const char *cmd_name, *dimm_name;
unsigned long cmd_mask, dsm_mask; unsigned long cmd_mask, dsm_mask;
u32 offset, fw_status = 0;
acpi_handle handle; acpi_handle handle;
unsigned int func; unsigned int func;
const u8 *uuid; const u8 *uuid;
u32 offset;
int rc, i; int rc, i;
func = cmd; func = cmd;
...@@ -317,6 +316,15 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, ...@@ -317,6 +316,15 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
out_obj->buffer.pointer + offset, out_size); out_obj->buffer.pointer + offset, out_size);
offset += out_size; offset += out_size;
} }
/*
* Set fw_status for all the commands with a known format to be
* later interpreted by xlat_status().
*/
if (i >= 1 && ((cmd >= ND_CMD_ARS_CAP && cmd <= ND_CMD_CLEAR_ERROR)
|| (cmd >= ND_CMD_SMART && cmd <= ND_CMD_VENDOR)))
fw_status = *(u32 *) out_obj->buffer.pointer;
if (offset + in_buf.buffer.length < buf_len) { if (offset + in_buf.buffer.length < buf_len) {
if (i >= 1) { if (i >= 1) {
/* /*
...@@ -325,7 +333,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, ...@@ -325,7 +333,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
*/ */
rc = buf_len - offset - in_buf.buffer.length; rc = buf_len - offset - in_buf.buffer.length;
if (cmd_rc) if (cmd_rc)
*cmd_rc = xlat_status(buf, cmd); *cmd_rc = xlat_status(buf, cmd, fw_status);
} else { } else {
dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n", dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
__func__, dimm_name, cmd_name, buf_len, __func__, dimm_name, cmd_name, buf_len,
...@@ -335,7 +343,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, ...@@ -335,7 +343,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
} else { } else {
rc = 0; rc = 0;
if (cmd_rc) if (cmd_rc)
*cmd_rc = xlat_status(buf, cmd); *cmd_rc = xlat_status(buf, cmd, fw_status);
} }
out: out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment