aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew.r.wilcox@intel.com>2011-05-20 13:03:42 -0400
committerMatthew Wilcox <matthew.r.wilcox@intel.com>2011-11-04 15:53:03 -0400
commit6bbf1acddeed0bfb345a5578f9fcada16f1e514f (patch)
tree965663c2a38ff10bc88fb2096fc0adbef500b11d /drivers/block
parenteac623ba7a91474a688eb5d0fcd0eaa6a56dc41c (diff)
NVMe: Rework ioctls
Remove the special-purpose IDENTIFY, GET_RANGE_TYPE, DOWNLOAD_FIRMWARE and ACTIVATE_FIRMWARE commands. Replace them with a generic ADMIN_CMD ioctl that can submit any admin command. Add a new ID ioctl that returns the namespace ID of the queried device. It corresponds to the SCSI Idlun ioctl. Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/nvme.c128
1 files changed, 40 insertions, 88 deletions
diff --git a/drivers/block/nvme.c b/drivers/block/nvme.c
index f5e51a6116e..9e3c724b95c 100644
--- a/drivers/block/nvme.c
+++ b/drivers/block/nvme.c
@@ -1033,51 +1033,6 @@ static void nvme_unmap_user_pages(struct nvme_dev *dev, int write,
1033 put_page(sg_page(&sg[i])); 1033 put_page(sg_page(&sg[i]));
1034} 1034}
1035 1035
1036static int nvme_submit_user_admin_command(struct nvme_dev *dev,
1037 unsigned long addr, unsigned length,
1038 struct nvme_command *cmd)
1039{
1040 int err, nents, tmplen = length;
1041 struct scatterlist *sg;
1042 struct nvme_prps *prps;
1043
1044 nents = nvme_map_user_pages(dev, 0, addr, length, &sg);
1045 if (nents < 0)
1046 return nents;
1047 prps = nvme_setup_prps(dev, &cmd->common, sg, &tmplen, GFP_KERNEL);
1048 if (tmplen != length)
1049 err = -ENOMEM;
1050 else
1051 err = nvme_submit_admin_cmd(dev, cmd, NULL);
1052 nvme_unmap_user_pages(dev, 0, addr, length, sg, nents);
1053 nvme_free_prps(dev, prps);
1054 return err ? -EIO : 0;
1055}
1056
1057static int nvme_identify(struct nvme_ns *ns, unsigned long addr, int cns)
1058{
1059 struct nvme_command c;
1060
1061 memset(&c, 0, sizeof(c));
1062 c.identify.opcode = nvme_admin_identify;
1063 c.identify.nsid = cns ? 0 : cpu_to_le32(ns->ns_id);
1064 c.identify.cns = cpu_to_le32(cns);
1065
1066 return nvme_submit_user_admin_command(ns->dev, addr, 4096, &c);
1067}
1068
1069static int nvme_get_range_type(struct nvme_ns *ns, unsigned long addr)
1070{
1071 struct nvme_command c;
1072
1073 memset(&c, 0, sizeof(c));
1074 c.features.opcode = nvme_admin_get_features;
1075 c.features.nsid = cpu_to_le32(ns->ns_id);
1076 c.features.fid = cpu_to_le32(NVME_FEAT_LBA_RANGE);
1077
1078 return nvme_submit_user_admin_command(ns->dev, addr, 4096, &c);
1079}
1080
1081static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio) 1036static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
1082{ 1037{
1083 struct nvme_dev *dev = ns->dev; 1038 struct nvme_dev *dev = ns->dev;
@@ -1096,10 +1051,11 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
1096 switch (io.opcode) { 1051 switch (io.opcode) {
1097 case nvme_cmd_write: 1052 case nvme_cmd_write:
1098 case nvme_cmd_read: 1053 case nvme_cmd_read:
1054 case nvme_cmd_compare:
1099 nents = nvme_map_user_pages(dev, io.opcode & 1, io.addr, 1055 nents = nvme_map_user_pages(dev, io.opcode & 1, io.addr,
1100 length, &sg); 1056 length, &sg);
1101 default: 1057 default:
1102 return -EFAULT; 1058 return -EINVAL;
1103 } 1059 }
1104 1060
1105 if (nents < 0) 1061 if (nents < 0)
@@ -1137,70 +1093,66 @@ static int nvme_submit_io(struct nvme_ns *ns, struct nvme_user_io __user *uio)
1137 return status; 1093 return status;
1138} 1094}
1139 1095
1140static int nvme_download_firmware(struct nvme_ns *ns, 1096static int nvme_user_admin_cmd(struct nvme_ns *ns,
1141 struct nvme_dlfw __user *udlfw) 1097 struct nvme_admin_cmd __user *ucmd)
1142{ 1098{
1143 struct nvme_dev *dev = ns->dev; 1099 struct nvme_dev *dev = ns->dev;
1144 struct nvme_dlfw dlfw; 1100 struct nvme_admin_cmd cmd;
1145 struct nvme_command c; 1101 struct nvme_command c;
1146 int nents, status, length; 1102 int status, length, nents = 0;
1147 struct scatterlist *sg; 1103 struct scatterlist *sg;
1148 struct nvme_prps *prps; 1104 struct nvme_prps *prps = NULL;
1149 1105
1150 if (copy_from_user(&dlfw, udlfw, sizeof(dlfw))) 1106 if (!capable(CAP_SYS_ADMIN))
1107 return -EACCES;
1108 if (copy_from_user(&cmd, ucmd, sizeof(cmd)))
1151 return -EFAULT; 1109 return -EFAULT;
1152 if (dlfw.length >= (1 << 30))
1153 return -EINVAL;
1154 length = dlfw.length * 4;
1155
1156 nents = nvme_map_user_pages(dev, 1, dlfw.addr, length, &sg);
1157 if (nents < 0)
1158 return nents;
1159 1110
1160 memset(&c, 0, sizeof(c)); 1111 memset(&c, 0, sizeof(c));
1161 c.dlfw.opcode = nvme_admin_download_fw; 1112 c.common.opcode = cmd.opcode;
1162 c.dlfw.numd = cpu_to_le32(dlfw.length); 1113 c.common.flags = cmd.flags;
1163 c.dlfw.offset = cpu_to_le32(dlfw.offset); 1114 c.common.nsid = cpu_to_le32(cmd.nsid);
1164 prps = nvme_setup_prps(dev, &c.common, sg, &length, GFP_KERNEL); 1115 c.common.cdw2[0] = cpu_to_le32(cmd.cdw2);
1165 if (length != dlfw.length * 4) 1116 c.common.cdw2[1] = cpu_to_le32(cmd.cdw3);
1117 c.common.cdw10[0] = cpu_to_le32(cmd.cdw10);
1118 c.common.cdw10[1] = cpu_to_le32(cmd.cdw11);
1119 c.common.cdw10[2] = cpu_to_le32(cmd.cdw12);
1120 c.common.cdw10[3] = cpu_to_le32(cmd.cdw13);
1121 c.common.cdw10[4] = cpu_to_le32(cmd.cdw14);
1122 c.common.cdw10[5] = cpu_to_le32(cmd.cdw15);
1123
1124 length = cmd.data_len;
1125 if (cmd.data_len) {
1126 nents = nvme_map_user_pages(dev, 1, cmd.addr, length, &sg);
1127 if (nents < 0)
1128 return nents;
1129 prps = nvme_setup_prps(dev, &c.common, sg, &length, GFP_KERNEL);
1130 }
1131
1132 if (length != cmd.data_len)
1166 status = -ENOMEM; 1133 status = -ENOMEM;
1167 else 1134 else
1168 status = nvme_submit_admin_cmd(dev, &c, NULL); 1135 status = nvme_submit_admin_cmd(dev, &c, NULL);
1169 nvme_unmap_user_pages(dev, 0, dlfw.addr, dlfw.length * 4, sg, nents); 1136 if (cmd.data_len) {
1170 nvme_free_prps(dev, prps); 1137 nvme_unmap_user_pages(dev, 0, cmd.addr, cmd.data_len, sg,
1138 nents);
1139 nvme_free_prps(dev, prps);
1140 }
1171 return status; 1141 return status;
1172} 1142}
1173 1143
1174static int nvme_activate_firmware(struct nvme_ns *ns, unsigned long arg)
1175{
1176 struct nvme_dev *dev = ns->dev;
1177 struct nvme_command c;
1178
1179 memset(&c, 0, sizeof(c));
1180 c.common.opcode = nvme_admin_activate_fw;
1181 c.common.rsvd10[0] = cpu_to_le32(arg);
1182
1183 return nvme_submit_admin_cmd(dev, &c, NULL);
1184}
1185
1186static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, 1144static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
1187 unsigned long arg) 1145 unsigned long arg)
1188{ 1146{
1189 struct nvme_ns *ns = bdev->bd_disk->private_data; 1147 struct nvme_ns *ns = bdev->bd_disk->private_data;
1190 1148
1191 switch (cmd) { 1149 switch (cmd) {
1192 case NVME_IOCTL_IDENTIFY_NS: 1150 case NVME_IOCTL_ID:
1193 return nvme_identify(ns, arg, 0); 1151 return ns->ns_id;
1194 case NVME_IOCTL_IDENTIFY_CTRL: 1152 case NVME_IOCTL_ADMIN_CMD:
1195 return nvme_identify(ns, arg, 1); 1153 return nvme_user_admin_cmd(ns, (void __user *)arg);
1196 case NVME_IOCTL_GET_RANGE_TYPE:
1197 return nvme_get_range_type(ns, arg);
1198 case NVME_IOCTL_SUBMIT_IO: 1154 case NVME_IOCTL_SUBMIT_IO:
1199 return nvme_submit_io(ns, (void __user *)arg); 1155 return nvme_submit_io(ns, (void __user *)arg);
1200 case NVME_IOCTL_DOWNLOAD_FW:
1201 return nvme_download_firmware(ns, (void __user *)arg);
1202 case NVME_IOCTL_ACTIVATE_FW:
1203 return nvme_activate_firmware(ns, arg);
1204 default: 1156 default:
1205 return -ENOTTY; 1157 return -ENOTTY;
1206 } 1158 }