xref: /freebsd/lib/libnvmf/nvmf_transport.c (revision a90b9d0159070121c221b966469c3e36d912bf82)
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 
19 struct nvmf_association *
20 nvmf_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 
48 void
49 nvmf_update_assocation(struct nvmf_association *na,
50     const struct nvme_controller_data *cdata)
51 {
52 	na->na_ops->update_association(na, cdata);
53 }
54 
55 void
56 nvmf_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 
64 const char *
65 nvmf_association_error(const struct nvmf_association *na)
66 {
67 	return (na->na_last_error);
68 }
69 
70 void
71 na_clear_error(struct nvmf_association *na)
72 {
73 	free(na->na_last_error);
74 	na->na_last_error = NULL;
75 }
76 
77 void
78 na_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 
91 struct nvmf_qpair *
92 nvmf_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 
109 void
110 nvmf_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 
124 struct nvmf_capsule *
125 nvmf_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 
143 struct nvmf_capsule *
144 nvmf_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 
158 int
159 nvmf_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 
173 void
174 nvmf_free_capsule(struct nvmf_capsule *nc)
175 {
176 	nc->nc_qpair->nq_association->na_ops->free_capsule(nc);
177 }
178 
179 int
180 nvmf_transmit_capsule(struct nvmf_capsule *nc)
181 {
182 	return (nc->nc_qpair->nq_association->na_ops->transmit_capsule(nc));
183 }
184 
185 int
186 nvmf_receive_capsule(struct nvmf_qpair *qp, struct nvmf_capsule **ncp)
187 {
188 	return (qp->nq_association->na_ops->receive_capsule(qp, ncp));
189 }
190 
191 const void *
192 nvmf_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 
198 const void *
199 nvmf_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 
205 uint8_t
206 nvmf_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 
216 size_t
217 nvmf_capsule_data_len(const struct nvmf_capsule *nc)
218 {
219 	return (nc->nc_qpair->nq_association->na_ops->capsule_data_len(nc));
220 }
221 
222 int
223 nvmf_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 
230 int
231 nvmf_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 
238 int
239 nvmf_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 
251 const char *
252 nvmf_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