Skip to content

Commit 60d3cd8

Browse files
damien-lemoalkeithbusch
authored andcommitted
nvmet: Add support for I/O queue management admin commands
The I/O submission queue management admin commands (nvme_admin_delete_sq, nvme_admin_create_sq, nvme_admin_delete_cq, and nvme_admin_create_cq) are mandatory admin commands for I/O controllers using the PCI transport, that is, support for these commands is mandatory for a a PCI target I/O controller. Implement support for these commands by adding the functions nvmet_execute_delete_sq(), nvmet_execute_create_sq(), nvmet_execute_delete_cq() and nvmet_execute_create_cq() to set as the execute method of requests for these commands. These functions will return an invalid opcode error for any controller that is not a PCI target controller. Support for the I/O queue management commands is also reported in the command effect log of PCI target controllers (using nvmet_get_cmd_effects_admin()). Each management command is backed by a controller fabric operation that can be defined by a PCI target controller driver to setup I/O queues using nvmet_sq_create() and nvmet_cq_create() or delete I/O queues using nvmet_sq_destroy(). As noted in a comment in nvmet_execute_create_sq(), we do not yet support sharing a single CQ between multiple SQs. Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Tested-by: Rick Wertenbroek <[email protected]> Tested-by: Manivannan Sadhasivam <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent 1eb380c commit 60d3cd8

File tree

2 files changed

+170
-3
lines changed

2 files changed

+170
-3
lines changed

drivers/nvme/target/admin-cmd.c

Lines changed: 162 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,142 @@
1212
#include <linux/unaligned.h>
1313
#include "nvmet.h"
1414

15+
static void nvmet_execute_delete_sq(struct nvmet_req *req)
16+
{
17+
struct nvmet_ctrl *ctrl = req->sq->ctrl;
18+
u16 sqid = le16_to_cpu(req->cmd->delete_queue.qid);
19+
u16 status;
20+
21+
if (!nvmet_is_pci_ctrl(ctrl)) {
22+
status = nvmet_report_invalid_opcode(req);
23+
goto complete;
24+
}
25+
26+
if (!sqid) {
27+
status = NVME_SC_QID_INVALID | NVME_STATUS_DNR;
28+
goto complete;
29+
}
30+
31+
status = nvmet_check_sqid(ctrl, sqid, false);
32+
if (status != NVME_SC_SUCCESS)
33+
goto complete;
34+
35+
status = ctrl->ops->delete_sq(ctrl, sqid);
36+
37+
complete:
38+
nvmet_req_complete(req, status);
39+
}
40+
41+
static void nvmet_execute_create_sq(struct nvmet_req *req)
42+
{
43+
struct nvmet_ctrl *ctrl = req->sq->ctrl;
44+
struct nvme_command *cmd = req->cmd;
45+
u16 sqid = le16_to_cpu(cmd->create_sq.sqid);
46+
u16 cqid = le16_to_cpu(cmd->create_sq.cqid);
47+
u16 sq_flags = le16_to_cpu(cmd->create_sq.sq_flags);
48+
u16 qsize = le16_to_cpu(cmd->create_sq.qsize);
49+
u64 prp1 = le64_to_cpu(cmd->create_sq.prp1);
50+
u16 status;
51+
52+
if (!nvmet_is_pci_ctrl(ctrl)) {
53+
status = nvmet_report_invalid_opcode(req);
54+
goto complete;
55+
}
56+
57+
if (!sqid) {
58+
status = NVME_SC_QID_INVALID | NVME_STATUS_DNR;
59+
goto complete;
60+
}
61+
62+
status = nvmet_check_sqid(ctrl, sqid, true);
63+
if (status != NVME_SC_SUCCESS)
64+
goto complete;
65+
66+
/*
67+
* Note: The NVMe specification allows multiple SQs to use the same CQ.
68+
* However, the target code does not really support that. So for now,
69+
* prevent this and fail the command if sqid and cqid are different.
70+
*/
71+
if (!cqid || cqid != sqid) {
72+
pr_err("SQ %u: Unsupported CQID %u\n", sqid, cqid);
73+
status = NVME_SC_CQ_INVALID | NVME_STATUS_DNR;
74+
goto complete;
75+
}
76+
77+
if (!qsize || qsize > NVME_CAP_MQES(ctrl->cap)) {
78+
status = NVME_SC_QUEUE_SIZE | NVME_STATUS_DNR;
79+
goto complete;
80+
}
81+
82+
status = ctrl->ops->create_sq(ctrl, sqid, sq_flags, qsize, prp1);
83+
84+
complete:
85+
nvmet_req_complete(req, status);
86+
}
87+
88+
static void nvmet_execute_delete_cq(struct nvmet_req *req)
89+
{
90+
struct nvmet_ctrl *ctrl = req->sq->ctrl;
91+
u16 cqid = le16_to_cpu(req->cmd->delete_queue.qid);
92+
u16 status;
93+
94+
if (!nvmet_is_pci_ctrl(ctrl)) {
95+
status = nvmet_report_invalid_opcode(req);
96+
goto complete;
97+
}
98+
99+
if (!cqid) {
100+
status = NVME_SC_QID_INVALID | NVME_STATUS_DNR;
101+
goto complete;
102+
}
103+
104+
status = nvmet_check_cqid(ctrl, cqid);
105+
if (status != NVME_SC_SUCCESS)
106+
goto complete;
107+
108+
status = ctrl->ops->delete_cq(ctrl, cqid);
109+
110+
complete:
111+
nvmet_req_complete(req, status);
112+
}
113+
114+
static void nvmet_execute_create_cq(struct nvmet_req *req)
115+
{
116+
struct nvmet_ctrl *ctrl = req->sq->ctrl;
117+
struct nvme_command *cmd = req->cmd;
118+
u16 cqid = le16_to_cpu(cmd->create_cq.cqid);
119+
u16 cq_flags = le16_to_cpu(cmd->create_cq.cq_flags);
120+
u16 qsize = le16_to_cpu(cmd->create_cq.qsize);
121+
u16 irq_vector = le16_to_cpu(cmd->create_cq.irq_vector);
122+
u64 prp1 = le64_to_cpu(cmd->create_cq.prp1);
123+
u16 status;
124+
125+
if (!nvmet_is_pci_ctrl(ctrl)) {
126+
status = nvmet_report_invalid_opcode(req);
127+
goto complete;
128+
}
129+
130+
if (!cqid) {
131+
status = NVME_SC_QID_INVALID | NVME_STATUS_DNR;
132+
goto complete;
133+
}
134+
135+
status = nvmet_check_cqid(ctrl, cqid);
136+
if (status != NVME_SC_SUCCESS)
137+
goto complete;
138+
139+
if (!qsize || qsize > NVME_CAP_MQES(ctrl->cap)) {
140+
status = NVME_SC_QUEUE_SIZE | NVME_STATUS_DNR;
141+
goto complete;
142+
}
143+
144+
status = ctrl->ops->create_cq(ctrl, cqid, cq_flags, qsize,
145+
prp1, irq_vector);
146+
147+
complete:
148+
nvmet_req_complete(req, status);
149+
}
150+
15151
u32 nvmet_get_log_page_len(struct nvme_command *cmd)
16152
{
17153
u32 len = le16_to_cpu(cmd->get_log_page.numdu);
@@ -230,8 +366,18 @@ static void nvmet_execute_get_log_page_smart(struct nvmet_req *req)
230366
nvmet_req_complete(req, status);
231367
}
232368

233-
static void nvmet_get_cmd_effects_admin(struct nvme_effects_log *log)
369+
static void nvmet_get_cmd_effects_admin(struct nvmet_ctrl *ctrl,
370+
struct nvme_effects_log *log)
234371
{
372+
/* For a PCI target controller, advertize support for the . */
373+
if (nvmet_is_pci_ctrl(ctrl)) {
374+
log->acs[nvme_admin_delete_sq] =
375+
log->acs[nvme_admin_create_sq] =
376+
log->acs[nvme_admin_delete_cq] =
377+
log->acs[nvme_admin_create_cq] =
378+
cpu_to_le32(NVME_CMD_EFFECTS_CSUPP);
379+
}
380+
235381
log->acs[nvme_admin_get_log_page] =
236382
log->acs[nvme_admin_identify] =
237383
log->acs[nvme_admin_abort_cmd] =
@@ -268,6 +414,7 @@ static void nvmet_get_cmd_effects_zns(struct nvme_effects_log *log)
268414

269415
static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
270416
{
417+
struct nvmet_ctrl *ctrl = req->sq->ctrl;
271418
struct nvme_effects_log *log;
272419
u16 status = NVME_SC_SUCCESS;
273420

@@ -279,15 +426,15 @@ static void nvmet_execute_get_log_cmd_effects_ns(struct nvmet_req *req)
279426

280427
switch (req->cmd->get_log_page.csi) {
281428
case NVME_CSI_NVM:
282-
nvmet_get_cmd_effects_admin(log);
429+
nvmet_get_cmd_effects_admin(ctrl, log);
283430
nvmet_get_cmd_effects_nvm(log);
284431
break;
285432
case NVME_CSI_ZNS:
286433
if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
287434
status = NVME_SC_INVALID_IO_CMD_SET;
288435
goto free;
289436
}
290-
nvmet_get_cmd_effects_admin(log);
437+
nvmet_get_cmd_effects_admin(ctrl, log);
291438
nvmet_get_cmd_effects_nvm(log);
292439
nvmet_get_cmd_effects_zns(log);
293440
break;
@@ -1335,9 +1482,21 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
13351482
return nvmet_parse_passthru_admin_cmd(req);
13361483

13371484
switch (cmd->common.opcode) {
1485+
case nvme_admin_delete_sq:
1486+
req->execute = nvmet_execute_delete_sq;
1487+
return 0;
1488+
case nvme_admin_create_sq:
1489+
req->execute = nvmet_execute_create_sq;
1490+
return 0;
13381491
case nvme_admin_get_log_page:
13391492
req->execute = nvmet_execute_get_log_page;
13401493
return 0;
1494+
case nvme_admin_delete_cq:
1495+
req->execute = nvmet_execute_delete_cq;
1496+
return 0;
1497+
case nvme_admin_create_cq:
1498+
req->execute = nvmet_execute_create_cq;
1499+
return 0;
13411500
case nvme_admin_identify:
13421501
req->execute = nvmet_execute_identify;
13431502
return 0;

drivers/nvme/target/nvmet.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,14 @@ struct nvmet_fabrics_ops {
408408
void (*discovery_chg)(struct nvmet_port *port);
409409
u8 (*get_mdts)(const struct nvmet_ctrl *ctrl);
410410
u16 (*get_max_queue_size)(const struct nvmet_ctrl *ctrl);
411+
412+
/* Operations mandatory for PCI target controllers */
413+
u16 (*create_sq)(struct nvmet_ctrl *ctrl, u16 sqid, u16 flags,
414+
u16 qsize, u64 prp1);
415+
u16 (*delete_sq)(struct nvmet_ctrl *ctrl, u16 sqid);
416+
u16 (*create_cq)(struct nvmet_ctrl *ctrl, u16 cqid, u16 flags,
417+
u16 qsize, u64 prp1, u16 irq_vector);
418+
u16 (*delete_cq)(struct nvmet_ctrl *ctrl, u16 cqid);
411419
};
412420

413421
#define NVMET_MAX_INLINE_BIOVEC 8

0 commit comments

Comments
 (0)