0001
0002
0003
0004
0005
0006 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0007 #include <linux/blkdev.h>
0008 #include "nvmet.h"
0009
0010 static void nvmet_execute_prop_set(struct nvmet_req *req)
0011 {
0012 u64 val = le64_to_cpu(req->cmd->prop_set.value);
0013 u16 status = 0;
0014
0015 if (!nvmet_check_transfer_len(req, 0))
0016 return;
0017
0018 if (req->cmd->prop_set.attrib & 1) {
0019 req->error_loc =
0020 offsetof(struct nvmf_property_set_command, attrib);
0021 status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
0022 goto out;
0023 }
0024
0025 switch (le32_to_cpu(req->cmd->prop_set.offset)) {
0026 case NVME_REG_CC:
0027 nvmet_update_cc(req->sq->ctrl, val);
0028 break;
0029 default:
0030 req->error_loc =
0031 offsetof(struct nvmf_property_set_command, offset);
0032 status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
0033 }
0034 out:
0035 nvmet_req_complete(req, status);
0036 }
0037
0038 static void nvmet_execute_prop_get(struct nvmet_req *req)
0039 {
0040 struct nvmet_ctrl *ctrl = req->sq->ctrl;
0041 u16 status = 0;
0042 u64 val = 0;
0043
0044 if (!nvmet_check_transfer_len(req, 0))
0045 return;
0046
0047 if (req->cmd->prop_get.attrib & 1) {
0048 switch (le32_to_cpu(req->cmd->prop_get.offset)) {
0049 case NVME_REG_CAP:
0050 val = ctrl->cap;
0051 break;
0052 default:
0053 status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
0054 break;
0055 }
0056 } else {
0057 switch (le32_to_cpu(req->cmd->prop_get.offset)) {
0058 case NVME_REG_VS:
0059 val = ctrl->subsys->ver;
0060 break;
0061 case NVME_REG_CC:
0062 val = ctrl->cc;
0063 break;
0064 case NVME_REG_CSTS:
0065 val = ctrl->csts;
0066 break;
0067 default:
0068 status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
0069 break;
0070 }
0071 }
0072
0073 if (status && req->cmd->prop_get.attrib & 1) {
0074 req->error_loc =
0075 offsetof(struct nvmf_property_get_command, offset);
0076 } else {
0077 req->error_loc =
0078 offsetof(struct nvmf_property_get_command, attrib);
0079 }
0080
0081 req->cqe->result.u64 = cpu_to_le64(val);
0082 nvmet_req_complete(req, status);
0083 }
0084
0085 u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req)
0086 {
0087 struct nvme_command *cmd = req->cmd;
0088
0089 switch (cmd->fabrics.fctype) {
0090 case nvme_fabrics_type_property_set:
0091 req->execute = nvmet_execute_prop_set;
0092 break;
0093 case nvme_fabrics_type_property_get:
0094 req->execute = nvmet_execute_prop_get;
0095 break;
0096 #ifdef CONFIG_NVME_TARGET_AUTH
0097 case nvme_fabrics_type_auth_send:
0098 req->execute = nvmet_execute_auth_send;
0099 break;
0100 case nvme_fabrics_type_auth_receive:
0101 req->execute = nvmet_execute_auth_receive;
0102 break;
0103 #endif
0104 default:
0105 pr_debug("received unknown capsule type 0x%x\n",
0106 cmd->fabrics.fctype);
0107 req->error_loc = offsetof(struct nvmf_common_command, fctype);
0108 return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
0109 }
0110
0111 return 0;
0112 }
0113
0114 u16 nvmet_parse_fabrics_io_cmd(struct nvmet_req *req)
0115 {
0116 struct nvme_command *cmd = req->cmd;
0117
0118 switch (cmd->fabrics.fctype) {
0119 #ifdef CONFIG_NVME_TARGET_AUTH
0120 case nvme_fabrics_type_auth_send:
0121 req->execute = nvmet_execute_auth_send;
0122 break;
0123 case nvme_fabrics_type_auth_receive:
0124 req->execute = nvmet_execute_auth_receive;
0125 break;
0126 #endif
0127 default:
0128 pr_debug("received unknown capsule type 0x%x\n",
0129 cmd->fabrics.fctype);
0130 req->error_loc = offsetof(struct nvmf_common_command, fctype);
0131 return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
0132 }
0133
0134 return 0;
0135 }
0136
0137 static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
0138 {
0139 struct nvmf_connect_command *c = &req->cmd->connect;
0140 u16 qid = le16_to_cpu(c->qid);
0141 u16 sqsize = le16_to_cpu(c->sqsize);
0142 struct nvmet_ctrl *old;
0143 u16 mqes = NVME_CAP_MQES(ctrl->cap);
0144 u16 ret;
0145
0146 if (!sqsize) {
0147 pr_warn("queue size zero!\n");
0148 req->error_loc = offsetof(struct nvmf_connect_command, sqsize);
0149 req->cqe->result.u32 = IPO_IATTR_CONNECT_SQE(sqsize);
0150 ret = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
0151 goto err;
0152 }
0153
0154 if (ctrl->sqs[qid] != NULL) {
0155 pr_warn("qid %u has already been created\n", qid);
0156 req->error_loc = offsetof(struct nvmf_connect_command, qid);
0157 return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR;
0158 }
0159
0160 if (sqsize > mqes) {
0161 pr_warn("sqsize %u is larger than MQES supported %u cntlid %d\n",
0162 sqsize, mqes, ctrl->cntlid);
0163 req->error_loc = offsetof(struct nvmf_connect_command, sqsize);
0164 req->cqe->result.u32 = IPO_IATTR_CONNECT_SQE(sqsize);
0165 return NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
0166 }
0167
0168 old = cmpxchg(&req->sq->ctrl, NULL, ctrl);
0169 if (old) {
0170 pr_warn("queue already connected!\n");
0171 req->error_loc = offsetof(struct nvmf_connect_command, opcode);
0172 return NVME_SC_CONNECT_CTRL_BUSY | NVME_SC_DNR;
0173 }
0174
0175
0176 nvmet_cq_setup(ctrl, req->cq, qid, sqsize + 1);
0177 nvmet_sq_setup(ctrl, req->sq, qid, sqsize + 1);
0178
0179 if (c->cattr & NVME_CONNECT_DISABLE_SQFLOW) {
0180 req->sq->sqhd_disabled = true;
0181 req->cqe->sq_head = cpu_to_le16(0xffff);
0182 }
0183
0184 if (ctrl->ops->install_queue) {
0185 ret = ctrl->ops->install_queue(req->sq);
0186 if (ret) {
0187 pr_err("failed to install queue %d cntlid %d ret %x\n",
0188 qid, ctrl->cntlid, ret);
0189 ctrl->sqs[qid] = NULL;
0190 goto err;
0191 }
0192 }
0193
0194 return 0;
0195
0196 err:
0197 req->sq->ctrl = NULL;
0198 return ret;
0199 }
0200
0201 static void nvmet_execute_admin_connect(struct nvmet_req *req)
0202 {
0203 struct nvmf_connect_command *c = &req->cmd->connect;
0204 struct nvmf_connect_data *d;
0205 struct nvmet_ctrl *ctrl = NULL;
0206 u16 status = 0;
0207 int ret;
0208
0209 if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data)))
0210 return;
0211
0212 d = kmalloc(sizeof(*d), GFP_KERNEL);
0213 if (!d) {
0214 status = NVME_SC_INTERNAL;
0215 goto complete;
0216 }
0217
0218 status = nvmet_copy_from_sgl(req, 0, d, sizeof(*d));
0219 if (status)
0220 goto out;
0221
0222
0223 req->cqe->result.u32 = 0;
0224
0225 if (c->recfmt != 0) {
0226 pr_warn("invalid connect version (%d).\n",
0227 le16_to_cpu(c->recfmt));
0228 req->error_loc = offsetof(struct nvmf_connect_command, recfmt);
0229 status = NVME_SC_CONNECT_FORMAT | NVME_SC_DNR;
0230 goto out;
0231 }
0232
0233 if (unlikely(d->cntlid != cpu_to_le16(0xffff))) {
0234 pr_warn("connect attempt for invalid controller ID %#x\n",
0235 d->cntlid);
0236 status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
0237 req->cqe->result.u32 = IPO_IATTR_CONNECT_DATA(cntlid);
0238 goto out;
0239 }
0240
0241 status = nvmet_alloc_ctrl(d->subsysnqn, d->hostnqn, req,
0242 le32_to_cpu(c->kato), &ctrl);
0243 if (status)
0244 goto out;
0245
0246 ctrl->pi_support = ctrl->port->pi_enable && ctrl->subsys->pi_support;
0247
0248 uuid_copy(&ctrl->hostid, &d->hostid);
0249
0250 ret = nvmet_setup_auth(ctrl);
0251 if (ret < 0) {
0252 pr_err("Failed to setup authentication, error %d\n", ret);
0253 nvmet_ctrl_put(ctrl);
0254 if (ret == -EPERM)
0255 status = (NVME_SC_CONNECT_INVALID_HOST | NVME_SC_DNR);
0256 else
0257 status = NVME_SC_INTERNAL;
0258 goto out;
0259 }
0260
0261 status = nvmet_install_queue(ctrl, req);
0262 if (status) {
0263 nvmet_ctrl_put(ctrl);
0264 goto out;
0265 }
0266
0267 pr_info("creating %s controller %d for subsystem %s for NQN %s%s%s.\n",
0268 nvmet_is_disc_subsys(ctrl->subsys) ? "discovery" : "nvm",
0269 ctrl->cntlid, ctrl->subsys->subsysnqn, ctrl->hostnqn,
0270 ctrl->pi_support ? " T10-PI is enabled" : "",
0271 nvmet_has_auth(ctrl) ? " with DH-HMAC-CHAP" : "");
0272 req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid);
0273
0274 if (nvmet_has_auth(ctrl))
0275 nvmet_init_auth(ctrl, req);
0276 out:
0277 kfree(d);
0278 complete:
0279 nvmet_req_complete(req, status);
0280 }
0281
0282 static void nvmet_execute_io_connect(struct nvmet_req *req)
0283 {
0284 struct nvmf_connect_command *c = &req->cmd->connect;
0285 struct nvmf_connect_data *d;
0286 struct nvmet_ctrl *ctrl;
0287 u16 qid = le16_to_cpu(c->qid);
0288 u16 status = 0;
0289
0290 if (!nvmet_check_transfer_len(req, sizeof(struct nvmf_connect_data)))
0291 return;
0292
0293 d = kmalloc(sizeof(*d), GFP_KERNEL);
0294 if (!d) {
0295 status = NVME_SC_INTERNAL;
0296 goto complete;
0297 }
0298
0299 status = nvmet_copy_from_sgl(req, 0, d, sizeof(*d));
0300 if (status)
0301 goto out;
0302
0303
0304 req->cqe->result.u32 = 0;
0305
0306 if (c->recfmt != 0) {
0307 pr_warn("invalid connect version (%d).\n",
0308 le16_to_cpu(c->recfmt));
0309 status = NVME_SC_CONNECT_FORMAT | NVME_SC_DNR;
0310 goto out;
0311 }
0312
0313 ctrl = nvmet_ctrl_find_get(d->subsysnqn, d->hostnqn,
0314 le16_to_cpu(d->cntlid), req);
0315 if (!ctrl) {
0316 status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
0317 goto out;
0318 }
0319
0320 if (unlikely(qid > ctrl->subsys->max_qid)) {
0321 pr_warn("invalid queue id (%d)\n", qid);
0322 status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
0323 req->cqe->result.u32 = IPO_IATTR_CONNECT_SQE(qid);
0324 goto out_ctrl_put;
0325 }
0326
0327 status = nvmet_install_queue(ctrl, req);
0328 if (status)
0329 goto out_ctrl_put;
0330
0331
0332 req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid);
0333
0334 pr_debug("adding queue %d to ctrl %d.\n", qid, ctrl->cntlid);
0335 req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid);
0336 if (nvmet_has_auth(ctrl))
0337 nvmet_init_auth(ctrl, req);
0338
0339 out:
0340 kfree(d);
0341 complete:
0342 nvmet_req_complete(req, status);
0343 return;
0344
0345 out_ctrl_put:
0346 nvmet_ctrl_put(ctrl);
0347 goto out;
0348 }
0349
0350 u16 nvmet_parse_connect_cmd(struct nvmet_req *req)
0351 {
0352 struct nvme_command *cmd = req->cmd;
0353
0354 if (!nvme_is_fabrics(cmd)) {
0355 pr_debug("invalid command 0x%x on unconnected queue.\n",
0356 cmd->fabrics.opcode);
0357 req->error_loc = offsetof(struct nvme_common_command, opcode);
0358 return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
0359 }
0360 if (cmd->fabrics.fctype != nvme_fabrics_type_connect) {
0361 pr_debug("invalid capsule type 0x%x on unconnected queue.\n",
0362 cmd->fabrics.fctype);
0363 req->error_loc = offsetof(struct nvmf_common_command, fctype);
0364 return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
0365 }
0366
0367 if (cmd->connect.qid == 0)
0368 req->execute = nvmet_execute_admin_connect;
0369 else
0370 req->execute = nvmet_execute_io_connect;
0371 return 0;
0372 }