1*83dc2f33SJohn Baldwin /*-
2*83dc2f33SJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause
3*83dc2f33SJohn Baldwin *
4*83dc2f33SJohn Baldwin * Copyright (c) 2023-2024 Chelsio Communications, Inc.
5*83dc2f33SJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org>
6*83dc2f33SJohn Baldwin */
7*83dc2f33SJohn Baldwin
8*83dc2f33SJohn Baldwin #include <err.h>
9*83dc2f33SJohn Baldwin #include <errno.h>
10*83dc2f33SJohn Baldwin #include <libnvmf.h>
11*83dc2f33SJohn Baldwin #include <stdlib.h>
12*83dc2f33SJohn Baldwin
13*83dc2f33SJohn Baldwin #include "internal.h"
14*83dc2f33SJohn Baldwin
15*83dc2f33SJohn Baldwin struct controller {
16*83dc2f33SJohn Baldwin struct nvmf_qpair *qp;
17*83dc2f33SJohn Baldwin
18*83dc2f33SJohn Baldwin uint64_t cap;
19*83dc2f33SJohn Baldwin uint32_t vs;
20*83dc2f33SJohn Baldwin uint32_t cc;
21*83dc2f33SJohn Baldwin uint32_t csts;
22*83dc2f33SJohn Baldwin
23*83dc2f33SJohn Baldwin bool shutdown;
24*83dc2f33SJohn Baldwin
25*83dc2f33SJohn Baldwin struct nvme_controller_data cdata;
26*83dc2f33SJohn Baldwin };
27*83dc2f33SJohn Baldwin
28*83dc2f33SJohn Baldwin static bool
update_cc(struct controller * c,uint32_t new_cc)29*83dc2f33SJohn Baldwin update_cc(struct controller *c, uint32_t new_cc)
30*83dc2f33SJohn Baldwin {
31*83dc2f33SJohn Baldwin uint32_t changes;
32*83dc2f33SJohn Baldwin
33*83dc2f33SJohn Baldwin if (c->shutdown)
34*83dc2f33SJohn Baldwin return (false);
35*83dc2f33SJohn Baldwin if (!nvmf_validate_cc(c->qp, c->cap, c->cc, new_cc))
36*83dc2f33SJohn Baldwin return (false);
37*83dc2f33SJohn Baldwin
38*83dc2f33SJohn Baldwin changes = c->cc ^ new_cc;
39*83dc2f33SJohn Baldwin c->cc = new_cc;
40*83dc2f33SJohn Baldwin
41*83dc2f33SJohn Baldwin /* Handle shutdown requests. */
42*83dc2f33SJohn Baldwin if (NVMEV(NVME_CC_REG_SHN, changes) != 0 &&
43*83dc2f33SJohn Baldwin NVMEV(NVME_CC_REG_SHN, new_cc) != 0) {
44*83dc2f33SJohn Baldwin c->csts &= ~NVMEM(NVME_CSTS_REG_SHST);
45*83dc2f33SJohn Baldwin c->csts |= NVMEF(NVME_CSTS_REG_SHST, NVME_SHST_COMPLETE);
46*83dc2f33SJohn Baldwin c->shutdown = true;
47*83dc2f33SJohn Baldwin }
48*83dc2f33SJohn Baldwin
49*83dc2f33SJohn Baldwin if (NVMEV(NVME_CC_REG_EN, changes) != 0) {
50*83dc2f33SJohn Baldwin if (NVMEV(NVME_CC_REG_EN, new_cc) == 0) {
51*83dc2f33SJohn Baldwin /* Controller reset. */
52*83dc2f33SJohn Baldwin c->csts = 0;
53*83dc2f33SJohn Baldwin c->shutdown = true;
54*83dc2f33SJohn Baldwin } else
55*83dc2f33SJohn Baldwin c->csts |= NVMEF(NVME_CSTS_REG_RDY, 1);
56*83dc2f33SJohn Baldwin }
57*83dc2f33SJohn Baldwin return (true);
58*83dc2f33SJohn Baldwin }
59*83dc2f33SJohn Baldwin
60*83dc2f33SJohn Baldwin static void
handle_property_get(const struct controller * c,const struct nvmf_capsule * nc,const struct nvmf_fabric_prop_get_cmd * pget)61*83dc2f33SJohn Baldwin handle_property_get(const struct controller *c, const struct nvmf_capsule *nc,
62*83dc2f33SJohn Baldwin const struct nvmf_fabric_prop_get_cmd *pget)
63*83dc2f33SJohn Baldwin {
64*83dc2f33SJohn Baldwin struct nvmf_fabric_prop_get_rsp rsp;
65*83dc2f33SJohn Baldwin
66*83dc2f33SJohn Baldwin nvmf_init_cqe(&rsp, nc, 0);
67*83dc2f33SJohn Baldwin
68*83dc2f33SJohn Baldwin switch (le32toh(pget->ofst)) {
69*83dc2f33SJohn Baldwin case NVMF_PROP_CAP:
70*83dc2f33SJohn Baldwin if (pget->attrib.size != NVMF_PROP_SIZE_8)
71*83dc2f33SJohn Baldwin goto error;
72*83dc2f33SJohn Baldwin rsp.value.u64 = htole64(c->cap);
73*83dc2f33SJohn Baldwin break;
74*83dc2f33SJohn Baldwin case NVMF_PROP_VS:
75*83dc2f33SJohn Baldwin if (pget->attrib.size != NVMF_PROP_SIZE_4)
76*83dc2f33SJohn Baldwin goto error;
77*83dc2f33SJohn Baldwin rsp.value.u32.low = htole32(c->vs);
78*83dc2f33SJohn Baldwin break;
79*83dc2f33SJohn Baldwin case NVMF_PROP_CC:
80*83dc2f33SJohn Baldwin if (pget->attrib.size != NVMF_PROP_SIZE_4)
81*83dc2f33SJohn Baldwin goto error;
82*83dc2f33SJohn Baldwin rsp.value.u32.low = htole32(c->cc);
83*83dc2f33SJohn Baldwin break;
84*83dc2f33SJohn Baldwin case NVMF_PROP_CSTS:
85*83dc2f33SJohn Baldwin if (pget->attrib.size != NVMF_PROP_SIZE_4)
86*83dc2f33SJohn Baldwin goto error;
87*83dc2f33SJohn Baldwin rsp.value.u32.low = htole32(c->csts);
88*83dc2f33SJohn Baldwin break;
89*83dc2f33SJohn Baldwin default:
90*83dc2f33SJohn Baldwin goto error;
91*83dc2f33SJohn Baldwin }
92*83dc2f33SJohn Baldwin
93*83dc2f33SJohn Baldwin nvmf_send_response(nc, &rsp);
94*83dc2f33SJohn Baldwin return;
95*83dc2f33SJohn Baldwin error:
96*83dc2f33SJohn Baldwin nvmf_send_generic_error(nc, NVME_SC_INVALID_FIELD);
97*83dc2f33SJohn Baldwin }
98*83dc2f33SJohn Baldwin
99*83dc2f33SJohn Baldwin static void
handle_property_set(struct controller * c,const struct nvmf_capsule * nc,const struct nvmf_fabric_prop_set_cmd * pset)100*83dc2f33SJohn Baldwin handle_property_set(struct controller *c, const struct nvmf_capsule *nc,
101*83dc2f33SJohn Baldwin const struct nvmf_fabric_prop_set_cmd *pset)
102*83dc2f33SJohn Baldwin {
103*83dc2f33SJohn Baldwin switch (le32toh(pset->ofst)) {
104*83dc2f33SJohn Baldwin case NVMF_PROP_CC:
105*83dc2f33SJohn Baldwin if (pset->attrib.size != NVMF_PROP_SIZE_4)
106*83dc2f33SJohn Baldwin goto error;
107*83dc2f33SJohn Baldwin if (!update_cc(c, le32toh(pset->value.u32.low)))
108*83dc2f33SJohn Baldwin goto error;
109*83dc2f33SJohn Baldwin break;
110*83dc2f33SJohn Baldwin default:
111*83dc2f33SJohn Baldwin goto error;
112*83dc2f33SJohn Baldwin }
113*83dc2f33SJohn Baldwin
114*83dc2f33SJohn Baldwin nvmf_send_success(nc);
115*83dc2f33SJohn Baldwin return;
116*83dc2f33SJohn Baldwin error:
117*83dc2f33SJohn Baldwin nvmf_send_generic_error(nc, NVME_SC_INVALID_FIELD);
118*83dc2f33SJohn Baldwin }
119*83dc2f33SJohn Baldwin
120*83dc2f33SJohn Baldwin static void
handle_fabrics_command(struct controller * c,const struct nvmf_capsule * nc,const struct nvmf_fabric_cmd * fc)121*83dc2f33SJohn Baldwin handle_fabrics_command(struct controller *c,
122*83dc2f33SJohn Baldwin const struct nvmf_capsule *nc, const struct nvmf_fabric_cmd *fc)
123*83dc2f33SJohn Baldwin {
124*83dc2f33SJohn Baldwin switch (fc->fctype) {
125*83dc2f33SJohn Baldwin case NVMF_FABRIC_COMMAND_PROPERTY_GET:
126*83dc2f33SJohn Baldwin handle_property_get(c, nc,
127*83dc2f33SJohn Baldwin (const struct nvmf_fabric_prop_get_cmd *)fc);
128*83dc2f33SJohn Baldwin break;
129*83dc2f33SJohn Baldwin case NVMF_FABRIC_COMMAND_PROPERTY_SET:
130*83dc2f33SJohn Baldwin handle_property_set(c, nc,
131*83dc2f33SJohn Baldwin (const struct nvmf_fabric_prop_set_cmd *)fc);
132*83dc2f33SJohn Baldwin break;
133*83dc2f33SJohn Baldwin case NVMF_FABRIC_COMMAND_CONNECT:
134*83dc2f33SJohn Baldwin warnx("CONNECT command on connected queue");
135*83dc2f33SJohn Baldwin nvmf_send_generic_error(nc, NVME_SC_COMMAND_SEQUENCE_ERROR);
136*83dc2f33SJohn Baldwin break;
137*83dc2f33SJohn Baldwin case NVMF_FABRIC_COMMAND_DISCONNECT:
138*83dc2f33SJohn Baldwin warnx("DISCONNECT command on admin queue");
139*83dc2f33SJohn Baldwin nvmf_send_error(nc, NVME_SCT_COMMAND_SPECIFIC,
140*83dc2f33SJohn Baldwin NVMF_FABRIC_SC_INVALID_QUEUE_TYPE);
141*83dc2f33SJohn Baldwin break;
142*83dc2f33SJohn Baldwin default:
143*83dc2f33SJohn Baldwin warnx("Unsupported fabrics command %#x", fc->fctype);
144*83dc2f33SJohn Baldwin nvmf_send_generic_error(nc, NVME_SC_INVALID_OPCODE);
145*83dc2f33SJohn Baldwin break;
146*83dc2f33SJohn Baldwin }
147*83dc2f33SJohn Baldwin }
148*83dc2f33SJohn Baldwin
149*83dc2f33SJohn Baldwin static void
handle_identify_command(const struct controller * c,const struct nvmf_capsule * nc,const struct nvme_command * cmd)150*83dc2f33SJohn Baldwin handle_identify_command(const struct controller *c,
151*83dc2f33SJohn Baldwin const struct nvmf_capsule *nc, const struct nvme_command *cmd)
152*83dc2f33SJohn Baldwin {
153*83dc2f33SJohn Baldwin uint8_t cns;
154*83dc2f33SJohn Baldwin
155*83dc2f33SJohn Baldwin cns = le32toh(cmd->cdw10) & 0xFF;
156*83dc2f33SJohn Baldwin switch (cns) {
157*83dc2f33SJohn Baldwin case 1:
158*83dc2f33SJohn Baldwin break;
159*83dc2f33SJohn Baldwin default:
160*83dc2f33SJohn Baldwin warnx("Unsupported CNS %#x for IDENTIFY", cns);
161*83dc2f33SJohn Baldwin goto error;
162*83dc2f33SJohn Baldwin }
163*83dc2f33SJohn Baldwin
164*83dc2f33SJohn Baldwin nvmf_send_controller_data(nc, &c->cdata, sizeof(c->cdata));
165*83dc2f33SJohn Baldwin return;
166*83dc2f33SJohn Baldwin error:
167*83dc2f33SJohn Baldwin nvmf_send_generic_error(nc, NVME_SC_INVALID_FIELD);
168*83dc2f33SJohn Baldwin }
169*83dc2f33SJohn Baldwin
170*83dc2f33SJohn Baldwin void
controller_handle_admin_commands(struct controller * c,handle_command * cb,void * cb_arg)171*83dc2f33SJohn Baldwin controller_handle_admin_commands(struct controller *c, handle_command *cb,
172*83dc2f33SJohn Baldwin void *cb_arg)
173*83dc2f33SJohn Baldwin {
174*83dc2f33SJohn Baldwin struct nvmf_qpair *qp = c->qp;
175*83dc2f33SJohn Baldwin const struct nvme_command *cmd;
176*83dc2f33SJohn Baldwin struct nvmf_capsule *nc;
177*83dc2f33SJohn Baldwin int error;
178*83dc2f33SJohn Baldwin
179*83dc2f33SJohn Baldwin for (;;) {
180*83dc2f33SJohn Baldwin error = nvmf_controller_receive_capsule(qp, &nc);
181*83dc2f33SJohn Baldwin if (error != 0) {
182*83dc2f33SJohn Baldwin if (error != ECONNRESET)
183*83dc2f33SJohn Baldwin warnc(error, "Failed to read command capsule");
184*83dc2f33SJohn Baldwin break;
185*83dc2f33SJohn Baldwin }
186*83dc2f33SJohn Baldwin
187*83dc2f33SJohn Baldwin cmd = nvmf_capsule_sqe(nc);
188*83dc2f33SJohn Baldwin
189*83dc2f33SJohn Baldwin /*
190*83dc2f33SJohn Baldwin * Only permit Fabrics commands while a controller is
191*83dc2f33SJohn Baldwin * disabled.
192*83dc2f33SJohn Baldwin */
193*83dc2f33SJohn Baldwin if (NVMEV(NVME_CC_REG_EN, c->cc) == 0 &&
194*83dc2f33SJohn Baldwin cmd->opc != NVME_OPC_FABRICS_COMMANDS) {
195*83dc2f33SJohn Baldwin warnx("Unsupported admin opcode %#x while disabled\n",
196*83dc2f33SJohn Baldwin cmd->opc);
197*83dc2f33SJohn Baldwin nvmf_send_generic_error(nc,
198*83dc2f33SJohn Baldwin NVME_SC_COMMAND_SEQUENCE_ERROR);
199*83dc2f33SJohn Baldwin nvmf_free_capsule(nc);
200*83dc2f33SJohn Baldwin continue;
201*83dc2f33SJohn Baldwin }
202*83dc2f33SJohn Baldwin
203*83dc2f33SJohn Baldwin if (cb(nc, cmd, cb_arg)) {
204*83dc2f33SJohn Baldwin nvmf_free_capsule(nc);
205*83dc2f33SJohn Baldwin continue;
206*83dc2f33SJohn Baldwin }
207*83dc2f33SJohn Baldwin
208*83dc2f33SJohn Baldwin switch (cmd->opc) {
209*83dc2f33SJohn Baldwin case NVME_OPC_FABRICS_COMMANDS:
210*83dc2f33SJohn Baldwin handle_fabrics_command(c, nc,
211*83dc2f33SJohn Baldwin (const struct nvmf_fabric_cmd *)cmd);
212*83dc2f33SJohn Baldwin break;
213*83dc2f33SJohn Baldwin case NVME_OPC_IDENTIFY:
214*83dc2f33SJohn Baldwin handle_identify_command(c, nc, cmd);
215*83dc2f33SJohn Baldwin break;
216*83dc2f33SJohn Baldwin default:
217*83dc2f33SJohn Baldwin warnx("Unsupported admin opcode %#x", cmd->opc);
218*83dc2f33SJohn Baldwin nvmf_send_generic_error(nc, NVME_SC_INVALID_OPCODE);
219*83dc2f33SJohn Baldwin break;
220*83dc2f33SJohn Baldwin }
221*83dc2f33SJohn Baldwin nvmf_free_capsule(nc);
222*83dc2f33SJohn Baldwin }
223*83dc2f33SJohn Baldwin }
224*83dc2f33SJohn Baldwin
225*83dc2f33SJohn Baldwin struct controller *
init_controller(struct nvmf_qpair * qp,const struct nvme_controller_data * cdata)226*83dc2f33SJohn Baldwin init_controller(struct nvmf_qpair *qp,
227*83dc2f33SJohn Baldwin const struct nvme_controller_data *cdata)
228*83dc2f33SJohn Baldwin {
229*83dc2f33SJohn Baldwin struct controller *c;
230*83dc2f33SJohn Baldwin
231*83dc2f33SJohn Baldwin c = calloc(1, sizeof(*c));
232*83dc2f33SJohn Baldwin c->qp = qp;
233*83dc2f33SJohn Baldwin c->cap = nvmf_controller_cap(c->qp);
234*83dc2f33SJohn Baldwin c->vs = cdata->ver;
235*83dc2f33SJohn Baldwin c->cdata = *cdata;
236*83dc2f33SJohn Baldwin
237*83dc2f33SJohn Baldwin return (c);
238*83dc2f33SJohn Baldwin }
239*83dc2f33SJohn Baldwin
240*83dc2f33SJohn Baldwin void
free_controller(struct controller * c)241*83dc2f33SJohn Baldwin free_controller(struct controller *c)
242*83dc2f33SJohn Baldwin {
243*83dc2f33SJohn Baldwin free(c);
244*83dc2f33SJohn Baldwin }
245