xref: /freebsd-src/sys/dev/nvmf/nvmf_transport.c (revision 365b89e8ea4af34a05f68aa28e77573e89fa00b2)
1aa1207eaSJohn Baldwin /*-
2aa1207eaSJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
3aa1207eaSJohn Baldwin  *
4aa1207eaSJohn Baldwin  * Copyright (c) 2022-2024 Chelsio Communications, Inc.
5aa1207eaSJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
6aa1207eaSJohn Baldwin  */
7aa1207eaSJohn Baldwin 
8aa1207eaSJohn Baldwin #include <sys/param.h>
9aa1207eaSJohn Baldwin #include <sys/kernel.h>
10aa1207eaSJohn Baldwin #include <sys/limits.h>
11aa1207eaSJohn Baldwin #include <sys/lock.h>
12aa1207eaSJohn Baldwin #include <sys/malloc.h>
13aa1207eaSJohn Baldwin #include <sys/mbuf.h>
14aa1207eaSJohn Baldwin #include <sys/module.h>
15*365b89e8SJohn Baldwin #include <sys/nv.h>
16aa1207eaSJohn Baldwin #include <sys/refcount.h>
17aa1207eaSJohn Baldwin #include <sys/sysctl.h>
18aa1207eaSJohn Baldwin #include <sys/sx.h>
19aa1207eaSJohn Baldwin #include <dev/nvme/nvme.h>
20aa1207eaSJohn Baldwin #include <dev/nvmf/nvmf.h>
21aa1207eaSJohn Baldwin #include <dev/nvmf/nvmf_transport.h>
22aa1207eaSJohn Baldwin #include <dev/nvmf/nvmf_transport_internal.h>
23aa1207eaSJohn Baldwin 
24aa1207eaSJohn Baldwin /* Transport-independent support for fabrics queue pairs and commands. */
25aa1207eaSJohn Baldwin 
26aa1207eaSJohn Baldwin struct nvmf_transport {
27aa1207eaSJohn Baldwin 	struct nvmf_transport_ops *nt_ops;
28aa1207eaSJohn Baldwin 
29aa1207eaSJohn Baldwin 	volatile u_int nt_active_qpairs;
30aa1207eaSJohn Baldwin 	SLIST_ENTRY(nvmf_transport) nt_link;
31aa1207eaSJohn Baldwin };
32aa1207eaSJohn Baldwin 
33aa1207eaSJohn Baldwin /* nvmf_transports[nvmf_trtype] is sorted by priority */
34aa1207eaSJohn Baldwin static SLIST_HEAD(, nvmf_transport) nvmf_transports[NVMF_TRTYPE_TCP + 1];
35aa1207eaSJohn Baldwin static struct sx nvmf_transports_lock;
36aa1207eaSJohn Baldwin 
37aa1207eaSJohn Baldwin static MALLOC_DEFINE(M_NVMF_TRANSPORT, "nvmf_xport",
38aa1207eaSJohn Baldwin     "NVMe over Fabrics transport");
39aa1207eaSJohn Baldwin 
40aa1207eaSJohn Baldwin SYSCTL_NODE(_kern, OID_AUTO, nvmf, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
41aa1207eaSJohn Baldwin     "NVMe over Fabrics");
42aa1207eaSJohn Baldwin 
43aa1207eaSJohn Baldwin static bool
44aa1207eaSJohn Baldwin nvmf_supported_trtype(enum nvmf_trtype trtype)
45aa1207eaSJohn Baldwin {
46aa1207eaSJohn Baldwin 	return (trtype < nitems(nvmf_transports));
47aa1207eaSJohn Baldwin }
48aa1207eaSJohn Baldwin 
49aa1207eaSJohn Baldwin struct nvmf_qpair *
50aa1207eaSJohn Baldwin nvmf_allocate_qpair(enum nvmf_trtype trtype, bool controller,
51*365b89e8SJohn Baldwin     const nvlist_t *params, nvmf_qpair_error_t *error_cb, void *error_cb_arg,
52aa1207eaSJohn Baldwin     nvmf_capsule_receive_t *receive_cb, void *receive_cb_arg)
53aa1207eaSJohn Baldwin {
54aa1207eaSJohn Baldwin 	struct nvmf_transport *nt;
55aa1207eaSJohn Baldwin 	struct nvmf_qpair *qp;
56aa1207eaSJohn Baldwin 
57aa1207eaSJohn Baldwin 	if (!nvmf_supported_trtype(trtype))
58aa1207eaSJohn Baldwin 		return (NULL);
59aa1207eaSJohn Baldwin 
60aa1207eaSJohn Baldwin 	sx_slock(&nvmf_transports_lock);
61aa1207eaSJohn Baldwin 	SLIST_FOREACH(nt, &nvmf_transports[trtype], nt_link) {
62aa1207eaSJohn Baldwin 		qp = nt->nt_ops->allocate_qpair(controller, params);
63aa1207eaSJohn Baldwin 		if (qp != NULL) {
64aa1207eaSJohn Baldwin 			refcount_acquire(&nt->nt_active_qpairs);
65aa1207eaSJohn Baldwin 			break;
66aa1207eaSJohn Baldwin 		}
67aa1207eaSJohn Baldwin 	}
68aa1207eaSJohn Baldwin 	sx_sunlock(&nvmf_transports_lock);
69aa1207eaSJohn Baldwin 	if (qp == NULL)
70aa1207eaSJohn Baldwin 		return (NULL);
71aa1207eaSJohn Baldwin 
72aa1207eaSJohn Baldwin 	qp->nq_transport = nt;
73aa1207eaSJohn Baldwin 	qp->nq_ops = nt->nt_ops;
74aa1207eaSJohn Baldwin 	qp->nq_controller = controller;
75aa1207eaSJohn Baldwin 	qp->nq_error = error_cb;
76aa1207eaSJohn Baldwin 	qp->nq_error_arg = error_cb_arg;
77aa1207eaSJohn Baldwin 	qp->nq_receive = receive_cb;
78aa1207eaSJohn Baldwin 	qp->nq_receive_arg = receive_cb_arg;
79*365b89e8SJohn Baldwin 	qp->nq_admin = nvlist_get_bool(params, "admin");
80aa1207eaSJohn Baldwin 	return (qp);
81aa1207eaSJohn Baldwin }
82aa1207eaSJohn Baldwin 
83aa1207eaSJohn Baldwin void
84aa1207eaSJohn Baldwin nvmf_free_qpair(struct nvmf_qpair *qp)
85aa1207eaSJohn Baldwin {
86aa1207eaSJohn Baldwin 	struct nvmf_transport *nt;
87aa1207eaSJohn Baldwin 
88aa1207eaSJohn Baldwin 	nt = qp->nq_transport;
89aa1207eaSJohn Baldwin 	qp->nq_ops->free_qpair(qp);
90aa1207eaSJohn Baldwin 	if (refcount_release(&nt->nt_active_qpairs))
91aa1207eaSJohn Baldwin 		wakeup(nt);
92aa1207eaSJohn Baldwin }
93aa1207eaSJohn Baldwin 
94aa1207eaSJohn Baldwin struct nvmf_capsule *
95aa1207eaSJohn Baldwin nvmf_allocate_command(struct nvmf_qpair *qp, const void *sqe, int how)
96aa1207eaSJohn Baldwin {
97aa1207eaSJohn Baldwin 	struct nvmf_capsule *nc;
98aa1207eaSJohn Baldwin 
99aa1207eaSJohn Baldwin 	KASSERT(how == M_WAITOK || how == M_NOWAIT,
100aa1207eaSJohn Baldwin 	    ("%s: invalid how", __func__));
101aa1207eaSJohn Baldwin 	nc = qp->nq_ops->allocate_capsule(qp, how);
102aa1207eaSJohn Baldwin 	if (nc == NULL)
103aa1207eaSJohn Baldwin 		return (NULL);
104aa1207eaSJohn Baldwin 
105aa1207eaSJohn Baldwin 	nc->nc_qpair = qp;
106aa1207eaSJohn Baldwin 	nc->nc_qe_len = sizeof(struct nvme_command);
107aa1207eaSJohn Baldwin 	memcpy(&nc->nc_sqe, sqe, nc->nc_qe_len);
108aa1207eaSJohn Baldwin 
109aa1207eaSJohn Baldwin 	/* 4.2 of NVMe base spec: Fabrics always uses SGL. */
110aa1207eaSJohn Baldwin 	nc->nc_sqe.fuse &= ~NVMEM(NVME_CMD_PSDT);
111aa1207eaSJohn Baldwin 	nc->nc_sqe.fuse |= NVMEF(NVME_CMD_PSDT, NVME_PSDT_SGL);
112aa1207eaSJohn Baldwin 	return (nc);
113aa1207eaSJohn Baldwin }
114aa1207eaSJohn Baldwin 
115aa1207eaSJohn Baldwin struct nvmf_capsule *
116aa1207eaSJohn Baldwin nvmf_allocate_response(struct nvmf_qpair *qp, const void *cqe, int how)
117aa1207eaSJohn Baldwin {
118aa1207eaSJohn Baldwin 	struct nvmf_capsule *nc;
119aa1207eaSJohn Baldwin 
120aa1207eaSJohn Baldwin 	KASSERT(how == M_WAITOK || how == M_NOWAIT,
121aa1207eaSJohn Baldwin 	    ("%s: invalid how", __func__));
122aa1207eaSJohn Baldwin 	nc = qp->nq_ops->allocate_capsule(qp, how);
123aa1207eaSJohn Baldwin 	if (nc == NULL)
124aa1207eaSJohn Baldwin 		return (NULL);
125aa1207eaSJohn Baldwin 
126aa1207eaSJohn Baldwin 	nc->nc_qpair = qp;
127aa1207eaSJohn Baldwin 	nc->nc_qe_len = sizeof(struct nvme_completion);
128aa1207eaSJohn Baldwin 	memcpy(&nc->nc_cqe, cqe, nc->nc_qe_len);
129aa1207eaSJohn Baldwin 	return (nc);
130aa1207eaSJohn Baldwin }
131aa1207eaSJohn Baldwin 
132aa1207eaSJohn Baldwin int
133aa1207eaSJohn Baldwin nvmf_capsule_append_data(struct nvmf_capsule *nc, struct memdesc *mem,
134aa1207eaSJohn Baldwin     size_t len, bool send, nvmf_io_complete_t *complete_cb,
135aa1207eaSJohn Baldwin     void *cb_arg)
136aa1207eaSJohn Baldwin {
137aa1207eaSJohn Baldwin 	if (nc->nc_data.io_len != 0)
138aa1207eaSJohn Baldwin 		return (EBUSY);
139aa1207eaSJohn Baldwin 
140aa1207eaSJohn Baldwin 	nc->nc_send_data = send;
141aa1207eaSJohn Baldwin 	nc->nc_data.io_mem = *mem;
142aa1207eaSJohn Baldwin 	nc->nc_data.io_len = len;
143aa1207eaSJohn Baldwin 	nc->nc_data.io_complete = complete_cb;
144aa1207eaSJohn Baldwin 	nc->nc_data.io_complete_arg = cb_arg;
145aa1207eaSJohn Baldwin 	return (0);
146aa1207eaSJohn Baldwin }
147aa1207eaSJohn Baldwin 
148aa1207eaSJohn Baldwin void
149aa1207eaSJohn Baldwin nvmf_free_capsule(struct nvmf_capsule *nc)
150aa1207eaSJohn Baldwin {
151aa1207eaSJohn Baldwin 	nc->nc_qpair->nq_ops->free_capsule(nc);
152aa1207eaSJohn Baldwin }
153aa1207eaSJohn Baldwin 
154aa1207eaSJohn Baldwin int
155aa1207eaSJohn Baldwin nvmf_transmit_capsule(struct nvmf_capsule *nc)
156aa1207eaSJohn Baldwin {
157aa1207eaSJohn Baldwin 	return (nc->nc_qpair->nq_ops->transmit_capsule(nc));
158aa1207eaSJohn Baldwin }
159aa1207eaSJohn Baldwin 
160aa1207eaSJohn Baldwin void
161aa1207eaSJohn Baldwin nvmf_abort_capsule_data(struct nvmf_capsule *nc, int error)
162aa1207eaSJohn Baldwin {
163aa1207eaSJohn Baldwin 	if (nc->nc_data.io_len != 0)
164aa1207eaSJohn Baldwin 		nvmf_complete_io_request(&nc->nc_data, 0, error);
165aa1207eaSJohn Baldwin }
166aa1207eaSJohn Baldwin 
167aa1207eaSJohn Baldwin void *
168aa1207eaSJohn Baldwin nvmf_capsule_sqe(struct nvmf_capsule *nc)
169aa1207eaSJohn Baldwin {
170aa1207eaSJohn Baldwin 	KASSERT(nc->nc_qe_len == sizeof(struct nvme_command),
171aa1207eaSJohn Baldwin 	    ("%s: capsule %p is not a command capsule", __func__, nc));
172aa1207eaSJohn Baldwin 	return (&nc->nc_sqe);
173aa1207eaSJohn Baldwin }
174aa1207eaSJohn Baldwin 
175aa1207eaSJohn Baldwin void *
176aa1207eaSJohn Baldwin nvmf_capsule_cqe(struct nvmf_capsule *nc)
177aa1207eaSJohn Baldwin {
178aa1207eaSJohn Baldwin 	KASSERT(nc->nc_qe_len == sizeof(struct nvme_completion),
179aa1207eaSJohn Baldwin 	    ("%s: capsule %p is not a response capsule", __func__, nc));
180aa1207eaSJohn Baldwin 	return (&nc->nc_cqe);
181aa1207eaSJohn Baldwin }
182aa1207eaSJohn Baldwin 
1834d3b659fSJohn Baldwin bool
1844d3b659fSJohn Baldwin nvmf_sqhd_valid(struct nvmf_capsule *nc)
1854d3b659fSJohn Baldwin {
1864d3b659fSJohn Baldwin 	KASSERT(nc->nc_qe_len == sizeof(struct nvme_completion),
1874d3b659fSJohn Baldwin 	    ("%s: capsule %p is not a response capsule", __func__, nc));
1884d3b659fSJohn Baldwin 	return (nc->nc_sqhd_valid);
1894d3b659fSJohn Baldwin }
1904d3b659fSJohn Baldwin 
191aa1207eaSJohn Baldwin uint8_t
192aa1207eaSJohn Baldwin nvmf_validate_command_capsule(struct nvmf_capsule *nc)
193aa1207eaSJohn Baldwin {
194aa1207eaSJohn Baldwin 	KASSERT(nc->nc_qe_len == sizeof(struct nvme_command),
195aa1207eaSJohn Baldwin 	    ("%s: capsule %p is not a command capsule", __func__, nc));
196aa1207eaSJohn Baldwin 
197aa1207eaSJohn Baldwin 	if (NVMEV(NVME_CMD_PSDT, nc->nc_sqe.fuse) != NVME_PSDT_SGL)
198aa1207eaSJohn Baldwin 		return (NVME_SC_INVALID_FIELD);
199aa1207eaSJohn Baldwin 
200aa1207eaSJohn Baldwin 	return (nc->nc_qpair->nq_ops->validate_command_capsule(nc));
201aa1207eaSJohn Baldwin }
202aa1207eaSJohn Baldwin 
203aa1207eaSJohn Baldwin size_t
204aa1207eaSJohn Baldwin nvmf_capsule_data_len(const struct nvmf_capsule *nc)
205aa1207eaSJohn Baldwin {
206aa1207eaSJohn Baldwin 	return (nc->nc_qpair->nq_ops->capsule_data_len(nc));
207aa1207eaSJohn Baldwin }
208aa1207eaSJohn Baldwin 
209aa1207eaSJohn Baldwin int
210aa1207eaSJohn Baldwin nvmf_receive_controller_data(struct nvmf_capsule *nc, uint32_t data_offset,
211aa1207eaSJohn Baldwin     struct memdesc *mem, size_t len, nvmf_io_complete_t *complete_cb,
212aa1207eaSJohn Baldwin     void *cb_arg)
213aa1207eaSJohn Baldwin {
214aa1207eaSJohn Baldwin 	struct nvmf_io_request io;
215aa1207eaSJohn Baldwin 
216aa1207eaSJohn Baldwin 	io.io_mem = *mem;
217aa1207eaSJohn Baldwin 	io.io_len = len;
218aa1207eaSJohn Baldwin 	io.io_complete = complete_cb;
219aa1207eaSJohn Baldwin 	io.io_complete_arg = cb_arg;
220aa1207eaSJohn Baldwin 	return (nc->nc_qpair->nq_ops->receive_controller_data(nc, data_offset,
221aa1207eaSJohn Baldwin 	    &io));
222aa1207eaSJohn Baldwin }
223aa1207eaSJohn Baldwin 
224aa1207eaSJohn Baldwin u_int
225aa1207eaSJohn Baldwin nvmf_send_controller_data(struct nvmf_capsule *nc, uint32_t data_offset,
226aa1207eaSJohn Baldwin     struct mbuf *m, size_t len)
227aa1207eaSJohn Baldwin {
228aa1207eaSJohn Baldwin 	MPASS(m_length(m, NULL) == len);
229aa1207eaSJohn Baldwin 	return (nc->nc_qpair->nq_ops->send_controller_data(nc, data_offset, m,
230aa1207eaSJohn Baldwin 	    len));
231aa1207eaSJohn Baldwin }
232aa1207eaSJohn Baldwin 
233aa1207eaSJohn Baldwin int
234*365b89e8SJohn Baldwin nvmf_pack_ioc_nvlist(const nvlist_t *nvl, struct nvmf_ioc_nv *nv)
235*365b89e8SJohn Baldwin {
236*365b89e8SJohn Baldwin 	void *packed;
237*365b89e8SJohn Baldwin 	int error;
238*365b89e8SJohn Baldwin 
239*365b89e8SJohn Baldwin 	error = nvlist_error(nvl);
240*365b89e8SJohn Baldwin 	if (error != 0)
241*365b89e8SJohn Baldwin 		return (error);
242*365b89e8SJohn Baldwin 
243*365b89e8SJohn Baldwin 	if (nv->size == 0) {
244*365b89e8SJohn Baldwin 		nv->len = nvlist_size(nvl);
245*365b89e8SJohn Baldwin 	} else {
246*365b89e8SJohn Baldwin 		packed = nvlist_pack(nvl, &nv->len);
247*365b89e8SJohn Baldwin 		if (packed == NULL)
248*365b89e8SJohn Baldwin 			error = ENOMEM;
249*365b89e8SJohn Baldwin 		else if (nv->len > nv->size)
250*365b89e8SJohn Baldwin 			error = EFBIG;
251*365b89e8SJohn Baldwin 		else
252*365b89e8SJohn Baldwin 			error = copyout(packed, nv->data, nv->len);
253*365b89e8SJohn Baldwin 		free(packed, M_NVLIST);
254*365b89e8SJohn Baldwin 	}
255*365b89e8SJohn Baldwin 	return (error);
256*365b89e8SJohn Baldwin }
257*365b89e8SJohn Baldwin 
258*365b89e8SJohn Baldwin int
259*365b89e8SJohn Baldwin nvmf_unpack_ioc_nvlist(const struct nvmf_ioc_nv *nv, nvlist_t **nvlp)
260*365b89e8SJohn Baldwin {
261*365b89e8SJohn Baldwin 	void *packed;
262*365b89e8SJohn Baldwin 	nvlist_t *nvl;
263*365b89e8SJohn Baldwin 	int error;
264*365b89e8SJohn Baldwin 
265*365b89e8SJohn Baldwin 	packed = malloc(nv->size, M_NVMF_TRANSPORT, M_WAITOK);
266*365b89e8SJohn Baldwin 	error = copyin(nv->data, packed, nv->size);
267*365b89e8SJohn Baldwin 	if (error != 0) {
268*365b89e8SJohn Baldwin 		free(packed, M_NVMF_TRANSPORT);
269*365b89e8SJohn Baldwin 		return (error);
270*365b89e8SJohn Baldwin 	}
271*365b89e8SJohn Baldwin 
272*365b89e8SJohn Baldwin 	nvl = nvlist_unpack(packed, nv->size, 0);
273*365b89e8SJohn Baldwin 	free(packed, M_NVMF_TRANSPORT);
274*365b89e8SJohn Baldwin 	if (nvl == NULL)
275*365b89e8SJohn Baldwin 		return (EINVAL);
276*365b89e8SJohn Baldwin 
277*365b89e8SJohn Baldwin 	*nvlp = nvl;
278*365b89e8SJohn Baldwin 	return (0);
279*365b89e8SJohn Baldwin }
280*365b89e8SJohn Baldwin 
281*365b89e8SJohn Baldwin bool
282*365b89e8SJohn Baldwin nvmf_validate_qpair_nvlist(const nvlist_t *nvl, bool controller)
283*365b89e8SJohn Baldwin {
284*365b89e8SJohn Baldwin 	uint64_t value, qsize;
285*365b89e8SJohn Baldwin 	bool admin, valid;
286*365b89e8SJohn Baldwin 
287*365b89e8SJohn Baldwin 	valid = true;
288*365b89e8SJohn Baldwin 	valid &= nvlist_exists_bool(nvl, "admin");
289*365b89e8SJohn Baldwin 	valid &= nvlist_exists_bool(nvl, "sq_flow_control");
290*365b89e8SJohn Baldwin 	valid &= nvlist_exists_number(nvl, "qsize");
291*365b89e8SJohn Baldwin 	valid &= nvlist_exists_number(nvl, "sqhd");
292*365b89e8SJohn Baldwin 	if (!controller)
293*365b89e8SJohn Baldwin 		valid &= nvlist_exists_number(nvl, "sqtail");
294*365b89e8SJohn Baldwin 	if (!valid)
295*365b89e8SJohn Baldwin 		return (false);
296*365b89e8SJohn Baldwin 
297*365b89e8SJohn Baldwin 	admin = nvlist_get_bool(nvl, "admin");
298*365b89e8SJohn Baldwin 	qsize = nvlist_get_number(nvl, "qsize");
299*365b89e8SJohn Baldwin 	if (admin) {
300*365b89e8SJohn Baldwin 		if (qsize < NVME_MIN_ADMIN_ENTRIES ||
301*365b89e8SJohn Baldwin 		    qsize > NVME_MAX_ADMIN_ENTRIES)
302*365b89e8SJohn Baldwin 			return (false);
303*365b89e8SJohn Baldwin 	} else {
304*365b89e8SJohn Baldwin 		if (qsize < NVME_MIN_IO_ENTRIES || qsize > NVME_MAX_IO_ENTRIES)
305*365b89e8SJohn Baldwin 			return (false);
306*365b89e8SJohn Baldwin 	}
307*365b89e8SJohn Baldwin 	value = nvlist_get_number(nvl, "sqhd");
308*365b89e8SJohn Baldwin 	if (value > qsize - 1)
309*365b89e8SJohn Baldwin 		return (false);
310*365b89e8SJohn Baldwin 	if (!controller) {
311*365b89e8SJohn Baldwin 		value = nvlist_get_number(nvl, "sqtail");
312*365b89e8SJohn Baldwin 		if (value > qsize - 1)
313*365b89e8SJohn Baldwin 			return (false);
314*365b89e8SJohn Baldwin 	}
315*365b89e8SJohn Baldwin 
316*365b89e8SJohn Baldwin 	return (true);
317*365b89e8SJohn Baldwin }
318*365b89e8SJohn Baldwin 
319*365b89e8SJohn Baldwin int
320aa1207eaSJohn Baldwin nvmf_transport_module_handler(struct module *mod, int what, void *arg)
321aa1207eaSJohn Baldwin {
322aa1207eaSJohn Baldwin 	struct nvmf_transport_ops *ops = arg;
323aa1207eaSJohn Baldwin 	struct nvmf_transport *nt, *nt2, *prev;
324aa1207eaSJohn Baldwin 	int error;
325aa1207eaSJohn Baldwin 
326aa1207eaSJohn Baldwin 	switch (what) {
327aa1207eaSJohn Baldwin 	case MOD_LOAD:
328aa1207eaSJohn Baldwin 		if (!nvmf_supported_trtype(ops->trtype)) {
329aa1207eaSJohn Baldwin 			printf("NVMF: Unsupported transport %u", ops->trtype);
330aa1207eaSJohn Baldwin 			return (EINVAL);
331aa1207eaSJohn Baldwin 		}
332aa1207eaSJohn Baldwin 
333aa1207eaSJohn Baldwin 		nt = malloc(sizeof(*nt), M_NVMF_TRANSPORT, M_WAITOK | M_ZERO);
334aa1207eaSJohn Baldwin 		nt->nt_ops = arg;
335aa1207eaSJohn Baldwin 
336aa1207eaSJohn Baldwin 		sx_xlock(&nvmf_transports_lock);
337aa1207eaSJohn Baldwin 		if (SLIST_EMPTY(&nvmf_transports[ops->trtype])) {
338aa1207eaSJohn Baldwin 			SLIST_INSERT_HEAD(&nvmf_transports[ops->trtype], nt,
339aa1207eaSJohn Baldwin 			    nt_link);
340aa1207eaSJohn Baldwin 		} else {
341aa1207eaSJohn Baldwin 			prev = NULL;
342aa1207eaSJohn Baldwin 			SLIST_FOREACH(nt2, &nvmf_transports[ops->trtype],
343aa1207eaSJohn Baldwin 			    nt_link) {
344aa1207eaSJohn Baldwin 				if (ops->priority > nt2->nt_ops->priority)
345aa1207eaSJohn Baldwin 					break;
346aa1207eaSJohn Baldwin 				prev = nt2;
347aa1207eaSJohn Baldwin 			}
348aa1207eaSJohn Baldwin 			if (prev == NULL)
349aa1207eaSJohn Baldwin 				SLIST_INSERT_HEAD(&nvmf_transports[ops->trtype],
350aa1207eaSJohn Baldwin 				    nt, nt_link);
351aa1207eaSJohn Baldwin 			else
352aa1207eaSJohn Baldwin 				SLIST_INSERT_AFTER(prev, nt, nt_link);
353aa1207eaSJohn Baldwin 		}
354aa1207eaSJohn Baldwin 		sx_xunlock(&nvmf_transports_lock);
355aa1207eaSJohn Baldwin 		return (0);
356aa1207eaSJohn Baldwin 
357aa1207eaSJohn Baldwin 	case MOD_QUIESCE:
358aa1207eaSJohn Baldwin 		if (!nvmf_supported_trtype(ops->trtype))
359aa1207eaSJohn Baldwin 			return (0);
360aa1207eaSJohn Baldwin 
361aa1207eaSJohn Baldwin 		sx_slock(&nvmf_transports_lock);
362aa1207eaSJohn Baldwin 		SLIST_FOREACH(nt, &nvmf_transports[ops->trtype], nt_link) {
363aa1207eaSJohn Baldwin 			if (nt->nt_ops == ops)
364aa1207eaSJohn Baldwin 				break;
365aa1207eaSJohn Baldwin 		}
366aa1207eaSJohn Baldwin 		if (nt == NULL) {
367aa1207eaSJohn Baldwin 			sx_sunlock(&nvmf_transports_lock);
368aa1207eaSJohn Baldwin 			return (0);
369aa1207eaSJohn Baldwin 		}
370aa1207eaSJohn Baldwin 		if (nt->nt_active_qpairs != 0) {
371aa1207eaSJohn Baldwin 			sx_sunlock(&nvmf_transports_lock);
372aa1207eaSJohn Baldwin 			return (EBUSY);
373aa1207eaSJohn Baldwin 		}
374aa1207eaSJohn Baldwin 		sx_sunlock(&nvmf_transports_lock);
375aa1207eaSJohn Baldwin 		return (0);
376aa1207eaSJohn Baldwin 
377aa1207eaSJohn Baldwin 	case MOD_UNLOAD:
378aa1207eaSJohn Baldwin 		if (!nvmf_supported_trtype(ops->trtype))
379aa1207eaSJohn Baldwin 			return (0);
380aa1207eaSJohn Baldwin 
381aa1207eaSJohn Baldwin 		sx_xlock(&nvmf_transports_lock);
382aa1207eaSJohn Baldwin 		prev = NULL;
383aa1207eaSJohn Baldwin 		SLIST_FOREACH(nt, &nvmf_transports[ops->trtype], nt_link) {
384aa1207eaSJohn Baldwin 			if (nt->nt_ops == ops)
385aa1207eaSJohn Baldwin 				break;
386aa1207eaSJohn Baldwin 			prev = nt;
387aa1207eaSJohn Baldwin 		}
388aa1207eaSJohn Baldwin 		if (nt == NULL) {
389aa1207eaSJohn Baldwin 			sx_xunlock(&nvmf_transports_lock);
390aa1207eaSJohn Baldwin 			return (0);
391aa1207eaSJohn Baldwin 		}
392aa1207eaSJohn Baldwin 
393aa1207eaSJohn Baldwin 		if (prev == NULL)
394aa1207eaSJohn Baldwin 			SLIST_REMOVE_HEAD(&nvmf_transports[ops->trtype],
395aa1207eaSJohn Baldwin 			    nt_link);
396aa1207eaSJohn Baldwin 		else
397aa1207eaSJohn Baldwin 			SLIST_REMOVE_AFTER(prev, nt_link);
398aa1207eaSJohn Baldwin 
399aa1207eaSJohn Baldwin 		error = 0;
400aa1207eaSJohn Baldwin 		while (nt->nt_active_qpairs != 0 && error == 0)
401aa1207eaSJohn Baldwin 			error = sx_sleep(nt, &nvmf_transports_lock, PCATCH,
402aa1207eaSJohn Baldwin 			    "nftunld", 0);
403aa1207eaSJohn Baldwin 		sx_xunlock(&nvmf_transports_lock);
404aa1207eaSJohn Baldwin 		if (error != 0)
405aa1207eaSJohn Baldwin 			return (error);
406aa1207eaSJohn Baldwin 		free(nt, M_NVMF_TRANSPORT);
407aa1207eaSJohn Baldwin 		return (0);
408aa1207eaSJohn Baldwin 
409aa1207eaSJohn Baldwin 	default:
410aa1207eaSJohn Baldwin 		return (EOPNOTSUPP);
411aa1207eaSJohn Baldwin 	}
412aa1207eaSJohn Baldwin }
413aa1207eaSJohn Baldwin 
414aa1207eaSJohn Baldwin static int
415aa1207eaSJohn Baldwin nvmf_transport_modevent(module_t mod __unused, int what, void *arg __unused)
416aa1207eaSJohn Baldwin {
417aa1207eaSJohn Baldwin 	switch (what) {
418aa1207eaSJohn Baldwin 	case MOD_LOAD:
419aa1207eaSJohn Baldwin 		for (u_int i = 0; i < nitems(nvmf_transports); i++)
420aa1207eaSJohn Baldwin 			SLIST_INIT(&nvmf_transports[i]);
421aa1207eaSJohn Baldwin 		sx_init(&nvmf_transports_lock, "nvmf transports");
422aa1207eaSJohn Baldwin 		return (0);
423aa1207eaSJohn Baldwin 	default:
424aa1207eaSJohn Baldwin 		return (EOPNOTSUPP);
425aa1207eaSJohn Baldwin 	}
426aa1207eaSJohn Baldwin }
427aa1207eaSJohn Baldwin 
428aa1207eaSJohn Baldwin static moduledata_t nvmf_transport_mod = {
429aa1207eaSJohn Baldwin 	"nvmf_transport",
430aa1207eaSJohn Baldwin 	nvmf_transport_modevent,
431aa1207eaSJohn Baldwin 	0
432aa1207eaSJohn Baldwin };
433aa1207eaSJohn Baldwin 
434aa1207eaSJohn Baldwin DECLARE_MODULE(nvmf_transport, nvmf_transport_mod, SI_SUB_DRIVERS,
435aa1207eaSJohn Baldwin     SI_ORDER_FIRST);
436aa1207eaSJohn Baldwin MODULE_VERSION(nvmf_transport, 1);
437