1 // SPDX-License-Identifier: GPL-2.0
3 * NVMe Fabrics command implementation.
4 * Copyright (c) 2015-2016 HGST, a Western Digital Company.
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 #include <linux/blkdev.h>
10 static void nvmet_execute_prop_set(struct nvmet_req
*req
)
12 u64 val
= le64_to_cpu(req
->cmd
->prop_set
.value
);
15 if (!nvmet_check_transfer_len(req
, 0))
18 if (req
->cmd
->prop_set
.attrib
& 1) {
20 offsetof(struct nvmf_property_set_command
, attrib
);
21 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
25 switch (le32_to_cpu(req
->cmd
->prop_set
.offset
)) {
27 nvmet_update_cc(req
->sq
->ctrl
, val
);
31 offsetof(struct nvmf_property_set_command
, offset
);
32 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
35 nvmet_req_complete(req
, status
);
38 static void nvmet_execute_prop_get(struct nvmet_req
*req
)
40 struct nvmet_ctrl
*ctrl
= req
->sq
->ctrl
;
44 if (!nvmet_check_transfer_len(req
, 0))
47 if (req
->cmd
->prop_get
.attrib
& 1) {
48 switch (le32_to_cpu(req
->cmd
->prop_get
.offset
)) {
53 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
57 switch (le32_to_cpu(req
->cmd
->prop_get
.offset
)) {
59 val
= ctrl
->subsys
->ver
;
68 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
73 if (status
&& req
->cmd
->prop_get
.attrib
& 1) {
75 offsetof(struct nvmf_property_get_command
, offset
);
78 offsetof(struct nvmf_property_get_command
, attrib
);
81 req
->cqe
->result
.u64
= cpu_to_le64(val
);
82 nvmet_req_complete(req
, status
);
85 u16
nvmet_parse_fabrics_cmd(struct nvmet_req
*req
)
87 struct nvme_command
*cmd
= req
->cmd
;
89 switch (cmd
->fabrics
.fctype
) {
90 case nvme_fabrics_type_property_set
:
91 req
->execute
= nvmet_execute_prop_set
;
93 case nvme_fabrics_type_property_get
:
94 req
->execute
= nvmet_execute_prop_get
;
97 pr_err("received unknown capsule type 0x%x\n",
99 req
->error_loc
= offsetof(struct nvmf_common_command
, fctype
);
100 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
106 static u16
nvmet_install_queue(struct nvmet_ctrl
*ctrl
, struct nvmet_req
*req
)
108 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
109 u16 qid
= le16_to_cpu(c
->qid
);
110 u16 sqsize
= le16_to_cpu(c
->sqsize
);
111 struct nvmet_ctrl
*old
;
114 old
= cmpxchg(&req
->sq
->ctrl
, NULL
, ctrl
);
116 pr_warn("queue already connected!\n");
117 req
->error_loc
= offsetof(struct nvmf_connect_command
, opcode
);
118 return NVME_SC_CONNECT_CTRL_BUSY
| NVME_SC_DNR
;
121 pr_warn("queue size zero!\n");
122 req
->error_loc
= offsetof(struct nvmf_connect_command
, sqsize
);
123 ret
= NVME_SC_CONNECT_INVALID_PARAM
| NVME_SC_DNR
;
127 /* note: convert queue size from 0's-based value to 1's-based value */
128 nvmet_cq_setup(ctrl
, req
->cq
, qid
, sqsize
+ 1);
129 nvmet_sq_setup(ctrl
, req
->sq
, qid
, sqsize
+ 1);
131 if (c
->cattr
& NVME_CONNECT_DISABLE_SQFLOW
) {
132 req
->sq
->sqhd_disabled
= true;
133 req
->cqe
->sq_head
= cpu_to_le16(0xffff);
136 if (ctrl
->ops
->install_queue
) {
137 ret
= ctrl
->ops
->install_queue(req
->sq
);
139 pr_err("failed to install queue %d cntlid %d ret %x\n",
140 qid
, ctrl
->cntlid
, ret
);
148 req
->sq
->ctrl
= NULL
;
152 static void nvmet_execute_admin_connect(struct nvmet_req
*req
)
154 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
155 struct nvmf_connect_data
*d
;
156 struct nvmet_ctrl
*ctrl
= NULL
;
159 if (!nvmet_check_transfer_len(req
, sizeof(struct nvmf_connect_data
)))
162 d
= kmalloc(sizeof(*d
), GFP_KERNEL
);
164 status
= NVME_SC_INTERNAL
;
168 status
= nvmet_copy_from_sgl(req
, 0, d
, sizeof(*d
));
172 /* zero out initial completion result, assign values as needed */
173 req
->cqe
->result
.u32
= 0;
175 if (c
->recfmt
!= 0) {
176 pr_warn("invalid connect version (%d).\n",
177 le16_to_cpu(c
->recfmt
));
178 req
->error_loc
= offsetof(struct nvmf_connect_command
, recfmt
);
179 status
= NVME_SC_CONNECT_FORMAT
| NVME_SC_DNR
;
183 if (unlikely(d
->cntlid
!= cpu_to_le16(0xffff))) {
184 pr_warn("connect attempt for invalid controller ID %#x\n",
186 status
= NVME_SC_CONNECT_INVALID_PARAM
| NVME_SC_DNR
;
187 req
->cqe
->result
.u32
= IPO_IATTR_CONNECT_DATA(cntlid
);
191 status
= nvmet_alloc_ctrl(d
->subsysnqn
, d
->hostnqn
, req
,
192 le32_to_cpu(c
->kato
), &ctrl
);
194 if (status
== (NVME_SC_INVALID_FIELD
| NVME_SC_DNR
))
196 offsetof(struct nvme_common_command
, opcode
);
200 ctrl
->pi_support
= ctrl
->port
->pi_enable
&& ctrl
->subsys
->pi_support
;
202 uuid_copy(&ctrl
->hostid
, &d
->hostid
);
204 status
= nvmet_install_queue(ctrl
, req
);
206 nvmet_ctrl_put(ctrl
);
210 pr_info("creating controller %d for subsystem %s for NQN %s%s.\n",
211 ctrl
->cntlid
, ctrl
->subsys
->subsysnqn
, ctrl
->hostnqn
,
212 ctrl
->pi_support
? " T10-PI is enabled" : "");
213 req
->cqe
->result
.u16
= cpu_to_le16(ctrl
->cntlid
);
218 nvmet_req_complete(req
, status
);
221 static void nvmet_execute_io_connect(struct nvmet_req
*req
)
223 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
224 struct nvmf_connect_data
*d
;
225 struct nvmet_ctrl
*ctrl
= NULL
;
226 u16 qid
= le16_to_cpu(c
->qid
);
229 if (!nvmet_check_transfer_len(req
, sizeof(struct nvmf_connect_data
)))
232 d
= kmalloc(sizeof(*d
), GFP_KERNEL
);
234 status
= NVME_SC_INTERNAL
;
238 status
= nvmet_copy_from_sgl(req
, 0, d
, sizeof(*d
));
242 /* zero out initial completion result, assign values as needed */
243 req
->cqe
->result
.u32
= 0;
245 if (c
->recfmt
!= 0) {
246 pr_warn("invalid connect version (%d).\n",
247 le16_to_cpu(c
->recfmt
));
248 status
= NVME_SC_CONNECT_FORMAT
| NVME_SC_DNR
;
252 status
= nvmet_ctrl_find_get(d
->subsysnqn
, d
->hostnqn
,
253 le16_to_cpu(d
->cntlid
),
258 if (unlikely(qid
> ctrl
->subsys
->max_qid
)) {
259 pr_warn("invalid queue id (%d)\n", qid
);
260 status
= NVME_SC_CONNECT_INVALID_PARAM
| NVME_SC_DNR
;
261 req
->cqe
->result
.u32
= IPO_IATTR_CONNECT_SQE(qid
);
265 status
= nvmet_install_queue(ctrl
, req
);
267 /* pass back cntlid that had the issue of installing queue */
268 req
->cqe
->result
.u16
= cpu_to_le16(ctrl
->cntlid
);
272 pr_debug("adding queue %d to ctrl %d.\n", qid
, ctrl
->cntlid
);
277 nvmet_req_complete(req
, status
);
281 nvmet_ctrl_put(ctrl
);
285 u16
nvmet_parse_connect_cmd(struct nvmet_req
*req
)
287 struct nvme_command
*cmd
= req
->cmd
;
289 if (!nvme_is_fabrics(cmd
)) {
290 pr_err("invalid command 0x%x on unconnected queue.\n",
291 cmd
->fabrics
.opcode
);
292 req
->error_loc
= offsetof(struct nvme_common_command
, opcode
);
293 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
295 if (cmd
->fabrics
.fctype
!= nvme_fabrics_type_connect
) {
296 pr_err("invalid capsule type 0x%x on unconnected queue.\n",
297 cmd
->fabrics
.fctype
);
298 req
->error_loc
= offsetof(struct nvmf_common_command
, fctype
);
299 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
302 if (cmd
->connect
.qid
== 0)
303 req
->execute
= nvmet_execute_admin_connect
;
305 req
->execute
= nvmet_execute_io_connect
;