12da066efSJohn Baldwin /*- 22da066efSJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 32da066efSJohn Baldwin * 42da066efSJohn Baldwin * Copyright (c) 2022-2024 Chelsio Communications, Inc. 52da066efSJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 62da066efSJohn Baldwin */ 72da066efSJohn Baldwin 82da066efSJohn Baldwin #include <sys/refcount.h> 92da066efSJohn Baldwin #include <assert.h> 102da066efSJohn Baldwin #include <errno.h> 112da066efSJohn Baldwin #include <stdarg.h> 122da066efSJohn Baldwin #include <stdio.h> 132da066efSJohn Baldwin #include <stdlib.h> 142da066efSJohn Baldwin #include <string.h> 152da066efSJohn Baldwin 162da066efSJohn Baldwin #include "libnvmf.h" 172da066efSJohn Baldwin #include "internal.h" 182da066efSJohn Baldwin 192da066efSJohn Baldwin struct nvmf_association * 202da066efSJohn Baldwin nvmf_allocate_association(enum nvmf_trtype trtype, bool controller, 212da066efSJohn Baldwin const struct nvmf_association_params *params) 222da066efSJohn Baldwin { 232da066efSJohn Baldwin struct nvmf_transport_ops *ops; 242da066efSJohn Baldwin struct nvmf_association *na; 252da066efSJohn Baldwin 262da066efSJohn Baldwin switch (trtype) { 272da066efSJohn Baldwin case NVMF_TRTYPE_TCP: 282da066efSJohn Baldwin ops = &tcp_ops; 292da066efSJohn Baldwin break; 302da066efSJohn Baldwin default: 312da066efSJohn Baldwin errno = EINVAL; 322da066efSJohn Baldwin return (NULL); 332da066efSJohn Baldwin } 342da066efSJohn Baldwin 352da066efSJohn Baldwin na = ops->allocate_association(controller, params); 362da066efSJohn Baldwin if (na == NULL) 372da066efSJohn Baldwin return (NULL); 382da066efSJohn Baldwin 392da066efSJohn Baldwin na->na_ops = ops; 402da066efSJohn Baldwin na->na_trtype = trtype; 412da066efSJohn Baldwin na->na_controller = controller; 422da066efSJohn Baldwin na->na_params = *params; 432da066efSJohn Baldwin na->na_last_error = NULL; 442da066efSJohn Baldwin refcount_init(&na->na_refs, 1); 452da066efSJohn Baldwin return (na); 462da066efSJohn Baldwin } 472da066efSJohn Baldwin 482da066efSJohn Baldwin void 492da066efSJohn Baldwin nvmf_update_assocation(struct nvmf_association *na, 502da066efSJohn Baldwin const struct nvme_controller_data *cdata) 512da066efSJohn Baldwin { 522da066efSJohn Baldwin na->na_ops->update_association(na, cdata); 532da066efSJohn Baldwin } 542da066efSJohn Baldwin 552da066efSJohn Baldwin void 562da066efSJohn Baldwin nvmf_free_association(struct nvmf_association *na) 572da066efSJohn Baldwin { 582da066efSJohn Baldwin if (refcount_release(&na->na_refs)) { 592da066efSJohn Baldwin free(na->na_last_error); 602da066efSJohn Baldwin na->na_ops->free_association(na); 612da066efSJohn Baldwin } 622da066efSJohn Baldwin } 632da066efSJohn Baldwin 642da066efSJohn Baldwin const char * 652da066efSJohn Baldwin nvmf_association_error(const struct nvmf_association *na) 662da066efSJohn Baldwin { 672da066efSJohn Baldwin return (na->na_last_error); 682da066efSJohn Baldwin } 692da066efSJohn Baldwin 702da066efSJohn Baldwin void 712da066efSJohn Baldwin na_clear_error(struct nvmf_association *na) 722da066efSJohn Baldwin { 732da066efSJohn Baldwin free(na->na_last_error); 742da066efSJohn Baldwin na->na_last_error = NULL; 752da066efSJohn Baldwin } 762da066efSJohn Baldwin 772da066efSJohn Baldwin void 782da066efSJohn Baldwin na_error(struct nvmf_association *na, const char *fmt, ...) 792da066efSJohn Baldwin { 802da066efSJohn Baldwin va_list ap; 812da066efSJohn Baldwin char *str; 822da066efSJohn Baldwin 832da066efSJohn Baldwin if (na->na_last_error != NULL) 842da066efSJohn Baldwin return; 852da066efSJohn Baldwin va_start(ap, fmt); 862da066efSJohn Baldwin vasprintf(&str, fmt, ap); 872da066efSJohn Baldwin va_end(ap); 882da066efSJohn Baldwin na->na_last_error = str; 892da066efSJohn Baldwin } 902da066efSJohn Baldwin 912da066efSJohn Baldwin struct nvmf_qpair * 922da066efSJohn Baldwin nvmf_allocate_qpair(struct nvmf_association *na, 932da066efSJohn Baldwin const struct nvmf_qpair_params *params) 942da066efSJohn Baldwin { 952da066efSJohn Baldwin struct nvmf_qpair *qp; 962da066efSJohn Baldwin 972da066efSJohn Baldwin na_clear_error(na); 982da066efSJohn Baldwin qp = na->na_ops->allocate_qpair(na, params); 992da066efSJohn Baldwin if (qp == NULL) 1002da066efSJohn Baldwin return (NULL); 1012da066efSJohn Baldwin 1022da066efSJohn Baldwin refcount_acquire(&na->na_refs); 1032da066efSJohn Baldwin qp->nq_association = na; 1042da066efSJohn Baldwin qp->nq_admin = params->admin; 1052da066efSJohn Baldwin TAILQ_INIT(&qp->nq_rx_capsules); 1062da066efSJohn Baldwin return (qp); 1072da066efSJohn Baldwin } 1082da066efSJohn Baldwin 1092da066efSJohn Baldwin void 1102da066efSJohn Baldwin nvmf_free_qpair(struct nvmf_qpair *qp) 1112da066efSJohn Baldwin { 1122da066efSJohn Baldwin struct nvmf_association *na; 1132da066efSJohn Baldwin struct nvmf_capsule *nc, *tc; 1142da066efSJohn Baldwin 1152da066efSJohn Baldwin TAILQ_FOREACH_SAFE(nc, &qp->nq_rx_capsules, nc_link, tc) { 1162da066efSJohn Baldwin TAILQ_REMOVE(&qp->nq_rx_capsules, nc, nc_link); 1172da066efSJohn Baldwin nvmf_free_capsule(nc); 1182da066efSJohn Baldwin } 1192da066efSJohn Baldwin na = qp->nq_association; 1202da066efSJohn Baldwin na->na_ops->free_qpair(qp); 1212da066efSJohn Baldwin nvmf_free_association(na); 1222da066efSJohn Baldwin } 1232da066efSJohn Baldwin 1242da066efSJohn Baldwin struct nvmf_capsule * 1252da066efSJohn Baldwin nvmf_allocate_command(struct nvmf_qpair *qp, const void *sqe) 1262da066efSJohn Baldwin { 1272da066efSJohn Baldwin struct nvmf_capsule *nc; 1282da066efSJohn Baldwin 1292da066efSJohn Baldwin nc = qp->nq_association->na_ops->allocate_capsule(qp); 1302da066efSJohn Baldwin if (nc == NULL) 1312da066efSJohn Baldwin return (NULL); 1322da066efSJohn Baldwin 1332da066efSJohn Baldwin nc->nc_qpair = qp; 1342da066efSJohn Baldwin nc->nc_qe_len = sizeof(struct nvme_command); 1352da066efSJohn Baldwin memcpy(&nc->nc_sqe, sqe, nc->nc_qe_len); 1362da066efSJohn Baldwin 1372da066efSJohn Baldwin /* 4.2 of NVMe base spec: Fabrics always uses SGL. */ 1382da066efSJohn Baldwin nc->nc_sqe.fuse &= ~NVMEM(NVME_CMD_PSDT); 1392da066efSJohn Baldwin nc->nc_sqe.fuse |= NVMEF(NVME_CMD_PSDT, NVME_PSDT_SGL); 1402da066efSJohn Baldwin return (nc); 1412da066efSJohn Baldwin } 1422da066efSJohn Baldwin 1432da066efSJohn Baldwin struct nvmf_capsule * 1442da066efSJohn Baldwin nvmf_allocate_response(struct nvmf_qpair *qp, const void *cqe) 1452da066efSJohn Baldwin { 1462da066efSJohn Baldwin struct nvmf_capsule *nc; 1472da066efSJohn Baldwin 1482da066efSJohn Baldwin nc = qp->nq_association->na_ops->allocate_capsule(qp); 1492da066efSJohn Baldwin if (nc == NULL) 1502da066efSJohn Baldwin return (NULL); 1512da066efSJohn Baldwin 1522da066efSJohn Baldwin nc->nc_qpair = qp; 1532da066efSJohn Baldwin nc->nc_qe_len = sizeof(struct nvme_completion); 1542da066efSJohn Baldwin memcpy(&nc->nc_cqe, cqe, nc->nc_qe_len); 1552da066efSJohn Baldwin return (nc); 1562da066efSJohn Baldwin } 1572da066efSJohn Baldwin 1582da066efSJohn Baldwin int 1592da066efSJohn Baldwin nvmf_capsule_append_data(struct nvmf_capsule *nc, void *buf, size_t len, 1602da066efSJohn Baldwin bool send) 1612da066efSJohn Baldwin { 1622da066efSJohn Baldwin if (nc->nc_qe_len == sizeof(struct nvme_completion)) 1632da066efSJohn Baldwin return (EINVAL); 1642da066efSJohn Baldwin if (nc->nc_data_len != 0) 1652da066efSJohn Baldwin return (EBUSY); 1662da066efSJohn Baldwin 1672da066efSJohn Baldwin nc->nc_data = buf; 1682da066efSJohn Baldwin nc->nc_data_len = len; 1692da066efSJohn Baldwin nc->nc_send_data = send; 1702da066efSJohn Baldwin return (0); 1712da066efSJohn Baldwin } 1722da066efSJohn Baldwin 1732da066efSJohn Baldwin void 1742da066efSJohn Baldwin nvmf_free_capsule(struct nvmf_capsule *nc) 1752da066efSJohn Baldwin { 1762da066efSJohn Baldwin nc->nc_qpair->nq_association->na_ops->free_capsule(nc); 1772da066efSJohn Baldwin } 1782da066efSJohn Baldwin 1792da066efSJohn Baldwin int 1802da066efSJohn Baldwin nvmf_transmit_capsule(struct nvmf_capsule *nc) 1812da066efSJohn Baldwin { 1822da066efSJohn Baldwin return (nc->nc_qpair->nq_association->na_ops->transmit_capsule(nc)); 1832da066efSJohn Baldwin } 1842da066efSJohn Baldwin 1852da066efSJohn Baldwin int 1862da066efSJohn Baldwin nvmf_receive_capsule(struct nvmf_qpair *qp, struct nvmf_capsule **ncp) 1872da066efSJohn Baldwin { 1882da066efSJohn Baldwin return (qp->nq_association->na_ops->receive_capsule(qp, ncp)); 1892da066efSJohn Baldwin } 1902da066efSJohn Baldwin 1912da066efSJohn Baldwin const void * 1922da066efSJohn Baldwin nvmf_capsule_sqe(const struct nvmf_capsule *nc) 1932da066efSJohn Baldwin { 1942da066efSJohn Baldwin assert(nc->nc_qe_len == sizeof(struct nvme_command)); 1952da066efSJohn Baldwin return (&nc->nc_sqe); 1962da066efSJohn Baldwin } 1972da066efSJohn Baldwin 1982da066efSJohn Baldwin const void * 1992da066efSJohn Baldwin nvmf_capsule_cqe(const struct nvmf_capsule *nc) 2002da066efSJohn Baldwin { 2012da066efSJohn Baldwin assert(nc->nc_qe_len == sizeof(struct nvme_completion)); 2022da066efSJohn Baldwin return (&nc->nc_cqe); 2032da066efSJohn Baldwin } 2042da066efSJohn Baldwin 2052da066efSJohn Baldwin uint8_t 2062da066efSJohn Baldwin nvmf_validate_command_capsule(const struct nvmf_capsule *nc) 2072da066efSJohn Baldwin { 2082da066efSJohn Baldwin assert(nc->nc_qe_len == sizeof(struct nvme_command)); 2092da066efSJohn Baldwin 2102da066efSJohn Baldwin if (NVMEV(NVME_CMD_PSDT, nc->nc_sqe.fuse) != NVME_PSDT_SGL) 2112da066efSJohn Baldwin return (NVME_SC_INVALID_FIELD); 2122da066efSJohn Baldwin 2132da066efSJohn Baldwin return (nc->nc_qpair->nq_association->na_ops->validate_command_capsule(nc)); 2142da066efSJohn Baldwin } 2152da066efSJohn Baldwin 2162da066efSJohn Baldwin size_t 2172da066efSJohn Baldwin nvmf_capsule_data_len(const struct nvmf_capsule *nc) 2182da066efSJohn Baldwin { 2192da066efSJohn Baldwin return (nc->nc_qpair->nq_association->na_ops->capsule_data_len(nc)); 2202da066efSJohn Baldwin } 2212da066efSJohn Baldwin 2222da066efSJohn Baldwin int 2232da066efSJohn Baldwin nvmf_receive_controller_data(const struct nvmf_capsule *nc, 2242da066efSJohn Baldwin uint32_t data_offset, void *buf, size_t len) 2252da066efSJohn Baldwin { 2262da066efSJohn Baldwin return (nc->nc_qpair->nq_association->na_ops->receive_controller_data(nc, 2272da066efSJohn Baldwin data_offset, buf, len)); 2282da066efSJohn Baldwin } 2292da066efSJohn Baldwin 2302da066efSJohn Baldwin int 2312da066efSJohn Baldwin nvmf_send_controller_data(const struct nvmf_capsule *nc, const void *buf, 2322da066efSJohn Baldwin size_t len) 2332da066efSJohn Baldwin { 2342da066efSJohn Baldwin return (nc->nc_qpair->nq_association->na_ops->send_controller_data(nc, 2352da066efSJohn Baldwin buf, len)); 2362da066efSJohn Baldwin } 2372da066efSJohn Baldwin 2382da066efSJohn Baldwin int 239*365b89e8SJohn Baldwin nvmf_kernel_handoff_params(struct nvmf_qpair *qp, nvlist_t **nvlp) 2402da066efSJohn Baldwin { 241*365b89e8SJohn Baldwin nvlist_t *nvl; 242*365b89e8SJohn Baldwin int error; 243*365b89e8SJohn Baldwin 244*365b89e8SJohn Baldwin nvl = nvlist_create(0); 245*365b89e8SJohn Baldwin nvlist_add_bool(nvl, "admin", qp->nq_admin); 246*365b89e8SJohn Baldwin nvlist_add_bool(nvl, "sq_flow_control", qp->nq_flow_control); 247*365b89e8SJohn Baldwin nvlist_add_number(nvl, "qsize", qp->nq_qsize); 248*365b89e8SJohn Baldwin nvlist_add_number(nvl, "sqhd", qp->nq_sqhd); 249*365b89e8SJohn Baldwin if (!qp->nq_association->na_controller) 250*365b89e8SJohn Baldwin nvlist_add_number(nvl, "sqtail", qp->nq_sqtail); 251*365b89e8SJohn Baldwin qp->nq_association->na_ops->kernel_handoff_params(qp, nvl); 252*365b89e8SJohn Baldwin error = nvlist_error(nvl); 253*365b89e8SJohn Baldwin if (error != 0) { 254*365b89e8SJohn Baldwin nvlist_destroy(nvl); 255*365b89e8SJohn Baldwin return (error); 256*365b89e8SJohn Baldwin } 257*365b89e8SJohn Baldwin 258*365b89e8SJohn Baldwin *nvlp = nvl; 259*365b89e8SJohn Baldwin return (0); 2602da066efSJohn Baldwin } 2612da066efSJohn Baldwin 2622da066efSJohn Baldwin const char * 2632da066efSJohn Baldwin nvmf_transport_type(uint8_t trtype) 2642da066efSJohn Baldwin { 2652da066efSJohn Baldwin static _Thread_local char buf[8]; 2662da066efSJohn Baldwin 2672da066efSJohn Baldwin switch (trtype) { 2682da066efSJohn Baldwin case NVMF_TRTYPE_RDMA: 2692da066efSJohn Baldwin return ("RDMA"); 2702da066efSJohn Baldwin case NVMF_TRTYPE_FC: 2712da066efSJohn Baldwin return ("Fibre Channel"); 2722da066efSJohn Baldwin case NVMF_TRTYPE_TCP: 2732da066efSJohn Baldwin return ("TCP"); 2742da066efSJohn Baldwin case NVMF_TRTYPE_INTRA_HOST: 2752da066efSJohn Baldwin return ("Intra-host"); 2762da066efSJohn Baldwin default: 2772da066efSJohn Baldwin snprintf(buf, sizeof(buf), "0x%02x\n", trtype); 2782da066efSJohn Baldwin return (buf); 2792da066efSJohn Baldwin } 2802da066efSJohn Baldwin } 281*365b89e8SJohn Baldwin 282*365b89e8SJohn Baldwin int 283*365b89e8SJohn Baldwin nvmf_pack_ioc_nvlist(struct nvmf_ioc_nv *nv, nvlist_t *nvl) 284*365b89e8SJohn Baldwin { 285*365b89e8SJohn Baldwin int error; 286*365b89e8SJohn Baldwin 287*365b89e8SJohn Baldwin memset(nv, 0, sizeof(*nv)); 288*365b89e8SJohn Baldwin 289*365b89e8SJohn Baldwin error = nvlist_error(nvl); 290*365b89e8SJohn Baldwin if (error) 291*365b89e8SJohn Baldwin return (error); 292*365b89e8SJohn Baldwin 293*365b89e8SJohn Baldwin nv->data = nvlist_pack(nvl, &nv->size); 294*365b89e8SJohn Baldwin if (nv->data == NULL) 295*365b89e8SJohn Baldwin return (ENOMEM); 296*365b89e8SJohn Baldwin 297*365b89e8SJohn Baldwin return (0); 298*365b89e8SJohn Baldwin } 299