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/sysctl.h> 92da066efSJohn Baldwin #include <errno.h> 102da066efSJohn Baldwin #include <fcntl.h> 112da066efSJohn Baldwin #include <stdio.h> 122da066efSJohn Baldwin #include <stdlib.h> 132da066efSJohn Baldwin #include <string.h> 142da066efSJohn Baldwin #include <unistd.h> 152da066efSJohn Baldwin #include <uuid.h> 162da066efSJohn Baldwin 172da066efSJohn Baldwin #include "libnvmf.h" 182da066efSJohn Baldwin #include "internal.h" 192da066efSJohn Baldwin 202da066efSJohn Baldwin static void 212da066efSJohn Baldwin nvmf_init_sqe(void *sqe, uint8_t opcode) 222da066efSJohn Baldwin { 232da066efSJohn Baldwin struct nvme_command *cmd = sqe; 242da066efSJohn Baldwin 252da066efSJohn Baldwin memset(cmd, 0, sizeof(*cmd)); 262da066efSJohn Baldwin cmd->opc = opcode; 272da066efSJohn Baldwin } 282da066efSJohn Baldwin 292da066efSJohn Baldwin static void 302da066efSJohn Baldwin nvmf_init_fabrics_sqe(void *sqe, uint8_t fctype) 312da066efSJohn Baldwin { 322da066efSJohn Baldwin struct nvmf_capsule_cmd *cmd = sqe; 332da066efSJohn Baldwin 342da066efSJohn Baldwin nvmf_init_sqe(sqe, NVME_OPC_FABRICS_COMMANDS); 352da066efSJohn Baldwin cmd->fctype = fctype; 362da066efSJohn Baldwin } 372da066efSJohn Baldwin 382da066efSJohn Baldwin struct nvmf_qpair * 392da066efSJohn Baldwin nvmf_connect(struct nvmf_association *na, 402da066efSJohn Baldwin const struct nvmf_qpair_params *params, uint16_t qid, u_int queue_size, 412da066efSJohn Baldwin const uint8_t hostid[16], uint16_t cntlid, const char *subnqn, 422da066efSJohn Baldwin const char *hostnqn, uint32_t kato) 432da066efSJohn Baldwin { 442da066efSJohn Baldwin struct nvmf_fabric_connect_cmd cmd; 452da066efSJohn Baldwin struct nvmf_fabric_connect_data data; 462da066efSJohn Baldwin const struct nvmf_fabric_connect_rsp *rsp; 472da066efSJohn Baldwin struct nvmf_qpair *qp; 482da066efSJohn Baldwin struct nvmf_capsule *cc, *rc; 492da066efSJohn Baldwin int error; 502da066efSJohn Baldwin uint16_t sqhd, status; 512da066efSJohn Baldwin 522da066efSJohn Baldwin qp = NULL; 532da066efSJohn Baldwin cc = NULL; 542da066efSJohn Baldwin rc = NULL; 552da066efSJohn Baldwin na_clear_error(na); 562da066efSJohn Baldwin if (na->na_controller) { 572da066efSJohn Baldwin na_error(na, "Cannot connect on a controller"); 582da066efSJohn Baldwin goto error; 592da066efSJohn Baldwin } 602da066efSJohn Baldwin 612da066efSJohn Baldwin if (params->admin != (qid == 0)) { 622da066efSJohn Baldwin na_error(na, "Admin queue must use Queue ID 0"); 632da066efSJohn Baldwin goto error; 642da066efSJohn Baldwin } 652da066efSJohn Baldwin 662da066efSJohn Baldwin if (qid == 0) { 672da066efSJohn Baldwin if (queue_size < NVME_MIN_ADMIN_ENTRIES || 682da066efSJohn Baldwin queue_size > NVME_MAX_ADMIN_ENTRIES) { 692da066efSJohn Baldwin na_error(na, "Invalid queue size %u", queue_size); 702da066efSJohn Baldwin goto error; 712da066efSJohn Baldwin } 722da066efSJohn Baldwin } else { 732da066efSJohn Baldwin if (queue_size < NVME_MIN_IO_ENTRIES || 742da066efSJohn Baldwin queue_size > NVME_MAX_IO_ENTRIES) { 752da066efSJohn Baldwin na_error(na, "Invalid queue size %u", queue_size); 762da066efSJohn Baldwin goto error; 772da066efSJohn Baldwin } 782da066efSJohn Baldwin 792da066efSJohn Baldwin /* KATO is only for Admin queues. */ 802da066efSJohn Baldwin if (kato != 0) { 812da066efSJohn Baldwin na_error(na, "Cannot set KATO on I/O queues"); 822da066efSJohn Baldwin goto error; 832da066efSJohn Baldwin } 842da066efSJohn Baldwin } 852da066efSJohn Baldwin 862da066efSJohn Baldwin qp = nvmf_allocate_qpair(na, params); 872da066efSJohn Baldwin if (qp == NULL) 882da066efSJohn Baldwin goto error; 892da066efSJohn Baldwin 902da066efSJohn Baldwin nvmf_init_fabrics_sqe(&cmd, NVMF_FABRIC_COMMAND_CONNECT); 912da066efSJohn Baldwin cmd.recfmt = 0; 922da066efSJohn Baldwin cmd.qid = htole16(qid); 932da066efSJohn Baldwin 942da066efSJohn Baldwin /* N.B. sqsize is 0's based. */ 952da066efSJohn Baldwin cmd.sqsize = htole16(queue_size - 1); 962da066efSJohn Baldwin if (!na->na_params.sq_flow_control) 972da066efSJohn Baldwin cmd.cattr |= NVMF_CONNECT_ATTR_DISABLE_SQ_FC; 982da066efSJohn Baldwin cmd.kato = htole32(kato); 992da066efSJohn Baldwin 1002da066efSJohn Baldwin cc = nvmf_allocate_command(qp, &cmd); 1012da066efSJohn Baldwin if (cc == NULL) { 1022da066efSJohn Baldwin na_error(na, "Failed to allocate command capsule: %s", 1032da066efSJohn Baldwin strerror(errno)); 1042da066efSJohn Baldwin goto error; 1052da066efSJohn Baldwin } 1062da066efSJohn Baldwin 1072da066efSJohn Baldwin memset(&data, 0, sizeof(data)); 1082da066efSJohn Baldwin memcpy(data.hostid, hostid, sizeof(data.hostid)); 1092da066efSJohn Baldwin data.cntlid = htole16(cntlid); 1102da066efSJohn Baldwin strlcpy(data.subnqn, subnqn, sizeof(data.subnqn)); 1112da066efSJohn Baldwin strlcpy(data.hostnqn, hostnqn, sizeof(data.hostnqn)); 1122da066efSJohn Baldwin 1132da066efSJohn Baldwin error = nvmf_capsule_append_data(cc, &data, sizeof(data), true); 1142da066efSJohn Baldwin if (error != 0) { 1152da066efSJohn Baldwin na_error(na, "Failed to append data to CONNECT capsule: %s", 1162da066efSJohn Baldwin strerror(error)); 1172da066efSJohn Baldwin goto error; 1182da066efSJohn Baldwin } 1192da066efSJohn Baldwin 1202da066efSJohn Baldwin error = nvmf_transmit_capsule(cc); 1212da066efSJohn Baldwin if (error != 0) { 1222da066efSJohn Baldwin na_error(na, "Failed to transmit CONNECT capsule: %s", 1232da066efSJohn Baldwin strerror(errno)); 1242da066efSJohn Baldwin goto error; 1252da066efSJohn Baldwin } 1262da066efSJohn Baldwin 1272da066efSJohn Baldwin error = nvmf_receive_capsule(qp, &rc); 1282da066efSJohn Baldwin if (error != 0) { 1292da066efSJohn Baldwin na_error(na, "Failed to receive CONNECT response: %s", 1302da066efSJohn Baldwin strerror(error)); 1312da066efSJohn Baldwin goto error; 1322da066efSJohn Baldwin } 1332da066efSJohn Baldwin 1342da066efSJohn Baldwin rsp = (const struct nvmf_fabric_connect_rsp *)&rc->nc_cqe; 1352da066efSJohn Baldwin status = le16toh(rc->nc_cqe.status); 1362da066efSJohn Baldwin if (status != 0) { 1372da066efSJohn Baldwin if (NVME_STATUS_GET_SC(status) == NVMF_FABRIC_SC_INVALID_PARAM) 1382da066efSJohn Baldwin na_error(na, 1392da066efSJohn Baldwin "CONNECT invalid parameter IATTR: %#x IPO: %#x", 1402da066efSJohn Baldwin rsp->status_code_specific.invalid.iattr, 1412da066efSJohn Baldwin rsp->status_code_specific.invalid.ipo); 1422da066efSJohn Baldwin else 1432da066efSJohn Baldwin na_error(na, "CONNECT failed, status %#x", status); 1442da066efSJohn Baldwin goto error; 1452da066efSJohn Baldwin } 1462da066efSJohn Baldwin 1472da066efSJohn Baldwin if (rc->nc_cqe.cid != cmd.cid) { 1482da066efSJohn Baldwin na_error(na, "Mismatched CID in CONNECT response"); 1492da066efSJohn Baldwin goto error; 1502da066efSJohn Baldwin } 1512da066efSJohn Baldwin 1522da066efSJohn Baldwin if (!rc->nc_sqhd_valid) { 1532da066efSJohn Baldwin na_error(na, "CONNECT response without valid SQHD"); 1542da066efSJohn Baldwin goto error; 1552da066efSJohn Baldwin } 1562da066efSJohn Baldwin 1572da066efSJohn Baldwin sqhd = le16toh(rsp->sqhd); 1582da066efSJohn Baldwin if (sqhd == 0xffff) { 1592da066efSJohn Baldwin if (na->na_params.sq_flow_control) { 1602da066efSJohn Baldwin na_error(na, "Controller disabled SQ flow control"); 1612da066efSJohn Baldwin goto error; 1622da066efSJohn Baldwin } 1632da066efSJohn Baldwin qp->nq_flow_control = false; 1642da066efSJohn Baldwin } else { 1652da066efSJohn Baldwin qp->nq_flow_control = true; 1662da066efSJohn Baldwin qp->nq_sqhd = sqhd; 1672da066efSJohn Baldwin qp->nq_sqtail = sqhd; 1682da066efSJohn Baldwin } 1692da066efSJohn Baldwin 1702da066efSJohn Baldwin if (rsp->status_code_specific.success.authreq) { 1712da066efSJohn Baldwin na_error(na, "CONNECT response requests authentication\n"); 1722da066efSJohn Baldwin goto error; 1732da066efSJohn Baldwin } 1742da066efSJohn Baldwin 1752da066efSJohn Baldwin qp->nq_qsize = queue_size; 1762da066efSJohn Baldwin qp->nq_cntlid = le16toh(rsp->status_code_specific.success.cntlid); 1772da066efSJohn Baldwin qp->nq_kato = kato; 1782da066efSJohn Baldwin /* XXX: Save qid in qp? */ 1792da066efSJohn Baldwin return (qp); 1802da066efSJohn Baldwin 1812da066efSJohn Baldwin error: 1822da066efSJohn Baldwin if (rc != NULL) 1832da066efSJohn Baldwin nvmf_free_capsule(rc); 1842da066efSJohn Baldwin if (cc != NULL) 1852da066efSJohn Baldwin nvmf_free_capsule(cc); 1862da066efSJohn Baldwin if (qp != NULL) 1872da066efSJohn Baldwin nvmf_free_qpair(qp); 1882da066efSJohn Baldwin return (NULL); 1892da066efSJohn Baldwin } 1902da066efSJohn Baldwin 1912da066efSJohn Baldwin uint16_t 1922da066efSJohn Baldwin nvmf_cntlid(struct nvmf_qpair *qp) 1932da066efSJohn Baldwin { 1942da066efSJohn Baldwin return (qp->nq_cntlid); 1952da066efSJohn Baldwin } 1962da066efSJohn Baldwin 1972da066efSJohn Baldwin int 1982da066efSJohn Baldwin nvmf_host_transmit_command(struct nvmf_capsule *nc) 1992da066efSJohn Baldwin { 2002da066efSJohn Baldwin struct nvmf_qpair *qp = nc->nc_qpair; 2012da066efSJohn Baldwin uint16_t new_sqtail; 2022da066efSJohn Baldwin int error; 2032da066efSJohn Baldwin 2042da066efSJohn Baldwin /* Fail if the queue is full. */ 2052da066efSJohn Baldwin new_sqtail = (qp->nq_sqtail + 1) % qp->nq_qsize; 2062da066efSJohn Baldwin if (new_sqtail == qp->nq_sqhd) 2072da066efSJohn Baldwin return (EBUSY); 2082da066efSJohn Baldwin 2092da066efSJohn Baldwin nc->nc_sqe.cid = htole16(qp->nq_cid); 2102da066efSJohn Baldwin 2112da066efSJohn Baldwin /* 4.2 Skip CID of 0xFFFF. */ 2122da066efSJohn Baldwin qp->nq_cid++; 2132da066efSJohn Baldwin if (qp->nq_cid == 0xFFFF) 2142da066efSJohn Baldwin qp->nq_cid = 0; 2152da066efSJohn Baldwin 2162da066efSJohn Baldwin error = nvmf_transmit_capsule(nc); 2172da066efSJohn Baldwin if (error != 0) 2182da066efSJohn Baldwin return (error); 2192da066efSJohn Baldwin 2202da066efSJohn Baldwin qp->nq_sqtail = new_sqtail; 2212da066efSJohn Baldwin return (0); 2222da066efSJohn Baldwin } 2232da066efSJohn Baldwin 2242da066efSJohn Baldwin /* Receive a single capsule and update SQ FC accounting. */ 2252da066efSJohn Baldwin static int 2262da066efSJohn Baldwin nvmf_host_receive_capsule(struct nvmf_qpair *qp, struct nvmf_capsule **ncp) 2272da066efSJohn Baldwin { 2282da066efSJohn Baldwin struct nvmf_capsule *nc; 2292da066efSJohn Baldwin int error; 2302da066efSJohn Baldwin 2312da066efSJohn Baldwin /* If the SQ is empty, there is no response to wait for. */ 2322da066efSJohn Baldwin if (qp->nq_sqhd == qp->nq_sqtail) 2332da066efSJohn Baldwin return (EWOULDBLOCK); 2342da066efSJohn Baldwin 2352da066efSJohn Baldwin error = nvmf_receive_capsule(qp, &nc); 2362da066efSJohn Baldwin if (error != 0) 2372da066efSJohn Baldwin return (error); 2382da066efSJohn Baldwin 2392da066efSJohn Baldwin if (qp->nq_flow_control) { 2402da066efSJohn Baldwin if (nc->nc_sqhd_valid) 2412da066efSJohn Baldwin qp->nq_sqhd = le16toh(nc->nc_cqe.sqhd); 2422da066efSJohn Baldwin } else { 2432da066efSJohn Baldwin /* 2442da066efSJohn Baldwin * If SQ FC is disabled, just advance the head for 2452da066efSJohn Baldwin * each response capsule received so that we track the 2462da066efSJohn Baldwin * number of outstanding commands. 2472da066efSJohn Baldwin */ 2482da066efSJohn Baldwin qp->nq_sqhd = (qp->nq_sqhd + 1) % qp->nq_qsize; 2492da066efSJohn Baldwin } 2502da066efSJohn Baldwin *ncp = nc; 2512da066efSJohn Baldwin return (0); 2522da066efSJohn Baldwin } 2532da066efSJohn Baldwin 2542da066efSJohn Baldwin int 2552da066efSJohn Baldwin nvmf_host_receive_response(struct nvmf_qpair *qp, struct nvmf_capsule **ncp) 2562da066efSJohn Baldwin { 2572da066efSJohn Baldwin struct nvmf_capsule *nc; 2582da066efSJohn Baldwin 2592da066efSJohn Baldwin /* Return the oldest previously received response. */ 2602da066efSJohn Baldwin if (!TAILQ_EMPTY(&qp->nq_rx_capsules)) { 2612da066efSJohn Baldwin nc = TAILQ_FIRST(&qp->nq_rx_capsules); 2622da066efSJohn Baldwin TAILQ_REMOVE(&qp->nq_rx_capsules, nc, nc_link); 2632da066efSJohn Baldwin *ncp = nc; 2642da066efSJohn Baldwin return (0); 2652da066efSJohn Baldwin } 2662da066efSJohn Baldwin 2672da066efSJohn Baldwin return (nvmf_host_receive_capsule(qp, ncp)); 2682da066efSJohn Baldwin } 2692da066efSJohn Baldwin 2702da066efSJohn Baldwin int 2712da066efSJohn Baldwin nvmf_host_wait_for_response(struct nvmf_capsule *cc, 2722da066efSJohn Baldwin struct nvmf_capsule **rcp) 2732da066efSJohn Baldwin { 2742da066efSJohn Baldwin struct nvmf_qpair *qp = cc->nc_qpair; 2752da066efSJohn Baldwin struct nvmf_capsule *rc; 2762da066efSJohn Baldwin int error; 2772da066efSJohn Baldwin 2782da066efSJohn Baldwin /* Check if a response was already received. */ 2792da066efSJohn Baldwin TAILQ_FOREACH(rc, &qp->nq_rx_capsules, nc_link) { 2802da066efSJohn Baldwin if (rc->nc_cqe.cid == cc->nc_sqe.cid) { 2812da066efSJohn Baldwin TAILQ_REMOVE(&qp->nq_rx_capsules, rc, nc_link); 2822da066efSJohn Baldwin *rcp = rc; 2832da066efSJohn Baldwin return (0); 2842da066efSJohn Baldwin } 2852da066efSJohn Baldwin } 2862da066efSJohn Baldwin 2872da066efSJohn Baldwin /* Wait for a response. */ 2882da066efSJohn Baldwin for (;;) { 2892da066efSJohn Baldwin error = nvmf_host_receive_capsule(qp, &rc); 2902da066efSJohn Baldwin if (error != 0) 2912da066efSJohn Baldwin return (error); 2922da066efSJohn Baldwin 2932da066efSJohn Baldwin if (rc->nc_cqe.cid != cc->nc_sqe.cid) { 2942da066efSJohn Baldwin TAILQ_INSERT_TAIL(&qp->nq_rx_capsules, rc, nc_link); 2952da066efSJohn Baldwin continue; 2962da066efSJohn Baldwin } 2972da066efSJohn Baldwin 2982da066efSJohn Baldwin *rcp = rc; 2992da066efSJohn Baldwin return (0); 3002da066efSJohn Baldwin } 3012da066efSJohn Baldwin } 3022da066efSJohn Baldwin 3032da066efSJohn Baldwin struct nvmf_capsule * 3042da066efSJohn Baldwin nvmf_keepalive(struct nvmf_qpair *qp) 3052da066efSJohn Baldwin { 3062da066efSJohn Baldwin struct nvme_command cmd; 3072da066efSJohn Baldwin 3082da066efSJohn Baldwin if (!qp->nq_admin) { 3092da066efSJohn Baldwin errno = EINVAL; 3102da066efSJohn Baldwin return (NULL); 3112da066efSJohn Baldwin } 3122da066efSJohn Baldwin 3132da066efSJohn Baldwin nvmf_init_sqe(&cmd, NVME_OPC_KEEP_ALIVE); 3142da066efSJohn Baldwin 3152da066efSJohn Baldwin return (nvmf_allocate_command(qp, &cmd)); 3162da066efSJohn Baldwin } 3172da066efSJohn Baldwin 3182da066efSJohn Baldwin static struct nvmf_capsule * 3192da066efSJohn Baldwin nvmf_get_property(struct nvmf_qpair *qp, uint32_t offset, uint8_t size) 3202da066efSJohn Baldwin { 3212da066efSJohn Baldwin struct nvmf_fabric_prop_get_cmd cmd; 3222da066efSJohn Baldwin 3232da066efSJohn Baldwin nvmf_init_fabrics_sqe(&cmd, NVMF_FABRIC_COMMAND_PROPERTY_GET); 3242da066efSJohn Baldwin switch (size) { 3252da066efSJohn Baldwin case 4: 3262da066efSJohn Baldwin cmd.attrib.size = NVMF_PROP_SIZE_4; 3272da066efSJohn Baldwin break; 3282da066efSJohn Baldwin case 8: 3292da066efSJohn Baldwin cmd.attrib.size = NVMF_PROP_SIZE_8; 3302da066efSJohn Baldwin break; 3312da066efSJohn Baldwin default: 3322da066efSJohn Baldwin errno = EINVAL; 3332da066efSJohn Baldwin return (NULL); 3342da066efSJohn Baldwin } 3352da066efSJohn Baldwin cmd.ofst = htole32(offset); 3362da066efSJohn Baldwin 3372da066efSJohn Baldwin return (nvmf_allocate_command(qp, &cmd)); 3382da066efSJohn Baldwin } 3392da066efSJohn Baldwin 3402da066efSJohn Baldwin int 3412da066efSJohn Baldwin nvmf_read_property(struct nvmf_qpair *qp, uint32_t offset, uint8_t size, 3422da066efSJohn Baldwin uint64_t *value) 3432da066efSJohn Baldwin { 3442da066efSJohn Baldwin struct nvmf_capsule *cc, *rc; 3452da066efSJohn Baldwin const struct nvmf_fabric_prop_get_rsp *rsp; 3462da066efSJohn Baldwin uint16_t status; 3472da066efSJohn Baldwin int error; 3482da066efSJohn Baldwin 3492da066efSJohn Baldwin if (!qp->nq_admin) 3502da066efSJohn Baldwin return (EINVAL); 3512da066efSJohn Baldwin 3522da066efSJohn Baldwin cc = nvmf_get_property(qp, offset, size); 3532da066efSJohn Baldwin if (cc == NULL) 3542da066efSJohn Baldwin return (errno); 3552da066efSJohn Baldwin 3562da066efSJohn Baldwin error = nvmf_host_transmit_command(cc); 3572da066efSJohn Baldwin if (error != 0) { 3582da066efSJohn Baldwin nvmf_free_capsule(cc); 3592da066efSJohn Baldwin return (error); 3602da066efSJohn Baldwin } 3612da066efSJohn Baldwin 3622da066efSJohn Baldwin error = nvmf_host_wait_for_response(cc, &rc); 3632da066efSJohn Baldwin nvmf_free_capsule(cc); 3642da066efSJohn Baldwin if (error != 0) 3652da066efSJohn Baldwin return (error); 3662da066efSJohn Baldwin 3672da066efSJohn Baldwin rsp = (const struct nvmf_fabric_prop_get_rsp *)&rc->nc_cqe; 3682da066efSJohn Baldwin status = le16toh(rc->nc_cqe.status); 3692da066efSJohn Baldwin if (status != 0) { 3702da066efSJohn Baldwin printf("NVMF: PROPERTY_GET failed, status %#x\n", status); 3712da066efSJohn Baldwin nvmf_free_capsule(rc); 3722da066efSJohn Baldwin return (EIO); 3732da066efSJohn Baldwin } 3742da066efSJohn Baldwin 3752da066efSJohn Baldwin if (size == 8) 3762da066efSJohn Baldwin *value = le64toh(rsp->value.u64); 3772da066efSJohn Baldwin else 3782da066efSJohn Baldwin *value = le32toh(rsp->value.u32.low); 3792da066efSJohn Baldwin nvmf_free_capsule(rc); 3802da066efSJohn Baldwin return (0); 3812da066efSJohn Baldwin } 3822da066efSJohn Baldwin 3832da066efSJohn Baldwin static struct nvmf_capsule * 3842da066efSJohn Baldwin nvmf_set_property(struct nvmf_qpair *qp, uint32_t offset, uint8_t size, 3852da066efSJohn Baldwin uint64_t value) 3862da066efSJohn Baldwin { 3872da066efSJohn Baldwin struct nvmf_fabric_prop_set_cmd cmd; 3882da066efSJohn Baldwin 3892da066efSJohn Baldwin nvmf_init_fabrics_sqe(&cmd, NVMF_FABRIC_COMMAND_PROPERTY_SET); 3902da066efSJohn Baldwin switch (size) { 3912da066efSJohn Baldwin case 4: 3922da066efSJohn Baldwin cmd.attrib.size = NVMF_PROP_SIZE_4; 3932da066efSJohn Baldwin cmd.value.u32.low = htole32(value); 3942da066efSJohn Baldwin break; 3952da066efSJohn Baldwin case 8: 3962da066efSJohn Baldwin cmd.attrib.size = NVMF_PROP_SIZE_8; 3972da066efSJohn Baldwin cmd.value.u64 = htole64(value); 3982da066efSJohn Baldwin break; 3992da066efSJohn Baldwin default: 4002da066efSJohn Baldwin errno = EINVAL; 4012da066efSJohn Baldwin return (NULL); 4022da066efSJohn Baldwin } 4032da066efSJohn Baldwin cmd.ofst = htole32(offset); 4042da066efSJohn Baldwin 4052da066efSJohn Baldwin return (nvmf_allocate_command(qp, &cmd)); 4062da066efSJohn Baldwin } 4072da066efSJohn Baldwin 4082da066efSJohn Baldwin int 4092da066efSJohn Baldwin nvmf_write_property(struct nvmf_qpair *qp, uint32_t offset, uint8_t size, 4102da066efSJohn Baldwin uint64_t value) 4112da066efSJohn Baldwin { 4122da066efSJohn Baldwin struct nvmf_capsule *cc, *rc; 4132da066efSJohn Baldwin uint16_t status; 4142da066efSJohn Baldwin int error; 4152da066efSJohn Baldwin 4162da066efSJohn Baldwin if (!qp->nq_admin) 4172da066efSJohn Baldwin return (EINVAL); 4182da066efSJohn Baldwin 4192da066efSJohn Baldwin cc = nvmf_set_property(qp, offset, size, value); 4202da066efSJohn Baldwin if (cc == NULL) 4212da066efSJohn Baldwin return (errno); 4222da066efSJohn Baldwin 4232da066efSJohn Baldwin error = nvmf_host_transmit_command(cc); 4242da066efSJohn Baldwin if (error != 0) { 4252da066efSJohn Baldwin nvmf_free_capsule(cc); 4262da066efSJohn Baldwin return (error); 4272da066efSJohn Baldwin } 4282da066efSJohn Baldwin 4292da066efSJohn Baldwin error = nvmf_host_wait_for_response(cc, &rc); 4302da066efSJohn Baldwin nvmf_free_capsule(cc); 4312da066efSJohn Baldwin if (error != 0) 4322da066efSJohn Baldwin return (error); 4332da066efSJohn Baldwin 4342da066efSJohn Baldwin status = le16toh(rc->nc_cqe.status); 4352da066efSJohn Baldwin if (status != 0) { 4362da066efSJohn Baldwin printf("NVMF: PROPERTY_SET failed, status %#x\n", status); 4372da066efSJohn Baldwin nvmf_free_capsule(rc); 4382da066efSJohn Baldwin return (EIO); 4392da066efSJohn Baldwin } 4402da066efSJohn Baldwin 4412da066efSJohn Baldwin nvmf_free_capsule(rc); 4422da066efSJohn Baldwin return (0); 4432da066efSJohn Baldwin } 4442da066efSJohn Baldwin 4452da066efSJohn Baldwin int 4462da066efSJohn Baldwin nvmf_hostid_from_hostuuid(uint8_t hostid[16]) 4472da066efSJohn Baldwin { 4482da066efSJohn Baldwin char hostuuid_str[64]; 4492da066efSJohn Baldwin uuid_t hostuuid; 4502da066efSJohn Baldwin size_t len; 4512da066efSJohn Baldwin uint32_t status; 4522da066efSJohn Baldwin 4532da066efSJohn Baldwin len = sizeof(hostuuid_str); 4542da066efSJohn Baldwin if (sysctlbyname("kern.hostuuid", hostuuid_str, &len, NULL, 0) != 0) 4552da066efSJohn Baldwin return (errno); 4562da066efSJohn Baldwin 4572da066efSJohn Baldwin uuid_from_string(hostuuid_str, &hostuuid, &status); 4582da066efSJohn Baldwin switch (status) { 4592da066efSJohn Baldwin case uuid_s_ok: 4602da066efSJohn Baldwin break; 4612da066efSJohn Baldwin case uuid_s_no_memory: 4622da066efSJohn Baldwin return (ENOMEM); 4632da066efSJohn Baldwin default: 4642da066efSJohn Baldwin return (EINVAL); 4652da066efSJohn Baldwin } 4662da066efSJohn Baldwin 4672da066efSJohn Baldwin uuid_enc_le(hostid, &hostuuid); 4682da066efSJohn Baldwin return (0); 4692da066efSJohn Baldwin } 4702da066efSJohn Baldwin 4712da066efSJohn Baldwin int 4722da066efSJohn Baldwin nvmf_nqn_from_hostuuid(char nqn[NVMF_NQN_MAX_LEN]) 4732da066efSJohn Baldwin { 4742da066efSJohn Baldwin char hostuuid_str[64]; 4752da066efSJohn Baldwin size_t len; 4762da066efSJohn Baldwin 4772da066efSJohn Baldwin len = sizeof(hostuuid_str); 4782da066efSJohn Baldwin if (sysctlbyname("kern.hostuuid", hostuuid_str, &len, NULL, 0) != 0) 4792da066efSJohn Baldwin return (errno); 4802da066efSJohn Baldwin 4812da066efSJohn Baldwin strlcpy(nqn, NVMF_NQN_UUID_PRE, NVMF_NQN_MAX_LEN); 4822da066efSJohn Baldwin strlcat(nqn, hostuuid_str, NVMF_NQN_MAX_LEN); 4832da066efSJohn Baldwin return (0); 4842da066efSJohn Baldwin } 4852da066efSJohn Baldwin 4862da066efSJohn Baldwin int 4872da066efSJohn Baldwin nvmf_host_identify_controller(struct nvmf_qpair *qp, 4882da066efSJohn Baldwin struct nvme_controller_data *cdata) 4892da066efSJohn Baldwin { 4902da066efSJohn Baldwin struct nvme_command cmd; 4912da066efSJohn Baldwin struct nvmf_capsule *cc, *rc; 4922da066efSJohn Baldwin int error; 4932da066efSJohn Baldwin uint16_t status; 4942da066efSJohn Baldwin 4952da066efSJohn Baldwin if (!qp->nq_admin) 4962da066efSJohn Baldwin return (EINVAL); 4972da066efSJohn Baldwin 4982da066efSJohn Baldwin nvmf_init_sqe(&cmd, NVME_OPC_IDENTIFY); 4992da066efSJohn Baldwin 5002da066efSJohn Baldwin /* 5.15.1 Use CNS of 0x01 for controller data. */ 5012da066efSJohn Baldwin cmd.cdw10 = htole32(1); 5022da066efSJohn Baldwin 5032da066efSJohn Baldwin cc = nvmf_allocate_command(qp, &cmd); 5042da066efSJohn Baldwin if (cc == NULL) 5052da066efSJohn Baldwin return (errno); 5062da066efSJohn Baldwin 5072da066efSJohn Baldwin error = nvmf_capsule_append_data(cc, cdata, sizeof(*cdata), false); 5082da066efSJohn Baldwin if (error != 0) { 5092da066efSJohn Baldwin nvmf_free_capsule(cc); 5102da066efSJohn Baldwin return (error); 5112da066efSJohn Baldwin } 5122da066efSJohn Baldwin 5132da066efSJohn Baldwin error = nvmf_host_transmit_command(cc); 5142da066efSJohn Baldwin if (error != 0) { 5152da066efSJohn Baldwin nvmf_free_capsule(cc); 5162da066efSJohn Baldwin return (error); 5172da066efSJohn Baldwin } 5182da066efSJohn Baldwin 5192da066efSJohn Baldwin error = nvmf_host_wait_for_response(cc, &rc); 5202da066efSJohn Baldwin nvmf_free_capsule(cc); 5212da066efSJohn Baldwin if (error != 0) 5222da066efSJohn Baldwin return (error); 5232da066efSJohn Baldwin 5242da066efSJohn Baldwin status = le16toh(rc->nc_cqe.status); 5252da066efSJohn Baldwin if (status != 0) { 5262da066efSJohn Baldwin printf("NVMF: IDENTIFY failed, status %#x\n", status); 5272da066efSJohn Baldwin nvmf_free_capsule(rc); 5282da066efSJohn Baldwin return (EIO); 5292da066efSJohn Baldwin } 5302da066efSJohn Baldwin 5312da066efSJohn Baldwin nvmf_free_capsule(rc); 5322da066efSJohn Baldwin return (0); 5332da066efSJohn Baldwin } 5342da066efSJohn Baldwin 5352da066efSJohn Baldwin int 5362da066efSJohn Baldwin nvmf_host_identify_namespace(struct nvmf_qpair *qp, uint32_t nsid, 5372da066efSJohn Baldwin struct nvme_namespace_data *nsdata) 5382da066efSJohn Baldwin { 5392da066efSJohn Baldwin struct nvme_command cmd; 5402da066efSJohn Baldwin struct nvmf_capsule *cc, *rc; 5412da066efSJohn Baldwin int error; 5422da066efSJohn Baldwin uint16_t status; 5432da066efSJohn Baldwin 5442da066efSJohn Baldwin if (!qp->nq_admin) 5452da066efSJohn Baldwin return (EINVAL); 5462da066efSJohn Baldwin 5472da066efSJohn Baldwin nvmf_init_sqe(&cmd, NVME_OPC_IDENTIFY); 5482da066efSJohn Baldwin 5492da066efSJohn Baldwin /* 5.15.1 Use CNS of 0x00 for namespace data. */ 5502da066efSJohn Baldwin cmd.cdw10 = htole32(0); 5512da066efSJohn Baldwin cmd.nsid = htole32(nsid); 5522da066efSJohn Baldwin 5532da066efSJohn Baldwin cc = nvmf_allocate_command(qp, &cmd); 5542da066efSJohn Baldwin if (cc == NULL) 5552da066efSJohn Baldwin return (errno); 5562da066efSJohn Baldwin 5572da066efSJohn Baldwin error = nvmf_capsule_append_data(cc, nsdata, sizeof(*nsdata), false); 5582da066efSJohn Baldwin if (error != 0) { 5592da066efSJohn Baldwin nvmf_free_capsule(cc); 5602da066efSJohn Baldwin return (error); 5612da066efSJohn Baldwin } 5622da066efSJohn Baldwin 5632da066efSJohn Baldwin error = nvmf_host_transmit_command(cc); 5642da066efSJohn Baldwin if (error != 0) { 5652da066efSJohn Baldwin nvmf_free_capsule(cc); 5662da066efSJohn Baldwin return (error); 5672da066efSJohn Baldwin } 5682da066efSJohn Baldwin 5692da066efSJohn Baldwin error = nvmf_host_wait_for_response(cc, &rc); 5702da066efSJohn Baldwin nvmf_free_capsule(cc); 5712da066efSJohn Baldwin if (error != 0) 5722da066efSJohn Baldwin return (error); 5732da066efSJohn Baldwin 5742da066efSJohn Baldwin status = le16toh(rc->nc_cqe.status); 5752da066efSJohn Baldwin if (status != 0) { 5762da066efSJohn Baldwin printf("NVMF: IDENTIFY failed, status %#x\n", status); 5772da066efSJohn Baldwin nvmf_free_capsule(rc); 5782da066efSJohn Baldwin return (EIO); 5792da066efSJohn Baldwin } 5802da066efSJohn Baldwin 5812da066efSJohn Baldwin nvmf_free_capsule(rc); 5822da066efSJohn Baldwin return (0); 5832da066efSJohn Baldwin } 5842da066efSJohn Baldwin 5852da066efSJohn Baldwin static int 5862da066efSJohn Baldwin nvmf_get_discovery_log_page(struct nvmf_qpair *qp, uint64_t offset, void *buf, 5872da066efSJohn Baldwin size_t len) 5882da066efSJohn Baldwin { 5892da066efSJohn Baldwin struct nvme_command cmd; 5902da066efSJohn Baldwin struct nvmf_capsule *cc, *rc; 5912da066efSJohn Baldwin size_t numd; 5922da066efSJohn Baldwin int error; 5932da066efSJohn Baldwin uint16_t status; 5942da066efSJohn Baldwin 5952da066efSJohn Baldwin if (len % 4 != 0 || len == 0 || offset % 4 != 0) 5962da066efSJohn Baldwin return (EINVAL); 5972da066efSJohn Baldwin 5982da066efSJohn Baldwin numd = (len / 4) - 1; 5992da066efSJohn Baldwin nvmf_init_sqe(&cmd, NVME_OPC_GET_LOG_PAGE); 6002da066efSJohn Baldwin cmd.cdw10 = htole32(numd << 16 | NVME_LOG_DISCOVERY); 6012da066efSJohn Baldwin cmd.cdw11 = htole32(numd >> 16); 6022da066efSJohn Baldwin cmd.cdw12 = htole32(offset); 6032da066efSJohn Baldwin cmd.cdw13 = htole32(offset >> 32); 6042da066efSJohn Baldwin 6052da066efSJohn Baldwin cc = nvmf_allocate_command(qp, &cmd); 6062da066efSJohn Baldwin if (cc == NULL) 6072da066efSJohn Baldwin return (errno); 6082da066efSJohn Baldwin 6092da066efSJohn Baldwin error = nvmf_capsule_append_data(cc, buf, len, false); 6102da066efSJohn Baldwin if (error != 0) { 6112da066efSJohn Baldwin nvmf_free_capsule(cc); 6122da066efSJohn Baldwin return (error); 6132da066efSJohn Baldwin } 6142da066efSJohn Baldwin 6152da066efSJohn Baldwin error = nvmf_host_transmit_command(cc); 6162da066efSJohn Baldwin if (error != 0) { 6172da066efSJohn Baldwin nvmf_free_capsule(cc); 6182da066efSJohn Baldwin return (error); 6192da066efSJohn Baldwin } 6202da066efSJohn Baldwin 6212da066efSJohn Baldwin error = nvmf_host_wait_for_response(cc, &rc); 6222da066efSJohn Baldwin nvmf_free_capsule(cc); 6232da066efSJohn Baldwin if (error != 0) 6242da066efSJohn Baldwin return (error); 6252da066efSJohn Baldwin 6262da066efSJohn Baldwin status = le16toh(rc->nc_cqe.status); 6272da066efSJohn Baldwin if (NVMEV(NVME_STATUS_SC, status) == 6282da066efSJohn Baldwin NVMF_FABRIC_SC_LOG_RESTART_DISCOVERY) { 6292da066efSJohn Baldwin nvmf_free_capsule(rc); 6302da066efSJohn Baldwin return (EAGAIN); 6312da066efSJohn Baldwin } 6322da066efSJohn Baldwin if (status != 0) { 6332da066efSJohn Baldwin printf("NVMF: GET_LOG_PAGE failed, status %#x\n", status); 6342da066efSJohn Baldwin nvmf_free_capsule(rc); 6352da066efSJohn Baldwin return (EIO); 6362da066efSJohn Baldwin } 6372da066efSJohn Baldwin 6382da066efSJohn Baldwin nvmf_free_capsule(rc); 6392da066efSJohn Baldwin return (0); 6402da066efSJohn Baldwin } 6412da066efSJohn Baldwin 6422da066efSJohn Baldwin int 6432da066efSJohn Baldwin nvmf_host_fetch_discovery_log_page(struct nvmf_qpair *qp, 6442da066efSJohn Baldwin struct nvme_discovery_log **logp) 6452da066efSJohn Baldwin { 6462da066efSJohn Baldwin struct nvme_discovery_log hdr, *log; 6472da066efSJohn Baldwin size_t payload_len; 6482da066efSJohn Baldwin int error; 6492da066efSJohn Baldwin 6502da066efSJohn Baldwin if (!qp->nq_admin) 6512da066efSJohn Baldwin return (EINVAL); 6522da066efSJohn Baldwin 6532da066efSJohn Baldwin log = NULL; 6542da066efSJohn Baldwin for (;;) { 6552da066efSJohn Baldwin error = nvmf_get_discovery_log_page(qp, 0, &hdr, sizeof(hdr)); 656408572a2SPierre Pronchery if (error != 0) { 657408572a2SPierre Pronchery free(log); 6582da066efSJohn Baldwin return (error); 659408572a2SPierre Pronchery } 6602da066efSJohn Baldwin nvme_discovery_log_swapbytes(&hdr); 6612da066efSJohn Baldwin 6622da066efSJohn Baldwin if (hdr.recfmt != 0) { 6632da066efSJohn Baldwin printf("NVMF: Unsupported discovery log format: %d\n", 6642da066efSJohn Baldwin hdr.recfmt); 665408572a2SPierre Pronchery free(log); 6662da066efSJohn Baldwin return (EINVAL); 6672da066efSJohn Baldwin } 6682da066efSJohn Baldwin 6692da066efSJohn Baldwin if (hdr.numrec > 1024) { 6702da066efSJohn Baldwin printf("NVMF: Too many discovery log entries: %ju\n", 6712da066efSJohn Baldwin (uintmax_t)hdr.numrec); 672408572a2SPierre Pronchery free(log); 6732da066efSJohn Baldwin return (EFBIG); 6742da066efSJohn Baldwin } 6752da066efSJohn Baldwin 6762da066efSJohn Baldwin payload_len = sizeof(log->entries[0]) * hdr.numrec; 6772da066efSJohn Baldwin log = reallocf(log, sizeof(*log) + payload_len); 6782da066efSJohn Baldwin if (log == NULL) 6792da066efSJohn Baldwin return (ENOMEM); 6802da066efSJohn Baldwin *log = hdr; 6812da066efSJohn Baldwin if (hdr.numrec == 0) 6822da066efSJohn Baldwin break; 6832da066efSJohn Baldwin 6842da066efSJohn Baldwin error = nvmf_get_discovery_log_page(qp, sizeof(hdr), 6852da066efSJohn Baldwin log->entries, payload_len); 6862da066efSJohn Baldwin if (error == EAGAIN) 6872da066efSJohn Baldwin continue; 6882da066efSJohn Baldwin if (error != 0) { 6892da066efSJohn Baldwin free(log); 6902da066efSJohn Baldwin return (error); 6912da066efSJohn Baldwin } 6922da066efSJohn Baldwin 6932da066efSJohn Baldwin /* Re-read the header and check the generation count. */ 6942da066efSJohn Baldwin error = nvmf_get_discovery_log_page(qp, 0, &hdr, sizeof(hdr)); 6952da066efSJohn Baldwin if (error != 0) { 6962da066efSJohn Baldwin free(log); 6972da066efSJohn Baldwin return (error); 6982da066efSJohn Baldwin } 6992da066efSJohn Baldwin nvme_discovery_log_swapbytes(&hdr); 7002da066efSJohn Baldwin 7012da066efSJohn Baldwin if (log->genctr != hdr.genctr) 7022da066efSJohn Baldwin continue; 7032da066efSJohn Baldwin 7042da066efSJohn Baldwin for (u_int i = 0; i < log->numrec; i++) 7052da066efSJohn Baldwin nvme_discovery_log_entry_swapbytes(&log->entries[i]); 7062da066efSJohn Baldwin break; 7072da066efSJohn Baldwin } 7082da066efSJohn Baldwin *logp = log; 7092da066efSJohn Baldwin return (0); 7102da066efSJohn Baldwin } 7112da066efSJohn Baldwin 7122da066efSJohn Baldwin int 713*8bba2c0fSJohn Baldwin nvmf_init_dle_from_admin_qp(struct nvmf_qpair *qp, 714*8bba2c0fSJohn Baldwin const struct nvme_controller_data *cdata, 715*8bba2c0fSJohn Baldwin struct nvme_discovery_log_entry *dle) 716*8bba2c0fSJohn Baldwin { 717*8bba2c0fSJohn Baldwin int error; 718*8bba2c0fSJohn Baldwin uint16_t cntlid; 719*8bba2c0fSJohn Baldwin 720*8bba2c0fSJohn Baldwin memset(dle, 0, sizeof(*dle)); 721*8bba2c0fSJohn Baldwin error = nvmf_populate_dle(qp, dle); 722*8bba2c0fSJohn Baldwin if (error != 0) 723*8bba2c0fSJohn Baldwin return (error); 724*8bba2c0fSJohn Baldwin if ((cdata->fcatt & 1) == 0) 725*8bba2c0fSJohn Baldwin cntlid = NVMF_CNTLID_DYNAMIC; 726*8bba2c0fSJohn Baldwin else 727*8bba2c0fSJohn Baldwin cntlid = cdata->ctrlr_id; 728*8bba2c0fSJohn Baldwin dle->cntlid = htole16(cntlid); 729*8bba2c0fSJohn Baldwin memcpy(dle->subnqn, cdata->subnqn, sizeof(dle->subnqn)); 730*8bba2c0fSJohn Baldwin return (0); 731*8bba2c0fSJohn Baldwin } 732*8bba2c0fSJohn Baldwin 733*8bba2c0fSJohn Baldwin int 7342da066efSJohn Baldwin nvmf_host_request_queues(struct nvmf_qpair *qp, u_int requested, u_int *actual) 7352da066efSJohn Baldwin { 7362da066efSJohn Baldwin struct nvme_command cmd; 7372da066efSJohn Baldwin struct nvmf_capsule *cc, *rc; 7382da066efSJohn Baldwin int error; 7392da066efSJohn Baldwin uint16_t status; 7402da066efSJohn Baldwin 7412da066efSJohn Baldwin if (!qp->nq_admin || requested < 1 || requested > 65535) 7422da066efSJohn Baldwin return (EINVAL); 7432da066efSJohn Baldwin 7442da066efSJohn Baldwin /* The number of queues is 0's based. */ 7452da066efSJohn Baldwin requested--; 7462da066efSJohn Baldwin 7472da066efSJohn Baldwin nvmf_init_sqe(&cmd, NVME_OPC_SET_FEATURES); 7482da066efSJohn Baldwin cmd.cdw10 = htole32(NVME_FEAT_NUMBER_OF_QUEUES); 7492da066efSJohn Baldwin 7502da066efSJohn Baldwin /* Same number of completion and submission queues. */ 7512da066efSJohn Baldwin cmd.cdw11 = htole32((requested << 16) | requested); 7522da066efSJohn Baldwin 7532da066efSJohn Baldwin cc = nvmf_allocate_command(qp, &cmd); 7542da066efSJohn Baldwin if (cc == NULL) 7552da066efSJohn Baldwin return (errno); 7562da066efSJohn Baldwin 7572da066efSJohn Baldwin error = nvmf_host_transmit_command(cc); 7582da066efSJohn Baldwin if (error != 0) { 7592da066efSJohn Baldwin nvmf_free_capsule(cc); 7602da066efSJohn Baldwin return (error); 7612da066efSJohn Baldwin } 7622da066efSJohn Baldwin 7632da066efSJohn Baldwin error = nvmf_host_wait_for_response(cc, &rc); 7642da066efSJohn Baldwin nvmf_free_capsule(cc); 7652da066efSJohn Baldwin if (error != 0) 7662da066efSJohn Baldwin return (error); 7672da066efSJohn Baldwin 7682da066efSJohn Baldwin status = le16toh(rc->nc_cqe.status); 7692da066efSJohn Baldwin if (status != 0) { 7702da066efSJohn Baldwin printf("NVMF: SET_FEATURES failed, status %#x\n", status); 7712da066efSJohn Baldwin nvmf_free_capsule(rc); 7722da066efSJohn Baldwin return (EIO); 7732da066efSJohn Baldwin } 7742da066efSJohn Baldwin 7752da066efSJohn Baldwin *actual = (le32toh(rc->nc_cqe.cdw0) & 0xffff) + 1; 7762da066efSJohn Baldwin nvmf_free_capsule(rc); 7772da066efSJohn Baldwin return (0); 7782da066efSJohn Baldwin } 7792da066efSJohn Baldwin 7802da066efSJohn Baldwin static bool 7812da066efSJohn Baldwin is_queue_pair_idle(struct nvmf_qpair *qp) 7822da066efSJohn Baldwin { 7832da066efSJohn Baldwin if (qp->nq_sqhd != qp->nq_sqtail) 7842da066efSJohn Baldwin return (false); 7852da066efSJohn Baldwin if (!TAILQ_EMPTY(&qp->nq_rx_capsules)) 7862da066efSJohn Baldwin return (false); 7872da066efSJohn Baldwin return (true); 7882da066efSJohn Baldwin } 7892da066efSJohn Baldwin 7902da066efSJohn Baldwin static int 791*8bba2c0fSJohn Baldwin prepare_queues_for_handoff(struct nvmf_ioc_nv *nv, 792*8bba2c0fSJohn Baldwin const struct nvme_discovery_log_entry *dle, const char *hostnqn, 793*8bba2c0fSJohn Baldwin struct nvmf_qpair *admin_qp, u_int num_queues, 794*8bba2c0fSJohn Baldwin struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata) 7952da066efSJohn Baldwin { 796*8bba2c0fSJohn Baldwin const struct nvmf_association *na = admin_qp->nq_association; 797*8bba2c0fSJohn Baldwin nvlist_t *nvl, *nvl_qp, *nvl_rparams; 7982da066efSJohn Baldwin u_int i; 7992da066efSJohn Baldwin int error; 8002da066efSJohn Baldwin 801365b89e8SJohn Baldwin if (num_queues == 0) 802365b89e8SJohn Baldwin return (EINVAL); 8032da066efSJohn Baldwin 804*8bba2c0fSJohn Baldwin /* Ensure trtype matches. */ 805*8bba2c0fSJohn Baldwin if (dle->trtype != na->na_trtype) 806*8bba2c0fSJohn Baldwin return (EINVAL); 807*8bba2c0fSJohn Baldwin 8082da066efSJohn Baldwin /* All queue pairs must be idle. */ 8092da066efSJohn Baldwin if (!is_queue_pair_idle(admin_qp)) 8102da066efSJohn Baldwin return (EBUSY); 8112da066efSJohn Baldwin for (i = 0; i < num_queues; i++) { 8122da066efSJohn Baldwin if (!is_queue_pair_idle(io_queues[i])) 8132da066efSJohn Baldwin return (EBUSY); 8142da066efSJohn Baldwin } 8152da066efSJohn Baldwin 816*8bba2c0fSJohn Baldwin /* Fill out reconnect parameters. */ 817*8bba2c0fSJohn Baldwin nvl_rparams = nvlist_create(0); 818*8bba2c0fSJohn Baldwin nvlist_add_binary(nvl_rparams, "dle", dle, sizeof(*dle)); 819*8bba2c0fSJohn Baldwin nvlist_add_string(nvl_rparams, "hostnqn", hostnqn); 820*8bba2c0fSJohn Baldwin nvlist_add_number(nvl_rparams, "num_io_queues", num_queues); 821*8bba2c0fSJohn Baldwin nvlist_add_number(nvl_rparams, "kato", admin_qp->nq_kato); 822*8bba2c0fSJohn Baldwin nvlist_add_number(nvl_rparams, "io_qsize", io_queues[0]->nq_qsize); 823*8bba2c0fSJohn Baldwin nvlist_add_bool(nvl_rparams, "sq_flow_control", 824*8bba2c0fSJohn Baldwin na->na_params.sq_flow_control); 825*8bba2c0fSJohn Baldwin switch (na->na_trtype) { 826*8bba2c0fSJohn Baldwin case NVMF_TRTYPE_TCP: 827*8bba2c0fSJohn Baldwin nvlist_add_bool(nvl_rparams, "header_digests", 828*8bba2c0fSJohn Baldwin na->na_params.tcp.header_digests); 829*8bba2c0fSJohn Baldwin nvlist_add_bool(nvl_rparams, "data_digests", 830*8bba2c0fSJohn Baldwin na->na_params.tcp.data_digests); 831*8bba2c0fSJohn Baldwin break; 832*8bba2c0fSJohn Baldwin default: 833*8bba2c0fSJohn Baldwin __unreachable(); 834*8bba2c0fSJohn Baldwin } 835*8bba2c0fSJohn Baldwin error = nvlist_error(nvl_rparams); 836*8bba2c0fSJohn Baldwin if (error != 0) { 837*8bba2c0fSJohn Baldwin nvlist_destroy(nvl_rparams); 838*8bba2c0fSJohn Baldwin return (error); 839*8bba2c0fSJohn Baldwin } 840*8bba2c0fSJohn Baldwin 841365b89e8SJohn Baldwin nvl = nvlist_create(0); 842*8bba2c0fSJohn Baldwin nvlist_add_number(nvl, "trtype", na->na_trtype); 843365b89e8SJohn Baldwin nvlist_add_number(nvl, "kato", admin_qp->nq_kato); 844*8bba2c0fSJohn Baldwin nvlist_move_nvlist(nvl, "rparams", nvl_rparams); 845365b89e8SJohn Baldwin 8462da066efSJohn Baldwin /* First, the admin queue. */ 847365b89e8SJohn Baldwin error = nvmf_kernel_handoff_params(admin_qp, &nvl_qp); 848365b89e8SJohn Baldwin if (error) { 849365b89e8SJohn Baldwin nvlist_destroy(nvl); 8502da066efSJohn Baldwin return (error); 851365b89e8SJohn Baldwin } 852365b89e8SJohn Baldwin nvlist_move_nvlist(nvl, "admin", nvl_qp); 8532da066efSJohn Baldwin 8542da066efSJohn Baldwin /* Next, the I/O queues. */ 8552da066efSJohn Baldwin for (i = 0; i < num_queues; i++) { 856365b89e8SJohn Baldwin error = nvmf_kernel_handoff_params(io_queues[i], &nvl_qp); 8572da066efSJohn Baldwin if (error) { 858365b89e8SJohn Baldwin nvlist_destroy(nvl); 8592da066efSJohn Baldwin return (error); 8602da066efSJohn Baldwin } 861365b89e8SJohn Baldwin nvlist_append_nvlist_array(nvl, "io", nvl_qp); 8622da066efSJohn Baldwin } 8632da066efSJohn Baldwin 864365b89e8SJohn Baldwin nvlist_add_binary(nvl, "cdata", cdata, sizeof(*cdata)); 865365b89e8SJohn Baldwin 866365b89e8SJohn Baldwin error = nvmf_pack_ioc_nvlist(nv, nvl); 867365b89e8SJohn Baldwin nvlist_destroy(nvl); 868365b89e8SJohn Baldwin return (error); 8692da066efSJohn Baldwin } 8702da066efSJohn Baldwin 8712da066efSJohn Baldwin int 872*8bba2c0fSJohn Baldwin nvmf_handoff_host(const struct nvme_discovery_log_entry *dle, 873*8bba2c0fSJohn Baldwin const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues, 8742da066efSJohn Baldwin struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata) 8752da066efSJohn Baldwin { 876365b89e8SJohn Baldwin struct nvmf_ioc_nv nv; 8772da066efSJohn Baldwin u_int i; 8782da066efSJohn Baldwin int error, fd; 8792da066efSJohn Baldwin 8802da066efSJohn Baldwin fd = open("/dev/nvmf", O_RDWR); 8812da066efSJohn Baldwin if (fd == -1) { 8822da066efSJohn Baldwin error = errno; 8832da066efSJohn Baldwin goto out; 8842da066efSJohn Baldwin } 8852da066efSJohn Baldwin 886*8bba2c0fSJohn Baldwin error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp, 887*8bba2c0fSJohn Baldwin num_queues, io_queues, cdata); 8882da066efSJohn Baldwin if (error != 0) 8892da066efSJohn Baldwin goto out; 8902da066efSJohn Baldwin 891365b89e8SJohn Baldwin if (ioctl(fd, NVMF_HANDOFF_HOST, &nv) == -1) 8922da066efSJohn Baldwin error = errno; 893365b89e8SJohn Baldwin free(nv.data); 8942da066efSJohn Baldwin 8952da066efSJohn Baldwin out: 8962da066efSJohn Baldwin if (fd >= 0) 8972da066efSJohn Baldwin close(fd); 8982da066efSJohn Baldwin for (i = 0; i < num_queues; i++) 8992da066efSJohn Baldwin (void)nvmf_free_qpair(io_queues[i]); 9002da066efSJohn Baldwin (void)nvmf_free_qpair(admin_qp); 9012da066efSJohn Baldwin return (error); 9022da066efSJohn Baldwin } 9032da066efSJohn Baldwin 9042da066efSJohn Baldwin int 9052da066efSJohn Baldwin nvmf_disconnect_host(const char *host) 9062da066efSJohn Baldwin { 9072da066efSJohn Baldwin int error, fd; 9082da066efSJohn Baldwin 9092da066efSJohn Baldwin error = 0; 9102da066efSJohn Baldwin fd = open("/dev/nvmf", O_RDWR); 9112da066efSJohn Baldwin if (fd == -1) { 9122da066efSJohn Baldwin error = errno; 9132da066efSJohn Baldwin goto out; 9142da066efSJohn Baldwin } 9152da066efSJohn Baldwin 9162da066efSJohn Baldwin if (ioctl(fd, NVMF_DISCONNECT_HOST, &host) == -1) 9172da066efSJohn Baldwin error = errno; 9182da066efSJohn Baldwin 9192da066efSJohn Baldwin out: 9202da066efSJohn Baldwin if (fd >= 0) 9212da066efSJohn Baldwin close(fd); 9222da066efSJohn Baldwin return (error); 9232da066efSJohn Baldwin } 9242da066efSJohn Baldwin 9252da066efSJohn Baldwin int 9262da066efSJohn Baldwin nvmf_disconnect_all(void) 9272da066efSJohn Baldwin { 9282da066efSJohn Baldwin int error, fd; 9292da066efSJohn Baldwin 9302da066efSJohn Baldwin error = 0; 9312da066efSJohn Baldwin fd = open("/dev/nvmf", O_RDWR); 9322da066efSJohn Baldwin if (fd == -1) { 9332da066efSJohn Baldwin error = errno; 9342da066efSJohn Baldwin goto out; 9352da066efSJohn Baldwin } 9362da066efSJohn Baldwin 9372da066efSJohn Baldwin if (ioctl(fd, NVMF_DISCONNECT_ALL) == -1) 9382da066efSJohn Baldwin error = errno; 9392da066efSJohn Baldwin 9402da066efSJohn Baldwin out: 9412da066efSJohn Baldwin if (fd >= 0) 9422da066efSJohn Baldwin close(fd); 9432da066efSJohn Baldwin return (error); 9442da066efSJohn Baldwin } 9452da066efSJohn Baldwin 946365b89e8SJohn Baldwin static int 947365b89e8SJohn Baldwin nvmf_read_ioc_nv(int fd, u_long com, nvlist_t **nvlp) 9482da066efSJohn Baldwin { 949365b89e8SJohn Baldwin struct nvmf_ioc_nv nv; 950365b89e8SJohn Baldwin nvlist_t *nvl; 951365b89e8SJohn Baldwin int error; 952365b89e8SJohn Baldwin 953365b89e8SJohn Baldwin memset(&nv, 0, sizeof(nv)); 954365b89e8SJohn Baldwin if (ioctl(fd, com, &nv) == -1) 9552da066efSJohn Baldwin return (errno); 956365b89e8SJohn Baldwin 957365b89e8SJohn Baldwin nv.data = malloc(nv.len); 958365b89e8SJohn Baldwin nv.size = nv.len; 959365b89e8SJohn Baldwin if (ioctl(fd, com, &nv) == -1) { 960365b89e8SJohn Baldwin error = errno; 961365b89e8SJohn Baldwin free(nv.data); 962365b89e8SJohn Baldwin return (error); 963365b89e8SJohn Baldwin } 964365b89e8SJohn Baldwin 965365b89e8SJohn Baldwin nvl = nvlist_unpack(nv.data, nv.len, 0); 966365b89e8SJohn Baldwin free(nv.data); 967365b89e8SJohn Baldwin if (nvl == NULL) 968365b89e8SJohn Baldwin return (EINVAL); 969365b89e8SJohn Baldwin 970365b89e8SJohn Baldwin *nvlp = nvl; 9712da066efSJohn Baldwin return (0); 9722da066efSJohn Baldwin } 9732da066efSJohn Baldwin 9742da066efSJohn Baldwin int 975365b89e8SJohn Baldwin nvmf_reconnect_params(int fd, nvlist_t **nvlp) 976365b89e8SJohn Baldwin { 977365b89e8SJohn Baldwin return (nvmf_read_ioc_nv(fd, NVMF_RECONNECT_PARAMS, nvlp)); 978365b89e8SJohn Baldwin } 979365b89e8SJohn Baldwin 980365b89e8SJohn Baldwin int 981*8bba2c0fSJohn Baldwin nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle, 982*8bba2c0fSJohn Baldwin const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues, 9832da066efSJohn Baldwin struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata) 9842da066efSJohn Baldwin { 985365b89e8SJohn Baldwin struct nvmf_ioc_nv nv; 9862da066efSJohn Baldwin u_int i; 9872da066efSJohn Baldwin int error; 9882da066efSJohn Baldwin 989*8bba2c0fSJohn Baldwin error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp, 990*8bba2c0fSJohn Baldwin num_queues, io_queues, cdata); 9912da066efSJohn Baldwin if (error != 0) 9922da066efSJohn Baldwin goto out; 9932da066efSJohn Baldwin 994365b89e8SJohn Baldwin if (ioctl(fd, NVMF_RECONNECT_HOST, &nv) == -1) 9952da066efSJohn Baldwin error = errno; 996365b89e8SJohn Baldwin free(nv.data); 9972da066efSJohn Baldwin 9982da066efSJohn Baldwin out: 9992da066efSJohn Baldwin for (i = 0; i < num_queues; i++) 10002da066efSJohn Baldwin (void)nvmf_free_qpair(io_queues[i]); 10012da066efSJohn Baldwin (void)nvmf_free_qpair(admin_qp); 10022da066efSJohn Baldwin return (error); 10032da066efSJohn Baldwin } 1004