xref: /freebsd/tools/tools/nvmf/nvmfd/controller.c (revision 83dc2f33394bfee9e5e64693dda36b69e75718fc)
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