xref: /spdk/lib/nvmf/transport.c (revision 407e88fd2ab020d753e33014cf759353a9901b51)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation. All rights reserved.
5  *   Copyright (c) 2018-2019 Mellanox Technologies LTD. All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "nvmf_internal.h"
37 #include "transport.h"
38 
39 #include "spdk/config.h"
40 #include "spdk/log.h"
41 #include "spdk/nvmf.h"
42 #include "spdk/queue.h"
43 #include "spdk/util.h"
44 
45 static const struct spdk_nvmf_transport_ops *const g_transport_ops[] = {
46 #ifdef SPDK_CONFIG_RDMA
47 	&spdk_nvmf_transport_rdma,
48 #endif
49 	&spdk_nvmf_transport_tcp,
50 #ifdef SPDK_CONFIG_FC
51 	&spdk_nvmf_transport_fc,
52 #endif
53 };
54 
55 #define NUM_TRANSPORTS (SPDK_COUNTOF(g_transport_ops))
56 #define MAX_MEMPOOL_NAME_LENGTH 40
57 
58 static inline const struct spdk_nvmf_transport_ops *
59 spdk_nvmf_get_transport_ops(enum spdk_nvme_transport_type type)
60 {
61 	size_t i;
62 	for (i = 0; i != NUM_TRANSPORTS; i++) {
63 		if (g_transport_ops[i]->type == type) {
64 			return g_transport_ops[i];
65 		}
66 	}
67 	return NULL;
68 }
69 
70 const struct spdk_nvmf_transport_opts *
71 spdk_nvmf_get_transport_opts(struct spdk_nvmf_transport *transport)
72 {
73 	return &transport->opts;
74 }
75 
76 spdk_nvme_transport_type_t
77 spdk_nvmf_get_transport_type(struct spdk_nvmf_transport *transport)
78 {
79 	return transport->ops->type;
80 }
81 
82 struct spdk_nvmf_transport *
83 spdk_nvmf_transport_create(enum spdk_nvme_transport_type type,
84 			   struct spdk_nvmf_transport_opts *opts)
85 {
86 	const struct spdk_nvmf_transport_ops *ops = NULL;
87 	struct spdk_nvmf_transport *transport;
88 	char spdk_mempool_name[MAX_MEMPOOL_NAME_LENGTH];
89 	int chars_written;
90 
91 	ops = spdk_nvmf_get_transport_ops(type);
92 	if (!ops) {
93 		SPDK_ERRLOG("Transport type '%s' unavailable.\n",
94 			    spdk_nvme_transport_id_trtype_str(type));
95 		return NULL;
96 	}
97 
98 	transport = ops->create(opts);
99 	if (!transport) {
100 		SPDK_ERRLOG("Unable to create new transport of type %s\n",
101 			    spdk_nvme_transport_id_trtype_str(type));
102 		return NULL;
103 	}
104 
105 	transport->ops = ops;
106 	transport->opts = *opts;
107 	chars_written = snprintf(spdk_mempool_name, MAX_MEMPOOL_NAME_LENGTH, "%s_%s_%s", "spdk_nvmf",
108 				 spdk_nvme_transport_id_trtype_str(type), "data");
109 	if (chars_written < 0) {
110 		SPDK_ERRLOG("Unable to generate transport data buffer pool name.\n");
111 		ops->destroy(transport);
112 		return NULL;
113 	}
114 
115 	transport->data_buf_pool = spdk_mempool_create(spdk_mempool_name,
116 				   opts->num_shared_buffers,
117 				   opts->io_unit_size + NVMF_DATA_BUFFER_ALIGNMENT,
118 				   SPDK_MEMPOOL_DEFAULT_CACHE_SIZE,
119 				   SPDK_ENV_SOCKET_ID_ANY);
120 
121 	if (!transport->data_buf_pool) {
122 		SPDK_ERRLOG("Unable to allocate buffer pool for poll group\n");
123 		ops->destroy(transport);
124 		return NULL;
125 	}
126 
127 	return transport;
128 }
129 
130 struct spdk_nvmf_transport *
131 spdk_nvmf_transport_get_first(struct spdk_nvmf_tgt *tgt)
132 {
133 	return TAILQ_FIRST(&tgt->transports);
134 }
135 
136 struct spdk_nvmf_transport *
137 spdk_nvmf_transport_get_next(struct spdk_nvmf_transport *transport)
138 {
139 	return TAILQ_NEXT(transport, link);
140 }
141 
142 int
143 spdk_nvmf_transport_destroy(struct spdk_nvmf_transport *transport)
144 {
145 	if (transport->data_buf_pool != NULL) {
146 		if (spdk_mempool_count(transport->data_buf_pool) !=
147 		    transport->opts.num_shared_buffers) {
148 			SPDK_ERRLOG("transport buffer pool count is %zu but should be %u\n",
149 				    spdk_mempool_count(transport->data_buf_pool),
150 				    transport->opts.num_shared_buffers);
151 		}
152 	}
153 
154 	spdk_mempool_free(transport->data_buf_pool);
155 
156 	return transport->ops->destroy(transport);
157 }
158 
159 int
160 spdk_nvmf_transport_listen(struct spdk_nvmf_transport *transport,
161 			   const struct spdk_nvme_transport_id *trid)
162 {
163 	return transport->ops->listen(transport, trid);
164 }
165 
166 int
167 spdk_nvmf_transport_stop_listen(struct spdk_nvmf_transport *transport,
168 				const struct spdk_nvme_transport_id *trid)
169 {
170 	return transport->ops->stop_listen(transport, trid);
171 }
172 
173 void
174 spdk_nvmf_transport_accept(struct spdk_nvmf_transport *transport, new_qpair_fn cb_fn)
175 {
176 	transport->ops->accept(transport, cb_fn);
177 }
178 
179 void
180 spdk_nvmf_transport_listener_discover(struct spdk_nvmf_transport *transport,
181 				      struct spdk_nvme_transport_id *trid,
182 				      struct spdk_nvmf_discovery_log_page_entry *entry)
183 {
184 	transport->ops->listener_discover(transport, trid, entry);
185 }
186 
187 struct spdk_nvmf_transport_poll_group *
188 spdk_nvmf_transport_poll_group_create(struct spdk_nvmf_transport *transport)
189 {
190 	struct spdk_nvmf_transport_poll_group *group;
191 	struct spdk_nvmf_transport_pg_cache_buf *buf;
192 
193 	group = transport->ops->poll_group_create(transport);
194 	if (!group) {
195 		return NULL;
196 	}
197 	group->transport = transport;
198 
199 	STAILQ_INIT(&group->buf_cache);
200 
201 	if (transport->opts.buf_cache_size) {
202 		group->buf_cache_count = 0;
203 		group->buf_cache_size = transport->opts.buf_cache_size;
204 		while (group->buf_cache_count < group->buf_cache_size) {
205 			buf = (struct spdk_nvmf_transport_pg_cache_buf *)spdk_mempool_get(transport->data_buf_pool);
206 			if (!buf) {
207 				SPDK_NOTICELOG("Unable to reserve the full number of buffers for the pg buffer cache.\n");
208 				break;
209 			}
210 			STAILQ_INSERT_HEAD(&group->buf_cache, buf, link);
211 			group->buf_cache_count++;
212 		}
213 	}
214 	return group;
215 }
216 
217 struct spdk_nvmf_transport_poll_group *
218 spdk_nvmf_transport_get_optimal_poll_group(struct spdk_nvmf_transport *transport,
219 		struct spdk_nvmf_qpair *qpair)
220 {
221 	if (transport->ops->get_optimal_poll_group) {
222 		return transport->ops->get_optimal_poll_group(qpair);
223 	} else {
224 		return NULL;
225 	}
226 }
227 
228 void
229 spdk_nvmf_transport_poll_group_destroy(struct spdk_nvmf_transport_poll_group *group)
230 {
231 	struct spdk_nvmf_transport_pg_cache_buf *buf, *tmp;
232 
233 	STAILQ_FOREACH_SAFE(buf, &group->buf_cache, link, tmp) {
234 		STAILQ_REMOVE(&group->buf_cache, buf, spdk_nvmf_transport_pg_cache_buf, link);
235 		spdk_mempool_put(group->transport->data_buf_pool, buf);
236 	}
237 	group->transport->ops->poll_group_destroy(group);
238 }
239 
240 int
241 spdk_nvmf_transport_poll_group_add(struct spdk_nvmf_transport_poll_group *group,
242 				   struct spdk_nvmf_qpair *qpair)
243 {
244 	if (qpair->transport) {
245 		assert(qpair->transport == group->transport);
246 		if (qpair->transport != group->transport) {
247 			return -1;
248 		}
249 	} else {
250 		qpair->transport = group->transport;
251 	}
252 
253 	return group->transport->ops->poll_group_add(group, qpair);
254 }
255 
256 int
257 spdk_nvmf_transport_poll_group_remove(struct spdk_nvmf_transport_poll_group *group,
258 				      struct spdk_nvmf_qpair *qpair)
259 {
260 	int rc = ENOTSUP;
261 
262 	assert(qpair->transport == group->transport);
263 	if (group->transport->ops->poll_group_remove) {
264 		rc = group->transport->ops->poll_group_remove(group, qpair);
265 	}
266 
267 	return rc;
268 }
269 
270 int
271 spdk_nvmf_transport_poll_group_poll(struct spdk_nvmf_transport_poll_group *group)
272 {
273 	return group->transport->ops->poll_group_poll(group);
274 }
275 
276 int
277 spdk_nvmf_transport_req_free(struct spdk_nvmf_request *req)
278 {
279 	return req->qpair->transport->ops->req_free(req);
280 }
281 
282 int
283 spdk_nvmf_transport_req_complete(struct spdk_nvmf_request *req)
284 {
285 	return req->qpair->transport->ops->req_complete(req);
286 }
287 
288 void
289 spdk_nvmf_transport_qpair_fini(struct spdk_nvmf_qpair *qpair)
290 {
291 	qpair->transport->ops->qpair_fini(qpair);
292 }
293 
294 int
295 spdk_nvmf_transport_qpair_get_peer_trid(struct spdk_nvmf_qpair *qpair,
296 					struct spdk_nvme_transport_id *trid)
297 {
298 	return qpair->transport->ops->qpair_get_peer_trid(qpair, trid);
299 }
300 
301 int
302 spdk_nvmf_transport_qpair_get_local_trid(struct spdk_nvmf_qpair *qpair,
303 		struct spdk_nvme_transport_id *trid)
304 {
305 	return qpair->transport->ops->qpair_get_local_trid(qpair, trid);
306 }
307 
308 int
309 spdk_nvmf_transport_qpair_get_listen_trid(struct spdk_nvmf_qpair *qpair,
310 		struct spdk_nvme_transport_id *trid)
311 {
312 	return qpair->transport->ops->qpair_get_listen_trid(qpair, trid);
313 }
314 
315 bool
316 spdk_nvmf_transport_opts_init(enum spdk_nvme_transport_type type,
317 			      struct spdk_nvmf_transport_opts *opts)
318 {
319 	const struct spdk_nvmf_transport_ops *ops;
320 
321 	ops = spdk_nvmf_get_transport_ops(type);
322 	if (!ops) {
323 		SPDK_ERRLOG("Transport type %s unavailable.\n",
324 			    spdk_nvme_transport_id_trtype_str(type));
325 		return false;
326 	}
327 
328 	ops->opts_init(opts);
329 	return true;
330 }
331 
332 int
333 spdk_nvmf_transport_qpair_set_sqsize(struct spdk_nvmf_qpair *qpair)
334 {
335 	if (qpair->transport->ops->qpair_set_sqsize) {
336 		return qpair->transport->ops->qpair_set_sqsize(qpair);
337 	}
338 
339 	return 0;
340 }
341 
342 int
343 spdk_nvmf_transport_poll_group_get_stat(struct spdk_nvmf_tgt *tgt,
344 					struct spdk_nvmf_transport *transport,
345 					struct spdk_nvmf_transport_poll_group_stat **stat)
346 {
347 	if (transport->ops->poll_group_get_stat) {
348 		return transport->ops->poll_group_get_stat(tgt, stat);
349 	} else {
350 		return -ENOTSUP;
351 	}
352 }
353 
354 void
355 spdk_nvmf_transport_poll_group_free_stat(struct spdk_nvmf_transport *transport,
356 		struct spdk_nvmf_transport_poll_group_stat *stat)
357 {
358 	if (transport->ops->poll_group_free_stat) {
359 		transport->ops->poll_group_free_stat(stat);
360 	}
361 }
362