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
)
22 if (!(req
->cmd
->prop_set
.attrib
& 1)) {
23 u64 val
= le64_to_cpu(req
->cmd
->prop_set
.value
);
25 switch (le32_to_cpu(req
->cmd
->prop_set
.offset
)) {
27 nvmet_update_cc(req
->sq
->ctrl
, val
);
30 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
34 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
37 nvmet_req_complete(req
, status
);
40 static void nvmet_execute_prop_get(struct nvmet_req
*req
)
42 struct nvmet_ctrl
*ctrl
= req
->sq
->ctrl
;
46 if (req
->cmd
->prop_get
.attrib
& 1) {
47 switch (le32_to_cpu(req
->cmd
->prop_get
.offset
)) {
52 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
56 switch (le32_to_cpu(req
->cmd
->prop_get
.offset
)) {
58 val
= ctrl
->subsys
->ver
;
67 status
= NVME_SC_INVALID_FIELD
| NVME_SC_DNR
;
72 req
->rsp
->result64
= cpu_to_le64(val
);
73 nvmet_req_complete(req
, status
);
76 int nvmet_parse_fabrics_cmd(struct nvmet_req
*req
)
78 struct nvme_command
*cmd
= req
->cmd
;
82 switch (cmd
->fabrics
.fctype
) {
83 case nvme_fabrics_type_property_set
:
85 req
->execute
= nvmet_execute_prop_set
;
87 case nvme_fabrics_type_property_get
:
89 req
->execute
= nvmet_execute_prop_get
;
92 pr_err("received unknown capsule type 0x%x\n",
94 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
100 static u16
nvmet_install_queue(struct nvmet_ctrl
*ctrl
, struct nvmet_req
*req
)
102 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
103 u16 qid
= le16_to_cpu(c
->qid
);
104 u16 sqsize
= le16_to_cpu(c
->sqsize
);
105 struct nvmet_ctrl
*old
;
107 old
= cmpxchg(&req
->sq
->ctrl
, NULL
, ctrl
);
109 pr_warn("queue already connected!\n");
110 return NVME_SC_CONNECT_CTRL_BUSY
| NVME_SC_DNR
;
113 nvmet_cq_setup(ctrl
, req
->cq
, qid
, sqsize
);
114 nvmet_sq_setup(ctrl
, req
->sq
, qid
, sqsize
);
118 static void nvmet_execute_admin_connect(struct nvmet_req
*req
)
120 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
121 struct nvmf_connect_data
*d
;
122 struct nvmet_ctrl
*ctrl
= NULL
;
125 d
= kmap(sg_page(req
->sg
)) + req
->sg
->offset
;
127 /* zero out initial completion result, assign values as needed */
128 req
->rsp
->result
= 0;
130 if (c
->recfmt
!= 0) {
131 pr_warn("invalid connect version (%d).\n",
132 le16_to_cpu(c
->recfmt
));
133 status
= NVME_SC_CONNECT_FORMAT
| NVME_SC_DNR
;
137 if (unlikely(d
->cntlid
!= cpu_to_le16(0xffff))) {
138 pr_warn("connect attempt for invalid controller ID %#x\n",
140 status
= NVME_SC_CONNECT_INVALID_PARAM
| NVME_SC_DNR
;
141 req
->rsp
->result
= IPO_IATTR_CONNECT_DATA(cntlid
);
145 status
= nvmet_alloc_ctrl(d
->subsysnqn
, d
->hostnqn
, req
,
146 le32_to_cpu(c
->kato
), &ctrl
);
150 status
= nvmet_install_queue(ctrl
, req
);
152 nvmet_ctrl_put(ctrl
);
156 pr_info("creating controller %d for NQN %s.\n",
157 ctrl
->cntlid
, ctrl
->hostnqn
);
158 req
->rsp
->result16
= cpu_to_le16(ctrl
->cntlid
);
161 kunmap(sg_page(req
->sg
));
162 nvmet_req_complete(req
, status
);
165 static void nvmet_execute_io_connect(struct nvmet_req
*req
)
167 struct nvmf_connect_command
*c
= &req
->cmd
->connect
;
168 struct nvmf_connect_data
*d
;
169 struct nvmet_ctrl
*ctrl
= NULL
;
170 u16 qid
= le16_to_cpu(c
->qid
);
173 d
= kmap(sg_page(req
->sg
)) + req
->sg
->offset
;
175 /* zero out initial completion result, assign values as needed */
176 req
->rsp
->result
= 0;
178 if (c
->recfmt
!= 0) {
179 pr_warn("invalid connect version (%d).\n",
180 le16_to_cpu(c
->recfmt
));
181 status
= NVME_SC_CONNECT_FORMAT
| NVME_SC_DNR
;
185 status
= nvmet_ctrl_find_get(d
->subsysnqn
, d
->hostnqn
,
186 le16_to_cpu(d
->cntlid
),
191 if (unlikely(qid
> ctrl
->subsys
->max_qid
)) {
192 pr_warn("invalid queue id (%d)\n", qid
);
193 status
= NVME_SC_CONNECT_INVALID_PARAM
| NVME_SC_DNR
;
194 req
->rsp
->result
= IPO_IATTR_CONNECT_SQE(qid
);
198 status
= nvmet_install_queue(ctrl
, req
);
200 /* pass back cntlid that had the issue of installing queue */
201 req
->rsp
->result16
= cpu_to_le16(ctrl
->cntlid
);
205 pr_info("adding queue %d to ctrl %d.\n", qid
, ctrl
->cntlid
);
208 kunmap(sg_page(req
->sg
));
209 nvmet_req_complete(req
, status
);
213 nvmet_ctrl_put(ctrl
);
217 int nvmet_parse_connect_cmd(struct nvmet_req
*req
)
219 struct nvme_command
*cmd
= req
->cmd
;
223 if (req
->cmd
->common
.opcode
!= nvme_fabrics_command
) {
224 pr_err("invalid command 0x%x on unconnected queue.\n",
225 cmd
->fabrics
.opcode
);
226 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
228 if (cmd
->fabrics
.fctype
!= nvme_fabrics_type_connect
) {
229 pr_err("invalid capsule type 0x%x on unconnected queue.\n",
230 cmd
->fabrics
.fctype
);
231 return NVME_SC_INVALID_OPCODE
| NVME_SC_DNR
;
234 req
->data_len
= sizeof(struct nvmf_connect_data
);
235 if (cmd
->connect
.qid
== 0)
236 req
->execute
= nvmet_execute_admin_connect
;
238 req
->execute
= nvmet_execute_io_connect
;