1/*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2022-2024 Chelsio Communications, Inc. 5 * Written by: John Baldwin <jhb@FreeBSD.org> 6 */ 7 8#include <sys/refcount.h> 9#include <assert.h> 10#include <errno.h> 11#include <stdarg.h> 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15 16#include "libnvmf.h" 17#include "internal.h" 18 19struct nvmf_association * 20nvmf_allocate_association(enum nvmf_trtype trtype, bool controller, 21 const struct nvmf_association_params *params) 22{ 23 struct nvmf_transport_ops *ops; 24 struct nvmf_association *na; 25 26 switch (trtype) { 27 case NVMF_TRTYPE_TCP: 28 ops = &tcp_ops; 29 break; 30 default: 31 errno = EINVAL; 32 return (NULL); 33 } 34 35 na = ops->allocate_association(controller, params); 36 if (na == NULL) 37 return (NULL); 38 39 na->na_ops = ops; 40 na->na_trtype = trtype; 41 na->na_controller = controller; 42 na->na_params = *params; 43 na->na_last_error = NULL; 44 refcount_init(&na->na_refs, 1); 45 return (na); 46} 47 48void 49nvmf_update_assocation(struct nvmf_association *na, 50 const struct nvme_controller_data *cdata) 51{ 52 na->na_ops->update_association(na, cdata); 53} 54 55void 56nvmf_free_association(struct nvmf_association *na) 57{ 58 if (refcount_release(&na->na_refs)) { 59 free(na->na_last_error); 60 na->na_ops->free_association(na); 61 } 62} 63 64const char * 65nvmf_association_error(const struct nvmf_association *na) 66{ 67 return (na->na_last_error); 68} 69 70void 71na_clear_error(struct nvmf_association *na) 72{ 73 free(na->na_last_error); 74 na->na_last_error = NULL; 75} 76 77void 78na_error(struct nvmf_association *na, const char *fmt, ...) 79{ 80 va_list ap; 81 char *str; 82 83 if (na->na_last_error != NULL) 84 return; 85 va_start(ap, fmt); 86 vasprintf(&str, fmt, ap); 87 va_end(ap); 88 na->na_last_error = str; 89} 90 91struct nvmf_qpair * 92nvmf_allocate_qpair(struct nvmf_association *na, 93 const struct nvmf_qpair_params *params) 94{ 95 struct nvmf_qpair *qp; 96 97 na_clear_error(na); 98 qp = na->na_ops->allocate_qpair(na, params); 99 if (qp == NULL) 100 return (NULL); 101 102 refcount_acquire(&na->na_refs); 103 qp->nq_association = na; 104 qp->nq_admin = params->admin; 105 TAILQ_INIT(&qp->nq_rx_capsules); 106 return (qp); 107} 108 109void 110nvmf_free_qpair(struct nvmf_qpair *qp) 111{ 112 struct nvmf_association *na; 113 struct nvmf_capsule *nc, *tc; 114 115 TAILQ_FOREACH_SAFE(nc, &qp->nq_rx_capsules, nc_link, tc) { 116 TAILQ_REMOVE(&qp->nq_rx_capsules, nc, nc_link); 117 nvmf_free_capsule(nc); 118 } 119 na = qp->nq_association; 120 na->na_ops->free_qpair(qp); 121 nvmf_free_association(na); 122} 123 124struct nvmf_capsule * 125nvmf_allocate_command(struct nvmf_qpair *qp, const void *sqe) 126{ 127 struct nvmf_capsule *nc; 128 129 nc = qp->nq_association->na_ops->allocate_capsule(qp); 130 if (nc == NULL) 131 return (NULL); 132 133 nc->nc_qpair = qp; 134 nc->nc_qe_len = sizeof(struct nvme_command); 135 memcpy(&nc->nc_sqe, sqe, nc->nc_qe_len); 136 137 /* 4.2 of NVMe base spec: Fabrics always uses SGL. */ 138 nc->nc_sqe.fuse &= ~NVMEM(NVME_CMD_PSDT); 139 nc->nc_sqe.fuse |= NVMEF(NVME_CMD_PSDT, NVME_PSDT_SGL); 140 return (nc); 141} 142 143struct nvmf_capsule * 144nvmf_allocate_response(struct nvmf_qpair *qp, const void *cqe) 145{ 146 struct nvmf_capsule *nc; 147 148 nc = qp->nq_association->na_ops->allocate_capsule(qp); 149 if (nc == NULL) 150 return (NULL); 151 152 nc->nc_qpair = qp; 153 nc->nc_qe_len = sizeof(struct nvme_completion); 154 memcpy(&nc->nc_cqe, cqe, nc->nc_qe_len); 155 return (nc); 156} 157 158int 159nvmf_capsule_append_data(struct nvmf_capsule *nc, void *buf, size_t len, 160 bool send) 161{ 162 if (nc->nc_qe_len == sizeof(struct nvme_completion)) 163 return (EINVAL); 164 if (nc->nc_data_len != 0) 165 return (EBUSY); 166 167 nc->nc_data = buf; 168 nc->nc_data_len = len; 169 nc->nc_send_data = send; 170 return (0); 171} 172 173void 174nvmf_free_capsule(struct nvmf_capsule *nc) 175{ 176 nc->nc_qpair->nq_association->na_ops->free_capsule(nc); 177} 178 179int 180nvmf_transmit_capsule(struct nvmf_capsule *nc) 181{ 182 return (nc->nc_qpair->nq_association->na_ops->transmit_capsule(nc)); 183} 184 185int 186nvmf_receive_capsule(struct nvmf_qpair *qp, struct nvmf_capsule **ncp) 187{ 188 return (qp->nq_association->na_ops->receive_capsule(qp, ncp)); 189} 190 191const void * 192nvmf_capsule_sqe(const struct nvmf_capsule *nc) 193{ 194 assert(nc->nc_qe_len == sizeof(struct nvme_command)); 195 return (&nc->nc_sqe); 196} 197 198const void * 199nvmf_capsule_cqe(const struct nvmf_capsule *nc) 200{ 201 assert(nc->nc_qe_len == sizeof(struct nvme_completion)); 202 return (&nc->nc_cqe); 203} 204 205uint8_t 206nvmf_validate_command_capsule(const struct nvmf_capsule *nc) 207{ 208 assert(nc->nc_qe_len == sizeof(struct nvme_command)); 209 210 if (NVMEV(NVME_CMD_PSDT, nc->nc_sqe.fuse) != NVME_PSDT_SGL) 211 return (NVME_SC_INVALID_FIELD); 212 213 return (nc->nc_qpair->nq_association->na_ops->validate_command_capsule(nc)); 214} 215 216size_t 217nvmf_capsule_data_len(const struct nvmf_capsule *nc) 218{ 219 return (nc->nc_qpair->nq_association->na_ops->capsule_data_len(nc)); 220} 221 222int 223nvmf_receive_controller_data(const struct nvmf_capsule *nc, 224 uint32_t data_offset, void *buf, size_t len) 225{ 226 return (nc->nc_qpair->nq_association->na_ops->receive_controller_data(nc, 227 data_offset, buf, len)); 228} 229 230int 231nvmf_send_controller_data(const struct nvmf_capsule *nc, const void *buf, 232 size_t len) 233{ 234 return (nc->nc_qpair->nq_association->na_ops->send_controller_data(nc, 235 buf, len)); 236} 237 238int 239nvmf_kernel_handoff_params(struct nvmf_qpair *qp, 240 struct nvmf_handoff_qpair_params *qparams) 241{ 242 memset(qparams, 0, sizeof(*qparams)); 243 qparams->admin = qp->nq_admin; 244 qparams->sq_flow_control = qp->nq_flow_control; 245 qparams->qsize = qp->nq_qsize; 246 qparams->sqhd = qp->nq_sqhd; 247 qparams->sqtail = qp->nq_sqtail; 248 return (qp->nq_association->na_ops->kernel_handoff_params(qp, qparams)); 249} 250 251const char * 252nvmf_transport_type(uint8_t trtype) 253{ 254 static _Thread_local char buf[8]; 255 256 switch (trtype) { 257 case NVMF_TRTYPE_RDMA: 258 return ("RDMA"); 259 case NVMF_TRTYPE_FC: 260 return ("Fibre Channel"); 261 case NVMF_TRTYPE_TCP: 262 return ("TCP"); 263 case NVMF_TRTYPE_INTRA_HOST: 264 return ("Intra-host"); 265 default: 266 snprintf(buf, sizeof(buf), "0x%02x\n", trtype); 267 return (buf); 268 } 269} 270