diff options
author | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2011-02-01 16:13:29 -0500 |
---|---|---|
committer | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2011-11-04 15:52:53 -0400 |
commit | a53295b6998f62d961c29e54051c1cf1d738c2b3 (patch) | |
tree | 835a6f4ecbb8de47c232d7a1c5b4f76292d4dc24 /drivers/block/nvme.c | |
parent | 7fc3cdabba75c2516b8b645eb0ca7907aea70415 (diff) |
NVMe: Add NVME_IOCTL_SUBMIT_IO
Allow userspace to submit synchronous I/O like the SCSI sg interface does.
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block/nvme.c')
-rw-r--r-- | drivers/block/nvme.c | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c index f44d6cd87ea2..40fb2e1bdfe4 100644 --- a/drivers/block/nvme.c +++ b/drivers/block/nvme.c | |||
@@ -780,6 +780,47 @@ static int nvme_get_range_type(struct nvme_ns *ns, unsigned long addr) | |||
780 | return nvme_submit_user_admin_command(ns->dev, addr, 4096, &c); | 780 | return nvme_submit_user_admin_command(ns->dev, addr, 4096, &c); |
781 | } | 781 | } |
782 | 782 | ||
783 | static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) | ||
784 | { | ||
785 | struct nvme_dev *dev = ns->dev; | ||
786 | struct nvme_queue *nvmeq; | ||
787 | struct nvme_user_io io; | ||
788 | struct nvme_command c; | ||
789 | unsigned length; | ||
790 | u32 result; | ||
791 | int nents, status; | ||
792 | struct scatterlist *sg; | ||
793 | |||
794 | if (copy_from_user(&io, uio, sizeof(io))) | ||
795 | return -EFAULT; | ||
796 | length = io.nblocks << io.block_shift; | ||
797 | nents = nvme_map_user_pages(dev, io.opcode & 1, io.addr, length, &sg); | ||
798 | if (nents < 0) | ||
799 | return nents; | ||
800 | |||
801 | memset(&c, 0, sizeof(c)); | ||
802 | c.rw.opcode = io.opcode; | ||
803 | c.rw.flags = io.flags; | ||
804 | c.rw.nsid = cpu_to_le32(io.nsid); | ||
805 | c.rw.slba = cpu_to_le64(io.slba); | ||
806 | c.rw.length = cpu_to_le16(io.nblocks - 1); | ||
807 | c.rw.control = cpu_to_le16(io.control); | ||
808 | c.rw.dsmgmt = cpu_to_le16(io.dsmgmt); | ||
809 | c.rw.reftag = cpu_to_le32(io.reftag); /* XXX: endian? */ | ||
810 | c.rw.apptag = cpu_to_le16(io.apptag); | ||
811 | c.rw.appmask = cpu_to_le16(io.appmask); | ||
812 | /* XXX: metadata */ | ||
813 | nvme_setup_prps(&c.common, sg, length); | ||
814 | |||
815 | nvmeq = get_nvmeq(ns); | ||
816 | status = nvme_submit_sync_cmd(nvmeq, &c, &result); | ||
817 | put_nvmeq(nvmeq); | ||
818 | |||
819 | nvme_unmap_user_pages(dev, io.opcode & 1, io.addr, length, sg, nents); | ||
820 | put_user(result, &uio->result); | ||
821 | return status; | ||
822 | } | ||
823 | |||
783 | static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, | 824 | static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, |
784 | unsigned long arg) | 825 | unsigned long arg) |
785 | { | 826 | { |
@@ -792,6 +833,8 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, | |||
792 | return nvme_identify(ns, arg, 1); | 833 | return nvme_identify(ns, arg, 1); |
793 | case NVME_IOCTL_GET_RANGE_TYPE: | 834 | case NVME_IOCTL_GET_RANGE_TYPE: |
794 | return nvme_get_range_type(ns, arg); | 835 | return nvme_get_range_type(ns, arg); |
836 | case NVME_IOCTL_SUBMIT_IO: | ||
837 | return nvme_submit_io(ns, (void __user *)arg); | ||
795 | default: | 838 | default: |
796 | return -ENOTTY; | 839 | return -ENOTTY; |
797 | } | 840 | } |