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