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
nvmf_init_cqe(void * cqe,const struct nvmf_capsule * nc,uint16_t status)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 *
nvmf_simple_response(const struct nvmf_capsule * nc,uint8_t sc_type,uint8_t sc_status)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
nvmf_controller_receive_capsule(struct nvmf_qpair * qp,struct nvmf_capsule ** ncp)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
nvmf_controller_transmit_response(struct nvmf_capsule * nc)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
nvmf_send_response(const struct nvmf_capsule * cc,const void * cqe)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
nvmf_send_error(const struct nvmf_capsule * cc,uint8_t sc_type,uint8_t sc_status)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
nvmf_send_generic_error(const struct nvmf_capsule * nc,uint8_t sc_status)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
nvmf_send_success(const struct nvmf_capsule * nc)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
nvmf_connect_invalid_parameters(const struct nvmf_capsule * cc,bool data,uint16_t offset)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 *
nvmf_accept(struct nvmf_association * na,const struct nvmf_qpair_params * params,struct nvmf_capsule ** ccp,struct nvmf_fabric_connect_data * data)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
nvmf_finish_accept(const struct nvmf_capsule * cc,uint16_t cntlid)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
nvmf_controller_cap(struct nvmf_qpair * qp)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
nvmf_validate_cc(struct nvmf_qpair * qp,uint64_t cap,uint32_t old_cc,uint32_t new_cc)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
nvmf_init_discovery_controller_data(struct nvmf_qpair * qp,struct nvme_controller_data * cdata)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
nvmf_init_io_controller_data(struct nvmf_qpair * qp,const char * serial,const char * subnqn,int nn,uint32_t ioccsz,struct nvme_controller_data * cdata)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
428e0649a35SJohn 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
nvmf_get_log_page_id(const struct nvme_command * cmd)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
nvmf_get_log_page_length(const struct nvme_command * cmd)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
nvmf_get_log_page_offset(const struct nvme_command * cmd)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
nvmf_handoff_controller_qpair(struct nvmf_qpair * qp,const struct nvmf_fabric_connect_cmd * cmd,const struct nvmf_fabric_connect_data * data,struct nvmf_ioc_nv * nv)4592da066efSJohn Baldwin nvmf_handoff_controller_qpair(struct nvmf_qpair *qp,
460*365b89e8SJohn Baldwin const struct nvmf_fabric_connect_cmd *cmd,
461*365b89e8SJohn Baldwin const struct nvmf_fabric_connect_data *data, struct nvmf_ioc_nv *nv)
4622da066efSJohn Baldwin {
463*365b89e8SJohn Baldwin nvlist_t *nvl, *nvl_qp;
464*365b89e8SJohn Baldwin int error;
465*365b89e8SJohn Baldwin
466*365b89e8SJohn Baldwin error = nvmf_kernel_handoff_params(qp, &nvl_qp);
467*365b89e8SJohn Baldwin if (error)
468*365b89e8SJohn Baldwin return (error);
469*365b89e8SJohn Baldwin
470*365b89e8SJohn Baldwin nvl = nvlist_create(0);
471*365b89e8SJohn Baldwin nvlist_add_number(nvl, "trtype", qp->nq_association->na_trtype);
472*365b89e8SJohn Baldwin nvlist_move_nvlist(nvl, "params", nvl_qp);
473*365b89e8SJohn Baldwin nvlist_add_binary(nvl, "cmd", cmd, sizeof(*cmd));
474*365b89e8SJohn Baldwin nvlist_add_binary(nvl, "data", data, sizeof(*data));
475*365b89e8SJohn Baldwin
476*365b89e8SJohn Baldwin error = nvmf_pack_ioc_nvlist(nv, nvl);
477*365b89e8SJohn Baldwin nvlist_destroy(nvl);
478*365b89e8SJohn Baldwin return (error);
4792da066efSJohn Baldwin }
480