mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
ec92777f2b
commit
39c686b862
|
@ -868,6 +868,7 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc)
|
||||||
struct acpi_device *adev;
|
struct acpi_device *adev;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
nd_desc->dsm_mask = acpi_desc->bus_dsm_force_en;
|
||||||
adev = to_acpi_dev(acpi_desc);
|
adev = to_acpi_dev(acpi_desc);
|
||||||
if (!adev)
|
if (!adev)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -107,6 +107,7 @@ struct acpi_nfit_desc {
|
||||||
struct nvdimm_bus *nvdimm_bus;
|
struct nvdimm_bus *nvdimm_bus;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
unsigned long dimm_dsm_force_en;
|
unsigned long dimm_dsm_force_en;
|
||||||
|
unsigned long bus_dsm_force_en;
|
||||||
int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
|
int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa,
|
||||||
void *iobuf, u64 len, int rw);
|
void *iobuf, u64 len, int rw);
|
||||||
};
|
};
|
||||||
|
|
|
@ -111,6 +111,11 @@ enum {
|
||||||
ND_CMD_VENDOR = 9,
|
ND_CMD_VENDOR = 9,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ND_ARS_VOLATILE = 1,
|
||||||
|
ND_ARS_PERSISTENT = 2,
|
||||||
|
};
|
||||||
|
|
||||||
static inline const char *nvdimm_bus_cmd_name(unsigned cmd)
|
static inline const char *nvdimm_bus_cmd_name(unsigned cmd)
|
||||||
{
|
{
|
||||||
static const char * const names[] = {
|
static const char * const names[] = {
|
||||||
|
@ -194,4 +199,9 @@ enum nd_driver_flags {
|
||||||
enum {
|
enum {
|
||||||
ND_MIN_NAMESPACE_SIZE = 0x00400000,
|
ND_MIN_NAMESPACE_SIZE = 0x00400000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ars_masks {
|
||||||
|
ARS_STATUS_MASK = 0x0000FFFF,
|
||||||
|
ARS_EXT_STATUS_SHIFT = 16,
|
||||||
|
};
|
||||||
#endif /* __NDCTL_H__ */
|
#endif /* __NDCTL_H__ */
|
||||||
|
|
|
@ -147,40 +147,24 @@ static struct nfit_test *to_nfit_test(struct device *dev)
|
||||||
return container_of(pdev, struct nfit_test, pdev);
|
return container_of(pdev, struct nfit_test, pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
|
static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd,
|
||||||
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
|
|
||||||
unsigned int buf_len)
|
unsigned int buf_len)
|
||||||
{
|
{
|
||||||
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
|
|
||||||
struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc);
|
|
||||||
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
|
|
||||||
int i, rc;
|
|
||||||
|
|
||||||
if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask))
|
|
||||||
return -ENOTTY;
|
|
||||||
|
|
||||||
/* lookup label space for the given dimm */
|
|
||||||
for (i = 0; i < ARRAY_SIZE(handle); i++)
|
|
||||||
if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i])
|
|
||||||
break;
|
|
||||||
if (i >= ARRAY_SIZE(handle))
|
|
||||||
return -ENXIO;
|
|
||||||
|
|
||||||
switch (cmd) {
|
|
||||||
case ND_CMD_GET_CONFIG_SIZE: {
|
|
||||||
struct nd_cmd_get_config_size *nd_cmd = buf;
|
|
||||||
|
|
||||||
if (buf_len < sizeof(*nd_cmd))
|
if (buf_len < sizeof(*nd_cmd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
nd_cmd->status = 0;
|
nd_cmd->status = 0;
|
||||||
nd_cmd->config_size = LABEL_SIZE;
|
nd_cmd->config_size = LABEL_SIZE;
|
||||||
nd_cmd->max_xfer = SZ_4K;
|
nd_cmd->max_xfer = SZ_4K;
|
||||||
rc = 0;
|
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
case ND_CMD_GET_CONFIG_DATA: {
|
|
||||||
struct nd_cmd_get_config_data_hdr *nd_cmd = buf;
|
static int nfit_test_cmd_get_config_data(struct nd_cmd_get_config_data_hdr
|
||||||
|
*nd_cmd, unsigned int buf_len, void *label)
|
||||||
|
{
|
||||||
unsigned int len, offset = nd_cmd->in_offset;
|
unsigned int len, offset = nd_cmd->in_offset;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (buf_len < sizeof(*nd_cmd))
|
if (buf_len < sizeof(*nd_cmd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -191,14 +175,18 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
|
||||||
|
|
||||||
nd_cmd->status = 0;
|
nd_cmd->status = 0;
|
||||||
len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
||||||
memcpy(nd_cmd->out_buf, t->label[i] + offset, len);
|
memcpy(nd_cmd->out_buf, label + offset, len);
|
||||||
rc = buf_len - sizeof(*nd_cmd) - len;
|
rc = buf_len - sizeof(*nd_cmd) - len;
|
||||||
break;
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
case ND_CMD_SET_CONFIG_DATA: {
|
|
||||||
struct nd_cmd_set_config_hdr *nd_cmd = buf;
|
static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd,
|
||||||
|
unsigned int buf_len, void *label)
|
||||||
|
{
|
||||||
unsigned int len, offset = nd_cmd->in_offset;
|
unsigned int len, offset = nd_cmd->in_offset;
|
||||||
u32 *status;
|
u32 *status;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (buf_len < sizeof(*nd_cmd))
|
if (buf_len < sizeof(*nd_cmd))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -207,16 +195,106 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
|
||||||
if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len)
|
if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
status = buf + nd_cmd->in_length + sizeof(*nd_cmd);
|
status = (void *)nd_cmd + nd_cmd->in_length + sizeof(*nd_cmd);
|
||||||
*status = 0;
|
*status = 0;
|
||||||
len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
len = min(nd_cmd->in_length, LABEL_SIZE - offset);
|
||||||
memcpy(t->label[i] + offset, nd_cmd->in_buf, len);
|
memcpy(label + offset, nd_cmd->in_buf, len);
|
||||||
rc = buf_len - sizeof(*nd_cmd) - (len + 4);
|
rc = buf_len - sizeof(*nd_cmd) - (len + 4);
|
||||||
break;
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd,
|
||||||
|
unsigned int buf_len)
|
||||||
|
{
|
||||||
|
if (buf_len < sizeof(*nd_cmd))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
nd_cmd->max_ars_out = 256;
|
||||||
|
nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfit_test_cmd_ars_start(struct nd_cmd_ars_start *nd_cmd,
|
||||||
|
unsigned int buf_len)
|
||||||
|
{
|
||||||
|
if (buf_len < sizeof(*nd_cmd))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
nd_cmd->status = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd,
|
||||||
|
unsigned int buf_len)
|
||||||
|
{
|
||||||
|
if (buf_len < sizeof(*nd_cmd))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
nd_cmd->out_length = 256;
|
||||||
|
nd_cmd->num_records = 0;
|
||||||
|
nd_cmd->status = 0;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc,
|
||||||
|
struct nvdimm *nvdimm, unsigned int cmd, void *buf,
|
||||||
|
unsigned int buf_len)
|
||||||
|
{
|
||||||
|
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
|
||||||
|
struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc);
|
||||||
|
int i, rc = 0;
|
||||||
|
|
||||||
|
if (nvdimm) {
|
||||||
|
struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm);
|
||||||
|
|
||||||
|
if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask))
|
||||||
|
return -ENOTTY;
|
||||||
|
|
||||||
|
/* lookup label space for the given dimm */
|
||||||
|
for (i = 0; i < ARRAY_SIZE(handle); i++)
|
||||||
|
if (__to_nfit_memdev(nfit_mem)->device_handle ==
|
||||||
|
handle[i])
|
||||||
|
break;
|
||||||
|
if (i >= ARRAY_SIZE(handle))
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case ND_CMD_GET_CONFIG_SIZE:
|
||||||
|
rc = nfit_test_cmd_get_config_size(buf, buf_len);
|
||||||
|
break;
|
||||||
|
case ND_CMD_GET_CONFIG_DATA:
|
||||||
|
rc = nfit_test_cmd_get_config_data(buf, buf_len,
|
||||||
|
t->label[i]);
|
||||||
|
break;
|
||||||
|
case ND_CMD_SET_CONFIG_DATA:
|
||||||
|
rc = nfit_test_cmd_set_config_data(buf, buf_len,
|
||||||
|
t->label[i]);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask))
|
||||||
|
return -ENOTTY;
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case ND_CMD_ARS_CAP:
|
||||||
|
rc = nfit_test_cmd_ars_cap(buf, buf_len);
|
||||||
|
break;
|
||||||
|
case ND_CMD_ARS_START:
|
||||||
|
rc = nfit_test_cmd_ars_start(buf, buf_len);
|
||||||
|
break;
|
||||||
|
case ND_CMD_ARS_STATUS:
|
||||||
|
rc = nfit_test_cmd_ars_status(buf, buf_len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTTY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -876,6 +954,9 @@ static void nfit_test0_setup(struct nfit_test *t)
|
||||||
set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en);
|
set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en);
|
||||||
set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
|
set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
|
||||||
set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
|
set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en);
|
||||||
|
set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en);
|
||||||
|
set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en);
|
||||||
|
set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en);
|
||||||
nd_desc = &acpi_desc->nd_desc;
|
nd_desc = &acpi_desc->nd_desc;
|
||||||
nd_desc->ndctl = nfit_test_ctl;
|
nd_desc->ndctl = nfit_test_ctl;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue