12da066efSJohn Baldwin /*- 22da066efSJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 32da066efSJohn Baldwin * 42da066efSJohn Baldwin * Copyright (c) 2024 Chelsio Communications, Inc. 52da066efSJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 62da066efSJohn Baldwin */ 72da066efSJohn Baldwin 82da066efSJohn Baldwin #include <sys/utsname.h> 92da066efSJohn Baldwin #include <assert.h> 102da066efSJohn Baldwin #include <errno.h> 112da066efSJohn Baldwin #include <string.h> 122da066efSJohn Baldwin #include <unistd.h> 132da066efSJohn Baldwin 142da066efSJohn Baldwin #include "libnvmf.h" 152da066efSJohn Baldwin #include "internal.h" 162da066efSJohn Baldwin #include "nvmft_subr.h" 172da066efSJohn Baldwin 182da066efSJohn Baldwin void 192da066efSJohn Baldwin nvmf_init_cqe(void *cqe, const struct nvmf_capsule *nc, uint16_t status) 202da066efSJohn Baldwin { 212da066efSJohn Baldwin struct nvme_completion *cpl = cqe; 222da066efSJohn Baldwin const struct nvme_command *cmd = nvmf_capsule_sqe(nc); 232da066efSJohn Baldwin 242da066efSJohn Baldwin memset(cpl, 0, sizeof(*cpl)); 252da066efSJohn Baldwin cpl->cid = cmd->cid; 262da066efSJohn Baldwin cpl->status = htole16(status); 272da066efSJohn Baldwin } 282da066efSJohn Baldwin 292da066efSJohn Baldwin static struct nvmf_capsule * 302da066efSJohn Baldwin nvmf_simple_response(const struct nvmf_capsule *nc, uint8_t sc_type, 312da066efSJohn Baldwin uint8_t sc_status) 322da066efSJohn Baldwin { 332da066efSJohn Baldwin struct nvme_completion cpl; 342da066efSJohn Baldwin uint16_t status; 352da066efSJohn Baldwin 362da066efSJohn Baldwin status = NVMEF(NVME_STATUS_SCT, sc_type) | 372da066efSJohn Baldwin NVMEF(NVME_STATUS_SC, sc_status); 382da066efSJohn Baldwin nvmf_init_cqe(&cpl, nc, status); 392da066efSJohn Baldwin return (nvmf_allocate_response(nc->nc_qpair, &cpl)); 402da066efSJohn Baldwin } 412da066efSJohn Baldwin 422da066efSJohn Baldwin int 432da066efSJohn Baldwin nvmf_controller_receive_capsule(struct nvmf_qpair *qp, 442da066efSJohn Baldwin struct nvmf_capsule **ncp) 452da066efSJohn Baldwin { 462da066efSJohn Baldwin struct nvmf_capsule *nc; 472da066efSJohn Baldwin int error; 482da066efSJohn Baldwin uint8_t sc_status; 492da066efSJohn Baldwin 502da066efSJohn Baldwin *ncp = NULL; 512da066efSJohn Baldwin error = nvmf_receive_capsule(qp, &nc); 522da066efSJohn Baldwin if (error != 0) 532da066efSJohn Baldwin return (error); 542da066efSJohn Baldwin 552da066efSJohn Baldwin sc_status = nvmf_validate_command_capsule(nc); 562da066efSJohn Baldwin if (sc_status != NVME_SC_SUCCESS) { 572da066efSJohn Baldwin nvmf_send_generic_error(nc, sc_status); 582da066efSJohn Baldwin nvmf_free_capsule(nc); 592da066efSJohn Baldwin return (EPROTO); 602da066efSJohn Baldwin } 612da066efSJohn Baldwin 622da066efSJohn Baldwin *ncp = nc; 632da066efSJohn Baldwin return (0); 642da066efSJohn Baldwin } 652da066efSJohn Baldwin 662da066efSJohn Baldwin int 672da066efSJohn Baldwin nvmf_controller_transmit_response(struct nvmf_capsule *nc) 682da066efSJohn Baldwin { 692da066efSJohn Baldwin struct nvmf_qpair *qp = nc->nc_qpair; 702da066efSJohn Baldwin 712da066efSJohn Baldwin /* Set SQHD. */ 722da066efSJohn Baldwin if (qp->nq_flow_control) { 732da066efSJohn Baldwin qp->nq_sqhd = (qp->nq_sqhd + 1) % qp->nq_qsize; 742da066efSJohn Baldwin nc->nc_cqe.sqhd = htole16(qp->nq_sqhd); 752da066efSJohn Baldwin } else 762da066efSJohn Baldwin nc->nc_cqe.sqhd = 0; 772da066efSJohn Baldwin 782da066efSJohn Baldwin return (nvmf_transmit_capsule(nc)); 792da066efSJohn Baldwin } 802da066efSJohn Baldwin 812da066efSJohn Baldwin int 822da066efSJohn Baldwin nvmf_send_response(const struct nvmf_capsule *cc, const void *cqe) 832da066efSJohn Baldwin { 842da066efSJohn Baldwin struct nvmf_capsule *rc; 852da066efSJohn Baldwin int error; 862da066efSJohn Baldwin 872da066efSJohn Baldwin rc = nvmf_allocate_response(cc->nc_qpair, cqe); 882da066efSJohn Baldwin if (rc == NULL) 892da066efSJohn Baldwin return (ENOMEM); 902da066efSJohn Baldwin error = nvmf_controller_transmit_response(rc); 912da066efSJohn Baldwin nvmf_free_capsule(rc); 922da066efSJohn Baldwin return (error); 932da066efSJohn Baldwin } 942da066efSJohn Baldwin 952da066efSJohn Baldwin int 962da066efSJohn Baldwin nvmf_send_error(const struct nvmf_capsule *cc, uint8_t sc_type, 972da066efSJohn Baldwin uint8_t sc_status) 982da066efSJohn Baldwin { 992da066efSJohn Baldwin struct nvmf_capsule *rc; 1002da066efSJohn Baldwin int error; 1012da066efSJohn Baldwin 1022da066efSJohn Baldwin rc = nvmf_simple_response(cc, sc_type, sc_status); 1032da066efSJohn Baldwin error = nvmf_controller_transmit_response(rc); 1042da066efSJohn Baldwin nvmf_free_capsule(rc); 1052da066efSJohn Baldwin return (error); 1062da066efSJohn Baldwin } 1072da066efSJohn Baldwin 1082da066efSJohn Baldwin int 1092da066efSJohn Baldwin nvmf_send_generic_error(const struct nvmf_capsule *nc, uint8_t sc_status) 1102da066efSJohn Baldwin { 1112da066efSJohn Baldwin return (nvmf_send_error(nc, NVME_SCT_GENERIC, sc_status)); 1122da066efSJohn Baldwin } 1132da066efSJohn Baldwin 1142da066efSJohn Baldwin int 1152da066efSJohn Baldwin nvmf_send_success(const struct nvmf_capsule *nc) 1162da066efSJohn Baldwin { 1172da066efSJohn Baldwin return (nvmf_send_generic_error(nc, NVME_SC_SUCCESS)); 1182da066efSJohn Baldwin } 1192da066efSJohn Baldwin 1202da066efSJohn Baldwin void 1212da066efSJohn Baldwin nvmf_connect_invalid_parameters(const struct nvmf_capsule *cc, bool data, 1222da066efSJohn Baldwin uint16_t offset) 1232da066efSJohn Baldwin { 1242da066efSJohn Baldwin struct nvmf_fabric_connect_rsp rsp; 1252da066efSJohn Baldwin struct nvmf_capsule *rc; 1262da066efSJohn Baldwin 1272da066efSJohn Baldwin nvmf_init_cqe(&rsp, cc, 1282da066efSJohn Baldwin NVMEF(NVME_STATUS_SCT, NVME_SCT_COMMAND_SPECIFIC) | 1292da066efSJohn Baldwin NVMEF(NVME_STATUS_SC, NVMF_FABRIC_SC_INVALID_PARAM)); 1302da066efSJohn Baldwin rsp.status_code_specific.invalid.ipo = htole16(offset); 1312da066efSJohn Baldwin rsp.status_code_specific.invalid.iattr = data ? 1 : 0; 1322da066efSJohn Baldwin rc = nvmf_allocate_response(cc->nc_qpair, &rsp); 1332da066efSJohn Baldwin nvmf_transmit_capsule(rc); 1342da066efSJohn Baldwin nvmf_free_capsule(rc); 1352da066efSJohn Baldwin } 1362da066efSJohn Baldwin 1372da066efSJohn Baldwin struct nvmf_qpair * 1382da066efSJohn Baldwin nvmf_accept(struct nvmf_association *na, const struct nvmf_qpair_params *params, 1392da066efSJohn Baldwin struct nvmf_capsule **ccp, struct nvmf_fabric_connect_data *data) 1402da066efSJohn Baldwin { 1412da066efSJohn Baldwin static const char hostid_zero[sizeof(data->hostid)]; 1422da066efSJohn Baldwin const struct nvmf_fabric_connect_cmd *cmd; 1432da066efSJohn Baldwin struct nvmf_qpair *qp; 1442da066efSJohn Baldwin struct nvmf_capsule *cc, *rc; 1452da066efSJohn Baldwin u_int qsize; 1462da066efSJohn Baldwin int error; 1472da066efSJohn Baldwin uint16_t cntlid; 1482da066efSJohn Baldwin uint8_t sc_status; 1492da066efSJohn Baldwin 1502da066efSJohn Baldwin qp = NULL; 1512da066efSJohn Baldwin cc = NULL; 1522da066efSJohn Baldwin rc = NULL; 1532da066efSJohn Baldwin *ccp = NULL; 1542da066efSJohn Baldwin na_clear_error(na); 1552da066efSJohn Baldwin if (!na->na_controller) { 1562da066efSJohn Baldwin na_error(na, "Cannot accept on a host"); 1572da066efSJohn Baldwin goto error; 1582da066efSJohn Baldwin } 1592da066efSJohn Baldwin 1602da066efSJohn Baldwin qp = nvmf_allocate_qpair(na, params); 1612da066efSJohn Baldwin if (qp == NULL) 1622da066efSJohn Baldwin goto error; 1632da066efSJohn Baldwin 1642da066efSJohn Baldwin /* Read the CONNECT capsule. */ 1652da066efSJohn Baldwin error = nvmf_receive_capsule(qp, &cc); 1662da066efSJohn Baldwin if (error != 0) { 1672da066efSJohn Baldwin na_error(na, "Failed to receive CONNECT: %s", strerror(error)); 1682da066efSJohn Baldwin goto error; 1692da066efSJohn Baldwin } 1702da066efSJohn Baldwin 1712da066efSJohn Baldwin sc_status = nvmf_validate_command_capsule(cc); 1722da066efSJohn Baldwin if (sc_status != 0) { 1732da066efSJohn Baldwin na_error(na, "CONNECT command failed to validate: %u", 1742da066efSJohn Baldwin sc_status); 1752da066efSJohn Baldwin rc = nvmf_simple_response(cc, NVME_SCT_GENERIC, sc_status); 1762da066efSJohn Baldwin goto error; 1772da066efSJohn Baldwin } 1782da066efSJohn Baldwin 1792da066efSJohn Baldwin cmd = nvmf_capsule_sqe(cc); 1802da066efSJohn Baldwin if (cmd->opcode != NVME_OPC_FABRICS_COMMANDS || 1812da066efSJohn Baldwin cmd->fctype != NVMF_FABRIC_COMMAND_CONNECT) { 1822da066efSJohn Baldwin na_error(na, "Invalid opcode in CONNECT (%u,%u)", cmd->opcode, 1832da066efSJohn Baldwin cmd->fctype); 1842da066efSJohn Baldwin rc = nvmf_simple_response(cc, NVME_SCT_GENERIC, 1852da066efSJohn Baldwin NVME_SC_INVALID_OPCODE); 1862da066efSJohn Baldwin goto error; 1872da066efSJohn Baldwin } 1882da066efSJohn Baldwin 1892da066efSJohn Baldwin if (cmd->recfmt != htole16(0)) { 1902da066efSJohn Baldwin na_error(na, "Unsupported CONNECT record format %u", 1912da066efSJohn Baldwin le16toh(cmd->recfmt)); 1922da066efSJohn Baldwin rc = nvmf_simple_response(cc, NVME_SCT_COMMAND_SPECIFIC, 1932da066efSJohn Baldwin NVMF_FABRIC_SC_INCOMPATIBLE_FORMAT); 1942da066efSJohn Baldwin goto error; 1952da066efSJohn Baldwin } 1962da066efSJohn Baldwin 1972da066efSJohn Baldwin qsize = le16toh(cmd->sqsize) + 1; 1982da066efSJohn Baldwin if (cmd->qid == 0) { 1992da066efSJohn Baldwin /* Admin queue limits. */ 2002da066efSJohn Baldwin if (qsize < NVME_MIN_ADMIN_ENTRIES || 2012da066efSJohn Baldwin qsize > NVME_MAX_ADMIN_ENTRIES || 2022da066efSJohn Baldwin qsize > na->na_params.max_admin_qsize) { 2032da066efSJohn Baldwin na_error(na, "Invalid queue size %u", qsize); 2042da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, false, 2052da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_cmd, sqsize)); 2062da066efSJohn Baldwin goto error; 2072da066efSJohn Baldwin } 2082da066efSJohn Baldwin qp->nq_admin = true; 2092da066efSJohn Baldwin } else { 2102da066efSJohn Baldwin /* I/O queues not allowed for discovery. */ 2112da066efSJohn Baldwin if (na->na_params.max_io_qsize == 0) { 2122da066efSJohn Baldwin na_error(na, "I/O queue on discovery controller"); 2132da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, false, 2142da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_cmd, qid)); 2152da066efSJohn Baldwin goto error; 2162da066efSJohn Baldwin } 2172da066efSJohn Baldwin 2182da066efSJohn Baldwin /* I/O queue limits. */ 2192da066efSJohn Baldwin if (qsize < NVME_MIN_IO_ENTRIES || 2202da066efSJohn Baldwin qsize > NVME_MAX_IO_ENTRIES || 2212da066efSJohn Baldwin qsize > na->na_params.max_io_qsize) { 2222da066efSJohn Baldwin na_error(na, "Invalid queue size %u", qsize); 2232da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, false, 2242da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_cmd, sqsize)); 2252da066efSJohn Baldwin goto error; 2262da066efSJohn Baldwin } 2272da066efSJohn Baldwin 2282da066efSJohn Baldwin /* KATO is reserved for I/O queues. */ 2292da066efSJohn Baldwin if (cmd->kato != 0) { 2302da066efSJohn Baldwin na_error(na, 2312da066efSJohn Baldwin "KeepAlive timeout specified for I/O queue"); 2322da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, false, 2332da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_cmd, kato)); 2342da066efSJohn Baldwin goto error; 2352da066efSJohn Baldwin } 2362da066efSJohn Baldwin qp->nq_admin = false; 2372da066efSJohn Baldwin } 2382da066efSJohn Baldwin qp->nq_qsize = qsize; 2392da066efSJohn Baldwin 2402da066efSJohn Baldwin /* Fetch CONNECT data. */ 2412da066efSJohn Baldwin if (nvmf_capsule_data_len(cc) != sizeof(*data)) { 2422da066efSJohn Baldwin na_error(na, "Invalid data payload length for CONNECT: %zu", 2432da066efSJohn Baldwin nvmf_capsule_data_len(cc)); 2442da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, false, 2452da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_cmd, sgl1)); 2462da066efSJohn Baldwin goto error; 2472da066efSJohn Baldwin } 2482da066efSJohn Baldwin 2492da066efSJohn Baldwin error = nvmf_receive_controller_data(cc, 0, data, sizeof(*data)); 2502da066efSJohn Baldwin if (error != 0) { 2512da066efSJohn Baldwin na_error(na, "Failed to read data for CONNECT: %s", 2522da066efSJohn Baldwin strerror(error)); 2532da066efSJohn Baldwin rc = nvmf_simple_response(cc, NVME_SCT_GENERIC, 2542da066efSJohn Baldwin NVME_SC_DATA_TRANSFER_ERROR); 2552da066efSJohn Baldwin goto error; 2562da066efSJohn Baldwin } 2572da066efSJohn Baldwin 2582da066efSJohn Baldwin /* The hostid must be non-zero. */ 2592da066efSJohn Baldwin if (memcmp(data->hostid, hostid_zero, sizeof(hostid_zero)) == 0) { 2602da066efSJohn Baldwin na_error(na, "HostID in CONNECT data is zero"); 2612da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, true, 2622da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_data, hostid)); 2632da066efSJohn Baldwin goto error; 2642da066efSJohn Baldwin } 2652da066efSJohn Baldwin 2662da066efSJohn Baldwin cntlid = le16toh(data->cntlid); 2672da066efSJohn Baldwin if (cmd->qid == 0) { 2682da066efSJohn Baldwin if (na->na_params.dynamic_controller_model) { 2692da066efSJohn Baldwin if (cntlid != NVMF_CNTLID_DYNAMIC) { 2702da066efSJohn Baldwin na_error(na, "Invalid controller ID %#x", 2712da066efSJohn Baldwin cntlid); 2722da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, true, 2732da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_data, 2742da066efSJohn Baldwin cntlid)); 2752da066efSJohn Baldwin goto error; 2762da066efSJohn Baldwin } 2772da066efSJohn Baldwin } else { 2782da066efSJohn Baldwin if (cntlid > NVMF_CNTLID_STATIC_MAX && 2792da066efSJohn Baldwin cntlid != NVMF_CNTLID_STATIC_ANY) { 2802da066efSJohn Baldwin na_error(na, "Invalid controller ID %#x", 2812da066efSJohn Baldwin cntlid); 2822da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, true, 2832da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_data, 2842da066efSJohn Baldwin cntlid)); 2852da066efSJohn Baldwin goto error; 2862da066efSJohn Baldwin } 2872da066efSJohn Baldwin } 2882da066efSJohn Baldwin } else { 2892da066efSJohn Baldwin /* Wildcard Controller IDs are only valid on an Admin queue. */ 2902da066efSJohn Baldwin if (cntlid > NVMF_CNTLID_STATIC_MAX) { 2912da066efSJohn Baldwin na_error(na, "Invalid controller ID %#x", cntlid); 2922da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, true, 2932da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_data, cntlid)); 2942da066efSJohn Baldwin goto error; 2952da066efSJohn Baldwin } 2962da066efSJohn Baldwin } 2972da066efSJohn Baldwin 2982da066efSJohn Baldwin /* Simple validation of each NQN. */ 2992da066efSJohn Baldwin if (!nvmf_nqn_valid(data->subnqn)) { 3002da066efSJohn Baldwin na_error(na, "Invalid SubNQN %.*s", (int)sizeof(data->subnqn), 3012da066efSJohn Baldwin data->subnqn); 3022da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, true, 3032da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_data, subnqn)); 3042da066efSJohn Baldwin goto error; 3052da066efSJohn Baldwin } 3062da066efSJohn Baldwin if (!nvmf_nqn_valid(data->hostnqn)) { 3072da066efSJohn Baldwin na_error(na, "Invalid HostNQN %.*s", (int)sizeof(data->hostnqn), 3082da066efSJohn Baldwin data->hostnqn); 3092da066efSJohn Baldwin nvmf_connect_invalid_parameters(cc, true, 3102da066efSJohn Baldwin offsetof(struct nvmf_fabric_connect_data, hostnqn)); 3112da066efSJohn Baldwin goto error; 3122da066efSJohn Baldwin } 3132da066efSJohn Baldwin 3142da066efSJohn Baldwin if (na->na_params.sq_flow_control || 3152da066efSJohn Baldwin (cmd->cattr & NVMF_CONNECT_ATTR_DISABLE_SQ_FC) == 0) 3162da066efSJohn Baldwin qp->nq_flow_control = true; 3172da066efSJohn Baldwin else 3182da066efSJohn Baldwin qp->nq_flow_control = false; 3192da066efSJohn Baldwin qp->nq_sqhd = 0; 3202da066efSJohn Baldwin qp->nq_kato = le32toh(cmd->kato); 3212da066efSJohn Baldwin *ccp = cc; 3222da066efSJohn Baldwin return (qp); 3232da066efSJohn Baldwin error: 3242da066efSJohn Baldwin if (rc != NULL) { 3252da066efSJohn Baldwin nvmf_transmit_capsule(rc); 3262da066efSJohn Baldwin nvmf_free_capsule(rc); 3272da066efSJohn Baldwin } 3282da066efSJohn Baldwin if (cc != NULL) 3292da066efSJohn Baldwin nvmf_free_capsule(cc); 3302da066efSJohn Baldwin if (qp != NULL) 3312da066efSJohn Baldwin nvmf_free_qpair(qp); 3322da066efSJohn Baldwin return (NULL); 3332da066efSJohn Baldwin } 3342da066efSJohn Baldwin 3352da066efSJohn Baldwin int 3362da066efSJohn Baldwin nvmf_finish_accept(const struct nvmf_capsule *cc, uint16_t cntlid) 3372da066efSJohn Baldwin { 3382da066efSJohn Baldwin struct nvmf_fabric_connect_rsp rsp; 3392da066efSJohn Baldwin struct nvmf_qpair *qp = cc->nc_qpair; 3402da066efSJohn Baldwin struct nvmf_capsule *rc; 3412da066efSJohn Baldwin int error; 3422da066efSJohn Baldwin 3432da066efSJohn Baldwin nvmf_init_cqe(&rsp, cc, 0); 3442da066efSJohn Baldwin if (qp->nq_flow_control) 3452da066efSJohn Baldwin rsp.sqhd = htole16(qp->nq_sqhd); 3462da066efSJohn Baldwin else 3472da066efSJohn Baldwin rsp.sqhd = htole16(0xffff); 3482da066efSJohn Baldwin rsp.status_code_specific.success.cntlid = htole16(cntlid); 3492da066efSJohn Baldwin rc = nvmf_allocate_response(qp, &rsp); 3502da066efSJohn Baldwin if (rc == NULL) 3512da066efSJohn Baldwin return (ENOMEM); 3522da066efSJohn Baldwin error = nvmf_transmit_capsule(rc); 3532da066efSJohn Baldwin nvmf_free_capsule(rc); 3542da066efSJohn Baldwin if (error == 0) 3552da066efSJohn Baldwin qp->nq_cntlid = cntlid; 3562da066efSJohn Baldwin return (error); 3572da066efSJohn Baldwin } 3582da066efSJohn Baldwin 3592da066efSJohn Baldwin uint64_t 3602da066efSJohn Baldwin nvmf_controller_cap(struct nvmf_qpair *qp) 3612da066efSJohn Baldwin { 3622da066efSJohn Baldwin const struct nvmf_association *na = qp->nq_association; 3632da066efSJohn Baldwin 3642da066efSJohn Baldwin return (_nvmf_controller_cap(na->na_params.max_io_qsize, 3652da066efSJohn Baldwin NVMF_CC_EN_TIMEOUT)); 3662da066efSJohn Baldwin } 3672da066efSJohn Baldwin 3682da066efSJohn Baldwin bool 3692da066efSJohn Baldwin nvmf_validate_cc(struct nvmf_qpair *qp, uint64_t cap, uint32_t old_cc, 3702da066efSJohn Baldwin uint32_t new_cc) 3712da066efSJohn Baldwin { 3722da066efSJohn Baldwin const struct nvmf_association *na = qp->nq_association; 3732da066efSJohn Baldwin 3742da066efSJohn Baldwin return (_nvmf_validate_cc(na->na_params.max_io_qsize, cap, old_cc, 3752da066efSJohn Baldwin new_cc)); 3762da066efSJohn Baldwin } 3772da066efSJohn Baldwin 3782da066efSJohn Baldwin void 3792da066efSJohn Baldwin nvmf_init_discovery_controller_data(struct nvmf_qpair *qp, 3802da066efSJohn Baldwin struct nvme_controller_data *cdata) 3812da066efSJohn Baldwin { 3822da066efSJohn Baldwin const struct nvmf_association *na = qp->nq_association; 3832da066efSJohn Baldwin struct utsname utsname; 3842da066efSJohn Baldwin char *cp; 3852da066efSJohn Baldwin 3862da066efSJohn Baldwin memset(cdata, 0, sizeof(*cdata)); 3872da066efSJohn Baldwin 3882da066efSJohn Baldwin /* 3892da066efSJohn Baldwin * 5.2 Figure 37 states model name and serial are reserved, 3902da066efSJohn Baldwin * but Linux includes them. Don't bother with serial, but 3912da066efSJohn Baldwin * do set model name. 3922da066efSJohn Baldwin */ 3932da066efSJohn Baldwin uname(&utsname); 3942da066efSJohn Baldwin nvmf_strpad(cdata->mn, utsname.sysname, sizeof(cdata->mn)); 3952da066efSJohn Baldwin nvmf_strpad(cdata->fr, utsname.release, sizeof(cdata->fr)); 3962da066efSJohn Baldwin cp = memchr(cdata->fr, '-', sizeof(cdata->fr)); 3972da066efSJohn Baldwin if (cp != NULL) 3982da066efSJohn Baldwin memset(cp, ' ', sizeof(cdata->fr) - (cp - (char *)cdata->fr)); 3992da066efSJohn Baldwin 4002da066efSJohn Baldwin cdata->ctrlr_id = htole16(qp->nq_cntlid); 4012da066efSJohn Baldwin cdata->ver = htole32(NVME_REV(1, 4)); 4022da066efSJohn Baldwin cdata->cntrltype = 2; 4032da066efSJohn Baldwin 4042da066efSJohn Baldwin cdata->lpa = NVMEF(NVME_CTRLR_DATA_LPA_EXT_DATA, 1); 4052da066efSJohn Baldwin cdata->elpe = 0; 4062da066efSJohn Baldwin 4072da066efSJohn Baldwin cdata->maxcmd = htole16(na->na_params.max_admin_qsize); 4082da066efSJohn Baldwin 4092da066efSJohn Baldwin /* Transport-specific? */ 4102da066efSJohn Baldwin cdata->sgls = htole32( 4112da066efSJohn Baldwin NVMEF(NVME_CTRLR_DATA_SGLS_TRANSPORT_DATA_BLOCK, 1) | 4122da066efSJohn Baldwin NVMEF(NVME_CTRLR_DATA_SGLS_ADDRESS_AS_OFFSET, 1) | 4132da066efSJohn Baldwin NVMEF(NVME_CTRLR_DATA_SGLS_NVM_COMMAND_SET, 1)); 4142da066efSJohn Baldwin 4152da066efSJohn Baldwin strlcpy(cdata->subnqn, NVMF_DISCOVERY_NQN, sizeof(cdata->subnqn)); 4162da066efSJohn Baldwin } 4172da066efSJohn Baldwin 4182da066efSJohn Baldwin void 4192da066efSJohn Baldwin nvmf_init_io_controller_data(struct nvmf_qpair *qp, const char *serial, 4202da066efSJohn Baldwin const char *subnqn, int nn, uint32_t ioccsz, 4212da066efSJohn Baldwin struct nvme_controller_data *cdata) 4222da066efSJohn Baldwin { 4232da066efSJohn Baldwin const struct nvmf_association *na = qp->nq_association; 4242da066efSJohn Baldwin struct utsname utsname; 4252da066efSJohn Baldwin 4262da066efSJohn Baldwin uname(&utsname); 4272da066efSJohn Baldwin 428*e0649a35SJohn Baldwin memset(cdata, 0, sizeof(*cdata)); 4292da066efSJohn Baldwin _nvmf_init_io_controller_data(qp->nq_cntlid, na->na_params.max_io_qsize, 4302da066efSJohn Baldwin serial, utsname.sysname, utsname.release, subnqn, nn, ioccsz, 4312da066efSJohn Baldwin sizeof(struct nvme_completion), cdata); 4322da066efSJohn Baldwin } 4332da066efSJohn Baldwin 4342da066efSJohn Baldwin uint8_t 4352da066efSJohn Baldwin nvmf_get_log_page_id(const struct nvme_command *cmd) 4362da066efSJohn Baldwin { 4372da066efSJohn Baldwin assert(cmd->opc == NVME_OPC_GET_LOG_PAGE); 4382da066efSJohn Baldwin return (le32toh(cmd->cdw10) & 0xff); 4392da066efSJohn Baldwin } 4402da066efSJohn Baldwin 4412da066efSJohn Baldwin uint64_t 4422da066efSJohn Baldwin nvmf_get_log_page_length(const struct nvme_command *cmd) 4432da066efSJohn Baldwin { 4442da066efSJohn Baldwin uint32_t numd; 4452da066efSJohn Baldwin 4462da066efSJohn Baldwin assert(cmd->opc == NVME_OPC_GET_LOG_PAGE); 4472da066efSJohn Baldwin numd = le32toh(cmd->cdw10) >> 16 | (le32toh(cmd->cdw11) & 0xffff) << 16; 4482da066efSJohn Baldwin return ((numd + 1) * 4); 4492da066efSJohn Baldwin } 4502da066efSJohn Baldwin 4512da066efSJohn Baldwin uint64_t 4522da066efSJohn Baldwin nvmf_get_log_page_offset(const struct nvme_command *cmd) 4532da066efSJohn Baldwin { 4542da066efSJohn Baldwin assert(cmd->opc == NVME_OPC_GET_LOG_PAGE); 4552da066efSJohn Baldwin return (le32toh(cmd->cdw12) | (uint64_t)le32toh(cmd->cdw13) << 32); 4562da066efSJohn Baldwin } 4572da066efSJohn Baldwin 4582da066efSJohn Baldwin int 4592da066efSJohn Baldwin nvmf_handoff_controller_qpair(struct nvmf_qpair *qp, 4602da066efSJohn Baldwin struct nvmf_handoff_controller_qpair *h) 4612da066efSJohn Baldwin { 4622da066efSJohn Baldwin h->trtype = qp->nq_association->na_trtype; 4632da066efSJohn Baldwin return (nvmf_kernel_handoff_params(qp, &h->params)); 4642da066efSJohn Baldwin } 465