Loading drivers/block/nvme.c +45 −0 Original line number Diff line number Diff line Loading @@ -829,6 +829,47 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) return status; } static int nvme_download_firmware(struct nvme_ns *ns, struct nvme_dlfw __user *udlfw) { struct nvme_dev *dev = ns->dev; struct nvme_dlfw dlfw; struct nvme_command c; int nents, status; struct scatterlist *sg; if (copy_from_user(&dlfw, udlfw, sizeof(dlfw))) return -EFAULT; if (dlfw.length >= (1 << 30)) return -EINVAL; nents = nvme_map_user_pages(dev, 1, dlfw.addr, dlfw.length * 4, &sg); if (nents < 0) return nents; memset(&c, 0, sizeof(c)); c.dlfw.opcode = nvme_admin_download_fw; c.dlfw.numd = cpu_to_le32(dlfw.length); c.dlfw.offset = cpu_to_le32(dlfw.offset); nvme_setup_prps(&c.common, sg, dlfw.length * 4); status = nvme_submit_admin_cmd(dev, &c, NULL); nvme_unmap_user_pages(dev, 0, dlfw.addr, dlfw.length * 4, sg, nents); return status; } static int nvme_activate_firmware(struct nvme_ns *ns, unsigned long arg) { struct nvme_dev *dev = ns->dev; struct nvme_command c; memset(&c, 0, sizeof(c)); c.common.opcode = nvme_admin_activate_fw; c.common.rsvd10[0] = cpu_to_le32(arg); return nvme_submit_admin_cmd(dev, &c, NULL); } static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { Loading @@ -843,6 +884,10 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, return nvme_get_range_type(ns, arg); case NVME_IOCTL_SUBMIT_IO: return nvme_submit_io(ns, (void __user *)arg); case NVME_IOCTL_DOWNLOAD_FW: return nvme_download_firmware(ns, (void __user *)arg); case NVME_IOCTL_ACTIVATE_FW: return nvme_activate_firmware(ns, arg); default: return -ENOTTY; } Loading include/linux/nvme.h +27 −6 Original line number Diff line number Diff line Loading @@ -262,7 +262,7 @@ struct nvme_create_cq { __u8 opcode; __u8 flags; __u16 command_id; __le32 rsvd1[5]; __u32 rsvd1[5]; __le64 prp1; __u64 rsvd8; __le16 cqid; Loading @@ -276,14 +276,14 @@ struct nvme_create_sq { __u8 opcode; __u8 flags; __u16 command_id; __le32 rsvd1[5]; __u32 rsvd1[5]; __le64 prp1; __u64 rsvd8; __le16 sqid; __le16 qsize; __le16 sq_flags; __le16 cqid; __le32 rsvd12[4]; __u32 rsvd12[4]; }; struct nvme_delete_queue { Loading @@ -292,8 +292,20 @@ struct nvme_delete_queue { __u16 command_id; __u32 rsvd1[9]; __le16 qid; __le16 rsvd10; __le32 rsvd11[5]; __u16 rsvd10; __u32 rsvd11[5]; }; struct nvme_download_firmware { __u8 opcode; __u8 flags; __u16 command_id; __u32 rsvd1[5]; __le64 prp1; __le64 prp2; __le32 numd; __le32 offset; __u32 rsvd12[4]; }; struct nvme_command { Loading @@ -305,6 +317,7 @@ struct nvme_command { struct nvme_create_cq create_cq; struct nvme_create_sq create_sq; struct nvme_delete_queue delete_queue; struct nvme_download_firmware dlfw; }; }; Loading Loading @@ -348,7 +361,7 @@ enum { struct nvme_completion { __le32 result; /* Used by admin commands to return data */ __le32 rsvd; __u32 rsvd; __le16 sq_head; /* how much of this queue may be reclaimed */ __le16 sq_id; /* submission queue that generated this entry */ __u16 command_id; /* of the command which completed */ Loading @@ -372,9 +385,17 @@ struct nvme_user_io { __u32 result; }; struct nvme_dlfw { __u64 addr; __u32 length; /* In dwords */ __u32 offset; /* In dwords */ }; #define NVME_IOCTL_IDENTIFY_NS _IOW('N', 0x40, struct nvme_id_ns) #define NVME_IOCTL_IDENTIFY_CTRL _IOW('N', 0x41, struct nvme_id_ctrl) #define NVME_IOCTL_GET_RANGE_TYPE _IOW('N', 0x42, struct nvme_lba_range_type) #define NVME_IOCTL_SUBMIT_IO _IOWR('N', 0x43, struct nvme_rw_command) #define NVME_IOCTL_DOWNLOAD_FW _IOR('N', 0x44, struct nvme_dlfw) #define NVME_IOCTL_ACTIVATE_FW _IO('N', 0x45) #endif /* _LINUX_NVME_H */ Loading
drivers/block/nvme.c +45 −0 Original line number Diff line number Diff line Loading @@ -829,6 +829,47 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) return status; } static int nvme_download_firmware(struct nvme_ns *ns, struct nvme_dlfw __user *udlfw) { struct nvme_dev *dev = ns->dev; struct nvme_dlfw dlfw; struct nvme_command c; int nents, status; struct scatterlist *sg; if (copy_from_user(&dlfw, udlfw, sizeof(dlfw))) return -EFAULT; if (dlfw.length >= (1 << 30)) return -EINVAL; nents = nvme_map_user_pages(dev, 1, dlfw.addr, dlfw.length * 4, &sg); if (nents < 0) return nents; memset(&c, 0, sizeof(c)); c.dlfw.opcode = nvme_admin_download_fw; c.dlfw.numd = cpu_to_le32(dlfw.length); c.dlfw.offset = cpu_to_le32(dlfw.offset); nvme_setup_prps(&c.common, sg, dlfw.length * 4); status = nvme_submit_admin_cmd(dev, &c, NULL); nvme_unmap_user_pages(dev, 0, dlfw.addr, dlfw.length * 4, sg, nents); return status; } static int nvme_activate_firmware(struct nvme_ns *ns, unsigned long arg) { struct nvme_dev *dev = ns->dev; struct nvme_command c; memset(&c, 0, sizeof(c)); c.common.opcode = nvme_admin_activate_fw; c.common.rsvd10[0] = cpu_to_le32(arg); return nvme_submit_admin_cmd(dev, &c, NULL); } static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long arg) { Loading @@ -843,6 +884,10 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, return nvme_get_range_type(ns, arg); case NVME_IOCTL_SUBMIT_IO: return nvme_submit_io(ns, (void __user *)arg); case NVME_IOCTL_DOWNLOAD_FW: return nvme_download_firmware(ns, (void __user *)arg); case NVME_IOCTL_ACTIVATE_FW: return nvme_activate_firmware(ns, arg); default: return -ENOTTY; } Loading
include/linux/nvme.h +27 −6 Original line number Diff line number Diff line Loading @@ -262,7 +262,7 @@ struct nvme_create_cq { __u8 opcode; __u8 flags; __u16 command_id; __le32 rsvd1[5]; __u32 rsvd1[5]; __le64 prp1; __u64 rsvd8; __le16 cqid; Loading @@ -276,14 +276,14 @@ struct nvme_create_sq { __u8 opcode; __u8 flags; __u16 command_id; __le32 rsvd1[5]; __u32 rsvd1[5]; __le64 prp1; __u64 rsvd8; __le16 sqid; __le16 qsize; __le16 sq_flags; __le16 cqid; __le32 rsvd12[4]; __u32 rsvd12[4]; }; struct nvme_delete_queue { Loading @@ -292,8 +292,20 @@ struct nvme_delete_queue { __u16 command_id; __u32 rsvd1[9]; __le16 qid; __le16 rsvd10; __le32 rsvd11[5]; __u16 rsvd10; __u32 rsvd11[5]; }; struct nvme_download_firmware { __u8 opcode; __u8 flags; __u16 command_id; __u32 rsvd1[5]; __le64 prp1; __le64 prp2; __le32 numd; __le32 offset; __u32 rsvd12[4]; }; struct nvme_command { Loading @@ -305,6 +317,7 @@ struct nvme_command { struct nvme_create_cq create_cq; struct nvme_create_sq create_sq; struct nvme_delete_queue delete_queue; struct nvme_download_firmware dlfw; }; }; Loading Loading @@ -348,7 +361,7 @@ enum { struct nvme_completion { __le32 result; /* Used by admin commands to return data */ __le32 rsvd; __u32 rsvd; __le16 sq_head; /* how much of this queue may be reclaimed */ __le16 sq_id; /* submission queue that generated this entry */ __u16 command_id; /* of the command which completed */ Loading @@ -372,9 +385,17 @@ struct nvme_user_io { __u32 result; }; struct nvme_dlfw { __u64 addr; __u32 length; /* In dwords */ __u32 offset; /* In dwords */ }; #define NVME_IOCTL_IDENTIFY_NS _IOW('N', 0x40, struct nvme_id_ns) #define NVME_IOCTL_IDENTIFY_CTRL _IOW('N', 0x41, struct nvme_id_ctrl) #define NVME_IOCTL_GET_RANGE_TYPE _IOW('N', 0x42, struct nvme_lba_range_type) #define NVME_IOCTL_SUBMIT_IO _IOWR('N', 0x43, struct nvme_rw_command) #define NVME_IOCTL_DOWNLOAD_FW _IOR('N', 0x44, struct nvme_dlfw) #define NVME_IOCTL_ACTIVATE_FW _IO('N', 0x45) #endif /* _LINUX_NVME_H */