root/drivers/nvme/target/fabrics-cmd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nvmet_execute_prop_set
  2. nvmet_execute_prop_get
  3. nvmet_parse_fabrics_cmd
  4. nvmet_install_queue
  5. nvmet_execute_admin_connect
  6. nvmet_execute_io_connect
  7. nvmet_parse_connect_cmd

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * NVMe Fabrics command implementation.
   4  * Copyright (c) 2015-2016 HGST, a Western Digital Company.
   5  */
   6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   7 #include <linux/blkdev.h>
   8 #include "nvmet.h"
   9 
  10 static void nvmet_execute_prop_set(struct nvmet_req *req)
  11 {
  12         u64 val = le64_to_cpu(req->cmd->prop_set.value);
  13         u16 status = 0;
  14 
  15         if (req->cmd->prop_set.attrib & 1) {
  16                 req->error_loc =
  17                         offsetof(struct nvmf_property_set_command, attrib);
  18                 status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
  19                 goto out;
  20         }
  21 
  22         switch (le32_to_cpu(req->cmd->prop_set.offset)) {
  23         case NVME_REG_CC:
  24                 nvmet_update_cc(req->sq->ctrl, val);
  25                 break;
  26         default:
  27                 req->error_loc =
  28                         offsetof(struct nvmf_property_set_command, offset);
  29                 status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
  30         }
  31 out:
  32         nvmet_req_complete(req, status);
  33 }
  34 
  35 static void nvmet_execute_prop_get(struct nvmet_req *req)
  36 {
  37         struct nvmet_ctrl *ctrl = req->sq->ctrl;
  38         u16 status = 0;
  39         u64 val = 0;
  40 
  41         if (req->cmd->prop_get.attrib & 1) {
  42                 switch (le32_to_cpu(req->cmd->prop_get.offset)) {
  43                 case NVME_REG_CAP:
  44                         val = ctrl->cap;
  45                         break;
  46                 default:
  47                         status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
  48                         break;
  49                 }
  50         } else {
  51                 switch (le32_to_cpu(req->cmd->prop_get.offset)) {
  52                 case NVME_REG_VS:
  53                         val = ctrl->subsys->ver;
  54                         break;
  55                 case NVME_REG_CC:
  56                         val = ctrl->cc;
  57                         break;
  58                 case NVME_REG_CSTS:
  59                         val = ctrl->csts;
  60                         break;
  61                 default:
  62                         status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
  63                         break;
  64                 }
  65         }
  66 
  67         if (status && req->cmd->prop_get.attrib & 1) {
  68                 req->error_loc =
  69                         offsetof(struct nvmf_property_get_command, offset);
  70         } else {
  71                 req->error_loc =
  72                         offsetof(struct nvmf_property_get_command, attrib);
  73         }
  74 
  75         req->cqe->result.u64 = cpu_to_le64(val);
  76         nvmet_req_complete(req, status);
  77 }
  78 
  79 u16 nvmet_parse_fabrics_cmd(struct nvmet_req *req)
  80 {
  81         struct nvme_command *cmd = req->cmd;
  82 
  83         switch (cmd->fabrics.fctype) {
  84         case nvme_fabrics_type_property_set:
  85                 req->data_len = 0;
  86                 req->execute = nvmet_execute_prop_set;
  87                 break;
  88         case nvme_fabrics_type_property_get:
  89                 req->data_len = 0;
  90                 req->execute = nvmet_execute_prop_get;
  91                 break;
  92         default:
  93                 pr_err("received unknown capsule type 0x%x\n",
  94                         cmd->fabrics.fctype);
  95                 req->error_loc = offsetof(struct nvmf_common_command, fctype);
  96                 return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
  97         }
  98 
  99         return 0;
 100 }
 101 
 102 static u16 nvmet_install_queue(struct nvmet_ctrl *ctrl, struct nvmet_req *req)
 103 {
 104         struct nvmf_connect_command *c = &req->cmd->connect;
 105         u16 qid = le16_to_cpu(c->qid);
 106         u16 sqsize = le16_to_cpu(c->sqsize);
 107         struct nvmet_ctrl *old;
 108         u16 ret;
 109 
 110         old = cmpxchg(&req->sq->ctrl, NULL, ctrl);
 111         if (old) {
 112                 pr_warn("queue already connected!\n");
 113                 req->error_loc = offsetof(struct nvmf_connect_command, opcode);
 114                 return NVME_SC_CONNECT_CTRL_BUSY | NVME_SC_DNR;
 115         }
 116         if (!sqsize) {
 117                 pr_warn("queue size zero!\n");
 118                 req->error_loc = offsetof(struct nvmf_connect_command, sqsize);
 119                 ret = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
 120                 goto err;
 121         }
 122 
 123         /* note: convert queue size from 0's-based value to 1's-based value */
 124         nvmet_cq_setup(ctrl, req->cq, qid, sqsize + 1);
 125         nvmet_sq_setup(ctrl, req->sq, qid, sqsize + 1);
 126 
 127         if (c->cattr & NVME_CONNECT_DISABLE_SQFLOW) {
 128                 req->sq->sqhd_disabled = true;
 129                 req->cqe->sq_head = cpu_to_le16(0xffff);
 130         }
 131 
 132         if (ctrl->ops->install_queue) {
 133                 ret = ctrl->ops->install_queue(req->sq);
 134                 if (ret) {
 135                         pr_err("failed to install queue %d cntlid %d ret %x\n",
 136                                 qid, ctrl->cntlid, ret);
 137                         goto err;
 138                 }
 139         }
 140 
 141         return 0;
 142 
 143 err:
 144         req->sq->ctrl = NULL;
 145         return ret;
 146 }
 147 
 148 static void nvmet_execute_admin_connect(struct nvmet_req *req)
 149 {
 150         struct nvmf_connect_command *c = &req->cmd->connect;
 151         struct nvmf_connect_data *d;
 152         struct nvmet_ctrl *ctrl = NULL;
 153         u16 status = 0;
 154 
 155         d = kmalloc(sizeof(*d), GFP_KERNEL);
 156         if (!d) {
 157                 status = NVME_SC_INTERNAL;
 158                 goto complete;
 159         }
 160 
 161         status = nvmet_copy_from_sgl(req, 0, d, sizeof(*d));
 162         if (status)
 163                 goto out;
 164 
 165         /* zero out initial completion result, assign values as needed */
 166         req->cqe->result.u32 = 0;
 167 
 168         if (c->recfmt != 0) {
 169                 pr_warn("invalid connect version (%d).\n",
 170                         le16_to_cpu(c->recfmt));
 171                 req->error_loc = offsetof(struct nvmf_connect_command, recfmt);
 172                 status = NVME_SC_CONNECT_FORMAT | NVME_SC_DNR;
 173                 goto out;
 174         }
 175 
 176         if (unlikely(d->cntlid != cpu_to_le16(0xffff))) {
 177                 pr_warn("connect attempt for invalid controller ID %#x\n",
 178                         d->cntlid);
 179                 status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
 180                 req->cqe->result.u32 = IPO_IATTR_CONNECT_DATA(cntlid);
 181                 goto out;
 182         }
 183 
 184         status = nvmet_alloc_ctrl(d->subsysnqn, d->hostnqn, req,
 185                                   le32_to_cpu(c->kato), &ctrl);
 186         if (status) {
 187                 if (status == (NVME_SC_INVALID_FIELD | NVME_SC_DNR))
 188                         req->error_loc =
 189                                 offsetof(struct nvme_common_command, opcode);
 190                 goto out;
 191         }
 192 
 193         uuid_copy(&ctrl->hostid, &d->hostid);
 194 
 195         status = nvmet_install_queue(ctrl, req);
 196         if (status) {
 197                 nvmet_ctrl_put(ctrl);
 198                 goto out;
 199         }
 200 
 201         pr_info("creating controller %d for subsystem %s for NQN %s.\n",
 202                 ctrl->cntlid, ctrl->subsys->subsysnqn, ctrl->hostnqn);
 203         req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid);
 204 
 205 out:
 206         kfree(d);
 207 complete:
 208         nvmet_req_complete(req, status);
 209 }
 210 
 211 static void nvmet_execute_io_connect(struct nvmet_req *req)
 212 {
 213         struct nvmf_connect_command *c = &req->cmd->connect;
 214         struct nvmf_connect_data *d;
 215         struct nvmet_ctrl *ctrl = NULL;
 216         u16 qid = le16_to_cpu(c->qid);
 217         u16 status = 0;
 218 
 219         d = kmalloc(sizeof(*d), GFP_KERNEL);
 220         if (!d) {
 221                 status = NVME_SC_INTERNAL;
 222                 goto complete;
 223         }
 224 
 225         status = nvmet_copy_from_sgl(req, 0, d, sizeof(*d));
 226         if (status)
 227                 goto out;
 228 
 229         /* zero out initial completion result, assign values as needed */
 230         req->cqe->result.u32 = 0;
 231 
 232         if (c->recfmt != 0) {
 233                 pr_warn("invalid connect version (%d).\n",
 234                         le16_to_cpu(c->recfmt));
 235                 status = NVME_SC_CONNECT_FORMAT | NVME_SC_DNR;
 236                 goto out;
 237         }
 238 
 239         status = nvmet_ctrl_find_get(d->subsysnqn, d->hostnqn,
 240                                      le16_to_cpu(d->cntlid),
 241                                      req, &ctrl);
 242         if (status)
 243                 goto out;
 244 
 245         if (unlikely(qid > ctrl->subsys->max_qid)) {
 246                 pr_warn("invalid queue id (%d)\n", qid);
 247                 status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR;
 248                 req->cqe->result.u32 = IPO_IATTR_CONNECT_SQE(qid);
 249                 goto out_ctrl_put;
 250         }
 251 
 252         status = nvmet_install_queue(ctrl, req);
 253         if (status) {
 254                 /* pass back cntlid that had the issue of installing queue */
 255                 req->cqe->result.u16 = cpu_to_le16(ctrl->cntlid);
 256                 goto out_ctrl_put;
 257         }
 258 
 259         pr_debug("adding queue %d to ctrl %d.\n", qid, ctrl->cntlid);
 260 
 261 out:
 262         kfree(d);
 263 complete:
 264         nvmet_req_complete(req, status);
 265         return;
 266 
 267 out_ctrl_put:
 268         nvmet_ctrl_put(ctrl);
 269         goto out;
 270 }
 271 
 272 u16 nvmet_parse_connect_cmd(struct nvmet_req *req)
 273 {
 274         struct nvme_command *cmd = req->cmd;
 275 
 276         if (!nvme_is_fabrics(cmd)) {
 277                 pr_err("invalid command 0x%x on unconnected queue.\n",
 278                         cmd->fabrics.opcode);
 279                 req->error_loc = offsetof(struct nvme_common_command, opcode);
 280                 return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
 281         }
 282         if (cmd->fabrics.fctype != nvme_fabrics_type_connect) {
 283                 pr_err("invalid capsule type 0x%x on unconnected queue.\n",
 284                         cmd->fabrics.fctype);
 285                 req->error_loc = offsetof(struct nvmf_common_command, fctype);
 286                 return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
 287         }
 288 
 289         req->data_len = sizeof(struct nvmf_connect_data);
 290         if (cmd->connect.qid == 0)
 291                 req->execute = nvmet_execute_admin_connect;
 292         else
 293                 req->execute = nvmet_execute_io_connect;
 294         return 0;
 295 }

/* [<][>][^][v][top][bottom][index][help] */