Skip to content

Commit

Permalink
nfit: fail DSMs that return non-zero status by default
Browse files Browse the repository at this point in the history
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: <[email protected]>
Signed-off-by: Dan Williams <[email protected]>
  • Loading branch information
djbw committed Sep 21, 2016
1 parent ecfb6d8 commit 11294d6
Showing 1 changed file with 28 additions and 20 deletions.
48 changes: 28 additions & 20 deletions drivers/acpi/nfit/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,74 +94,70 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc)
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_ars_status *ars_status;
struct nd_cmd_ars_start *ars_start;
struct nd_cmd_ars_cap *ars_cap;
u16 flags;

switch (cmd) {
case ND_CMD_ARS_CAP:
ars_cap = buf;
if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE)
if ((status & 0xffff) == NFIT_ARS_CAP_NONE)
return -ENOTTY;

/* Command failed */
if (ars_cap->status & 0xffff)
if (status & 0xffff)
return -EIO;

/* No supported scan types for this range */
flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE;
if ((ars_cap->status >> 16 & flags) == 0)
if ((status >> 16 & flags) == 0)
return -ENOTTY;
break;
case ND_CMD_ARS_START:
ars_start = buf;
/* ARS is in progress */
if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY)
if ((status & 0xffff) == NFIT_ARS_START_BUSY)
return -EBUSY;

/* Command failed */
if (ars_start->status & 0xffff)
if (status & 0xffff)
return -EIO;
break;
case ND_CMD_ARS_STATUS:
ars_status = buf;
/* Command failed */
if (ars_status->status & 0xffff)
if (status & 0xffff)
return -EIO;
/* Check extended status (Upper two bytes) */
if (ars_status->status == NFIT_ARS_STATUS_DONE)
if (status == NFIT_ARS_STATUS_DONE)
return 0;

/* ARS is in progress */
if (ars_status->status == NFIT_ARS_STATUS_BUSY)
if (status == NFIT_ARS_STATUS_BUSY)
return -EBUSY;

/* No ARS performed for the current boot */
if (ars_status->status == NFIT_ARS_STATUS_NONE)
if (status == NFIT_ARS_STATUS_NONE)
return -EAGAIN;

/*
* ARS interrupted, either we overflowed or some other
* agent wants the scan to stop. If we didn't overflow
* 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)
return -ENOSPC;
return 0;
}

/* Unknown status */
if (ars_status->status >> 16)
if (status >> 16)
return -EIO;
break;
case ND_CMD_CLEAR_ERROR:
clear_err = buf;
if (clear_err->status & 0xffff)
if (status & 0xffff)
return -EIO;
if (!clear_err->cleared)
return -EIO;
Expand All @@ -172,6 +168,9 @@ static int xlat_status(void *buf, unsigned int cmd)
break;
}

/* all other non-zero status results in an error */
if (status)
return -EIO;
return 0;
}

Expand All @@ -186,10 +185,10 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
struct nd_cmd_pkg *call_pkg = NULL;
const char *cmd_name, *dimm_name;
unsigned long cmd_mask, dsm_mask;
u32 offset, fw_status = 0;
acpi_handle handle;
unsigned int func;
const u8 *uuid;
u32 offset;
int rc, i;

func = cmd;
Expand Down Expand Up @@ -317,6 +316,15 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
out_obj->buffer.pointer + 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 (i >= 1) {
/*
Expand All @@ -325,7 +333,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
*/
rc = buf_len - offset - in_buf.buffer.length;
if (cmd_rc)
*cmd_rc = xlat_status(buf, cmd);
*cmd_rc = xlat_status(buf, cmd, fw_status);
} else {
dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n",
__func__, dimm_name, cmd_name, buf_len,
Expand All @@ -335,7 +343,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc,
} else {
rc = 0;
if (cmd_rc)
*cmd_rc = xlat_status(buf, cmd);
*cmd_rc = xlat_status(buf, cmd, fw_status);
}

out:
Expand Down

0 comments on commit 11294d6

Please sign in to comment.