diff options
author | Dan Williams <dan.j.williams@intel.com> | 2016-09-21 12:21:26 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2016-09-21 12:35:19 -0400 |
commit | 11294d63ac915230a36b0603c62134ef7b173d0a (patch) | |
tree | af6ca958a7d5213c512c7640e0b453cecf3a97e9 | |
parent | ecfb6d8a041cc2ca80bc69ffc20c00067d190df5 (diff) |
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>
-rw-r--r-- | drivers/acpi/nfit/core.c | 48 |
1 files changed, 28 insertions, 20 deletions
diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 80cc7c089a15..e1d5ea6d5e40 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c | |||
@@ -94,54 +94,50 @@ static struct acpi_device *to_acpi_dev(struct acpi_nfit_desc *acpi_desc) | |||
94 | return to_acpi_device(acpi_desc->dev); | 94 | return to_acpi_device(acpi_desc->dev); |
95 | } | 95 | } |
96 | 96 | ||
97 | static int xlat_status(void *buf, unsigned int cmd) | 97 | static int xlat_status(void *buf, unsigned int cmd, u32 status) |
98 | { | 98 | { |
99 | struct nd_cmd_clear_error *clear_err; | 99 | struct nd_cmd_clear_error *clear_err; |
100 | struct nd_cmd_ars_status *ars_status; | 100 | struct nd_cmd_ars_status *ars_status; |
101 | struct nd_cmd_ars_start *ars_start; | ||
102 | struct nd_cmd_ars_cap *ars_cap; | ||
103 | u16 flags; | 101 | u16 flags; |
104 | 102 | ||
105 | switch (cmd) { | 103 | switch (cmd) { |
106 | case ND_CMD_ARS_CAP: | 104 | case ND_CMD_ARS_CAP: |
107 | ars_cap = buf; | 105 | if ((status & 0xffff) == NFIT_ARS_CAP_NONE) |
108 | if ((ars_cap->status & 0xffff) == NFIT_ARS_CAP_NONE) | ||
109 | return -ENOTTY; | 106 | return -ENOTTY; |
110 | 107 | ||
111 | /* Command failed */ | 108 | /* Command failed */ |
112 | if (ars_cap->status & 0xffff) | 109 | if (status & 0xffff) |
113 | return -EIO; | 110 | return -EIO; |
114 | 111 | ||
115 | /* No supported scan types for this range */ | 112 | /* No supported scan types for this range */ |
116 | flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE; | 113 | flags = ND_ARS_PERSISTENT | ND_ARS_VOLATILE; |
117 | if ((ars_cap->status >> 16 & flags) == 0) | 114 | if ((status >> 16 & flags) == 0) |
118 | return -ENOTTY; | 115 | return -ENOTTY; |
119 | break; | 116 | break; |
120 | case ND_CMD_ARS_START: | 117 | case ND_CMD_ARS_START: |
121 | ars_start = buf; | ||
122 | /* ARS is in progress */ | 118 | /* ARS is in progress */ |
123 | if ((ars_start->status & 0xffff) == NFIT_ARS_START_BUSY) | 119 | if ((status & 0xffff) == NFIT_ARS_START_BUSY) |
124 | return -EBUSY; | 120 | return -EBUSY; |
125 | 121 | ||
126 | /* Command failed */ | 122 | /* Command failed */ |
127 | if (ars_start->status & 0xffff) | 123 | if (status & 0xffff) |
128 | return -EIO; | 124 | return -EIO; |
129 | break; | 125 | break; |
130 | case ND_CMD_ARS_STATUS: | 126 | case ND_CMD_ARS_STATUS: |
131 | ars_status = buf; | 127 | ars_status = buf; |
132 | /* Command failed */ | 128 | /* Command failed */ |
133 | if (ars_status->status & 0xffff) | 129 | if (status & 0xffff) |
134 | return -EIO; | 130 | return -EIO; |
135 | /* Check extended status (Upper two bytes) */ | 131 | /* Check extended status (Upper two bytes) */ |
136 | if (ars_status->status == NFIT_ARS_STATUS_DONE) | 132 | if (status == NFIT_ARS_STATUS_DONE) |
137 | return 0; | 133 | return 0; |
138 | 134 | ||
139 | /* ARS is in progress */ | 135 | /* ARS is in progress */ |
140 | if (ars_status->status == NFIT_ARS_STATUS_BUSY) | 136 | if (status == NFIT_ARS_STATUS_BUSY) |
141 | return -EBUSY; | 137 | return -EBUSY; |
142 | 138 | ||
143 | /* No ARS performed for the current boot */ | 139 | /* No ARS performed for the current boot */ |
144 | if (ars_status->status == NFIT_ARS_STATUS_NONE) | 140 | if (status == NFIT_ARS_STATUS_NONE) |
145 | return -EAGAIN; | 141 | return -EAGAIN; |
146 | 142 | ||
147 | /* | 143 | /* |
@@ -149,19 +145,19 @@ static int xlat_status(void *buf, unsigned int cmd) | |||
149 | * agent wants the scan to stop. If we didn't overflow | 145 | * agent wants the scan to stop. If we didn't overflow |
150 | * then just continue with the returned results. | 146 | * then just continue with the returned results. |
151 | */ | 147 | */ |
152 | if (ars_status->status == NFIT_ARS_STATUS_INTR) { | 148 | if (status == NFIT_ARS_STATUS_INTR) { |
153 | if (ars_status->flags & NFIT_ARS_F_OVERFLOW) | 149 | if (ars_status->flags & NFIT_ARS_F_OVERFLOW) |
154 | return -ENOSPC; | 150 | return -ENOSPC; |
155 | return 0; | 151 | return 0; |
156 | } | 152 | } |
157 | 153 | ||
158 | /* Unknown status */ | 154 | /* Unknown status */ |
159 | if (ars_status->status >> 16) | 155 | if (status >> 16) |
160 | return -EIO; | 156 | return -EIO; |
161 | break; | 157 | break; |
162 | case ND_CMD_CLEAR_ERROR: | 158 | case ND_CMD_CLEAR_ERROR: |
163 | clear_err = buf; | 159 | clear_err = buf; |
164 | if (clear_err->status & 0xffff) | 160 | if (status & 0xffff) |
165 | return -EIO; | 161 | return -EIO; |
166 | if (!clear_err->cleared) | 162 | if (!clear_err->cleared) |
167 | return -EIO; | 163 | return -EIO; |
@@ -172,6 +168,9 @@ static int xlat_status(void *buf, unsigned int cmd) | |||
172 | break; | 168 | break; |
173 | } | 169 | } |
174 | 170 | ||
171 | /* all other non-zero status results in an error */ | ||
172 | if (status) | ||
173 | return -EIO; | ||
175 | return 0; | 174 | return 0; |
176 | } | 175 | } |
177 | 176 | ||
@@ -186,10 +185,10 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
186 | struct nd_cmd_pkg *call_pkg = NULL; | 185 | struct nd_cmd_pkg *call_pkg = NULL; |
187 | const char *cmd_name, *dimm_name; | 186 | const char *cmd_name, *dimm_name; |
188 | unsigned long cmd_mask, dsm_mask; | 187 | unsigned long cmd_mask, dsm_mask; |
188 | u32 offset, fw_status = 0; | ||
189 | acpi_handle handle; | 189 | acpi_handle handle; |
190 | unsigned int func; | 190 | unsigned int func; |
191 | const u8 *uuid; | 191 | const u8 *uuid; |
192 | u32 offset; | ||
193 | int rc, i; | 192 | int rc, i; |
194 | 193 | ||
195 | func = cmd; | 194 | func = cmd; |
@@ -317,6 +316,15 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
317 | out_obj->buffer.pointer + offset, out_size); | 316 | out_obj->buffer.pointer + offset, out_size); |
318 | offset += out_size; | 317 | offset += out_size; |
319 | } | 318 | } |
319 | |||
320 | /* | ||
321 | * Set fw_status for all the commands with a known format to be | ||
322 | * later interpreted by xlat_status(). | ||
323 | */ | ||
324 | if (i >= 1 && ((cmd >= ND_CMD_ARS_CAP && cmd <= ND_CMD_CLEAR_ERROR) | ||
325 | || (cmd >= ND_CMD_SMART && cmd <= ND_CMD_VENDOR))) | ||
326 | fw_status = *(u32 *) out_obj->buffer.pointer; | ||
327 | |||
320 | if (offset + in_buf.buffer.length < buf_len) { | 328 | if (offset + in_buf.buffer.length < buf_len) { |
321 | if (i >= 1) { | 329 | if (i >= 1) { |
322 | /* | 330 | /* |
@@ -325,7 +333,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
325 | */ | 333 | */ |
326 | rc = buf_len - offset - in_buf.buffer.length; | 334 | rc = buf_len - offset - in_buf.buffer.length; |
327 | if (cmd_rc) | 335 | if (cmd_rc) |
328 | *cmd_rc = xlat_status(buf, cmd); | 336 | *cmd_rc = xlat_status(buf, cmd, fw_status); |
329 | } else { | 337 | } else { |
330 | dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n", | 338 | dev_err(dev, "%s:%s underrun cmd: %s buf_len: %d out_len: %d\n", |
331 | __func__, dimm_name, cmd_name, buf_len, | 339 | __func__, dimm_name, cmd_name, buf_len, |
@@ -335,7 +343,7 @@ static int acpi_nfit_ctl(struct nvdimm_bus_descriptor *nd_desc, | |||
335 | } else { | 343 | } else { |
336 | rc = 0; | 344 | rc = 0; |
337 | if (cmd_rc) | 345 | if (cmd_rc) |
338 | *cmd_rc = xlat_status(buf, cmd); | 346 | *cmd_rc = xlat_status(buf, cmd, fw_status); |
339 | } | 347 | } |
340 | 348 | ||
341 | out: | 349 | out: |