History

nvmet: add passthru code to process commands

Add passthru command handling capability for the NVMeOF target and export passthru APIs which are used to integrate passthru code with nvmet-core. The new file passthru.c handles passthru cmd parsing and execution. In the passthru mode, we create a block layer request from the nvmet request and map the data on to the block layer request. Admin commands and features are on an allow list as there are a number of each that don't make too much sense with passthrough. We use an allow list such that new commands can be considered before being blindly passed through. In both cases, vendor specific commands are always allowed. We also reject reservation IO commands as the underlying device cannot differentiate between multiple hosts behind a fabric.

Logan Gunthorpe committed 6 years ago

Commit c1fef731 parent 24493b86 files · +510 −2Browse files

Unified · Split

6 files
  1. drivers/nvme/target/Makefile +1 −0
  2. drivers/nvme/target/admin-cmd.c +5 −2
  3. drivers/nvme/target/core.c +3 −0
  4. drivers/nvme/target/nvmet.h +39 −0
  5. drivers/nvme/target/passthru.c +458 −0
  6. include/linux/nvme.h +4 −0
drivers/nvme/target/Makefile+1−0
@@ -11,6 +11,7 @@ obj-$(CONFIG_NVME_TARGET_TCP) += nvmet-tcp.o · 10 unmodified lines
1111
1212 nvmet-y += core.o configfs.o admin-cmd.o fabrics-cmd.o \
1313 discovery.o io-cmd-file.o io-cmd-bdev.o
14+nvmet-$(CONFIG_NVME_TARGET_PASSTHRU) += passthru.o
1415 nvme-loop-y += loop.o
1516 nvmet-rdma-y += rdma.o
1617 nvmet-fc-y += fc.o
drivers/nvme/target/admin-cmd.c+5−2
@@ -749,7 +749,7 @@ u16 nvmet_set_feat_async_event(struct nvmet_req *req, u32 mask) · 748 unmodified lines
749749 return 0;
750750 }
751751
752−static void nvmet_execute_set_features(struct nvmet_req *req)
752+void nvmet_execute_set_features(struct nvmet_req *req)
753753 {
754754 struct nvmet_subsys *subsys = req->sq->ctrl->subsys;
755755 u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10);
@@ -824,7 +824,7 @@ void nvmet_get_feat_async_event(struct nvmet_req *req) · 68 unmodified lines
824824 nvmet_set_result(req, READ_ONCE(req->sq->ctrl->aen_enabled));
825825 }
826826
827−static void nvmet_execute_get_features(struct nvmet_req *req)
827+void nvmet_execute_get_features(struct nvmet_req *req)
828828 {
829829 struct nvmet_subsys *subsys = req->sq->ctrl->subsys;
830830 u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10);
@@ -940,6 +940,9 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req) · 109 unmodified lines
940940 if (unlikely(ret))
941941 return ret;
942942
943+ if (nvmet_req_passthru_ctrl(req))
944+ return nvmet_parse_passthru_admin_cmd(req);
945+
943946 switch (cmd->common.opcode) {
944947 case nvme_admin_get_log_page:
945948 req->execute = nvmet_execute_get_log_page;
drivers/nvme/target/core.c+3−0
@@ -849,6 +849,9 @@ static u16 nvmet_parse_io_cmd(struct nvmet_req *req) · 848 unmodified lines
849849 if (unlikely(ret))
850850 return ret;
851851
852+ if (nvmet_req_passthru_ctrl(req))
853+ return nvmet_parse_passthru_io_cmd(req);
854+
852855 req->ns = nvmet_find_namespace(req->sq->ctrl, cmd->rw.nsid);
853856 if (unlikely(!req->ns)) {
854857 req->error_loc = offsetof(struct nvme_common_command, nsid);
drivers/nvme/target/nvmet.h+39−0
@@ -242,6 +242,10 @@ struct nvmet_subsys { · 241 unmodified lines
242242 struct config_group allowed_hosts_group;
243243
244244 struct nvmet_subsys_model __rcu *model;
245+
246+#ifdef CONFIG_NVME_TARGET_PASSTHRU
247+ struct nvme_ctrl *passthru_ctrl;
248+#endif /* CONFIG_NVME_TARGET_PASSTHRU */
245249 };
246250
247251 static inline struct nvmet_subsys *to_subsys(struct config_item *item)
@@ -321,6 +325,11 @@ struct nvmet_req { · 73 unmodified lines
321325 struct bio_vec *bvec;
322326 struct work_struct work;
323327 } f;
328+ struct {
329+ struct request *rq;
330+ struct work_struct work;
331+ bool use_workqueue;
332+ } p;
324333 };
325334 int sg_cnt;
326335 int metadata_sg_cnt;
@@ -400,6 +409,8 @@ void nvmet_req_complete(struct nvmet_req *req, u16 status); · 73 unmodified lines
400409 int nvmet_req_alloc_sgls(struct nvmet_req *req);
401410 void nvmet_req_free_sgls(struct nvmet_req *req);
402411
412+void nvmet_execute_set_features(struct nvmet_req *req);
413+void nvmet_execute_get_features(struct nvmet_req *req);
403414 void nvmet_execute_keep_alive(struct nvmet_req *req);
404415
405416 void nvmet_cq_setup(struct nvmet_ctrl *ctrl, struct nvmet_cq *cq, u16 qid,
@@ -532,6 +543,34 @@ static inline u32 nvmet_dsm_len(struct nvmet_req *req) · 126 unmodified lines
532543 sizeof(struct nvme_dsm_range);
533544 }
534545
546+#ifdef CONFIG_NVME_TARGET_PASSTHRU
547+u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req);
548+u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req);
549+static inline struct nvme_ctrl *nvmet_passthru_ctrl(struct nvmet_subsys *subsys)
550+{
551+ return subsys->passthru_ctrl;
552+}
553+#else /* CONFIG_NVME_TARGET_PASSTHRU */
554+static inline u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
555+{
556+ return 0;
557+}
558+static inline u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req)
559+{
560+ return 0;
561+}
562+static inline struct nvme_ctrl *nvmet_passthru_ctrl(struct nvmet_subsys *subsys)
563+{
564+ return NULL;
565+}
566+#endif /* CONFIG_NVME_TARGET_PASSTHRU */
567+
568+static inline struct nvme_ctrl *
569+nvmet_req_passthru_ctrl(struct nvmet_req *req)
570+{
571+ return nvmet_passthru_ctrl(req->sq->ctrl->subsys);
572+}
573+
535574 u16 errno_to_nvme_status(struct nvmet_req *req, int errno);
536575
537576 /* Convert a 32-bit number to a 16-bit 0's based number */
drivers/nvme/target/passthru.c+458−0
@@ -0,0 +1,458 @@
1+// SPDX-License-Identifier: GPL-2.0
2+/*
3+ * NVMe Over Fabrics Target Passthrough command implementation.
4+ *
5+ * Copyright (c) 2017-2018 Western Digital Corporation or its
6+ * affiliates.
7+ * Copyright (c) 2019-2020, Eideticom Inc.
8+ *
9+ */
10+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11+#include <linux/module.h>
12+
13+#include "../host/nvme.h"
14+#include "nvmet.h"
15+
16+MODULE_IMPORT_NS(NVME_TARGET_PASSTHRU);
17+
18+static u16 nvmet_passthru_override_id_ctrl(struct nvmet_req *req)
19+{
20+ struct nvmet_ctrl *ctrl = req->sq->ctrl;
21+ struct nvme_ctrl *pctrl = ctrl->subsys->passthru_ctrl;
22+ u16 status = NVME_SC_SUCCESS;
23+ struct nvme_id_ctrl *id;
24+ u32 max_hw_sectors;
25+ int page_shift;
26+
27+ id = kzalloc(sizeof(*id), GFP_KERNEL);
28+ if (!id)
29+ return NVME_SC_INTERNAL;
30+
31+ status = nvmet_copy_from_sgl(req, 0, id, sizeof(*id));
32+ if (status)
33+ goto out_free;
34+
35+ id->cntlid = cpu_to_le16(ctrl->cntlid);
36+ id->ver = cpu_to_le32(ctrl->subsys->ver);
37+
38+ /*
39+ * The passthru NVMe driver may have a limit on the number of segments
40+ * which depends on the host's memory fragementation. To solve this,
41+ * ensure mdts is limited to the pages equal to the number of segments.
42+ */
43+ max_hw_sectors = min_not_zero(pctrl->max_segments << (PAGE_SHIFT - 9),
44+ pctrl->max_hw_sectors);
45+
46+ page_shift = NVME_CAP_MPSMIN(ctrl->cap) + 12;
47+
48+ id->mdts = ilog2(max_hw_sectors) + 9 - page_shift;
49+
50+ id->acl = 3;
51+ /*
52+ * We export aerl limit for the fabrics controller, update this when
53+ * passthru based aerl support is added.
54+ */
55+ id->aerl = NVMET_ASYNC_EVENTS - 1;
56+
57+ /* emulate kas as most of the PCIe ctrl don't have a support for kas */
58+ id->kas = cpu_to_le16(NVMET_KAS);
59+
60+ /* don't support host memory buffer */
61+ id->hmpre = 0;
62+ id->hmmin = 0;
63+
64+ id->sqes = min_t(__u8, ((0x6 << 4) | 0x6), id->sqes);
65+ id->cqes = min_t(__u8, ((0x4 << 4) | 0x4), id->cqes);
66+ id->maxcmd = cpu_to_le16(NVMET_MAX_CMD);
67+
68+ /* don't support fuse commands */
69+ id->fuses = 0;
70+
71+ id->sgls = cpu_to_le32(1 << 0); /* we always support SGLs */
72+ if (ctrl->ops->flags & NVMF_KEYED_SGLS)
73+ id->sgls |= cpu_to_le32(1 << 2);
74+ if (req->port->inline_data_size)
75+ id->sgls |= cpu_to_le32(1 << 20);
76+
77+ /*
78+ * When passsthru controller is setup using nvme-loop transport it will
79+ * export the passthru ctrl subsysnqn (PCIe NVMe ctrl) and will fail in
80+ * the nvme/host/core.c in the nvme_init_subsystem()->nvme_active_ctrl()
81+ * code path with duplicate ctr subsynqn. In order to prevent that we
82+ * mask the passthru-ctrl subsysnqn with the target ctrl subsysnqn.
83+ */
84+ memcpy(id->subnqn, ctrl->subsysnqn, sizeof(id->subnqn));
85+
86+ /* use fabric id-ctrl values */
87+ id->ioccsz = cpu_to_le32((sizeof(struct nvme_command) +
88+ req->port->inline_data_size) / 16);
89+ id->iorcsz = cpu_to_le32(sizeof(struct nvme_completion) / 16);
90+
91+ id->msdbd = ctrl->ops->msdbd;
92+
93+ /* Support multipath connections with fabrics */
94+ id->cmic |= 1 << 1;
95+
96+ /* Disable reservations, see nvmet_parse_passthru_io_cmd() */
97+ id->oncs &= cpu_to_le16(~NVME_CTRL_ONCS_RESERVATIONS);
98+
99+ status = nvmet_copy_to_sgl(req, 0, id, sizeof(struct nvme_id_ctrl));
100+
101+out_free:
102+ kfree(id);
103+ return status;
104+}
105+
106+static u16 nvmet_passthru_override_id_ns(struct nvmet_req *req)
107+{
108+ u16 status = NVME_SC_SUCCESS;
109+ struct nvme_id_ns *id;
110+ int i;
111+
112+ id = kzalloc(sizeof(*id), GFP_KERNEL);
113+ if (!id)
114+ return NVME_SC_INTERNAL;
115+
116+ status = nvmet_copy_from_sgl(req, 0, id, sizeof(struct nvme_id_ns));
117+ if (status)
118+ goto out_free;
119+
120+ for (i = 0; i < (id->nlbaf + 1); i++)
121+ if (id->lbaf[i].ms)
122+ memset(&id->lbaf[i], 0, sizeof(id->lbaf[i]));
123+
124+ id->flbas = id->flbas & ~(1 << 4);
125+
126+ /*
127+ * Presently the NVMEof target code does not support sending
128+ * metadata, so we must disable it here. This should be updated
129+ * once target starts supporting metadata.
130+ */
131+ id->mc = 0;
132+
133+ status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));
134+
135+out_free:
136+ kfree(id);
137+ return status;
138+}
139+
140+static void nvmet_passthru_execute_cmd_work(struct work_struct *w)
141+{
142+ struct nvmet_req *req = container_of(w, struct nvmet_req, p.work);
143+ struct request *rq = req->p.rq;
144+ u16 status;
145+
146+ nvme_execute_passthru_rq(rq);
147+
148+ status = nvme_req(rq)->status;
149+ if (status == NVME_SC_SUCCESS &&
150+ req->cmd->common.opcode == nvme_admin_identify) {
151+ switch (req->cmd->identify.cns) {
152+ case NVME_ID_CNS_CTRL:
153+ nvmet_passthru_override_id_ctrl(req);
154+ break;
155+ case NVME_ID_CNS_NS:
156+ nvmet_passthru_override_id_ns(req);
157+ break;
158+ }
159+ }
160+
161+ req->cqe->result = nvme_req(rq)->result;
162+ nvmet_req_complete(req, status);
163+ blk_put_request(rq);
164+}
165+
166+static void nvmet_passthru_req_done(struct request *rq,
167+ blk_status_t blk_status)
168+{
169+ struct nvmet_req *req = rq->end_io_data;
170+
171+ req->cqe->result = nvme_req(rq)->result;
172+ nvmet_req_complete(req, nvme_req(rq)->status);
173+ blk_put_request(rq);
174+}
175+
176+static int nvmet_passthru_map_sg(struct nvmet_req *req, struct request *rq)
177+{
178+ int sg_cnt = req->sg_cnt;
179+ struct scatterlist *sg;
180+ int op_flags = 0;
181+ struct bio *bio;
182+ int i, ret;
183+
184+ if (req->cmd->common.opcode == nvme_cmd_flush)
185+ op_flags = REQ_FUA;
186+ else if (nvme_is_write(req->cmd))
187+ op_flags = REQ_SYNC | REQ_IDLE;
188+
189+ bio = bio_alloc(GFP_KERNEL, min(sg_cnt, BIO_MAX_PAGES));
190+ bio->bi_end_io = bio_put;
191+ bio->bi_opf = req_op(rq) | op_flags;
192+
193+ for_each_sg(req->sg, sg, req->sg_cnt, i) {
194+ if (bio_add_pc_page(rq->q, bio, sg_page(sg), sg->length,
195+ sg->offset) < sg->length) {
196+ bio_put(bio);
197+ return -EINVAL;
198+ }
199+ sg_cnt--;
200+ }
201+
202+ ret = blk_rq_append_bio(rq, &bio);
203+ if (unlikely(ret)) {
204+ bio_put(bio);
205+ return ret;
206+ }
207+
208+ return 0;
209+}
210+
211+static void nvmet_passthru_execute_cmd(struct nvmet_req *req)
212+{
213+ struct nvme_ctrl *ctrl = nvmet_req_passthru_ctrl(req);
214+ struct request_queue *q = ctrl->admin_q;
215+ struct nvme_ns *ns = NULL;
216+ struct request *rq = NULL;
217+ u32 effects;
218+ u16 status;
219+ int ret;
220+
221+ if (likely(req->sq->qid != 0)) {
222+ u32 nsid = le32_to_cpu(req->cmd->common.nsid);
223+
224+ ns = nvme_find_get_ns(ctrl, nsid);
225+ if (unlikely(!ns)) {
226+ pr_err("failed to get passthru ns nsid:%u\n", nsid);
227+ status = NVME_SC_INVALID_NS | NVME_SC_DNR;
228+ goto fail_out;
229+ }
230+
231+ q = ns->queue;
232+ }
233+
234+ rq = nvme_alloc_request(q, req->cmd, BLK_MQ_REQ_NOWAIT, NVME_QID_ANY);
235+ if (IS_ERR(rq)) {
236+ rq = NULL;
237+ status = NVME_SC_INTERNAL;
238+ goto fail_out;
239+ }
240+
241+ if (req->sg_cnt) {
242+ ret = nvmet_passthru_map_sg(req, rq);
243+ if (unlikely(ret)) {
244+ status = NVME_SC_INTERNAL;
245+ goto fail_out;
246+ }
247+ }
248+
249+ /*
250+ * If there are effects for the command we are about to execute, or
251+ * an end_req function we need to use nvme_execute_passthru_rq()
252+ * synchronously in a work item seeing the end_req function and
253+ * nvme_passthru_end() can't be called in the request done callback
254+ * which is typically in interrupt context.
255+ */
256+ effects = nvme_command_effects(ctrl, ns, req->cmd->common.opcode);
257+ if (req->p.use_workqueue || effects) {
258+ INIT_WORK(&req->p.work, nvmet_passthru_execute_cmd_work);
259+ req->p.rq = rq;
260+ schedule_work(&req->p.work);
261+ } else {
262+ rq->end_io_data = req;
263+ blk_execute_rq_nowait(rq->q, ns ? ns->disk : NULL, rq, 0,
264+ nvmet_passthru_req_done);
265+ }
266+
267+ if (ns)
268+ nvme_put_ns(ns);
269+
270+ return;
271+
272+fail_out:
273+ if (ns)
274+ nvme_put_ns(ns);
275+ nvmet_req_complete(req, status);
276+ blk_put_request(rq);
277+}
278+
279+/*
280+ * We need to emulate set host behaviour to ensure that any requested
281+ * behaviour of the target's host matches the requested behaviour
282+ * of the device's host and fail otherwise.
283+ */
284+static void nvmet_passthru_set_host_behaviour(struct nvmet_req *req)
285+{
286+ struct nvme_ctrl *ctrl = nvmet_req_passthru_ctrl(req);
287+ struct nvme_feat_host_behavior *host;
288+ u16 status = NVME_SC_INTERNAL;
289+ int ret;
290+
291+ host = kzalloc(sizeof(*host) * 2, GFP_KERNEL);
292+ if (!host)
293+ goto out_complete_req;
294+
295+ ret = nvme_get_features(ctrl, NVME_FEAT_HOST_BEHAVIOR, 0,
296+ host, sizeof(*host), NULL);
297+ if (ret)
298+ goto out_free_host;
299+
300+ status = nvmet_copy_from_sgl(req, 0, &host[1], sizeof(*host));
301+ if (status)
302+ goto out_free_host;
303+
304+ if (memcmp(&host[0], &host[1], sizeof(host[0]))) {
305+ pr_warn("target host has requested different behaviour from the local host\n");
306+ status = NVME_SC_INTERNAL;
307+ }
308+
309+out_free_host:
310+ kfree(host);
311+out_complete_req:
312+ nvmet_req_complete(req, status);
313+}
314+
315+static u16 nvmet_setup_passthru_command(struct nvmet_req *req)
316+{
317+ req->p.use_workqueue = false;
318+ req->execute = nvmet_passthru_execute_cmd;
319+ return NVME_SC_SUCCESS;
320+}
321+
322+u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req)
323+{
324+ switch (req->cmd->common.opcode) {
325+ case nvme_cmd_resv_register:
326+ case nvme_cmd_resv_report:
327+ case nvme_cmd_resv_acquire:
328+ case nvme_cmd_resv_release:
329+ /*
330+ * Reservations cannot be supported properly because the
331+ * underlying device has no way of differentiating different
332+ * hosts that connect via fabrics. This could potentially be
333+ * emulated in the future if regular targets grow support for
334+ * this feature.
335+ */
336+ return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
337+ }
338+
339+ return nvmet_setup_passthru_command(req);
340+}
341+
342+/*
343+ * Only features that are emulated or specifically allowed in the list are
344+ * passed down to the controller. This function implements the allow list for
345+ * both get and set features.
346+ */
347+static u16 nvmet_passthru_get_set_features(struct nvmet_req *req)
348+{
349+ switch (le32_to_cpu(req->cmd->features.fid)) {
350+ case NVME_FEAT_ARBITRATION:
351+ case NVME_FEAT_POWER_MGMT:
352+ case NVME_FEAT_LBA_RANGE:
353+ case NVME_FEAT_TEMP_THRESH:
354+ case NVME_FEAT_ERR_RECOVERY:
355+ case NVME_FEAT_VOLATILE_WC:
356+ case NVME_FEAT_WRITE_ATOMIC:
357+ case NVME_FEAT_AUTO_PST:
358+ case NVME_FEAT_TIMESTAMP:
359+ case NVME_FEAT_HCTM:
360+ case NVME_FEAT_NOPSC:
361+ case NVME_FEAT_RRL:
362+ case NVME_FEAT_PLM_CONFIG:
363+ case NVME_FEAT_PLM_WINDOW:
364+ case NVME_FEAT_HOST_BEHAVIOR:
365+ case NVME_FEAT_SANITIZE:
366+ case NVME_FEAT_VENDOR_START ... NVME_FEAT_VENDOR_END:
367+ return nvmet_setup_passthru_command(req);
368+
369+ case NVME_FEAT_ASYNC_EVENT:
370+ /* There is no support for forwarding ASYNC events */
371+ case NVME_FEAT_IRQ_COALESCE:
372+ case NVME_FEAT_IRQ_CONFIG:
373+ /* The IRQ settings will not apply to the target controller */
374+ case NVME_FEAT_HOST_MEM_BUF:
375+ /*
376+ * Any HMB that's set will not be passed through and will
377+ * not work as expected
378+ */
379+ case NVME_FEAT_SW_PROGRESS:
380+ /*
381+ * The Pre-Boot Software Load Count doesn't make much
382+ * sense for a target to export
383+ */
384+ case NVME_FEAT_RESV_MASK:
385+ case NVME_FEAT_RESV_PERSIST:
386+ /* No reservations, see nvmet_parse_passthru_io_cmd() */
387+ default:
388+ return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
389+ }
390+}
391+
392+u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
393+{
394+ /*
395+ * Passthru all vendor specific commands
396+ */
397+ if (req->cmd->common.opcode >= nvme_admin_vendor_start)
398+ return nvmet_setup_passthru_command(req);
399+
400+ switch (req->cmd->common.opcode) {
401+ case nvme_admin_async_event:
402+ req->execute = nvmet_execute_async_event;
403+ return NVME_SC_SUCCESS;
404+ case nvme_admin_keep_alive:
405+ /*
406+ * Most PCIe ctrls don't support keep alive cmd, we route keep
407+ * alive to the non-passthru mode. In future please change this
408+ * code when PCIe ctrls with keep alive support available.
409+ */
410+ req->execute = nvmet_execute_keep_alive;
411+ return NVME_SC_SUCCESS;
412+ case nvme_admin_set_features:
413+ switch (le32_to_cpu(req->cmd->features.fid)) {
414+ case NVME_FEAT_ASYNC_EVENT:
415+ case NVME_FEAT_KATO:
416+ case NVME_FEAT_NUM_QUEUES:
417+ case NVME_FEAT_HOST_ID:
418+ req->execute = nvmet_execute_set_features;
419+ return NVME_SC_SUCCESS;
420+ case NVME_FEAT_HOST_BEHAVIOR:
421+ req->execute = nvmet_passthru_set_host_behaviour;
422+ return NVME_SC_SUCCESS;
423+ default:
424+ return nvmet_passthru_get_set_features(req);
425+ }
426+ break;
427+ case nvme_admin_get_features:
428+ switch (le32_to_cpu(req->cmd->features.fid)) {
429+ case NVME_FEAT_ASYNC_EVENT:
430+ case NVME_FEAT_KATO:
431+ case NVME_FEAT_NUM_QUEUES:
432+ case NVME_FEAT_HOST_ID:
433+ req->execute = nvmet_execute_get_features;
434+ return NVME_SC_SUCCESS;
435+ default:
436+ return nvmet_passthru_get_set_features(req);
437+ }
438+ break;
439+ case nvme_admin_identify:
440+ switch (req->cmd->identify.cns) {
441+ case NVME_ID_CNS_CTRL:
442+ req->execute = nvmet_passthru_execute_cmd;
443+ req->p.use_workqueue = true;
444+ return NVME_SC_SUCCESS;
445+ case NVME_ID_CNS_NS:
446+ req->execute = nvmet_passthru_execute_cmd;
447+ req->p.use_workqueue = true;
448+ return NVME_SC_SUCCESS;
449+ default:
450+ return nvmet_setup_passthru_command(req);
451+ }
452+ case nvme_admin_get_log_page:
453+ return nvmet_setup_passthru_command(req);
454+ default:
455+ /* Reject commands not in the allowlist above */
456+ return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
457+ }
458+}
include/linux/nvme.h+4−0
@@ -312,6 +312,7 @@ enum { · 311 unmodified lines
312312 NVME_CTRL_ONCS_WRITE_UNCORRECTABLE = 1 << 1,
313313 NVME_CTRL_ONCS_DSM = 1 << 2,
314314 NVME_CTRL_ONCS_WRITE_ZEROES = 1 << 3,
315+ NVME_CTRL_ONCS_RESERVATIONS = 1 << 5,
315316 NVME_CTRL_ONCS_TIMESTAMP = 1 << 6,
316317 NVME_CTRL_VWC_PRESENT = 1 << 0,
317318 NVME_CTRL_OACS_SEC_SUPP = 1 << 0,
@@ -982,6 +983,7 @@ enum nvme_admin_opcode { · 664 unmodified lines
982983 nvme_admin_security_recv = 0x82,
983984 nvme_admin_sanitize_nvm = 0x84,
984985 nvme_admin_get_lba_status = 0x86,
986+ nvme_admin_vendor_start = 0xC0,
985987 };
986988
987989 #define nvme_admin_opcode_name(opcode) { opcode, #opcode }
@@ -1045,6 +1047,8 @@ enum { · 57 unmodified lines
10451047 NVME_FEAT_RESV_MASK = 0x82,
10461048 NVME_FEAT_RESV_PERSIST = 0x83,
10471049 NVME_FEAT_WRITE_PROTECT = 0x84,
1050+ NVME_FEAT_VENDOR_START = 0xC0,
1051+ NVME_FEAT_VENDOR_END = 0xFF,
10481052 NVME_LOG_ERROR = 0x01,
10491053 NVME_LOG_SMART = 0x02,
10501054 NVME_LOG_FW_SLOT = 0x03,