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 *
nvmf_allocate_association(enum nvmf_trtype trtype,bool controller,const struct nvmf_association_params * params)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
nvmf_update_assocation(struct nvmf_association * na,const struct nvme_controller_data * cdata)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
nvmf_free_association(struct nvmf_association * na)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 *
nvmf_association_error(const struct nvmf_association * na)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
na_clear_error(struct nvmf_association * na)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
na_error(struct nvmf_association * na,const char * fmt,...)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 *
nvmf_allocate_qpair(struct nvmf_association * na,const struct nvmf_qpair_params * params)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
nvmf_free_qpair(struct nvmf_qpair * qp)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 *
nvmf_allocate_command(struct nvmf_qpair * qp,const void * sqe)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 *
nvmf_allocate_response(struct nvmf_qpair * qp,const void * cqe)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
nvmf_capsule_append_data(struct nvmf_capsule * nc,void * buf,size_t len,bool send)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
nvmf_free_capsule(struct nvmf_capsule * nc)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
nvmf_transmit_capsule(struct nvmf_capsule * nc)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
nvmf_receive_capsule(struct nvmf_qpair * qp,struct nvmf_capsule ** ncp)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 *
nvmf_capsule_sqe(const struct nvmf_capsule * nc)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 *
nvmf_capsule_cqe(const struct nvmf_capsule * nc)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
nvmf_validate_command_capsule(const struct nvmf_capsule * nc)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
nvmf_capsule_data_len(const struct nvmf_capsule * nc)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
nvmf_receive_controller_data(const struct nvmf_capsule * nc,uint32_t data_offset,void * buf,size_t len)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
nvmf_send_controller_data(const struct nvmf_capsule * nc,const void * buf,size_t len)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
nvmf_kernel_handoff_params(struct nvmf_qpair * qp,nvlist_t ** nvlp)239365b89e8SJohn Baldwin nvmf_kernel_handoff_params(struct nvmf_qpair *qp, nvlist_t **nvlp)
2402da066efSJohn Baldwin {
241365b89e8SJohn Baldwin nvlist_t *nvl;
242365b89e8SJohn Baldwin int error;
243365b89e8SJohn Baldwin
244365b89e8SJohn Baldwin nvl = nvlist_create(0);
245365b89e8SJohn Baldwin nvlist_add_bool(nvl, "admin", qp->nq_admin);
246365b89e8SJohn Baldwin nvlist_add_bool(nvl, "sq_flow_control", qp->nq_flow_control);
247365b89e8SJohn Baldwin nvlist_add_number(nvl, "qsize", qp->nq_qsize);
248365b89e8SJohn Baldwin nvlist_add_number(nvl, "sqhd", qp->nq_sqhd);
249365b89e8SJohn Baldwin if (!qp->nq_association->na_controller)
250365b89e8SJohn Baldwin nvlist_add_number(nvl, "sqtail", qp->nq_sqtail);
251365b89e8SJohn Baldwin qp->nq_association->na_ops->kernel_handoff_params(qp, nvl);
252365b89e8SJohn Baldwin error = nvlist_error(nvl);
253365b89e8SJohn Baldwin if (error != 0) {
254365b89e8SJohn Baldwin nvlist_destroy(nvl);
255365b89e8SJohn Baldwin return (error);
256365b89e8SJohn Baldwin }
257365b89e8SJohn Baldwin
258365b89e8SJohn Baldwin *nvlp = nvl;
259365b89e8SJohn Baldwin return (0);
2602da066efSJohn Baldwin }
2612da066efSJohn Baldwin
262*8bba2c0fSJohn Baldwin int
nvmf_populate_dle(struct nvmf_qpair * qp,struct nvme_discovery_log_entry * dle)263*8bba2c0fSJohn Baldwin nvmf_populate_dle(struct nvmf_qpair *qp, struct nvme_discovery_log_entry *dle)
264*8bba2c0fSJohn Baldwin {
265*8bba2c0fSJohn Baldwin struct nvmf_association *na = qp->nq_association;
266*8bba2c0fSJohn Baldwin
267*8bba2c0fSJohn Baldwin dle->trtype = na->na_trtype;
268*8bba2c0fSJohn Baldwin return (na->na_ops->populate_dle(qp, dle));
269*8bba2c0fSJohn Baldwin }
270*8bba2c0fSJohn Baldwin
2712da066efSJohn Baldwin const char *
nvmf_transport_type(uint8_t trtype)2722da066efSJohn Baldwin nvmf_transport_type(uint8_t trtype)
2732da066efSJohn Baldwin {
2742da066efSJohn Baldwin static _Thread_local char buf[8];
2752da066efSJohn Baldwin
2762da066efSJohn Baldwin switch (trtype) {
2772da066efSJohn Baldwin case NVMF_TRTYPE_RDMA:
2782da066efSJohn Baldwin return ("RDMA");
2792da066efSJohn Baldwin case NVMF_TRTYPE_FC:
2802da066efSJohn Baldwin return ("Fibre Channel");
2812da066efSJohn Baldwin case NVMF_TRTYPE_TCP:
2822da066efSJohn Baldwin return ("TCP");
2832da066efSJohn Baldwin case NVMF_TRTYPE_INTRA_HOST:
2842da066efSJohn Baldwin return ("Intra-host");
2852da066efSJohn Baldwin default:
2862da066efSJohn Baldwin snprintf(buf, sizeof(buf), "0x%02x\n", trtype);
2872da066efSJohn Baldwin return (buf);
2882da066efSJohn Baldwin }
2892da066efSJohn Baldwin }
290365b89e8SJohn Baldwin
291365b89e8SJohn Baldwin int
nvmf_pack_ioc_nvlist(struct nvmf_ioc_nv * nv,nvlist_t * nvl)292365b89e8SJohn Baldwin nvmf_pack_ioc_nvlist(struct nvmf_ioc_nv *nv, nvlist_t *nvl)
293365b89e8SJohn Baldwin {
294365b89e8SJohn Baldwin int error;
295365b89e8SJohn Baldwin
296365b89e8SJohn Baldwin memset(nv, 0, sizeof(*nv));
297365b89e8SJohn Baldwin
298365b89e8SJohn Baldwin error = nvlist_error(nvl);
299365b89e8SJohn Baldwin if (error)
300365b89e8SJohn Baldwin return (error);
301365b89e8SJohn Baldwin
302365b89e8SJohn Baldwin nv->data = nvlist_pack(nvl, &nv->size);
303365b89e8SJohn Baldwin if (nv->data == NULL)
304365b89e8SJohn Baldwin return (ENOMEM);
305365b89e8SJohn Baldwin
306365b89e8SJohn Baldwin return (0);
307365b89e8SJohn Baldwin }
308