aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2016-09-21 12:21:26 -0400
committerDan Williams <dan.j.williams@intel.com>2016-09-21 12:35:19 -0400
commit11294d63ac915230a36b0603c62134ef7b173d0a (patch)
treeaf6ca958a7d5213c512c7640e0b453cecf3a97e9
parentecfb6d8a041cc2ca80bc69ffc20c00067d190df5 (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.c48
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
97static int xlat_status(void *buf, unsigned int cmd) 97static 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: