1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Discovery service for the NVMe over Fabrics target.
4*4882a593Smuzhiyun * Copyright (C) 2016 Intel Corporation. All rights reserved.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7*4882a593Smuzhiyun #include <linux/slab.h>
8*4882a593Smuzhiyun #include <generated/utsrelease.h>
9*4882a593Smuzhiyun #include "nvmet.h"
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun struct nvmet_subsys *nvmet_disc_subsys;
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun static u64 nvmet_genctr;
14*4882a593Smuzhiyun
__nvmet_disc_changed(struct nvmet_port * port,struct nvmet_ctrl * ctrl)15*4882a593Smuzhiyun static void __nvmet_disc_changed(struct nvmet_port *port,
16*4882a593Smuzhiyun struct nvmet_ctrl *ctrl)
17*4882a593Smuzhiyun {
18*4882a593Smuzhiyun if (ctrl->port != port)
19*4882a593Smuzhiyun return;
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun if (nvmet_aen_bit_disabled(ctrl, NVME_AEN_BIT_DISC_CHANGE))
22*4882a593Smuzhiyun return;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE,
25*4882a593Smuzhiyun NVME_AER_NOTICE_DISC_CHANGED, NVME_LOG_DISC);
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun
nvmet_port_disc_changed(struct nvmet_port * port,struct nvmet_subsys * subsys)28*4882a593Smuzhiyun void nvmet_port_disc_changed(struct nvmet_port *port,
29*4882a593Smuzhiyun struct nvmet_subsys *subsys)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun struct nvmet_ctrl *ctrl;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun lockdep_assert_held(&nvmet_config_sem);
34*4882a593Smuzhiyun nvmet_genctr++;
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun mutex_lock(&nvmet_disc_subsys->lock);
37*4882a593Smuzhiyun list_for_each_entry(ctrl, &nvmet_disc_subsys->ctrls, subsys_entry) {
38*4882a593Smuzhiyun if (subsys && !nvmet_host_allowed(subsys, ctrl->hostnqn))
39*4882a593Smuzhiyun continue;
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun __nvmet_disc_changed(port, ctrl);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun mutex_unlock(&nvmet_disc_subsys->lock);
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun /* If transport can signal change, notify transport */
46*4882a593Smuzhiyun if (port->tr_ops && port->tr_ops->discovery_chg)
47*4882a593Smuzhiyun port->tr_ops->discovery_chg(port);
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun
__nvmet_subsys_disc_changed(struct nvmet_port * port,struct nvmet_subsys * subsys,struct nvmet_host * host)50*4882a593Smuzhiyun static void __nvmet_subsys_disc_changed(struct nvmet_port *port,
51*4882a593Smuzhiyun struct nvmet_subsys *subsys,
52*4882a593Smuzhiyun struct nvmet_host *host)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun struct nvmet_ctrl *ctrl;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun mutex_lock(&nvmet_disc_subsys->lock);
57*4882a593Smuzhiyun list_for_each_entry(ctrl, &nvmet_disc_subsys->ctrls, subsys_entry) {
58*4882a593Smuzhiyun if (host && strcmp(nvmet_host_name(host), ctrl->hostnqn))
59*4882a593Smuzhiyun continue;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun __nvmet_disc_changed(port, ctrl);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun mutex_unlock(&nvmet_disc_subsys->lock);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun
nvmet_subsys_disc_changed(struct nvmet_subsys * subsys,struct nvmet_host * host)66*4882a593Smuzhiyun void nvmet_subsys_disc_changed(struct nvmet_subsys *subsys,
67*4882a593Smuzhiyun struct nvmet_host *host)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun struct nvmet_port *port;
70*4882a593Smuzhiyun struct nvmet_subsys_link *s;
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun nvmet_genctr++;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun list_for_each_entry(port, nvmet_ports, global_entry)
75*4882a593Smuzhiyun list_for_each_entry(s, &port->subsystems, entry) {
76*4882a593Smuzhiyun if (s->subsys != subsys)
77*4882a593Smuzhiyun continue;
78*4882a593Smuzhiyun __nvmet_subsys_disc_changed(port, subsys, host);
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun }
81*4882a593Smuzhiyun
nvmet_referral_enable(struct nvmet_port * parent,struct nvmet_port * port)82*4882a593Smuzhiyun void nvmet_referral_enable(struct nvmet_port *parent, struct nvmet_port *port)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun down_write(&nvmet_config_sem);
85*4882a593Smuzhiyun if (list_empty(&port->entry)) {
86*4882a593Smuzhiyun list_add_tail(&port->entry, &parent->referrals);
87*4882a593Smuzhiyun port->enabled = true;
88*4882a593Smuzhiyun nvmet_port_disc_changed(parent, NULL);
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun up_write(&nvmet_config_sem);
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
nvmet_referral_disable(struct nvmet_port * parent,struct nvmet_port * port)93*4882a593Smuzhiyun void nvmet_referral_disable(struct nvmet_port *parent, struct nvmet_port *port)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun down_write(&nvmet_config_sem);
96*4882a593Smuzhiyun if (!list_empty(&port->entry)) {
97*4882a593Smuzhiyun port->enabled = false;
98*4882a593Smuzhiyun list_del_init(&port->entry);
99*4882a593Smuzhiyun nvmet_port_disc_changed(parent, NULL);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun up_write(&nvmet_config_sem);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
nvmet_format_discovery_entry(struct nvmf_disc_rsp_page_hdr * hdr,struct nvmet_port * port,char * subsys_nqn,char * traddr,u8 type,u32 numrec)104*4882a593Smuzhiyun static void nvmet_format_discovery_entry(struct nvmf_disc_rsp_page_hdr *hdr,
105*4882a593Smuzhiyun struct nvmet_port *port, char *subsys_nqn, char *traddr,
106*4882a593Smuzhiyun u8 type, u32 numrec)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun struct nvmf_disc_rsp_page_entry *e = &hdr->entries[numrec];
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun e->trtype = port->disc_addr.trtype;
111*4882a593Smuzhiyun e->adrfam = port->disc_addr.adrfam;
112*4882a593Smuzhiyun e->treq = port->disc_addr.treq;
113*4882a593Smuzhiyun e->portid = port->disc_addr.portid;
114*4882a593Smuzhiyun /* we support only dynamic controllers */
115*4882a593Smuzhiyun e->cntlid = cpu_to_le16(NVME_CNTLID_DYNAMIC);
116*4882a593Smuzhiyun e->asqsz = cpu_to_le16(NVME_AQ_DEPTH);
117*4882a593Smuzhiyun e->subtype = type;
118*4882a593Smuzhiyun memcpy(e->trsvcid, port->disc_addr.trsvcid, NVMF_TRSVCID_SIZE);
119*4882a593Smuzhiyun memcpy(e->traddr, traddr, NVMF_TRADDR_SIZE);
120*4882a593Smuzhiyun memcpy(e->tsas.common, port->disc_addr.tsas.common, NVMF_TSAS_SIZE);
121*4882a593Smuzhiyun strncpy(e->subnqn, subsys_nqn, NVMF_NQN_SIZE);
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun /*
125*4882a593Smuzhiyun * nvmet_set_disc_traddr - set a correct discovery log entry traddr
126*4882a593Smuzhiyun *
127*4882a593Smuzhiyun * IP based transports (e.g RDMA) can listen on "any" ipv4/ipv6 addresses
128*4882a593Smuzhiyun * (INADDR_ANY or IN6ADDR_ANY_INIT). The discovery log page traddr reply
129*4882a593Smuzhiyun * must not contain that "any" IP address. If the transport implements
130*4882a593Smuzhiyun * .disc_traddr, use it. this callback will set the discovery traddr
131*4882a593Smuzhiyun * from the req->port address in case the port in question listens
132*4882a593Smuzhiyun * "any" IP address.
133*4882a593Smuzhiyun */
nvmet_set_disc_traddr(struct nvmet_req * req,struct nvmet_port * port,char * traddr)134*4882a593Smuzhiyun static void nvmet_set_disc_traddr(struct nvmet_req *req, struct nvmet_port *port,
135*4882a593Smuzhiyun char *traddr)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun if (req->ops->disc_traddr)
138*4882a593Smuzhiyun req->ops->disc_traddr(req, port, traddr);
139*4882a593Smuzhiyun else
140*4882a593Smuzhiyun memcpy(traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE);
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
discovery_log_entries(struct nvmet_req * req)143*4882a593Smuzhiyun static size_t discovery_log_entries(struct nvmet_req *req)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun struct nvmet_ctrl *ctrl = req->sq->ctrl;
146*4882a593Smuzhiyun struct nvmet_subsys_link *p;
147*4882a593Smuzhiyun struct nvmet_port *r;
148*4882a593Smuzhiyun size_t entries = 0;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun list_for_each_entry(p, &req->port->subsystems, entry) {
151*4882a593Smuzhiyun if (!nvmet_host_allowed(p->subsys, ctrl->hostnqn))
152*4882a593Smuzhiyun continue;
153*4882a593Smuzhiyun entries++;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun list_for_each_entry(r, &req->port->referrals, entry)
156*4882a593Smuzhiyun entries++;
157*4882a593Smuzhiyun return entries;
158*4882a593Smuzhiyun }
159*4882a593Smuzhiyun
nvmet_execute_disc_get_log_page(struct nvmet_req * req)160*4882a593Smuzhiyun static void nvmet_execute_disc_get_log_page(struct nvmet_req *req)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun const int entry_size = sizeof(struct nvmf_disc_rsp_page_entry);
163*4882a593Smuzhiyun struct nvmet_ctrl *ctrl = req->sq->ctrl;
164*4882a593Smuzhiyun struct nvmf_disc_rsp_page_hdr *hdr;
165*4882a593Smuzhiyun u64 offset = nvmet_get_log_page_offset(req->cmd);
166*4882a593Smuzhiyun size_t data_len = nvmet_get_log_page_len(req->cmd);
167*4882a593Smuzhiyun size_t alloc_len;
168*4882a593Smuzhiyun struct nvmet_subsys_link *p;
169*4882a593Smuzhiyun struct nvmet_port *r;
170*4882a593Smuzhiyun u32 numrec = 0;
171*4882a593Smuzhiyun u16 status = 0;
172*4882a593Smuzhiyun void *buffer;
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if (!nvmet_check_transfer_len(req, data_len))
175*4882a593Smuzhiyun return;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (req->cmd->get_log_page.lid != NVME_LOG_DISC) {
178*4882a593Smuzhiyun req->error_loc =
179*4882a593Smuzhiyun offsetof(struct nvme_get_log_page_command, lid);
180*4882a593Smuzhiyun status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
181*4882a593Smuzhiyun goto out;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /* Spec requires dword aligned offsets */
185*4882a593Smuzhiyun if (offset & 0x3) {
186*4882a593Smuzhiyun req->error_loc =
187*4882a593Smuzhiyun offsetof(struct nvme_get_log_page_command, lpo);
188*4882a593Smuzhiyun status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
189*4882a593Smuzhiyun goto out;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun /*
193*4882a593Smuzhiyun * Make sure we're passing at least a buffer of response header size.
194*4882a593Smuzhiyun * If host provided data len is less than the header size, only the
195*4882a593Smuzhiyun * number of bytes requested by host will be sent to host.
196*4882a593Smuzhiyun */
197*4882a593Smuzhiyun down_read(&nvmet_config_sem);
198*4882a593Smuzhiyun alloc_len = sizeof(*hdr) + entry_size * discovery_log_entries(req);
199*4882a593Smuzhiyun buffer = kzalloc(alloc_len, GFP_KERNEL);
200*4882a593Smuzhiyun if (!buffer) {
201*4882a593Smuzhiyun up_read(&nvmet_config_sem);
202*4882a593Smuzhiyun status = NVME_SC_INTERNAL;
203*4882a593Smuzhiyun goto out;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun hdr = buffer;
207*4882a593Smuzhiyun list_for_each_entry(p, &req->port->subsystems, entry) {
208*4882a593Smuzhiyun char traddr[NVMF_TRADDR_SIZE];
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun if (!nvmet_host_allowed(p->subsys, ctrl->hostnqn))
211*4882a593Smuzhiyun continue;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun nvmet_set_disc_traddr(req, req->port, traddr);
214*4882a593Smuzhiyun nvmet_format_discovery_entry(hdr, req->port,
215*4882a593Smuzhiyun p->subsys->subsysnqn, traddr,
216*4882a593Smuzhiyun NVME_NQN_NVME, numrec);
217*4882a593Smuzhiyun numrec++;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun list_for_each_entry(r, &req->port->referrals, entry) {
221*4882a593Smuzhiyun nvmet_format_discovery_entry(hdr, r,
222*4882a593Smuzhiyun NVME_DISC_SUBSYS_NAME,
223*4882a593Smuzhiyun r->disc_addr.traddr,
224*4882a593Smuzhiyun NVME_NQN_DISC, numrec);
225*4882a593Smuzhiyun numrec++;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun hdr->genctr = cpu_to_le64(nvmet_genctr);
229*4882a593Smuzhiyun hdr->numrec = cpu_to_le64(numrec);
230*4882a593Smuzhiyun hdr->recfmt = cpu_to_le16(0);
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun nvmet_clear_aen_bit(req, NVME_AEN_BIT_DISC_CHANGE);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun up_read(&nvmet_config_sem);
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun status = nvmet_copy_to_sgl(req, 0, buffer + offset, data_len);
237*4882a593Smuzhiyun kfree(buffer);
238*4882a593Smuzhiyun out:
239*4882a593Smuzhiyun nvmet_req_complete(req, status);
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun
nvmet_execute_disc_identify(struct nvmet_req * req)242*4882a593Smuzhiyun static void nvmet_execute_disc_identify(struct nvmet_req *req)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun struct nvmet_ctrl *ctrl = req->sq->ctrl;
245*4882a593Smuzhiyun struct nvme_id_ctrl *id;
246*4882a593Smuzhiyun const char model[] = "Linux";
247*4882a593Smuzhiyun u16 status = 0;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun if (!nvmet_check_transfer_len(req, NVME_IDENTIFY_DATA_SIZE))
250*4882a593Smuzhiyun return;
251*4882a593Smuzhiyun
252*4882a593Smuzhiyun if (req->cmd->identify.cns != NVME_ID_CNS_CTRL) {
253*4882a593Smuzhiyun req->error_loc = offsetof(struct nvme_identify, cns);
254*4882a593Smuzhiyun status = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
255*4882a593Smuzhiyun goto out;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun id = kzalloc(sizeof(*id), GFP_KERNEL);
259*4882a593Smuzhiyun if (!id) {
260*4882a593Smuzhiyun status = NVME_SC_INTERNAL;
261*4882a593Smuzhiyun goto out;
262*4882a593Smuzhiyun }
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun memset(id->sn, ' ', sizeof(id->sn));
265*4882a593Smuzhiyun bin2hex(id->sn, &ctrl->subsys->serial,
266*4882a593Smuzhiyun min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
267*4882a593Smuzhiyun memset(id->fr, ' ', sizeof(id->fr));
268*4882a593Smuzhiyun memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
269*4882a593Smuzhiyun memcpy_and_pad(id->fr, sizeof(id->fr),
270*4882a593Smuzhiyun UTS_RELEASE, strlen(UTS_RELEASE), ' ');
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun /* no limit on data transfer sizes for now */
273*4882a593Smuzhiyun id->mdts = 0;
274*4882a593Smuzhiyun id->cntlid = cpu_to_le16(ctrl->cntlid);
275*4882a593Smuzhiyun id->ver = cpu_to_le32(ctrl->subsys->ver);
276*4882a593Smuzhiyun id->lpa = (1 << 2);
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /* no enforcement soft-limit for maxcmd - pick arbitrary high value */
279*4882a593Smuzhiyun id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun id->sgls = cpu_to_le32(1 << 0); /* we always support SGLs */
282*4882a593Smuzhiyun if (ctrl->ops->flags & NVMF_KEYED_SGLS)
283*4882a593Smuzhiyun id->sgls |= cpu_to_le32(1 << 2);
284*4882a593Smuzhiyun if (req->port->inline_data_size)
285*4882a593Smuzhiyun id->sgls |= cpu_to_le32(1 << 20);
286*4882a593Smuzhiyun
287*4882a593Smuzhiyun id->oaes = cpu_to_le32(NVMET_DISC_AEN_CFG_OPTIONAL);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun strlcpy(id->subnqn, ctrl->subsys->subsysnqn, sizeof(id->subnqn));
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun kfree(id);
294*4882a593Smuzhiyun out:
295*4882a593Smuzhiyun nvmet_req_complete(req, status);
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
nvmet_execute_disc_set_features(struct nvmet_req * req)298*4882a593Smuzhiyun static void nvmet_execute_disc_set_features(struct nvmet_req *req)
299*4882a593Smuzhiyun {
300*4882a593Smuzhiyun u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10);
301*4882a593Smuzhiyun u16 stat;
302*4882a593Smuzhiyun
303*4882a593Smuzhiyun if (!nvmet_check_transfer_len(req, 0))
304*4882a593Smuzhiyun return;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun switch (cdw10 & 0xff) {
307*4882a593Smuzhiyun case NVME_FEAT_KATO:
308*4882a593Smuzhiyun stat = nvmet_set_feat_kato(req);
309*4882a593Smuzhiyun break;
310*4882a593Smuzhiyun case NVME_FEAT_ASYNC_EVENT:
311*4882a593Smuzhiyun stat = nvmet_set_feat_async_event(req,
312*4882a593Smuzhiyun NVMET_DISC_AEN_CFG_OPTIONAL);
313*4882a593Smuzhiyun break;
314*4882a593Smuzhiyun default:
315*4882a593Smuzhiyun req->error_loc =
316*4882a593Smuzhiyun offsetof(struct nvme_common_command, cdw10);
317*4882a593Smuzhiyun stat = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
318*4882a593Smuzhiyun break;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun nvmet_req_complete(req, stat);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
nvmet_execute_disc_get_features(struct nvmet_req * req)324*4882a593Smuzhiyun static void nvmet_execute_disc_get_features(struct nvmet_req *req)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10);
327*4882a593Smuzhiyun u16 stat = 0;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun if (!nvmet_check_transfer_len(req, 0))
330*4882a593Smuzhiyun return;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun switch (cdw10 & 0xff) {
333*4882a593Smuzhiyun case NVME_FEAT_KATO:
334*4882a593Smuzhiyun nvmet_get_feat_kato(req);
335*4882a593Smuzhiyun break;
336*4882a593Smuzhiyun case NVME_FEAT_ASYNC_EVENT:
337*4882a593Smuzhiyun nvmet_get_feat_async_event(req);
338*4882a593Smuzhiyun break;
339*4882a593Smuzhiyun default:
340*4882a593Smuzhiyun req->error_loc =
341*4882a593Smuzhiyun offsetof(struct nvme_common_command, cdw10);
342*4882a593Smuzhiyun stat = NVME_SC_INVALID_FIELD | NVME_SC_DNR;
343*4882a593Smuzhiyun break;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun nvmet_req_complete(req, stat);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
nvmet_parse_discovery_cmd(struct nvmet_req * req)349*4882a593Smuzhiyun u16 nvmet_parse_discovery_cmd(struct nvmet_req *req)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun struct nvme_command *cmd = req->cmd;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun if (unlikely(!(req->sq->ctrl->csts & NVME_CSTS_RDY))) {
354*4882a593Smuzhiyun pr_err("got cmd %d while not ready\n",
355*4882a593Smuzhiyun cmd->common.opcode);
356*4882a593Smuzhiyun req->error_loc =
357*4882a593Smuzhiyun offsetof(struct nvme_common_command, opcode);
358*4882a593Smuzhiyun return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun switch (cmd->common.opcode) {
362*4882a593Smuzhiyun case nvme_admin_set_features:
363*4882a593Smuzhiyun req->execute = nvmet_execute_disc_set_features;
364*4882a593Smuzhiyun return 0;
365*4882a593Smuzhiyun case nvme_admin_get_features:
366*4882a593Smuzhiyun req->execute = nvmet_execute_disc_get_features;
367*4882a593Smuzhiyun return 0;
368*4882a593Smuzhiyun case nvme_admin_async_event:
369*4882a593Smuzhiyun req->execute = nvmet_execute_async_event;
370*4882a593Smuzhiyun return 0;
371*4882a593Smuzhiyun case nvme_admin_keep_alive:
372*4882a593Smuzhiyun req->execute = nvmet_execute_keep_alive;
373*4882a593Smuzhiyun return 0;
374*4882a593Smuzhiyun case nvme_admin_get_log_page:
375*4882a593Smuzhiyun req->execute = nvmet_execute_disc_get_log_page;
376*4882a593Smuzhiyun return 0;
377*4882a593Smuzhiyun case nvme_admin_identify:
378*4882a593Smuzhiyun req->execute = nvmet_execute_disc_identify;
379*4882a593Smuzhiyun return 0;
380*4882a593Smuzhiyun default:
381*4882a593Smuzhiyun pr_err("unhandled cmd %d\n", cmd->common.opcode);
382*4882a593Smuzhiyun req->error_loc = offsetof(struct nvme_common_command, opcode);
383*4882a593Smuzhiyun return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun
nvmet_init_discovery(void)388*4882a593Smuzhiyun int __init nvmet_init_discovery(void)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun nvmet_disc_subsys =
391*4882a593Smuzhiyun nvmet_subsys_alloc(NVME_DISC_SUBSYS_NAME, NVME_NQN_DISC);
392*4882a593Smuzhiyun return PTR_ERR_OR_ZERO(nvmet_disc_subsys);
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun
nvmet_exit_discovery(void)395*4882a593Smuzhiyun void nvmet_exit_discovery(void)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun nvmet_subsys_put(nvmet_disc_subsys);
398*4882a593Smuzhiyun }
399