2 * NVMe Fabrics command implementation.
3 * Copyright (c) 2015-2016 HGST, a Western Digital Company.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15 #include <linux/blkdev.h>
18 static void nvmet_execute_prop_set(struct nvmet_req
*req
)
20 u64 val
= le64_to_cpu(req
->cmd
->prop_set
.value
);
23 if (req
->cmd
->prop_set
.attrib
& 1) {
25 offsetof(struct nvmf_property_set_command
, attrib
);
26 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
30 switch (le32_to_cpu(req
->cmd
->prop_set
.offset
)) {
32 nvmet_update_cc(req
->sq
->ctrl
, val
);
36 offsetof(struct nvmf_property_set_command
, offset
);
37 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
40 nvmet_req_complete(req
, status
);
43 static void nvmet_execute_prop_get(struct nvmet_req
*req
)
45 struct nvmet_ctrl
*ctrl
= req
->sq
->ctrl
;
49 if (req
->cmd
->prop_get
.attrib
& 1) {
50 switch (le32_to_cpu(req
->cmd
->prop_get
.offset
)) {
55 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
59 switch (le32_to_cpu(req
->cmd
->prop_get
.offset
)) {
61 val
= ctrl
->subsys
->ver
;
70 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
75 if (status
&& req
->cmd
->prop_get
.attrib
& 1) {
77 offsetof(struct nvmf_property_get_command
, offset
);
80 offsetof(struct nvmf_property_get_command
, attrib
);
83 req
->rsp
->result
.u64
= cpu_to_le64(val
);
84 nvmet_req_complete(req
, status
);
87 u16
nvmet_parse_fabrics_cmd(struct nvmet_req
*req
)
89 struct nvme_command
*cmd
= req
->cmd
;
91 switch (cmd
->fabrics
.fctype
) {
92 case nvme_fabrics_type_property_set
:
94 req
->execute
= nvmet_execute_prop_set
;
96 case nvme_fabrics_type_property_get
:
98 req
->execute
= nvmet_execute_prop_get
;
101 pr_err("received unknown capsule type 0x%x\n",
102 cmd
->fabrics
.fctype
);
103 req
->error_loc
= offsetof(struct nvmf_common_command
, fctype
);
104 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
110 static u16
nvmet_install_queue(struct nvmet_ctrl
*ctrl
, struct nvmet_req
*req
)
112 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
113 u16 qid
= le16_to_cpu(c
->qid
);
114 u16 sqsize
= le16_to_cpu(c
->sqsize
);
115 struct nvmet_ctrl
*old
;
117 old
= cmpxchg(&req
->sq
->ctrl
, NULL
, ctrl
);
119 pr_warn("queue already connected!\n");
120 req
->error_loc
= offsetof(struct nvmf_connect_command
, opcode
);
121 return NVME_SC_CONNECT_CTRL_BUSY
| NVME_SC_DNR
;
124 pr_warn("queue size zero!\n");
125 req
->error_loc
= offsetof(struct nvmf_connect_command
, sqsize
);
126 return NVME_SC_CONNECT_INVALID_PARAM
| NVME_SC_DNR
;
129 /* note: convert queue size from 0's-based value to 1's-based value */
130 nvmet_cq_setup(ctrl
, req
->cq
, qid
, sqsize
+ 1);
131 nvmet_sq_setup(ctrl
, req
->sq
, qid
, sqsize
+ 1);
133 if (c
->cattr
& NVME_CONNECT_DISABLE_SQFLOW
) {
134 req
->sq
->sqhd_disabled
= true;
135 req
->rsp
->sq_head
= cpu_to_le16(0xffff);
138 if (ctrl
->ops
->install_queue
) {
139 u16 ret
= ctrl
->ops
->install_queue(req
->sq
);
142 pr_err("failed to install queue %d cntlid %d ret %x\n",
143 qid
, ret
, ctrl
->cntlid
);
151 static void nvmet_execute_admin_connect(struct nvmet_req
*req
)
153 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
154 struct nvmf_connect_data
*d
;
155 struct nvmet_ctrl
*ctrl
= NULL
;
158 d
= kmalloc(sizeof(*d
), GFP_KERNEL
);
160 status
= NVME_SC_INTERNAL
;
164 status
= nvmet_copy_from_sgl(req
, 0, d
, sizeof(*d
));
168 /* zero out initial completion result, assign values as needed */
169 req
->rsp
->result
.u32
= 0;
171 if (c
->recfmt
!= 0) {
172 pr_warn("invalid connect version (%d).\n",
173 le16_to_cpu(c
->recfmt
));
174 req
->error_loc
= offsetof(struct nvmf_connect_command
, recfmt
);
175 status
= NVME_SC_CONNECT_FORMAT
| NVME_SC_DNR
;
179 if (unlikely(d
->cntlid
!= cpu_to_le16(0xffff))) {
180 pr_warn("connect attempt for invalid controller ID %#x\n",
182 status
= NVME_SC_CONNECT_INVALID_PARAM
| NVME_SC_DNR
;
183 req
->rsp
->result
.u32
= IPO_IATTR_CONNECT_DATA(cntlid
);
187 status
= nvmet_alloc_ctrl(d
->subsysnqn
, d
->hostnqn
, req
,
188 le32_to_cpu(c
->kato
), &ctrl
);
190 if (status
== (NVME_SC_INVALID_FIELD
| NVME_SC_DNR
))
192 offsetof(struct nvme_common_command
, opcode
);
196 uuid_copy(&ctrl
->hostid
, &d
->hostid
);
198 status
= nvmet_install_queue(ctrl
, req
);
200 nvmet_ctrl_put(ctrl
);
204 pr_info("creating controller %d for subsystem %s for NQN %s.\n",
205 ctrl
->cntlid
, ctrl
->subsys
->subsysnqn
, ctrl
->hostnqn
);
206 req
->rsp
->result
.u16
= cpu_to_le16(ctrl
->cntlid
);
211 nvmet_req_complete(req
, status
);
214 static void nvmet_execute_io_connect(struct nvmet_req
*req
)
216 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
217 struct nvmf_connect_data
*d
;
218 struct nvmet_ctrl
*ctrl
= NULL
;
219 u16 qid
= le16_to_cpu(c
->qid
);
222 d
= kmalloc(sizeof(*d
), GFP_KERNEL
);
224 status
= NVME_SC_INTERNAL
;
228 status
= nvmet_copy_from_sgl(req
, 0, d
, sizeof(*d
));
232 /* zero out initial completion result, assign values as needed */
233 req
->rsp
->result
.u32
= 0;
235 if (c
->recfmt
!= 0) {
236 pr_warn("invalid connect version (%d).\n",
237 le16_to_cpu(c
->recfmt
));
238 status
= NVME_SC_CONNECT_FORMAT
| NVME_SC_DNR
;
242 status
= nvmet_ctrl_find_get(d
->subsysnqn
, d
->hostnqn
,
243 le16_to_cpu(d
->cntlid
),
248 if (unlikely(qid
> ctrl
->subsys
->max_qid
)) {
249 pr_warn("invalid queue id (%d)\n", qid
);
250 status
= NVME_SC_CONNECT_INVALID_PARAM
| NVME_SC_DNR
;
251 req
->rsp
->result
.u32
= IPO_IATTR_CONNECT_SQE(qid
);
255 status
= nvmet_install_queue(ctrl
, req
);
257 /* pass back cntlid that had the issue of installing queue */
258 req
->rsp
->result
.u16
= cpu_to_le16(ctrl
->cntlid
);
262 pr_debug("adding queue %d to ctrl %d.\n", qid
, ctrl
->cntlid
);
267 nvmet_req_complete(req
, status
);
271 nvmet_ctrl_put(ctrl
);
275 u16
nvmet_parse_connect_cmd(struct nvmet_req
*req
)
277 struct nvme_command
*cmd
= req
->cmd
;
279 if (cmd
->common
.opcode
!= nvme_fabrics_command
) {
280 pr_err("invalid command 0x%x on unconnected queue.\n",
281 cmd
->fabrics
.opcode
);
282 req
->error_loc
= offsetof(struct nvme_common_command
, opcode
);
283 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
285 if (cmd
->fabrics
.fctype
!= nvme_fabrics_type_connect
) {
286 pr_err("invalid capsule type 0x%x on unconnected queue.\n",
287 cmd
->fabrics
.fctype
);
288 req
->error_loc
= offsetof(struct nvmf_common_command
, fctype
);
289 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
292 req
->data_len
= sizeof(struct nvmf_connect_data
);
293 if (cmd
->connect
.qid
== 0)
294 req
->execute
= nvmet_execute_admin_connect
;
296 req
->execute
= nvmet_execute_io_connect
;