mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-02 20:44:00 +00:00
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: Dan Williams <dan.j.williams@intel.com>
This commit is contained in:
parent
ecfb6d8a04
commit
11294d63ac
1 changed files with 28 additions and 20 deletions
|
@ -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)
|
||||||
* 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)
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
} 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:
|
||||||
|
|
Loading…
Add table
Reference in a new issue