diff options
Diffstat (limited to 'drivers/nvdimm')
-rw-r--r-- | drivers/nvdimm/bus.c | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/drivers/nvdimm/bus.c b/drivers/nvdimm/bus.c index cb2042a12b76..395a9fbbc69d 100644 --- a/drivers/nvdimm/bus.c +++ b/drivers/nvdimm/bus.c | |||
@@ -439,6 +439,12 @@ static const struct nd_cmd_desc __nd_cmd_dimm_descs[] = { | |||
439 | .out_num = 3, | 439 | .out_num = 3, |
440 | .out_sizes = { 4, 4, UINT_MAX, }, | 440 | .out_sizes = { 4, 4, UINT_MAX, }, |
441 | }, | 441 | }, |
442 | [ND_CMD_CALL] = { | ||
443 | .in_num = 2, | ||
444 | .in_sizes = { sizeof(struct nd_cmd_pkg), UINT_MAX, }, | ||
445 | .out_num = 1, | ||
446 | .out_sizes = { UINT_MAX, }, | ||
447 | }, | ||
442 | }; | 448 | }; |
443 | 449 | ||
444 | const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd) | 450 | const struct nd_cmd_desc *nd_cmd_dimm_desc(int cmd) |
@@ -473,6 +479,12 @@ static const struct nd_cmd_desc __nd_cmd_bus_descs[] = { | |||
473 | .out_num = 3, | 479 | .out_num = 3, |
474 | .out_sizes = { 4, 4, 8, }, | 480 | .out_sizes = { 4, 4, 8, }, |
475 | }, | 481 | }, |
482 | [ND_CMD_CALL] = { | ||
483 | .in_num = 2, | ||
484 | .in_sizes = { sizeof(struct nd_cmd_pkg), UINT_MAX, }, | ||
485 | .out_num = 1, | ||
486 | .out_sizes = { UINT_MAX, }, | ||
487 | }, | ||
476 | }; | 488 | }; |
477 | 489 | ||
478 | const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd) | 490 | const struct nd_cmd_desc *nd_cmd_bus_desc(int cmd) |
@@ -500,6 +512,10 @@ u32 nd_cmd_in_size(struct nvdimm *nvdimm, int cmd, | |||
500 | struct nd_cmd_vendor_hdr *hdr = buf; | 512 | struct nd_cmd_vendor_hdr *hdr = buf; |
501 | 513 | ||
502 | return hdr->in_length; | 514 | return hdr->in_length; |
515 | } else if (cmd == ND_CMD_CALL) { | ||
516 | struct nd_cmd_pkg *pkg = buf; | ||
517 | |||
518 | return pkg->nd_size_in; | ||
503 | } | 519 | } |
504 | 520 | ||
505 | return UINT_MAX; | 521 | return UINT_MAX; |
@@ -522,6 +538,12 @@ u32 nd_cmd_out_size(struct nvdimm *nvdimm, int cmd, | |||
522 | return out_field[1]; | 538 | return out_field[1]; |
523 | else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2) | 539 | else if (!nvdimm && cmd == ND_CMD_ARS_STATUS && idx == 2) |
524 | return out_field[1] - 8; | 540 | return out_field[1] - 8; |
541 | else if (cmd == ND_CMD_CALL) { | ||
542 | struct nd_cmd_pkg *pkg = (struct nd_cmd_pkg *) in_field; | ||
543 | |||
544 | return pkg->nd_size_out; | ||
545 | } | ||
546 | |||
525 | 547 | ||
526 | return UINT_MAX; | 548 | return UINT_MAX; |
527 | } | 549 | } |
@@ -588,6 +610,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
588 | unsigned int cmd = _IOC_NR(ioctl_cmd); | 610 | unsigned int cmd = _IOC_NR(ioctl_cmd); |
589 | void __user *p = (void __user *) arg; | 611 | void __user *p = (void __user *) arg; |
590 | struct device *dev = &nvdimm_bus->dev; | 612 | struct device *dev = &nvdimm_bus->dev; |
613 | struct nd_cmd_pkg pkg; | ||
591 | const char *cmd_name, *dimm_name; | 614 | const char *cmd_name, *dimm_name; |
592 | unsigned long cmd_mask; | 615 | unsigned long cmd_mask; |
593 | void *buf; | 616 | void *buf; |
@@ -605,6 +628,11 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
605 | dimm_name = "bus"; | 628 | dimm_name = "bus"; |
606 | } | 629 | } |
607 | 630 | ||
631 | if (cmd == ND_CMD_CALL) { | ||
632 | if (copy_from_user(&pkg, p, sizeof(pkg))) | ||
633 | return -EFAULT; | ||
634 | } | ||
635 | |||
608 | if (!desc || (desc->out_num + desc->in_num == 0) || | 636 | if (!desc || (desc->out_num + desc->in_num == 0) || |
609 | !test_bit(cmd, &cmd_mask)) | 637 | !test_bit(cmd, &cmd_mask)) |
610 | return -ENOTTY; | 638 | return -ENOTTY; |
@@ -616,6 +644,7 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
616 | case ND_CMD_SET_CONFIG_DATA: | 644 | case ND_CMD_SET_CONFIG_DATA: |
617 | case ND_CMD_ARS_START: | 645 | case ND_CMD_ARS_START: |
618 | case ND_CMD_CLEAR_ERROR: | 646 | case ND_CMD_CLEAR_ERROR: |
647 | case ND_CMD_CALL: | ||
619 | dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n", | 648 | dev_dbg(&nvdimm_bus->dev, "'%s' command while read-only.\n", |
620 | nvdimm ? nvdimm_cmd_name(cmd) | 649 | nvdimm ? nvdimm_cmd_name(cmd) |
621 | : nvdimm_bus_cmd_name(cmd)); | 650 | : nvdimm_bus_cmd_name(cmd)); |
@@ -643,6 +672,16 @@ static int __nd_ioctl(struct nvdimm_bus *nvdimm_bus, struct nvdimm *nvdimm, | |||
643 | in_len += in_size; | 672 | in_len += in_size; |
644 | } | 673 | } |
645 | 674 | ||
675 | if (cmd == ND_CMD_CALL) { | ||
676 | dev_dbg(dev, "%s:%s, idx: %llu, in: %zu, out: %zu, len %zu\n", | ||
677 | __func__, dimm_name, pkg.nd_command, | ||
678 | in_len, out_len, buf_len); | ||
679 | |||
680 | for (i = 0; i < ARRAY_SIZE(pkg.nd_reserved2); i++) | ||
681 | if (pkg.nd_reserved2[i]) | ||
682 | return -EINVAL; | ||
683 | } | ||
684 | |||
646 | /* process an output envelope */ | 685 | /* process an output envelope */ |
647 | for (i = 0; i < desc->out_num; i++) { | 686 | for (i = 0; i < desc->out_num; i++) { |
648 | u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, | 687 | u32 out_size = nd_cmd_out_size(nvdimm, cmd, desc, i, |