diff options
author | Vishal Verma <vishal.l.verma@intel.com> | 2015-07-09 15:25:36 -0400 |
---|---|---|
committer | Dan Williams <dan.j.williams@intel.com> | 2015-07-27 22:53:19 -0400 |
commit | 39c686b862cdb2049b90e095b6c6c727b2a7ab60 (patch) | |
tree | 4858a38b3c4441bad3e9599ff8cf0de01be13817 /tools | |
parent | ec92777f2ba93c00387b8fe53780c25adc57c744 (diff) |
libnvdimm: Add DSM support for Address Range Scrub commands
Add support for the three ARS DSM commands:
- Query ARS Capabilities - Queries the firmware to check if a given
range supports scrub, and if so, which type (persistent vs. volatile)
- Start ARS - Starts a scrub for a given range/type
- Query ARS Status - Checks status of a previously started scrub, and
provides the error logs if any.
The commands are described by the example DSM spec at:
http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf
Also add these commands to the nfit_test test framework, and return
canned data.
Signed-off-by: Vishal Verma <vishal.l.verma@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/testing/nvdimm/test/nfit.c | 199 |
1 files changed, 140 insertions, 59 deletions
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index d0bdae40ccc9..28dba918524e 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c | |||
@@ -147,75 +147,153 @@ static struct nfit_test *to_nfit_test(struct device *dev) | |||
147 | return container_of(pdev, struct nfit_test, pdev); | 147 | return container_of(pdev, struct nfit_test, pdev); |
148 | } | 148 | } |
149 | 149 | ||
150 | static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd, | ||
151 | unsigned int buf_len) | ||
152 | { | ||
153 | if (buf_len < sizeof(*nd_cmd)) | ||
154 | return -EINVAL; | ||
155 | |||
156 | nd_cmd->status = 0; | ||
157 | nd_cmd->config_size = LABEL_SIZE; | ||
158 | nd_cmd->max_xfer = SZ_4K; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int nfit_test_cmd_get_config_data(struct nd_cmd_get_config_data_hdr | ||
164 | *nd_cmd, unsigned int buf_len, void *label) | ||
165 | { | ||
166 | unsigned int len, offset = nd_cmd->in_offset; | ||
167 | int rc; | ||
168 | |||
169 | if (buf_len < sizeof(*nd_cmd)) | ||
170 | return -EINVAL; | ||
171 | if (offset >= LABEL_SIZE) | ||
172 | return -EINVAL; | ||
173 | if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len) | ||
174 | return -EINVAL; | ||
175 | |||
176 | nd_cmd->status = 0; | ||
177 | len = min(nd_cmd->in_length, LABEL_SIZE - offset); | ||
178 | memcpy(nd_cmd->out_buf, label + offset, len); | ||
179 | rc = buf_len - sizeof(*nd_cmd) - len; | ||
180 | |||
181 | return rc; | ||
182 | } | ||
183 | |||
184 | static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd, | ||
185 | unsigned int buf_len, void *label) | ||
186 | { | ||
187 | unsigned int len, offset = nd_cmd->in_offset; | ||
188 | u32 *status; | ||
189 | int rc; | ||
190 | |||
191 | if (buf_len < sizeof(*nd_cmd)) | ||
192 | return -EINVAL; | ||
193 | if (offset >= LABEL_SIZE) | ||
194 | return -EINVAL; | ||
195 | if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len) | ||
196 | return -EINVAL; | ||
197 | |||
198 | status = (void *)nd_cmd + nd_cmd->in_length + sizeof(*nd_cmd); | ||
199 | *status = 0; | ||
200 | len = min(nd_cmd->in_length, LABEL_SIZE - offset); | ||
201 | memcpy(label + offset, nd_cmd->in_buf, len); | ||
202 | rc = buf_len - sizeof(*nd_cmd) - (len + 4); | ||
203 | |||
204 | return rc; | ||
205 | } | ||
206 | |||
207 | static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, | ||
208 | unsigned int buf_len) | ||
209 | { | ||
210 | if (buf_len < sizeof(*nd_cmd)) | ||
211 | return -EINVAL; | ||
212 | |||
213 | nd_cmd->max_ars_out = 256; | ||
214 | nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16; | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int nfit_test_cmd_ars_start(struct nd_cmd_ars_start *nd_cmd, | ||
220 | unsigned int buf_len) | ||
221 | { | ||
222 | if (buf_len < sizeof(*nd_cmd)) | ||
223 | return -EINVAL; | ||
224 | |||
225 | nd_cmd->status = 0; | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd, | ||
231 | unsigned int buf_len) | ||
232 | { | ||
233 | if (buf_len < sizeof(*nd_cmd)) | ||
234 | return -EINVAL; | ||
235 | |||
236 | nd_cmd->out_length = 256; | ||
237 | nd_cmd->num_records = 0; | ||
238 | nd_cmd->status = 0; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
150 | static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, | 243 | static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, |
151 | struct nvdimm *nvdimm, unsigned int cmd, void *buf, | 244 | struct nvdimm *nvdimm, unsigned int cmd, void *buf, |
152 | unsigned int buf_len) | 245 | unsigned int buf_len) |
153 | { | 246 | { |
154 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); | 247 | struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); |
155 | struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); | 248 | struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); |
156 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | 249 | int i, rc = 0; |
157 | int i, rc; | 250 | |
251 | if (nvdimm) { | ||
252 | struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); | ||
158 | 253 | ||
159 | if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) | 254 | if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) |
160 | return -ENOTTY; | 255 | return -ENOTTY; |
161 | 256 | ||
162 | /* lookup label space for the given dimm */ | 257 | /* lookup label space for the given dimm */ |
163 | for (i = 0; i < ARRAY_SIZE(handle); i++) | 258 | for (i = 0; i < ARRAY_SIZE(handle); i++) |
164 | if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i]) | 259 | if (__to_nfit_memdev(nfit_mem)->device_handle == |
260 | handle[i]) | ||
261 | break; | ||
262 | if (i >= ARRAY_SIZE(handle)) | ||
263 | return -ENXIO; | ||
264 | |||
265 | switch (cmd) { | ||
266 | case ND_CMD_GET_CONFIG_SIZE: | ||
267 | rc = nfit_test_cmd_get_config_size(buf, buf_len); | ||
165 | break; | 268 | break; |
166 | if (i >= ARRAY_SIZE(handle)) | 269 | case ND_CMD_GET_CONFIG_DATA: |
167 | return -ENXIO; | 270 | rc = nfit_test_cmd_get_config_data(buf, buf_len, |
271 | t->label[i]); | ||
272 | break; | ||
273 | case ND_CMD_SET_CONFIG_DATA: | ||
274 | rc = nfit_test_cmd_set_config_data(buf, buf_len, | ||
275 | t->label[i]); | ||
276 | break; | ||
277 | default: | ||
278 | return -ENOTTY; | ||
279 | } | ||
280 | } else { | ||
281 | if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask)) | ||
282 | return -ENOTTY; | ||
168 | 283 | ||
169 | switch (cmd) { | 284 | switch (cmd) { |
170 | case ND_CMD_GET_CONFIG_SIZE: { | 285 | case ND_CMD_ARS_CAP: |
171 | struct nd_cmd_get_config_size *nd_cmd = buf; | 286 | rc = nfit_test_cmd_ars_cap(buf, buf_len); |
172 | 287 | break; | |
173 | if (buf_len < sizeof(*nd_cmd)) | 288 | case ND_CMD_ARS_START: |
174 | return -EINVAL; | 289 | rc = nfit_test_cmd_ars_start(buf, buf_len); |
175 | nd_cmd->status = 0; | 290 | break; |
176 | nd_cmd->config_size = LABEL_SIZE; | 291 | case ND_CMD_ARS_STATUS: |
177 | nd_cmd->max_xfer = SZ_4K; | 292 | rc = nfit_test_cmd_ars_status(buf, buf_len); |
178 | rc = 0; | 293 | break; |
179 | break; | 294 | default: |
180 | } | 295 | return -ENOTTY; |
181 | case ND_CMD_GET_CONFIG_DATA: { | 296 | } |
182 | struct nd_cmd_get_config_data_hdr *nd_cmd = buf; | ||
183 | unsigned int len, offset = nd_cmd->in_offset; | ||
184 | |||
185 | if (buf_len < sizeof(*nd_cmd)) | ||
186 | return -EINVAL; | ||
187 | if (offset >= LABEL_SIZE) | ||
188 | return -EINVAL; | ||
189 | if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len) | ||
190 | return -EINVAL; | ||
191 | |||
192 | nd_cmd->status = 0; | ||
193 | len = min(nd_cmd->in_length, LABEL_SIZE - offset); | ||
194 | memcpy(nd_cmd->out_buf, t->label[i] + offset, len); | ||
195 | rc = buf_len - sizeof(*nd_cmd) - len; | ||
196 | break; | ||
197 | } | ||
198 | case ND_CMD_SET_CONFIG_DATA: { | ||
199 | struct nd_cmd_set_config_hdr *nd_cmd = buf; | ||
200 | unsigned int len, offset = nd_cmd->in_offset; | ||
201 | u32 *status; | ||
202 | |||
203 | if (buf_len < sizeof(*nd_cmd)) | ||
204 | return -EINVAL; | ||
205 | if (offset >= LABEL_SIZE) | ||
206 | return -EINVAL; | ||
207 | if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len) | ||
208 | return -EINVAL; | ||
209 | |||
210 | status = buf + nd_cmd->in_length + sizeof(*nd_cmd); | ||
211 | *status = 0; | ||
212 | len = min(nd_cmd->in_length, LABEL_SIZE - offset); | ||
213 | memcpy(t->label[i] + offset, nd_cmd->in_buf, len); | ||
214 | rc = buf_len - sizeof(*nd_cmd) - (len + 4); | ||
215 | break; | ||
216 | } | ||
217 | default: | ||
218 | return -ENOTTY; | ||
219 | } | 297 | } |
220 | 298 | ||
221 | return rc; | 299 | return rc; |
@@ -876,6 +954,9 @@ static void nfit_test0_setup(struct nfit_test *t) | |||
876 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); | 954 | set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); |
877 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); | 955 | set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); |
878 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); | 956 | set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); |
957 | set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); | ||
958 | set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); | ||
959 | set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); | ||
879 | nd_desc = &acpi_desc->nd_desc; | 960 | nd_desc = &acpi_desc->nd_desc; |
880 | nd_desc->ndctl = nfit_test_ctl; | 961 | nd_desc->ndctl = nfit_test_ctl; |
881 | } | 962 | } |