summaryrefslogtreecommitdiff
path: root/drivers/nvdimm/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nvdimm/bus.c')
-rw-r--r--drivers/nvdimm/bus.c50
1 files changed, 46 insertions, 4 deletions
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c
index 7cbc3d58d176..f085f8bceae8 100644
--- a/drivers/nvdimm/bus.c
+++ b/drivers/nvdimm/bus.c
@@ -444,6 +444,12 @@ static const struct nd_cmd_desc __nd_cmd_dimm_descs[] = {
.out_num = 3,
.out_sizes = { 4, 4, UINT_MAX, },
},
+ [ND_CMD_CALL] = {
+ .in_num = 2,
+ .in_sizes = { sizeof(struct nd_cmd_pkg), UINT_MAX, },
+ .out_num = 1,
+ .out_sizes = { UINT_MAX, },
+ },
};
const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd)
@@ -478,6 +484,12 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = {
.out_num = 3,
.out_sizes = { 4, 4, 8, },
},
+ [ND_CMD_CALL] = {
+ .in_num = 2,
+ .in_sizes = { sizeof(struct nd_cmd_pkg), UINT_MAX, },
+ .out_num = 1,
+ .out_sizes = { UINT_MAX, },
+ },
};
const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd)
@@ -505,6 +517,10 @@ u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd,
struct nd_cmd_vendor_hdr *hdr = buf;
return hdr->in_length;
+ } else if (cmd == ND_CMD_CALL) {
+ struct nd_cmd_pkg *pkg = buf;
+
+ return pkg->nd_size_in;
}
return UINT_MAX;
@@ -527,6 +543,12 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd,
return out_field[1];
else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2)
return out_field[1] - 8;
+ else if (cmd == ND_CMD_CALL) {
+ struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field;
+
+ return pkg->nd_size_out;
+ }
+
return UINT_MAX;
}
@@ -593,25 +615,31 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
unsigned int cmd = _IOC_NR(ioctl_cmd);
void __user *p = (void __user *) arg;
struct device *dev = &nvdimm_bus->dev;
+ struct nd_cmd_pkg pkg;
const char *cmd_name, *dimm_name;
- unsigned long dsm_mask;
+ unsigned long cmd_mask;
void *buf;
int rc, i;
if (nvdimm) {
desc = nd_cmd_dimm_desc(cmd);
cmd_name = nvdimm_cmd_name(cmd);
- dsm_mask = nvdimm->dsm_mask ? *(nvdimm->dsm_mask) : 0;
+ cmd_mask = nvdimm->cmd_mask;
dimm_name = dev_name(&nvdimm->dev);
} else {
desc = nd_cmd_bus_desc(cmd);
cmd_name = nvdimm_bus_cmd_name(cmd);
- dsm_mask = nd_desc->dsm_mask;
+ cmd_mask = nd_desc->cmd_mask;
dimm_name = "bus";
}
+ if (cmd == ND_CMD_CALL) {
+ if (copy_from_user(&pkg, p, sizeof(pkg)))
+ return -EFAULT;
+ }
+
if (!desc || (desc->out_num + desc->in_num == 0) ||
- !test_bit(cmd, &dsm_mask))
+ !test_bit(cmd, &cmd_mask))
return -ENOTTY;
/* fail write commands (when read-only) */
@@ -621,6 +649,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
case ND_CMD_SET_CONFIG_DATA:
case ND_CMD_ARS_START:
case ND_CMD_CLEAR_ERROR:
+ case ND_CMD_CALL:
dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n",
nvdimm ? nvdimm_cmd_name(cmd)
: nvdimm_bus_cmd_name(cmd));
@@ -648,6 +677,16 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm,
in_len += in_size;
}
+ if (cmd == ND_CMD_CALL) {
+ dev_dbg(dev, "%s:%s, idx: %llu, in: %zu, out: %zu, len %zu\n",
+ __func__, dimm_name, pkg.nd_command,
+ in_len, out_len, buf_len);
+
+ for (i = 0; i < ARRAY_SIZE(pkg.nd_reserved2); i++)
+ if (pkg.nd_reserved2[i])
+ return -EINVAL;
+ }
+
/* process an output envelope */
for (i = 0; i < desc->out_num; i++) {
u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i,
@@ -788,6 +827,9 @@ int __init nvdimm_bus_init(void)
{
int rc;
+ BUILD_BUG_ON(sizeof(struct nd_smart_payload) != 128);
+ BUILD_BUG_ON(sizeof(struct nd_smart_threshold_payload) != 8);
+
rc = bus_register(&nvdimm_bus_type);
if (rc)
return rc;