2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2023-2024 Chelsio Communications, Inc.
5 * Written by: John Baldwin <jhb@FreeBSD.org>
16 struct nvmf_qpair *qp;
25 struct nvme_controller_data cdata;
29 update_cc(struct controller *c, uint32_t new_cc)
35 if (!nvmf_validate_cc(c->qp, c->cap, c->cc, new_cc))
38 changes = c->cc ^ new_cc;
41 /* Handle shutdown requests. */
42 if (NVMEV(NVME_CC_REG_SHN, changes) != 0 &&
43 NVMEV(NVME_CC_REG_SHN, new_cc) != 0) {
44 c->csts &= ~NVMEM(NVME_CSTS_REG_SHST);
45 c->csts |= NVMEF(NVME_CSTS_REG_SHST, NVME_SHST_COMPLETE);
49 if (NVMEV(NVME_CC_REG_EN, changes) != 0) {
50 if (NVMEV(NVME_CC_REG_EN, new_cc) == 0) {
51 /* Controller reset. */
55 c->csts |= NVMEF(NVME_CSTS_REG_RDY, 1);
61 handle_property_get(const struct controller *c, const struct nvmf_capsule *nc,
62 const struct nvmf_fabric_prop_get_cmd *pget)
64 struct nvmf_fabric_prop_get_rsp rsp;
66 nvmf_init_cqe(&rsp, nc, 0);
68 switch (le32toh(pget->ofst)) {
70 if (pget->attrib.size != NVMF_PROP_SIZE_8)
72 rsp.value.u64 = htole64(c->cap);
75 if (pget->attrib.size != NVMF_PROP_SIZE_4)
77 rsp.value.u32.low = htole32(c->vs);
80 if (pget->attrib.size != NVMF_PROP_SIZE_4)
82 rsp.value.u32.low = htole32(c->cc);
85 if (pget->attrib.size != NVMF_PROP_SIZE_4)
87 rsp.value.u32.low = htole32(c->csts);
93 nvmf_send_response(nc, &rsp);
96 nvmf_send_generic_error(nc, NVME_SC_INVALID_FIELD);
100 handle_property_set(struct controller *c, const struct nvmf_capsule *nc,
101 const struct nvmf_fabric_prop_set_cmd *pset)
103 switch (le32toh(pset->ofst)) {
105 if (pset->attrib.size != NVMF_PROP_SIZE_4)
107 if (!update_cc(c, le32toh(pset->value.u32.low)))
114 nvmf_send_success(nc);
117 nvmf_send_generic_error(nc, NVME_SC_INVALID_FIELD);
121 handle_fabrics_command(struct controller *c,
122 const struct nvmf_capsule *nc, const struct nvmf_fabric_cmd *fc)
124 switch (fc->fctype) {
125 case NVMF_FABRIC_COMMAND_PROPERTY_GET:
126 handle_property_get(c, nc,
127 (const struct nvmf_fabric_prop_get_cmd *)fc);
129 case NVMF_FABRIC_COMMAND_PROPERTY_SET:
130 handle_property_set(c, nc,
131 (const struct nvmf_fabric_prop_set_cmd *)fc);
133 case NVMF_FABRIC_COMMAND_CONNECT:
134 warnx("CONNECT command on connected queue");
135 nvmf_send_generic_error(nc, NVME_SC_COMMAND_SEQUENCE_ERROR);
137 case NVMF_FABRIC_COMMAND_DISCONNECT:
138 warnx("DISCONNECT command on admin queue");
139 nvmf_send_error(nc, NVME_SCT_COMMAND_SPECIFIC,
140 NVMF_FABRIC_SC_INVALID_QUEUE_TYPE);
143 warnx("Unsupported fabrics command %#x", fc->fctype);
144 nvmf_send_generic_error(nc, NVME_SC_INVALID_OPCODE);
150 handle_identify_command(const struct controller *c,
151 const struct nvmf_capsule *nc, const struct nvme_command *cmd)
155 cns = le32toh(cmd->cdw10) & 0xFF;
160 warnx("Unsupported CNS %#x for IDENTIFY", cns);
164 nvmf_send_controller_data(nc, &c->cdata, sizeof(c->cdata));
167 nvmf_send_generic_error(nc, NVME_SC_INVALID_FIELD);
171 controller_handle_admin_commands(struct controller *c, handle_command *cb,
174 struct nvmf_qpair *qp = c->qp;
175 const struct nvme_command *cmd;
176 struct nvmf_capsule *nc;
180 error = nvmf_controller_receive_capsule(qp, &nc);
182 if (error != ECONNRESET)
183 warnc(error, "Failed to read command capsule");
187 cmd = nvmf_capsule_sqe(nc);
190 * Only permit Fabrics commands while a controller is
193 if (NVMEV(NVME_CC_REG_EN, c->cc) == 0 &&
194 cmd->opc != NVME_OPC_FABRICS_COMMANDS) {
195 warnx("Unsupported admin opcode %#x whiled disabled\n",
197 nvmf_send_generic_error(nc,
198 NVME_SC_COMMAND_SEQUENCE_ERROR);
199 nvmf_free_capsule(nc);
203 if (cb(nc, cmd, cb_arg)) {
204 nvmf_free_capsule(nc);
209 case NVME_OPC_FABRICS_COMMANDS:
210 handle_fabrics_command(c, nc,
211 (const struct nvmf_fabric_cmd *)cmd);
213 case NVME_OPC_IDENTIFY:
214 handle_identify_command(c, nc, cmd);
217 warnx("Unsupported admin opcode %#x", cmd->opc);
218 nvmf_send_generic_error(nc, NVME_SC_INVALID_OPCODE);
221 nvmf_free_capsule(nc);
226 init_controller(struct nvmf_qpair *qp,
227 const struct nvme_controller_data *cdata)
229 struct controller *c;
231 c = calloc(1, sizeof(*c));
233 c->cap = nvmf_controller_cap(c->qp);
241 free_controller(struct controller *c)