diff options
| author | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2011-02-03 10:58:26 -0500 |
|---|---|---|
| committer | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2011-11-04 15:52:54 -0400 |
| commit | 6ee44cdced04a53dc4f27eb97067e6cd33784726 (patch) | |
| tree | 1f018425a216da0a58c7f36b830925fbb9aa41a7 | |
| parent | 7a63e07b9a98b77dd075e06b93c1d8dc871ddad5 (diff) | |
NVMe: Add download / activate firmware ioctls
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
| -rw-r--r-- | drivers/block/nvme.c | 45 | ||||
| -rw-r--r-- | include/linux/nvme.h | 33 |
2 files changed, 72 insertions, 6 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c index 744db3877c42..7cdf7f69cdcd 100644 --- a/drivers/block/nvme.c +++ b/drivers/block/nvme.c | |||
| @@ -829,6 +829,47 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) | |||
| 829 | return status; | 829 | return status; |
| 830 | } | 830 | } |
| 831 | 831 | ||
| 832 | static int nvme_download_firmware(struct nvme_ns *ns, | ||
| 833 | struct nvme_dlfw __user *udlfw) | ||
| 834 | { | ||
| 835 | struct nvme_dev *dev = ns->dev; | ||
| 836 | struct nvme_dlfw dlfw; | ||
| 837 | struct nvme_command c; | ||
| 838 | int nents, status; | ||
| 839 | struct scatterlist *sg; | ||
| 840 | |||
| 841 | if (copy_from_user(&dlfw, udlfw, sizeof(dlfw))) | ||
| 842 | return -EFAULT; | ||
| 843 | if (dlfw.length >= (1 << 30)) | ||
| 844 | return -EINVAL; | ||
| 845 | |||
| 846 | nents = nvme_map_user_pages(dev, 1, dlfw.addr, dlfw.length * 4, &sg); | ||
| 847 | if (nents < 0) | ||
| 848 | return nents; | ||
| 849 | |||
| 850 | memset(&c, 0, sizeof(c)); | ||
| 851 | c.dlfw.opcode = nvme_admin_download_fw; | ||
| 852 | c.dlfw.numd = cpu_to_le32(dlfw.length); | ||
| 853 | c.dlfw.offset = cpu_to_le32(dlfw.offset); | ||
| 854 | nvme_setup_prps(&c.common, sg, dlfw.length * 4); | ||
| 855 | |||
| 856 | status = nvme_submit_admin_cmd(dev, &c, NULL); | ||
| 857 | nvme_unmap_user_pages(dev, 0, dlfw.addr, dlfw.length * 4, sg, nents); | ||
| 858 | return status; | ||
| 859 | } | ||
| 860 | |||
| 861 | static int nvme_activate_firmware(struct nvme_ns *ns, unsigned long arg) | ||
| 862 | { | ||
| 863 | struct nvme_dev *dev = ns->dev; | ||
| 864 | struct nvme_command c; | ||
| 865 | |||
| 866 | memset(&c, 0, sizeof(c)); | ||
| 867 | c.common.opcode = nvme_admin_activate_fw; | ||
| 868 | c.common.rsvd10[0] = cpu_to_le32(arg); | ||
| 869 | |||
| 870 | return nvme_submit_admin_cmd(dev, &c, NULL); | ||
| 871 | } | ||
| 872 | |||
| 832 | static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, | 873 | static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, |
| 833 | unsigned long arg) | 874 | unsigned long arg) |
| 834 | { | 875 | { |
| @@ -843,6 +884,10 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, | |||
| 843 | return nvme_get_range_type(ns, arg); | 884 | return nvme_get_range_type(ns, arg); |
| 844 | case NVME_IOCTL_SUBMIT_IO: | 885 | case NVME_IOCTL_SUBMIT_IO: |
| 845 | return nvme_submit_io(ns, (void __user *)arg); | 886 | return nvme_submit_io(ns, (void __user *)arg); |
| 887 | case NVME_IOCTL_DOWNLOAD_FW: | ||
| 888 | return nvme_download_firmware(ns, (void __user *)arg); | ||
| 889 | case NVME_IOCTL_ACTIVATE_FW: | ||
| 890 | return nvme_activate_firmware(ns, arg); | ||
| 846 | default: | 891 | default: |
| 847 | return -ENOTTY; | 892 | return -ENOTTY; |
| 848 | } | 893 | } |
diff --git a/include/linux/nvme.h b/include/linux/nvme.h index dbbdc126401b..8eed0e432eef 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h | |||
| @@ -262,7 +262,7 @@ struct nvme_create_cq { | |||
| 262 | __u8 opcode; | 262 | __u8 opcode; |
| 263 | __u8 flags; | 263 | __u8 flags; |
| 264 | __u16 command_id; | 264 | __u16 command_id; |
| 265 | __le32 rsvd1[5]; | 265 | __u32 rsvd1[5]; |
| 266 | __le64 prp1; | 266 | __le64 prp1; |
| 267 | __u64 rsvd8; | 267 | __u64 rsvd8; |
| 268 | __le16 cqid; | 268 | __le16 cqid; |
| @@ -276,14 +276,14 @@ struct nvme_create_sq { | |||
| 276 | __u8 opcode; | 276 | __u8 opcode; |
| 277 | __u8 flags; | 277 | __u8 flags; |
| 278 | __u16 command_id; | 278 | __u16 command_id; |
| 279 | __le32 rsvd1[5]; | 279 | __u32 rsvd1[5]; |
| 280 | __le64 prp1; | 280 | __le64 prp1; |
| 281 | __u64 rsvd8; | 281 | __u64 rsvd8; |
| 282 | __le16 sqid; | 282 | __le16 sqid; |
| 283 | __le16 qsize; | 283 | __le16 qsize; |
| 284 | __le16 sq_flags; | 284 | __le16 sq_flags; |
| 285 | __le16 cqid; | 285 | __le16 cqid; |
| 286 | __le32 rsvd12[4]; | 286 | __u32 rsvd12[4]; |
| 287 | }; | 287 | }; |
| 288 | 288 | ||
| 289 | struct nvme_delete_queue { | 289 | struct nvme_delete_queue { |
| @@ -292,8 +292,20 @@ struct nvme_delete_queue { | |||
| 292 | __u16 command_id; | 292 | __u16 command_id; |
| 293 | __u32 rsvd1[9]; | 293 | __u32 rsvd1[9]; |
| 294 | __le16 qid; | 294 | __le16 qid; |
| 295 | __le16 rsvd10; | 295 | __u16 rsvd10; |
| 296 | __le32 rsvd11[5]; | 296 | __u32 rsvd11[5]; |
| 297 | }; | ||
| 298 | |||
| 299 | struct nvme_download_firmware { | ||
| 300 | __u8 opcode; | ||
| 301 | __u8 flags; | ||
| 302 | __u16 command_id; | ||
| 303 | __u32 rsvd1[5]; | ||
| 304 | __le64 prp1; | ||
| 305 | __le64 prp2; | ||
| 306 | __le32 numd; | ||
| 307 | __le32 offset; | ||
| 308 | __u32 rsvd12[4]; | ||
| 297 | }; | 309 | }; |
| 298 | 310 | ||
| 299 | struct nvme_command { | 311 | struct nvme_command { |
| @@ -305,6 +317,7 @@ struct nvme_command { | |||
| 305 | struct nvme_create_cq create_cq; | 317 | struct nvme_create_cq create_cq; |
| 306 | struct nvme_create_sq create_sq; | 318 | struct nvme_create_sq create_sq; |
| 307 | struct nvme_delete_queue delete_queue; | 319 | struct nvme_delete_queue delete_queue; |
| 320 | struct nvme_download_firmware dlfw; | ||
| 308 | }; | 321 | }; |
| 309 | }; | 322 | }; |
| 310 | 323 | ||
| @@ -348,7 +361,7 @@ enum { | |||
| 348 | 361 | ||
| 349 | struct nvme_completion { | 362 | struct nvme_completion { |
| 350 | __le32 result; /* Used by admin commands to return data */ | 363 | __le32 result; /* Used by admin commands to return data */ |
| 351 | __le32 rsvd; | 364 | __u32 rsvd; |
| 352 | __le16 sq_head; /* how much of this queue may be reclaimed */ | 365 | __le16 sq_head; /* how much of this queue may be reclaimed */ |
| 353 | __le16 sq_id; /* submission queue that generated this entry */ | 366 | __le16 sq_id; /* submission queue that generated this entry */ |
| 354 | __u16 command_id; /* of the command which completed */ | 367 | __u16 command_id; /* of the command which completed */ |
| @@ -372,9 +385,17 @@ struct nvme_user_io { | |||
| 372 | __u32 result; | 385 | __u32 result; |
| 373 | }; | 386 | }; |
| 374 | 387 | ||
| 388 | struct nvme_dlfw { | ||
| 389 | __u64 addr; | ||
| 390 | __u32 length; /* In dwords */ | ||
| 391 | __u32 offset; /* In dwords */ | ||
| 392 | }; | ||
| 393 | |||
| 375 | #define NVME_IOCTL_IDENTIFY_NS _IOW('N', 0x40, struct nvme_id_ns) | 394 | #define NVME_IOCTL_IDENTIFY_NS _IOW('N', 0x40, struct nvme_id_ns) |
| 376 | #define NVME_IOCTL_IDENTIFY_CTRL _IOW('N', 0x41, struct nvme_id_ctrl) | 395 | #define NVME_IOCTL_IDENTIFY_CTRL _IOW('N', 0x41, struct nvme_id_ctrl) |
| 377 | #define NVME_IOCTL_GET_RANGE_TYPE _IOW('N', 0x42, struct nvme_lba_range_type) | 396 | #define NVME_IOCTL_GET_RANGE_TYPE _IOW('N', 0x42, struct nvme_lba_range_type) |
| 378 | #define NVME_IOCTL_SUBMIT_IO _IOWR('N', 0x43, struct nvme_rw_command) | 397 | #define NVME_IOCTL_SUBMIT_IO _IOWR('N', 0x43, struct nvme_rw_command) |
| 398 | #define NVME_IOCTL_DOWNLOAD_FW _IOR('N', 0x44, struct nvme_dlfw) | ||
| 399 | #define NVME_IOCTL_ACTIVATE_FW _IO('N', 0x45) | ||
| 379 | 400 | ||
| 380 | #endif /* _LINUX_NVME_H */ | 401 | #endif /* _LINUX_NVME_H */ |
