xref: /freebsd-src/sys/dev/nvmf/host/nvmf.c (revision 8bba2c0f8958443790b1f3abc0675719da987e87)
1a1eda741SJohn Baldwin /*-
2a1eda741SJohn Baldwin  * SPDX-License-Identifier: BSD-2-Clause
3a1eda741SJohn Baldwin  *
4a1eda741SJohn Baldwin  * Copyright (c) 2023-2024 Chelsio Communications, Inc.
5a1eda741SJohn Baldwin  * Written by: John Baldwin <jhb@FreeBSD.org>
6a1eda741SJohn Baldwin  */
7a1eda741SJohn Baldwin 
8a1eda741SJohn Baldwin #include <sys/param.h>
9a1eda741SJohn Baldwin #include <sys/bus.h>
10a1eda741SJohn Baldwin #include <sys/conf.h>
11365b89e8SJohn Baldwin #include <sys/dnv.h>
12f46d4971SJohn Baldwin #include <sys/eventhandler.h>
13a1eda741SJohn Baldwin #include <sys/lock.h>
14a1eda741SJohn Baldwin #include <sys/kernel.h>
15a1eda741SJohn Baldwin #include <sys/malloc.h>
16a1eda741SJohn Baldwin #include <sys/memdesc.h>
17a1eda741SJohn Baldwin #include <sys/module.h>
18a1eda741SJohn Baldwin #include <sys/mutex.h>
19365b89e8SJohn Baldwin #include <sys/nv.h>
20f46d4971SJohn Baldwin #include <sys/reboot.h>
21a1eda741SJohn Baldwin #include <sys/sx.h>
22aacaeeeeSJohn Baldwin #include <sys/sysctl.h>
23a1eda741SJohn Baldwin #include <sys/taskqueue.h>
24a1eda741SJohn Baldwin #include <dev/nvme/nvme.h>
25a1eda741SJohn Baldwin #include <dev/nvmf/nvmf.h>
26a1eda741SJohn Baldwin #include <dev/nvmf/nvmf_transport.h>
27a1eda741SJohn Baldwin #include <dev/nvmf/host/nvmf_var.h>
28a1eda741SJohn Baldwin 
29a1eda741SJohn Baldwin static struct cdevsw nvmf_cdevsw;
30a1eda741SJohn Baldwin 
31aacaeeeeSJohn Baldwin bool nvmf_fail_disconnect = false;
32aacaeeeeSJohn Baldwin SYSCTL_BOOL(_kern_nvmf, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN,
33aacaeeeeSJohn Baldwin     &nvmf_fail_disconnect, 0, "Fail I/O requests on connection failure");
34aacaeeeeSJohn Baldwin 
35a1eda741SJohn Baldwin MALLOC_DEFINE(M_NVMF, "nvmf", "NVMe over Fabrics host");
36a1eda741SJohn Baldwin 
37a1eda741SJohn Baldwin static void	nvmf_disconnect_task(void *arg, int pending);
38f46d4971SJohn Baldwin static void	nvmf_shutdown_pre_sync(void *arg, int howto);
39f46d4971SJohn Baldwin static void	nvmf_shutdown_post_sync(void *arg, int howto);
40a1eda741SJohn Baldwin 
41a1eda741SJohn Baldwin void
42a1eda741SJohn Baldwin nvmf_complete(void *arg, const struct nvme_completion *cqe)
43a1eda741SJohn Baldwin {
44a1eda741SJohn Baldwin 	struct nvmf_completion_status *status = arg;
45a1eda741SJohn Baldwin 	struct mtx *mtx;
46a1eda741SJohn Baldwin 
47a1eda741SJohn Baldwin 	status->cqe = *cqe;
48a1eda741SJohn Baldwin 	mtx = mtx_pool_find(mtxpool_sleep, status);
49a1eda741SJohn Baldwin 	mtx_lock(mtx);
50a1eda741SJohn Baldwin 	status->done = true;
51a1eda741SJohn Baldwin 	mtx_unlock(mtx);
52a1eda741SJohn Baldwin 	wakeup(status);
53a1eda741SJohn Baldwin }
54a1eda741SJohn Baldwin 
55a1eda741SJohn Baldwin void
56a1eda741SJohn Baldwin nvmf_io_complete(void *arg, size_t xfered, int error)
57a1eda741SJohn Baldwin {
58a1eda741SJohn Baldwin 	struct nvmf_completion_status *status = arg;
59a1eda741SJohn Baldwin 	struct mtx *mtx;
60a1eda741SJohn Baldwin 
61a1eda741SJohn Baldwin 	status->io_error = error;
62a1eda741SJohn Baldwin 	mtx = mtx_pool_find(mtxpool_sleep, status);
63a1eda741SJohn Baldwin 	mtx_lock(mtx);
64a1eda741SJohn Baldwin 	status->io_done = true;
65a1eda741SJohn Baldwin 	mtx_unlock(mtx);
66a1eda741SJohn Baldwin 	wakeup(status);
67a1eda741SJohn Baldwin }
68a1eda741SJohn Baldwin 
69a1eda741SJohn Baldwin void
70a1eda741SJohn Baldwin nvmf_wait_for_reply(struct nvmf_completion_status *status)
71a1eda741SJohn Baldwin {
72a1eda741SJohn Baldwin 	struct mtx *mtx;
73a1eda741SJohn Baldwin 
74a1eda741SJohn Baldwin 	mtx = mtx_pool_find(mtxpool_sleep, status);
75a1eda741SJohn Baldwin 	mtx_lock(mtx);
76a1eda741SJohn Baldwin 	while (!status->done || !status->io_done)
77a1eda741SJohn Baldwin 		mtx_sleep(status, mtx, 0, "nvmfcmd", 0);
78a1eda741SJohn Baldwin 	mtx_unlock(mtx);
79a1eda741SJohn Baldwin }
80a1eda741SJohn Baldwin 
81a1eda741SJohn Baldwin static int
82a1eda741SJohn Baldwin nvmf_read_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size,
83a1eda741SJohn Baldwin     uint64_t *value)
84a1eda741SJohn Baldwin {
85a1eda741SJohn Baldwin 	const struct nvmf_fabric_prop_get_rsp *rsp;
86a1eda741SJohn Baldwin 	struct nvmf_completion_status status;
87a1eda741SJohn Baldwin 
88a1eda741SJohn Baldwin 	nvmf_status_init(&status);
89a1eda741SJohn Baldwin 	if (!nvmf_cmd_get_property(sc, offset, size, nvmf_complete, &status,
90a1eda741SJohn Baldwin 	    M_WAITOK))
91a1eda741SJohn Baldwin 		return (ECONNABORTED);
92a1eda741SJohn Baldwin 	nvmf_wait_for_reply(&status);
93a1eda741SJohn Baldwin 
94a1eda741SJohn Baldwin 	if (status.cqe.status != 0) {
95a1eda741SJohn Baldwin 		device_printf(sc->dev, "PROPERTY_GET failed, status %#x\n",
96a1eda741SJohn Baldwin 		    le16toh(status.cqe.status));
97a1eda741SJohn Baldwin 		return (EIO);
98a1eda741SJohn Baldwin 	}
99a1eda741SJohn Baldwin 
100a1eda741SJohn Baldwin 	rsp = (const struct nvmf_fabric_prop_get_rsp *)&status.cqe;
101a1eda741SJohn Baldwin 	if (size == 8)
102a1eda741SJohn Baldwin 		*value = le64toh(rsp->value.u64);
103a1eda741SJohn Baldwin 	else
104a1eda741SJohn Baldwin 		*value = le32toh(rsp->value.u32.low);
105a1eda741SJohn Baldwin 	return (0);
106a1eda741SJohn Baldwin }
107a1eda741SJohn Baldwin 
108a1eda741SJohn Baldwin static int
109a1eda741SJohn Baldwin nvmf_write_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size,
110a1eda741SJohn Baldwin     uint64_t value)
111a1eda741SJohn Baldwin {
112a1eda741SJohn Baldwin 	struct nvmf_completion_status status;
113a1eda741SJohn Baldwin 
114a1eda741SJohn Baldwin 	nvmf_status_init(&status);
115a1eda741SJohn Baldwin 	if (!nvmf_cmd_set_property(sc, offset, size, value, nvmf_complete, &status,
116a1eda741SJohn Baldwin 	    M_WAITOK))
117a1eda741SJohn Baldwin 		return (ECONNABORTED);
118a1eda741SJohn Baldwin 	nvmf_wait_for_reply(&status);
119a1eda741SJohn Baldwin 
120a1eda741SJohn Baldwin 	if (status.cqe.status != 0) {
121a1eda741SJohn Baldwin 		device_printf(sc->dev, "PROPERTY_SET failed, status %#x\n",
122a1eda741SJohn Baldwin 		    le16toh(status.cqe.status));
123a1eda741SJohn Baldwin 		return (EIO);
124a1eda741SJohn Baldwin 	}
125a1eda741SJohn Baldwin 	return (0);
126a1eda741SJohn Baldwin }
127a1eda741SJohn Baldwin 
128a1eda741SJohn Baldwin static void
129a1eda741SJohn Baldwin nvmf_shutdown_controller(struct nvmf_softc *sc)
130a1eda741SJohn Baldwin {
131a1eda741SJohn Baldwin 	uint64_t cc;
132a1eda741SJohn Baldwin 	int error;
133a1eda741SJohn Baldwin 
134a1eda741SJohn Baldwin 	error = nvmf_read_property(sc, NVMF_PROP_CC, 4, &cc);
135a1eda741SJohn Baldwin 	if (error != 0) {
136a1eda741SJohn Baldwin 		device_printf(sc->dev, "Failed to fetch CC for shutdown\n");
137a1eda741SJohn Baldwin 		return;
138a1eda741SJohn Baldwin 	}
139a1eda741SJohn Baldwin 
140a1eda741SJohn Baldwin 	cc |= NVMEF(NVME_CC_REG_SHN, NVME_SHN_NORMAL);
141a1eda741SJohn Baldwin 
142a1eda741SJohn Baldwin 	error = nvmf_write_property(sc, NVMF_PROP_CC, 4, cc);
143a1eda741SJohn Baldwin 	if (error != 0)
144a1eda741SJohn Baldwin 		device_printf(sc->dev,
145a1eda741SJohn Baldwin 		    "Failed to set CC to trigger shutdown\n");
146a1eda741SJohn Baldwin }
147a1eda741SJohn Baldwin 
148a1eda741SJohn Baldwin static void
149a1eda741SJohn Baldwin nvmf_check_keep_alive(void *arg)
150a1eda741SJohn Baldwin {
151a1eda741SJohn Baldwin 	struct nvmf_softc *sc = arg;
152a1eda741SJohn Baldwin 	int traffic;
153a1eda741SJohn Baldwin 
154a1eda741SJohn Baldwin 	traffic = atomic_readandclear_int(&sc->ka_active_rx_traffic);
155a1eda741SJohn Baldwin 	if (traffic == 0) {
156a1eda741SJohn Baldwin 		device_printf(sc->dev,
157a1eda741SJohn Baldwin 		    "disconnecting due to KeepAlive timeout\n");
158a1eda741SJohn Baldwin 		nvmf_disconnect(sc);
159a1eda741SJohn Baldwin 		return;
160a1eda741SJohn Baldwin 	}
161a1eda741SJohn Baldwin 
162a1eda741SJohn Baldwin 	callout_schedule_sbt(&sc->ka_rx_timer, sc->ka_rx_sbt, 0, C_HARDCLOCK);
163a1eda741SJohn Baldwin }
164a1eda741SJohn Baldwin 
165a1eda741SJohn Baldwin static void
166a1eda741SJohn Baldwin nvmf_keep_alive_complete(void *arg, const struct nvme_completion *cqe)
167a1eda741SJohn Baldwin {
168a1eda741SJohn Baldwin 	struct nvmf_softc *sc = arg;
169a1eda741SJohn Baldwin 
170a1eda741SJohn Baldwin 	atomic_store_int(&sc->ka_active_rx_traffic, 1);
171a1eda741SJohn Baldwin 	if (cqe->status != 0) {
172a1eda741SJohn Baldwin 		device_printf(sc->dev,
173a1eda741SJohn Baldwin 		    "KeepAlive response reported status %#x\n",
174a1eda741SJohn Baldwin 		    le16toh(cqe->status));
175a1eda741SJohn Baldwin 	}
176a1eda741SJohn Baldwin }
177a1eda741SJohn Baldwin 
178a1eda741SJohn Baldwin static void
179a1eda741SJohn Baldwin nvmf_send_keep_alive(void *arg)
180a1eda741SJohn Baldwin {
181a1eda741SJohn Baldwin 	struct nvmf_softc *sc = arg;
182a1eda741SJohn Baldwin 	int traffic;
183a1eda741SJohn Baldwin 
184a1eda741SJohn Baldwin 	/*
185a1eda741SJohn Baldwin 	 * Don't bother sending a KeepAlive command if TKAS is active
186a1eda741SJohn Baldwin 	 * and another command has been sent during the interval.
187a1eda741SJohn Baldwin 	 */
188a1eda741SJohn Baldwin 	traffic = atomic_load_int(&sc->ka_active_tx_traffic);
189a1eda741SJohn Baldwin 	if (traffic == 0 && !nvmf_cmd_keep_alive(sc, nvmf_keep_alive_complete,
190a1eda741SJohn Baldwin 	    sc, M_NOWAIT))
191a1eda741SJohn Baldwin 		device_printf(sc->dev,
192a1eda741SJohn Baldwin 		    "Failed to allocate KeepAlive command\n");
193a1eda741SJohn Baldwin 
194a1eda741SJohn Baldwin 	/* Clear ka_active_tx_traffic after sending the keep alive command. */
195a1eda741SJohn Baldwin 	atomic_store_int(&sc->ka_active_tx_traffic, 0);
196a1eda741SJohn Baldwin 
197a1eda741SJohn Baldwin 	callout_schedule_sbt(&sc->ka_tx_timer, sc->ka_tx_sbt, 0, C_HARDCLOCK);
198a1eda741SJohn Baldwin }
199a1eda741SJohn Baldwin 
200a1eda741SJohn Baldwin int
201365b89e8SJohn Baldwin nvmf_copyin_handoff(const struct nvmf_ioc_nv *nv, nvlist_t **nvlp)
202a1eda741SJohn Baldwin {
203*8bba2c0fSJohn Baldwin 	const struct nvme_discovery_log_entry *dle;
204*8bba2c0fSJohn Baldwin 	const struct nvme_controller_data *cdata;
205365b89e8SJohn Baldwin 	const nvlist_t *const *io;
206*8bba2c0fSJohn Baldwin 	const nvlist_t *admin, *rparams;
207365b89e8SJohn Baldwin 	nvlist_t *nvl;
208365b89e8SJohn Baldwin 	size_t i, num_io_queues;
209365b89e8SJohn Baldwin 	uint32_t qsize;
210a1eda741SJohn Baldwin 	int error;
211a1eda741SJohn Baldwin 
212365b89e8SJohn Baldwin 	error = nvmf_unpack_ioc_nvlist(nv, &nvl);
213a1eda741SJohn Baldwin 	if (error != 0)
214365b89e8SJohn Baldwin 		return (error);
215a1eda741SJohn Baldwin 
216365b89e8SJohn Baldwin 	if (!nvlist_exists_number(nvl, "trtype") ||
217365b89e8SJohn Baldwin 	    !nvlist_exists_nvlist(nvl, "admin") ||
218365b89e8SJohn Baldwin 	    !nvlist_exists_nvlist_array(nvl, "io") ||
219*8bba2c0fSJohn Baldwin 	    !nvlist_exists_binary(nvl, "cdata") ||
220*8bba2c0fSJohn Baldwin 	    !nvlist_exists_nvlist(nvl, "rparams"))
221*8bba2c0fSJohn Baldwin 		goto invalid;
222*8bba2c0fSJohn Baldwin 
223*8bba2c0fSJohn Baldwin 	rparams = nvlist_get_nvlist(nvl, "rparams");
224*8bba2c0fSJohn Baldwin 	if (!nvlist_exists_binary(rparams, "dle") ||
225*8bba2c0fSJohn Baldwin 	    !nvlist_exists_string(rparams, "hostnqn") ||
226*8bba2c0fSJohn Baldwin 	    !nvlist_exists_number(rparams, "num_io_queues") ||
227*8bba2c0fSJohn Baldwin 	    !nvlist_exists_number(rparams, "io_qsize"))
228365b89e8SJohn Baldwin 		goto invalid;
229365b89e8SJohn Baldwin 
230365b89e8SJohn Baldwin 	admin = nvlist_get_nvlist(nvl, "admin");
231365b89e8SJohn Baldwin 	if (!nvmf_validate_qpair_nvlist(admin, false))
232365b89e8SJohn Baldwin 		goto invalid;
233365b89e8SJohn Baldwin 	if (!nvlist_get_bool(admin, "admin"))
234365b89e8SJohn Baldwin 		goto invalid;
235365b89e8SJohn Baldwin 
236365b89e8SJohn Baldwin 	io = nvlist_get_nvlist_array(nvl, "io", &num_io_queues);
237*8bba2c0fSJohn Baldwin 	if (num_io_queues < 1 ||
238*8bba2c0fSJohn Baldwin 	    num_io_queues != nvlist_get_number(rparams, "num_io_queues"))
239365b89e8SJohn Baldwin 		goto invalid;
240365b89e8SJohn Baldwin 	for (i = 0; i < num_io_queues; i++) {
241365b89e8SJohn Baldwin 		if (!nvmf_validate_qpair_nvlist(io[i], false))
242365b89e8SJohn Baldwin 			goto invalid;
243a1eda741SJohn Baldwin 	}
244a1eda741SJohn Baldwin 
245a1eda741SJohn Baldwin 	/* Require all I/O queues to be the same size. */
246*8bba2c0fSJohn Baldwin 	qsize = nvlist_get_number(rparams, "io_qsize");
247*8bba2c0fSJohn Baldwin 	for (i = 0; i < num_io_queues; i++) {
248365b89e8SJohn Baldwin 		if (nvlist_get_number(io[i], "qsize") != qsize)
249365b89e8SJohn Baldwin 			goto invalid;
250a1eda741SJohn Baldwin 	}
251a1eda741SJohn Baldwin 
252*8bba2c0fSJohn Baldwin 	cdata = nvlist_get_binary(nvl, "cdata", &i);
253*8bba2c0fSJohn Baldwin 	if (i != sizeof(*cdata))
254*8bba2c0fSJohn Baldwin 		goto invalid;
255*8bba2c0fSJohn Baldwin 	dle = nvlist_get_binary(rparams, "dle", &i);
256*8bba2c0fSJohn Baldwin 	if (i != sizeof(*dle))
257*8bba2c0fSJohn Baldwin 		goto invalid;
258*8bba2c0fSJohn Baldwin 
259*8bba2c0fSJohn Baldwin 	if (memcmp(dle->subnqn, cdata->subnqn, sizeof(cdata->subnqn)) != 0)
260365b89e8SJohn Baldwin 		goto invalid;
261365b89e8SJohn Baldwin 
262365b89e8SJohn Baldwin 	*nvlp = nvl;
263a1eda741SJohn Baldwin 	return (0);
264365b89e8SJohn Baldwin invalid:
265365b89e8SJohn Baldwin 	nvlist_destroy(nvl);
266365b89e8SJohn Baldwin 	return (EINVAL);
267a1eda741SJohn Baldwin }
268a1eda741SJohn Baldwin 
269a1eda741SJohn Baldwin static int
270a1eda741SJohn Baldwin nvmf_probe(device_t dev)
271a1eda741SJohn Baldwin {
272365b89e8SJohn Baldwin 	const nvlist_t *nvl = device_get_ivars(dev);
273365b89e8SJohn Baldwin 	const struct nvme_controller_data *cdata;
274a1eda741SJohn Baldwin 
275365b89e8SJohn Baldwin 	if (nvl == NULL)
276a1eda741SJohn Baldwin 		return (ENXIO);
277a1eda741SJohn Baldwin 
278365b89e8SJohn Baldwin 	cdata = nvlist_get_binary(nvl, "cdata", NULL);
279365b89e8SJohn Baldwin 	device_set_descf(dev, "Fabrics: %.256s", cdata->subnqn);
280a1eda741SJohn Baldwin 	return (BUS_PROBE_DEFAULT);
281a1eda741SJohn Baldwin }
282a1eda741SJohn Baldwin 
283a1eda741SJohn Baldwin static int
284*8bba2c0fSJohn Baldwin nvmf_establish_connection(struct nvmf_softc *sc, nvlist_t *nvl)
285a1eda741SJohn Baldwin {
286365b89e8SJohn Baldwin 	const nvlist_t *const *io;
287365b89e8SJohn Baldwin 	const nvlist_t *admin;
288365b89e8SJohn Baldwin 	uint64_t kato;
289365b89e8SJohn Baldwin 	size_t num_io_queues;
290365b89e8SJohn Baldwin 	enum nvmf_trtype trtype;
291a1eda741SJohn Baldwin 	char name[16];
292a1eda741SJohn Baldwin 
293365b89e8SJohn Baldwin 	trtype = nvlist_get_number(nvl, "trtype");
294365b89e8SJohn Baldwin 	admin = nvlist_get_nvlist(nvl, "admin");
295365b89e8SJohn Baldwin 	io = nvlist_get_nvlist_array(nvl, "io", &num_io_queues);
296365b89e8SJohn Baldwin 	kato = dnvlist_get_number(nvl, "kato", 0);
297365b89e8SJohn Baldwin 
298a1eda741SJohn Baldwin 	/* Setup the admin queue. */
299365b89e8SJohn Baldwin 	sc->admin = nvmf_init_qp(sc, trtype, admin, "admin queue", 0);
300a1eda741SJohn Baldwin 	if (sc->admin == NULL) {
301a1eda741SJohn Baldwin 		device_printf(sc->dev, "Failed to setup admin queue\n");
302a1eda741SJohn Baldwin 		return (ENXIO);
303a1eda741SJohn Baldwin 	}
304a1eda741SJohn Baldwin 
305a1eda741SJohn Baldwin 	/* Setup I/O queues. */
306365b89e8SJohn Baldwin 	sc->io = malloc(num_io_queues * sizeof(*sc->io), M_NVMF,
307a1eda741SJohn Baldwin 	    M_WAITOK | M_ZERO);
308365b89e8SJohn Baldwin 	sc->num_io_queues = num_io_queues;
309a1eda741SJohn Baldwin 	for (u_int i = 0; i < sc->num_io_queues; i++) {
310a1eda741SJohn Baldwin 		snprintf(name, sizeof(name), "I/O queue %u", i);
311365b89e8SJohn Baldwin 		sc->io[i] = nvmf_init_qp(sc, trtype, io[i], name, i);
312a1eda741SJohn Baldwin 		if (sc->io[i] == NULL) {
313a1eda741SJohn Baldwin 			device_printf(sc->dev, "Failed to setup I/O queue %u\n",
314*8bba2c0fSJohn Baldwin 			    i);
315a1eda741SJohn Baldwin 			return (ENXIO);
316a1eda741SJohn Baldwin 		}
317a1eda741SJohn Baldwin 	}
318a1eda741SJohn Baldwin 
319a1eda741SJohn Baldwin 	/* Start KeepAlive timers. */
320365b89e8SJohn Baldwin 	if (kato != 0) {
321a1eda741SJohn Baldwin 		sc->ka_traffic = NVMEV(NVME_CTRLR_DATA_CTRATT_TBKAS,
322a1eda741SJohn Baldwin 		    sc->cdata->ctratt) != 0;
323365b89e8SJohn Baldwin 		sc->ka_rx_sbt = mstosbt(kato);
324a1eda741SJohn Baldwin 		sc->ka_tx_sbt = sc->ka_rx_sbt / 2;
325a1eda741SJohn Baldwin 		callout_reset_sbt(&sc->ka_rx_timer, sc->ka_rx_sbt, 0,
326a1eda741SJohn Baldwin 		    nvmf_check_keep_alive, sc, C_HARDCLOCK);
327a1eda741SJohn Baldwin 		callout_reset_sbt(&sc->ka_tx_timer, sc->ka_tx_sbt, 0,
328a1eda741SJohn Baldwin 		    nvmf_send_keep_alive, sc, C_HARDCLOCK);
329a1eda741SJohn Baldwin 	}
330a1eda741SJohn Baldwin 
331365b89e8SJohn Baldwin 	memcpy(sc->cdata, nvlist_get_binary(nvl, "cdata", NULL),
332365b89e8SJohn Baldwin 	    sizeof(*sc->cdata));
333365b89e8SJohn Baldwin 
334*8bba2c0fSJohn Baldwin 	/* Save reconnect parameters. */
335*8bba2c0fSJohn Baldwin 	nvlist_destroy(sc->rparams);
336*8bba2c0fSJohn Baldwin 	sc->rparams = nvlist_take_nvlist(nvl, "rparams");
337*8bba2c0fSJohn Baldwin 
338a1eda741SJohn Baldwin 	return (0);
339a1eda741SJohn Baldwin }
340a1eda741SJohn Baldwin 
34102ddb305SJohn Baldwin typedef bool nvmf_scan_active_ns_cb(struct nvmf_softc *, uint32_t,
34202ddb305SJohn Baldwin     const struct nvme_namespace_data *, void *);
34302ddb305SJohn Baldwin 
344a1eda741SJohn Baldwin static bool
34502ddb305SJohn Baldwin nvmf_scan_active_nslist(struct nvmf_softc *sc, struct nvme_ns_list *nslist,
34602ddb305SJohn Baldwin     struct nvme_namespace_data *data, uint32_t *nsidp,
34702ddb305SJohn Baldwin     nvmf_scan_active_ns_cb *cb, void *cb_arg)
348a1eda741SJohn Baldwin {
349a1eda741SJohn Baldwin 	struct nvmf_completion_status status;
350a1eda741SJohn Baldwin 	uint32_t nsid;
351a1eda741SJohn Baldwin 
352a1eda741SJohn Baldwin 	nvmf_status_init(&status);
353a1eda741SJohn Baldwin 	nvmf_status_wait_io(&status);
354a1eda741SJohn Baldwin 	if (!nvmf_cmd_identify_active_namespaces(sc, *nsidp, nslist,
355a1eda741SJohn Baldwin 	    nvmf_complete, &status, nvmf_io_complete, &status, M_WAITOK)) {
356a1eda741SJohn Baldwin 		device_printf(sc->dev,
357a1eda741SJohn Baldwin 		    "failed to send IDENTIFY active namespaces command\n");
358a1eda741SJohn Baldwin 		return (false);
359a1eda741SJohn Baldwin 	}
360a1eda741SJohn Baldwin 	nvmf_wait_for_reply(&status);
361a1eda741SJohn Baldwin 
362a1eda741SJohn Baldwin 	if (status.cqe.status != 0) {
363a1eda741SJohn Baldwin 		device_printf(sc->dev,
364a1eda741SJohn Baldwin 		    "IDENTIFY active namespaces failed, status %#x\n",
365a1eda741SJohn Baldwin 		    le16toh(status.cqe.status));
366a1eda741SJohn Baldwin 		return (false);
367a1eda741SJohn Baldwin 	}
368a1eda741SJohn Baldwin 
369a1eda741SJohn Baldwin 	if (status.io_error != 0) {
370a1eda741SJohn Baldwin 		device_printf(sc->dev,
371a1eda741SJohn Baldwin 		    "IDENTIFY active namespaces failed with I/O error %d\n",
372a1eda741SJohn Baldwin 		    status.io_error);
373a1eda741SJohn Baldwin 		return (false);
374a1eda741SJohn Baldwin 	}
375a1eda741SJohn Baldwin 
376a1eda741SJohn Baldwin 	for (u_int i = 0; i < nitems(nslist->ns); i++) {
377a1eda741SJohn Baldwin 		nsid = nslist->ns[i];
378a1eda741SJohn Baldwin 		if (nsid == 0) {
379a1eda741SJohn Baldwin 			*nsidp = 0;
380a1eda741SJohn Baldwin 			return (true);
381a1eda741SJohn Baldwin 		}
382a1eda741SJohn Baldwin 
383a1eda741SJohn Baldwin 		nvmf_status_init(&status);
384a1eda741SJohn Baldwin 		nvmf_status_wait_io(&status);
385a1eda741SJohn Baldwin 		if (!nvmf_cmd_identify_namespace(sc, nsid, data, nvmf_complete,
386a1eda741SJohn Baldwin 		    &status, nvmf_io_complete, &status, M_WAITOK)) {
387a1eda741SJohn Baldwin 			device_printf(sc->dev,
388a1eda741SJohn Baldwin 			    "failed to send IDENTIFY namespace %u command\n",
389a1eda741SJohn Baldwin 			    nsid);
390a1eda741SJohn Baldwin 			return (false);
391a1eda741SJohn Baldwin 		}
392a1eda741SJohn Baldwin 		nvmf_wait_for_reply(&status);
393a1eda741SJohn Baldwin 
394a1eda741SJohn Baldwin 		if (status.cqe.status != 0) {
395a1eda741SJohn Baldwin 			device_printf(sc->dev,
396a1eda741SJohn Baldwin 			    "IDENTIFY namespace %u failed, status %#x\n", nsid,
397a1eda741SJohn Baldwin 			    le16toh(status.cqe.status));
398a1eda741SJohn Baldwin 			return (false);
399a1eda741SJohn Baldwin 		}
400a1eda741SJohn Baldwin 
401a1eda741SJohn Baldwin 		if (status.io_error != 0) {
402a1eda741SJohn Baldwin 			device_printf(sc->dev,
403a1eda741SJohn Baldwin 			    "IDENTIFY namespace %u failed with I/O error %d\n",
404a1eda741SJohn Baldwin 			    nsid, status.io_error);
405a1eda741SJohn Baldwin 			return (false);
406a1eda741SJohn Baldwin 		}
407a1eda741SJohn Baldwin 
408a1eda741SJohn Baldwin 		nvme_namespace_data_swapbytes(data);
40902ddb305SJohn Baldwin 		if (!cb(sc, nsid, data, cb_arg))
41002ddb305SJohn Baldwin 			return (false);
411a1eda741SJohn Baldwin 	}
412a1eda741SJohn Baldwin 
413a1eda741SJohn Baldwin 	MPASS(nsid == nslist->ns[nitems(nslist->ns) - 1] && nsid != 0);
414a1eda741SJohn Baldwin 
4158922c5b8SJohn Baldwin 	if (nsid >= NVME_GLOBAL_NAMESPACE_TAG - 1)
416a1eda741SJohn Baldwin 		*nsidp = 0;
417a1eda741SJohn Baldwin 	else
4188922c5b8SJohn Baldwin 		*nsidp = nsid;
419a1eda741SJohn Baldwin 	return (true);
420a1eda741SJohn Baldwin }
421a1eda741SJohn Baldwin 
422a1eda741SJohn Baldwin static bool
42302ddb305SJohn Baldwin nvmf_scan_active_namespaces(struct nvmf_softc *sc, nvmf_scan_active_ns_cb *cb,
42402ddb305SJohn Baldwin     void *cb_arg)
425a1eda741SJohn Baldwin {
426a1eda741SJohn Baldwin 	struct nvme_namespace_data *data;
427a1eda741SJohn Baldwin 	struct nvme_ns_list *nslist;
428a1eda741SJohn Baldwin 	uint32_t nsid;
429a1eda741SJohn Baldwin 	bool retval;
430a1eda741SJohn Baldwin 
431a1eda741SJohn Baldwin 	nslist = malloc(sizeof(*nslist), M_NVMF, M_WAITOK);
432a1eda741SJohn Baldwin 	data = malloc(sizeof(*data), M_NVMF, M_WAITOK);
433a1eda741SJohn Baldwin 
434a1eda741SJohn Baldwin 	nsid = 0;
435a1eda741SJohn Baldwin 	retval = true;
436a1eda741SJohn Baldwin 	for (;;) {
43702ddb305SJohn Baldwin 		if (!nvmf_scan_active_nslist(sc, nslist, data, &nsid, cb,
43802ddb305SJohn Baldwin 		    cb_arg)) {
439a1eda741SJohn Baldwin 			retval = false;
440a1eda741SJohn Baldwin 			break;
441a1eda741SJohn Baldwin 		}
442a1eda741SJohn Baldwin 		if (nsid == 0)
443a1eda741SJohn Baldwin 			break;
444a1eda741SJohn Baldwin 	}
445a1eda741SJohn Baldwin 
446a1eda741SJohn Baldwin 	free(data, M_NVMF);
447a1eda741SJohn Baldwin 	free(nslist, M_NVMF);
448a1eda741SJohn Baldwin 	return (retval);
449a1eda741SJohn Baldwin }
450a1eda741SJohn Baldwin 
45102ddb305SJohn Baldwin static bool
45202ddb305SJohn Baldwin nvmf_add_ns(struct nvmf_softc *sc, uint32_t nsid,
45302ddb305SJohn Baldwin     const struct nvme_namespace_data *data, void *arg __unused)
45402ddb305SJohn Baldwin {
45502ddb305SJohn Baldwin 	if (sc->ns[nsid - 1] != NULL) {
45602ddb305SJohn Baldwin 		device_printf(sc->dev,
45702ddb305SJohn Baldwin 		    "duplicate namespace %u in active namespace list\n",
45802ddb305SJohn Baldwin 		    nsid);
45902ddb305SJohn Baldwin 		return (false);
46002ddb305SJohn Baldwin 	}
46102ddb305SJohn Baldwin 
46202ddb305SJohn Baldwin 	/*
46302ddb305SJohn Baldwin 	 * As in nvme_ns_construct, a size of zero indicates an
46402ddb305SJohn Baldwin 	 * invalid namespace.
46502ddb305SJohn Baldwin 	 */
46602ddb305SJohn Baldwin 	if (data->nsze == 0) {
46702ddb305SJohn Baldwin 		device_printf(sc->dev,
46802ddb305SJohn Baldwin 		    "ignoring active namespace %u with zero size\n", nsid);
46902ddb305SJohn Baldwin 		return (true);
47002ddb305SJohn Baldwin 	}
47102ddb305SJohn Baldwin 
47202ddb305SJohn Baldwin 	sc->ns[nsid - 1] = nvmf_init_ns(sc, nsid, data);
47302ddb305SJohn Baldwin 
47402ddb305SJohn Baldwin 	nvmf_sim_rescan_ns(sc, nsid);
47502ddb305SJohn Baldwin 	return (true);
47602ddb305SJohn Baldwin }
47702ddb305SJohn Baldwin 
47802ddb305SJohn Baldwin static bool
47902ddb305SJohn Baldwin nvmf_add_namespaces(struct nvmf_softc *sc)
48002ddb305SJohn Baldwin {
48102ddb305SJohn Baldwin 	sc->ns = mallocarray(sc->cdata->nn, sizeof(*sc->ns), M_NVMF,
48202ddb305SJohn Baldwin 	    M_WAITOK | M_ZERO);
48302ddb305SJohn Baldwin 	return (nvmf_scan_active_namespaces(sc, nvmf_add_ns, NULL));
48402ddb305SJohn Baldwin }
48502ddb305SJohn Baldwin 
486a1eda741SJohn Baldwin static int
487a1eda741SJohn Baldwin nvmf_attach(device_t dev)
488a1eda741SJohn Baldwin {
489a1eda741SJohn Baldwin 	struct make_dev_args mda;
490a1eda741SJohn Baldwin 	struct nvmf_softc *sc = device_get_softc(dev);
491*8bba2c0fSJohn Baldwin 	nvlist_t *nvl = device_get_ivars(dev);
492365b89e8SJohn Baldwin 	const nvlist_t * const *io;
493931dd5feSJohn Baldwin 	struct sysctl_oid *oid;
494a1eda741SJohn Baldwin 	uint64_t val;
495a1eda741SJohn Baldwin 	u_int i;
496a1eda741SJohn Baldwin 	int error;
497a1eda741SJohn Baldwin 
498365b89e8SJohn Baldwin 	if (nvl == NULL)
499a1eda741SJohn Baldwin 		return (ENXIO);
500a1eda741SJohn Baldwin 
501a1eda741SJohn Baldwin 	sc->dev = dev;
502365b89e8SJohn Baldwin 	sc->trtype = nvlist_get_number(nvl, "trtype");
503a1eda741SJohn Baldwin 	callout_init(&sc->ka_rx_timer, 1);
504a1eda741SJohn Baldwin 	callout_init(&sc->ka_tx_timer, 1);
505a1eda741SJohn Baldwin 	sx_init(&sc->connection_lock, "nvmf connection");
506a1eda741SJohn Baldwin 	TASK_INIT(&sc->disconnect_task, 0, nvmf_disconnect_task, sc);
507a1eda741SJohn Baldwin 
508931dd5feSJohn Baldwin 	oid = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev),
509931dd5feSJohn Baldwin 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "ioq",
510931dd5feSJohn Baldwin 	    CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "I/O Queues");
511931dd5feSJohn Baldwin 	sc->ioq_oid_list = SYSCTL_CHILDREN(oid);
512931dd5feSJohn Baldwin 
513365b89e8SJohn Baldwin 	sc->cdata = malloc(sizeof(*sc->cdata), M_NVMF, M_WAITOK);
514a1eda741SJohn Baldwin 
515a1eda741SJohn Baldwin 	nvmf_init_aer(sc);
516a1eda741SJohn Baldwin 
517365b89e8SJohn Baldwin 	error = nvmf_establish_connection(sc, nvl);
518a1eda741SJohn Baldwin 	if (error != 0)
519a1eda741SJohn Baldwin 		goto out;
520a1eda741SJohn Baldwin 
521a1eda741SJohn Baldwin 	error = nvmf_read_property(sc, NVMF_PROP_CAP, 8, &sc->cap);
522a1eda741SJohn Baldwin 	if (error != 0) {
523a1eda741SJohn Baldwin 		device_printf(sc->dev, "Failed to fetch CAP\n");
524a1eda741SJohn Baldwin 		error = ENXIO;
525a1eda741SJohn Baldwin 		goto out;
526a1eda741SJohn Baldwin 	}
527a1eda741SJohn Baldwin 
528a1eda741SJohn Baldwin 	error = nvmf_read_property(sc, NVMF_PROP_VS, 4, &val);
529a1eda741SJohn Baldwin 	if (error != 0) {
530a1eda741SJohn Baldwin 		device_printf(sc->dev, "Failed to fetch VS\n");
531a1eda741SJohn Baldwin 		error = ENXIO;
532a1eda741SJohn Baldwin 		goto out;
533a1eda741SJohn Baldwin 	}
534a1eda741SJohn Baldwin 	sc->vs = val;
535a1eda741SJohn Baldwin 
536a1eda741SJohn Baldwin 	/* Honor MDTS if it is set. */
537a1eda741SJohn Baldwin 	sc->max_xfer_size = maxphys;
538a1eda741SJohn Baldwin 	if (sc->cdata->mdts != 0) {
539a1eda741SJohn Baldwin 		sc->max_xfer_size = ulmin(sc->max_xfer_size,
540a1eda741SJohn Baldwin 		    1 << (sc->cdata->mdts + NVME_MPS_SHIFT +
541a1eda741SJohn Baldwin 		    NVME_CAP_HI_MPSMIN(sc->cap >> 32)));
542a1eda741SJohn Baldwin 	}
543a1eda741SJohn Baldwin 
544365b89e8SJohn Baldwin 	io = nvlist_get_nvlist_array(nvl, "io", NULL);
545365b89e8SJohn Baldwin 	sc->max_pending_io = nvlist_get_number(io[0], "qsize") *
546365b89e8SJohn Baldwin 	    sc->num_io_queues;
5473ff90d91SJohn Baldwin 
548a1eda741SJohn Baldwin 	error = nvmf_init_sim(sc);
549a1eda741SJohn Baldwin 	if (error != 0)
550a1eda741SJohn Baldwin 		goto out;
551a1eda741SJohn Baldwin 
552a1eda741SJohn Baldwin 	error = nvmf_start_aer(sc);
553a1eda741SJohn Baldwin 	if (error != 0) {
554a1eda741SJohn Baldwin 		nvmf_destroy_sim(sc);
555a1eda741SJohn Baldwin 		goto out;
556a1eda741SJohn Baldwin 	}
557a1eda741SJohn Baldwin 
558a1eda741SJohn Baldwin 	if (!nvmf_add_namespaces(sc)) {
559a1eda741SJohn Baldwin 		nvmf_destroy_sim(sc);
560a1eda741SJohn Baldwin 		goto out;
561a1eda741SJohn Baldwin 	}
562a1eda741SJohn Baldwin 
563a1eda741SJohn Baldwin 	make_dev_args_init(&mda);
564a1eda741SJohn Baldwin 	mda.mda_devsw = &nvmf_cdevsw;
565a1eda741SJohn Baldwin 	mda.mda_uid = UID_ROOT;
566a1eda741SJohn Baldwin 	mda.mda_gid = GID_WHEEL;
567a1eda741SJohn Baldwin 	mda.mda_mode = 0600;
568a1eda741SJohn Baldwin 	mda.mda_si_drv1 = sc;
569a1eda741SJohn Baldwin 	error = make_dev_s(&mda, &sc->cdev, "%s", device_get_nameunit(dev));
570a1eda741SJohn Baldwin 	if (error != 0) {
571a1eda741SJohn Baldwin 		nvmf_destroy_sim(sc);
572a1eda741SJohn Baldwin 		goto out;
573a1eda741SJohn Baldwin 	}
574a1eda741SJohn Baldwin 
575f46d4971SJohn Baldwin 	sc->shutdown_pre_sync_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync,
576f46d4971SJohn Baldwin 	    nvmf_shutdown_pre_sync, sc, SHUTDOWN_PRI_FIRST);
577f46d4971SJohn Baldwin 	sc->shutdown_post_sync_eh = EVENTHANDLER_REGISTER(shutdown_post_sync,
5786751f65eSJohn Baldwin 	    nvmf_shutdown_post_sync, sc, SHUTDOWN_PRI_LAST);
579f46d4971SJohn Baldwin 
580a1eda741SJohn Baldwin 	return (0);
581a1eda741SJohn Baldwin out:
582a1eda741SJohn Baldwin 	if (sc->ns != NULL) {
583a1eda741SJohn Baldwin 		for (i = 0; i < sc->cdata->nn; i++) {
584a1eda741SJohn Baldwin 			if (sc->ns[i] != NULL)
585a1eda741SJohn Baldwin 				nvmf_destroy_ns(sc->ns[i]);
586a1eda741SJohn Baldwin 		}
587a1eda741SJohn Baldwin 		free(sc->ns, M_NVMF);
588a1eda741SJohn Baldwin 	}
589a1eda741SJohn Baldwin 
590a1eda741SJohn Baldwin 	callout_drain(&sc->ka_tx_timer);
591a1eda741SJohn Baldwin 	callout_drain(&sc->ka_rx_timer);
592a1eda741SJohn Baldwin 
593a1eda741SJohn Baldwin 	if (sc->admin != NULL)
594a1eda741SJohn Baldwin 		nvmf_shutdown_controller(sc);
595a1eda741SJohn Baldwin 
596a1eda741SJohn Baldwin 	for (i = 0; i < sc->num_io_queues; i++) {
597a1eda741SJohn Baldwin 		if (sc->io[i] != NULL)
598a1eda741SJohn Baldwin 			nvmf_destroy_qp(sc->io[i]);
599a1eda741SJohn Baldwin 	}
600a1eda741SJohn Baldwin 	free(sc->io, M_NVMF);
601a1eda741SJohn Baldwin 	if (sc->admin != NULL)
602a1eda741SJohn Baldwin 		nvmf_destroy_qp(sc->admin);
603a1eda741SJohn Baldwin 
604a1eda741SJohn Baldwin 	nvmf_destroy_aer(sc);
605a1eda741SJohn Baldwin 
606a1eda741SJohn Baldwin 	taskqueue_drain(taskqueue_thread, &sc->disconnect_task);
607a1eda741SJohn Baldwin 	sx_destroy(&sc->connection_lock);
608*8bba2c0fSJohn Baldwin 	nvlist_destroy(sc->rparams);
609a1eda741SJohn Baldwin 	free(sc->cdata, M_NVMF);
610a1eda741SJohn Baldwin 	return (error);
611a1eda741SJohn Baldwin }
612a1eda741SJohn Baldwin 
613a1eda741SJohn Baldwin void
614a1eda741SJohn Baldwin nvmf_disconnect(struct nvmf_softc *sc)
615a1eda741SJohn Baldwin {
616a1eda741SJohn Baldwin 	taskqueue_enqueue(taskqueue_thread, &sc->disconnect_task);
617a1eda741SJohn Baldwin }
618a1eda741SJohn Baldwin 
619a1eda741SJohn Baldwin static void
620a1eda741SJohn Baldwin nvmf_disconnect_task(void *arg, int pending __unused)
621a1eda741SJohn Baldwin {
622a1eda741SJohn Baldwin 	struct nvmf_softc *sc = arg;
623a1eda741SJohn Baldwin 	u_int i;
624a1eda741SJohn Baldwin 
625a1eda741SJohn Baldwin 	sx_xlock(&sc->connection_lock);
626a1eda741SJohn Baldwin 	if (sc->admin == NULL) {
627a1eda741SJohn Baldwin 		/*
628a1eda741SJohn Baldwin 		 * Ignore transport errors if there is no active
629a1eda741SJohn Baldwin 		 * association.
630a1eda741SJohn Baldwin 		 */
631a1eda741SJohn Baldwin 		sx_xunlock(&sc->connection_lock);
632a1eda741SJohn Baldwin 		return;
633a1eda741SJohn Baldwin 	}
634a1eda741SJohn Baldwin 
635a1eda741SJohn Baldwin 	if (sc->detaching) {
636a1eda741SJohn Baldwin 		if (sc->admin != NULL) {
637a1eda741SJohn Baldwin 			/*
638a1eda741SJohn Baldwin 			 * This unsticks the detach process if a
639a1eda741SJohn Baldwin 			 * transport error occurs during detach.
640a1eda741SJohn Baldwin 			 */
641a1eda741SJohn Baldwin 			nvmf_shutdown_qp(sc->admin);
642a1eda741SJohn Baldwin 		}
643a1eda741SJohn Baldwin 		sx_xunlock(&sc->connection_lock);
644a1eda741SJohn Baldwin 		return;
645a1eda741SJohn Baldwin 	}
646a1eda741SJohn Baldwin 
647a1eda741SJohn Baldwin 	if (sc->cdev == NULL) {
648a1eda741SJohn Baldwin 		/*
649a1eda741SJohn Baldwin 		 * Transport error occurred during attach (nvmf_add_namespaces).
650a1eda741SJohn Baldwin 		 * Shutdown the admin queue.
651a1eda741SJohn Baldwin 		 */
652a1eda741SJohn Baldwin 		nvmf_shutdown_qp(sc->admin);
653a1eda741SJohn Baldwin 		sx_xunlock(&sc->connection_lock);
654a1eda741SJohn Baldwin 		return;
655a1eda741SJohn Baldwin 	}
656a1eda741SJohn Baldwin 
657a1eda741SJohn Baldwin 	callout_drain(&sc->ka_tx_timer);
658a1eda741SJohn Baldwin 	callout_drain(&sc->ka_rx_timer);
659a1eda741SJohn Baldwin 	sc->ka_traffic = false;
660a1eda741SJohn Baldwin 
661a1eda741SJohn Baldwin 	/* Quiesce namespace consumers. */
662a1eda741SJohn Baldwin 	nvmf_disconnect_sim(sc);
663a1eda741SJohn Baldwin 	for (i = 0; i < sc->cdata->nn; i++) {
664a1eda741SJohn Baldwin 		if (sc->ns[i] != NULL)
665a1eda741SJohn Baldwin 			nvmf_disconnect_ns(sc->ns[i]);
666a1eda741SJohn Baldwin 	}
667a1eda741SJohn Baldwin 
668a1eda741SJohn Baldwin 	/* Shutdown the existing qpairs. */
669a1eda741SJohn Baldwin 	for (i = 0; i < sc->num_io_queues; i++) {
670a1eda741SJohn Baldwin 		nvmf_destroy_qp(sc->io[i]);
671a1eda741SJohn Baldwin 	}
672a1eda741SJohn Baldwin 	free(sc->io, M_NVMF);
673a1eda741SJohn Baldwin 	sc->io = NULL;
674a1eda741SJohn Baldwin 	sc->num_io_queues = 0;
675a1eda741SJohn Baldwin 	nvmf_destroy_qp(sc->admin);
676a1eda741SJohn Baldwin 	sc->admin = NULL;
677a1eda741SJohn Baldwin 
678a1eda741SJohn Baldwin 	sx_xunlock(&sc->connection_lock);
679a1eda741SJohn Baldwin }
680a1eda741SJohn Baldwin 
681a1eda741SJohn Baldwin static int
682365b89e8SJohn Baldwin nvmf_reconnect_host(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv)
683a1eda741SJohn Baldwin {
684365b89e8SJohn Baldwin 	const struct nvme_controller_data *cdata;
685365b89e8SJohn Baldwin 	nvlist_t *nvl;
686a1eda741SJohn Baldwin 	u_int i;
687a1eda741SJohn Baldwin 	int error;
688a1eda741SJohn Baldwin 
689365b89e8SJohn Baldwin 	error = nvmf_copyin_handoff(nv, &nvl);
690365b89e8SJohn Baldwin 	if (error != 0)
691365b89e8SJohn Baldwin 		return (error);
692365b89e8SJohn Baldwin 
693a1eda741SJohn Baldwin 	/* XXX: Should we permit changing the transport type? */
694365b89e8SJohn Baldwin 	if (sc->trtype != nvlist_get_number(nvl, "trtype")) {
695a1eda741SJohn Baldwin 		device_printf(sc->dev,
696a1eda741SJohn Baldwin 		    "transport type mismatch on reconnect\n");
697a1eda741SJohn Baldwin 		return (EINVAL);
698a1eda741SJohn Baldwin 	}
699a1eda741SJohn Baldwin 
700a1eda741SJohn Baldwin 	sx_xlock(&sc->connection_lock);
701a1eda741SJohn Baldwin 	if (sc->admin != NULL || sc->detaching) {
702a1eda741SJohn Baldwin 		error = EBUSY;
703a1eda741SJohn Baldwin 		goto out;
704a1eda741SJohn Baldwin 	}
705a1eda741SJohn Baldwin 
706a1eda741SJohn Baldwin 	/*
707a1eda741SJohn Baldwin 	 * Ensure this is for the same controller.  Note that the
708a1eda741SJohn Baldwin 	 * controller ID can vary across associations if the remote
709a1eda741SJohn Baldwin 	 * system is using the dynamic controller model.  This merely
710a1eda741SJohn Baldwin 	 * ensures the new association is connected to the same NVMe
711a1eda741SJohn Baldwin 	 * subsystem.
712a1eda741SJohn Baldwin 	 */
713365b89e8SJohn Baldwin 	cdata = nvlist_get_binary(nvl, "cdata", NULL);
714365b89e8SJohn Baldwin 	if (memcmp(sc->cdata->subnqn, cdata->subnqn,
715365b89e8SJohn Baldwin 	    sizeof(cdata->subnqn)) != 0) {
716a1eda741SJohn Baldwin 		device_printf(sc->dev,
717a1eda741SJohn Baldwin 		    "controller subsystem NQN mismatch on reconnect\n");
718a1eda741SJohn Baldwin 		error = EINVAL;
719a1eda741SJohn Baldwin 		goto out;
720a1eda741SJohn Baldwin 	}
721a1eda741SJohn Baldwin 
722a1eda741SJohn Baldwin 	/*
723a1eda741SJohn Baldwin 	 * XXX: Require same number and size of I/O queues so that
724a1eda741SJohn Baldwin 	 * max_pending_io is still correct?
725a1eda741SJohn Baldwin 	 */
726a1eda741SJohn Baldwin 
727365b89e8SJohn Baldwin 	error = nvmf_establish_connection(sc, nvl);
728a1eda741SJohn Baldwin 	if (error != 0)
729a1eda741SJohn Baldwin 		goto out;
730a1eda741SJohn Baldwin 
731a1eda741SJohn Baldwin 	error = nvmf_start_aer(sc);
732a1eda741SJohn Baldwin 	if (error != 0)
733a1eda741SJohn Baldwin 		goto out;
734a1eda741SJohn Baldwin 
735a1eda741SJohn Baldwin 	device_printf(sc->dev,
736a1eda741SJohn Baldwin 	    "established new association with %u I/O queues\n",
737a1eda741SJohn Baldwin 	    sc->num_io_queues);
738a1eda741SJohn Baldwin 
739a1eda741SJohn Baldwin 	/* Restart namespace consumers. */
740a1eda741SJohn Baldwin 	for (i = 0; i < sc->cdata->nn; i++) {
741a1eda741SJohn Baldwin 		if (sc->ns[i] != NULL)
742a1eda741SJohn Baldwin 			nvmf_reconnect_ns(sc->ns[i]);
743a1eda741SJohn Baldwin 	}
744a1eda741SJohn Baldwin 	nvmf_reconnect_sim(sc);
745e140f85dSJohn Baldwin 
746e140f85dSJohn Baldwin 	nvmf_rescan_all_ns(sc);
747a1eda741SJohn Baldwin out:
748a1eda741SJohn Baldwin 	sx_xunlock(&sc->connection_lock);
749365b89e8SJohn Baldwin 	nvlist_destroy(nvl);
750a1eda741SJohn Baldwin 	return (error);
751a1eda741SJohn Baldwin }
752a1eda741SJohn Baldwin 
753f46d4971SJohn Baldwin static void
754f46d4971SJohn Baldwin nvmf_shutdown_pre_sync(void *arg, int howto)
755f46d4971SJohn Baldwin {
756f46d4971SJohn Baldwin 	struct nvmf_softc *sc = arg;
757f46d4971SJohn Baldwin 
758f46d4971SJohn Baldwin 	if ((howto & RB_NOSYNC) != 0 || SCHEDULER_STOPPED())
759f46d4971SJohn Baldwin 		return;
760f46d4971SJohn Baldwin 
761f46d4971SJohn Baldwin 	/*
762f46d4971SJohn Baldwin 	 * If this association is disconnected, abort any pending
763f46d4971SJohn Baldwin 	 * requests with an error to permit filesystems to unmount
764f46d4971SJohn Baldwin 	 * without hanging.
765f46d4971SJohn Baldwin 	 */
766f46d4971SJohn Baldwin 	sx_xlock(&sc->connection_lock);
767f46d4971SJohn Baldwin 	if (sc->admin != NULL || sc->detaching) {
768f46d4971SJohn Baldwin 		sx_xunlock(&sc->connection_lock);
769f46d4971SJohn Baldwin 		return;
770f46d4971SJohn Baldwin 	}
771f46d4971SJohn Baldwin 
772f46d4971SJohn Baldwin 	for (u_int i = 0; i < sc->cdata->nn; i++) {
773f46d4971SJohn Baldwin 		if (sc->ns[i] != NULL)
774f46d4971SJohn Baldwin 			nvmf_shutdown_ns(sc->ns[i]);
775f46d4971SJohn Baldwin 	}
776f46d4971SJohn Baldwin 	nvmf_shutdown_sim(sc);
777f46d4971SJohn Baldwin 	sx_xunlock(&sc->connection_lock);
778f46d4971SJohn Baldwin }
779f46d4971SJohn Baldwin 
780f46d4971SJohn Baldwin static void
781f46d4971SJohn Baldwin nvmf_shutdown_post_sync(void *arg, int howto)
782f46d4971SJohn Baldwin {
783f46d4971SJohn Baldwin 	struct nvmf_softc *sc = arg;
784f46d4971SJohn Baldwin 
785f46d4971SJohn Baldwin 	if ((howto & RB_NOSYNC) != 0 || SCHEDULER_STOPPED())
786f46d4971SJohn Baldwin 		return;
787f46d4971SJohn Baldwin 
788f46d4971SJohn Baldwin 	/*
789f46d4971SJohn Baldwin 	 * If this association is connected, disconnect gracefully.
790f46d4971SJohn Baldwin 	 */
791f46d4971SJohn Baldwin 	sx_xlock(&sc->connection_lock);
792f46d4971SJohn Baldwin 	if (sc->admin == NULL || sc->detaching) {
793f46d4971SJohn Baldwin 		sx_xunlock(&sc->connection_lock);
794f46d4971SJohn Baldwin 		return;
795f46d4971SJohn Baldwin 	}
796f46d4971SJohn Baldwin 
797f46d4971SJohn Baldwin 	callout_drain(&sc->ka_tx_timer);
798f46d4971SJohn Baldwin 	callout_drain(&sc->ka_rx_timer);
799f46d4971SJohn Baldwin 
800f46d4971SJohn Baldwin 	nvmf_shutdown_controller(sc);
8016751f65eSJohn Baldwin 
8026751f65eSJohn Baldwin 	/*
8036751f65eSJohn Baldwin 	 * Quiesce consumers so that any commands submitted after this
8046751f65eSJohn Baldwin 	 * fail with an error.  Notably, nda(4) calls nda_flush() from
8056751f65eSJohn Baldwin 	 * a post_sync handler that might be ordered after this one.
8066751f65eSJohn Baldwin 	 */
8076751f65eSJohn Baldwin 	for (u_int i = 0; i < sc->cdata->nn; i++) {
8086751f65eSJohn Baldwin 		if (sc->ns[i] != NULL)
8096751f65eSJohn Baldwin 			nvmf_shutdown_ns(sc->ns[i]);
8106751f65eSJohn Baldwin 	}
8116751f65eSJohn Baldwin 	nvmf_shutdown_sim(sc);
8126751f65eSJohn Baldwin 
813f46d4971SJohn Baldwin 	for (u_int i = 0; i < sc->num_io_queues; i++) {
814f46d4971SJohn Baldwin 		nvmf_destroy_qp(sc->io[i]);
815f46d4971SJohn Baldwin 	}
816f46d4971SJohn Baldwin 	nvmf_destroy_qp(sc->admin);
817f46d4971SJohn Baldwin 	sc->admin = NULL;
818f46d4971SJohn Baldwin 	sx_xunlock(&sc->connection_lock);
819f46d4971SJohn Baldwin }
820f46d4971SJohn Baldwin 
821a1eda741SJohn Baldwin static int
822a1eda741SJohn Baldwin nvmf_detach(device_t dev)
823a1eda741SJohn Baldwin {
824a1eda741SJohn Baldwin 	struct nvmf_softc *sc = device_get_softc(dev);
825a1eda741SJohn Baldwin 	u_int i;
826a1eda741SJohn Baldwin 
827a1eda741SJohn Baldwin 	destroy_dev(sc->cdev);
828a1eda741SJohn Baldwin 
829a1eda741SJohn Baldwin 	sx_xlock(&sc->connection_lock);
830a1eda741SJohn Baldwin 	sc->detaching = true;
831a1eda741SJohn Baldwin 	sx_xunlock(&sc->connection_lock);
832a1eda741SJohn Baldwin 
833f46d4971SJohn Baldwin 	EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->shutdown_pre_sync_eh);
834a6ec2147SJohn Baldwin 	EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->shutdown_post_sync_eh);
835f46d4971SJohn Baldwin 
836a1eda741SJohn Baldwin 	nvmf_destroy_sim(sc);
837a1eda741SJohn Baldwin 	for (i = 0; i < sc->cdata->nn; i++) {
838a1eda741SJohn Baldwin 		if (sc->ns[i] != NULL)
839a1eda741SJohn Baldwin 			nvmf_destroy_ns(sc->ns[i]);
840a1eda741SJohn Baldwin 	}
841a1eda741SJohn Baldwin 	free(sc->ns, M_NVMF);
842a1eda741SJohn Baldwin 
843a1eda741SJohn Baldwin 	callout_drain(&sc->ka_tx_timer);
844a1eda741SJohn Baldwin 	callout_drain(&sc->ka_rx_timer);
845a1eda741SJohn Baldwin 
846a1eda741SJohn Baldwin 	if (sc->admin != NULL)
847a1eda741SJohn Baldwin 		nvmf_shutdown_controller(sc);
848a1eda741SJohn Baldwin 
849a1eda741SJohn Baldwin 	for (i = 0; i < sc->num_io_queues; i++) {
850a1eda741SJohn Baldwin 		nvmf_destroy_qp(sc->io[i]);
851a1eda741SJohn Baldwin 	}
852a1eda741SJohn Baldwin 	free(sc->io, M_NVMF);
853a1eda741SJohn Baldwin 
854a1eda741SJohn Baldwin 	taskqueue_drain(taskqueue_thread, &sc->disconnect_task);
855a1eda741SJohn Baldwin 
856a1eda741SJohn Baldwin 	if (sc->admin != NULL)
857a1eda741SJohn Baldwin 		nvmf_destroy_qp(sc->admin);
858a1eda741SJohn Baldwin 
859a1eda741SJohn Baldwin 	nvmf_destroy_aer(sc);
860a1eda741SJohn Baldwin 
861a1eda741SJohn Baldwin 	sx_destroy(&sc->connection_lock);
862*8bba2c0fSJohn Baldwin 	nvlist_destroy(sc->rparams);
863a1eda741SJohn Baldwin 	free(sc->cdata, M_NVMF);
864a1eda741SJohn Baldwin 	return (0);
865a1eda741SJohn Baldwin }
866a1eda741SJohn Baldwin 
8678a082ca8SJohn Baldwin static void
8688a082ca8SJohn Baldwin nvmf_rescan_ns_1(struct nvmf_softc *sc, uint32_t nsid,
8698a082ca8SJohn Baldwin     const struct nvme_namespace_data *data)
8708a082ca8SJohn Baldwin {
8718a082ca8SJohn Baldwin 	struct nvmf_namespace *ns;
8728a082ca8SJohn Baldwin 
8738a082ca8SJohn Baldwin 	/* XXX: Needs locking around sc->ns[]. */
8748a082ca8SJohn Baldwin 	ns = sc->ns[nsid - 1];
8758a082ca8SJohn Baldwin 	if (data->nsze == 0) {
8768a082ca8SJohn Baldwin 		/* XXX: Needs locking */
8778a082ca8SJohn Baldwin 		if (ns != NULL) {
8788a082ca8SJohn Baldwin 			nvmf_destroy_ns(ns);
8798a082ca8SJohn Baldwin 			sc->ns[nsid - 1] = NULL;
8808a082ca8SJohn Baldwin 		}
8818a082ca8SJohn Baldwin 	} else {
8828a082ca8SJohn Baldwin 		/* XXX: Needs locking */
8838a082ca8SJohn Baldwin 		if (ns == NULL) {
8848a082ca8SJohn Baldwin 			sc->ns[nsid - 1] = nvmf_init_ns(sc, nsid, data);
8858a082ca8SJohn Baldwin 		} else {
8868a082ca8SJohn Baldwin 			if (!nvmf_update_ns(ns, data)) {
8878a082ca8SJohn Baldwin 				nvmf_destroy_ns(ns);
8888a082ca8SJohn Baldwin 				sc->ns[nsid - 1] = NULL;
8898a082ca8SJohn Baldwin 			}
8908a082ca8SJohn Baldwin 		}
8918a082ca8SJohn Baldwin 	}
8928a082ca8SJohn Baldwin 
8938a082ca8SJohn Baldwin 	nvmf_sim_rescan_ns(sc, nsid);
8948a082ca8SJohn Baldwin }
8958a082ca8SJohn Baldwin 
896a1eda741SJohn Baldwin void
897a1eda741SJohn Baldwin nvmf_rescan_ns(struct nvmf_softc *sc, uint32_t nsid)
898a1eda741SJohn Baldwin {
899a1eda741SJohn Baldwin 	struct nvmf_completion_status status;
900a1eda741SJohn Baldwin 	struct nvme_namespace_data *data;
901a1eda741SJohn Baldwin 
902a1eda741SJohn Baldwin 	data = malloc(sizeof(*data), M_NVMF, M_WAITOK);
903a1eda741SJohn Baldwin 
904a1eda741SJohn Baldwin 	nvmf_status_init(&status);
905a1eda741SJohn Baldwin 	nvmf_status_wait_io(&status);
906a1eda741SJohn Baldwin 	if (!nvmf_cmd_identify_namespace(sc, nsid, data, nvmf_complete,
907a1eda741SJohn Baldwin 	    &status, nvmf_io_complete, &status, M_WAITOK)) {
908a1eda741SJohn Baldwin 		device_printf(sc->dev,
909a1eda741SJohn Baldwin 		    "failed to send IDENTIFY namespace %u command\n", nsid);
910a1eda741SJohn Baldwin 		free(data, M_NVMF);
911a1eda741SJohn Baldwin 		return;
912a1eda741SJohn Baldwin 	}
913a1eda741SJohn Baldwin 	nvmf_wait_for_reply(&status);
914a1eda741SJohn Baldwin 
915a1eda741SJohn Baldwin 	if (status.cqe.status != 0) {
916a1eda741SJohn Baldwin 		device_printf(sc->dev,
917a1eda741SJohn Baldwin 		    "IDENTIFY namespace %u failed, status %#x\n", nsid,
918a1eda741SJohn Baldwin 		    le16toh(status.cqe.status));
919a1eda741SJohn Baldwin 		free(data, M_NVMF);
920a1eda741SJohn Baldwin 		return;
921a1eda741SJohn Baldwin 	}
922a1eda741SJohn Baldwin 
923a1eda741SJohn Baldwin 	if (status.io_error != 0) {
924a1eda741SJohn Baldwin 		device_printf(sc->dev,
925a1eda741SJohn Baldwin 		    "IDENTIFY namespace %u failed with I/O error %d\n",
926a1eda741SJohn Baldwin 		    nsid, status.io_error);
927a1eda741SJohn Baldwin 		free(data, M_NVMF);
928a1eda741SJohn Baldwin 		return;
929a1eda741SJohn Baldwin 	}
930a1eda741SJohn Baldwin 
931a1eda741SJohn Baldwin 	nvme_namespace_data_swapbytes(data);
932a1eda741SJohn Baldwin 
9338a082ca8SJohn Baldwin 	nvmf_rescan_ns_1(sc, nsid, data);
934a1eda741SJohn Baldwin 
935a1eda741SJohn Baldwin 	free(data, M_NVMF);
936a1eda741SJohn Baldwin }
937a1eda741SJohn Baldwin 
938f6d434f1SJohn Baldwin static void
939f6d434f1SJohn Baldwin nvmf_purge_namespaces(struct nvmf_softc *sc, uint32_t first_nsid,
940f6d434f1SJohn Baldwin     uint32_t next_valid_nsid)
941f6d434f1SJohn Baldwin {
942f6d434f1SJohn Baldwin 	struct nvmf_namespace *ns;
943f6d434f1SJohn Baldwin 
944f6d434f1SJohn Baldwin 	for (uint32_t nsid = first_nsid; nsid < next_valid_nsid; nsid++)
945f6d434f1SJohn Baldwin 	{
946f6d434f1SJohn Baldwin 		/* XXX: Needs locking around sc->ns[]. */
947f6d434f1SJohn Baldwin 		ns = sc->ns[nsid - 1];
948f6d434f1SJohn Baldwin 		if (ns != NULL) {
949f6d434f1SJohn Baldwin 			nvmf_destroy_ns(ns);
950f6d434f1SJohn Baldwin 			sc->ns[nsid - 1] = NULL;
951f6d434f1SJohn Baldwin 
952f6d434f1SJohn Baldwin 			nvmf_sim_rescan_ns(sc, nsid);
953f6d434f1SJohn Baldwin 		}
954f6d434f1SJohn Baldwin 	}
955f6d434f1SJohn Baldwin }
956f6d434f1SJohn Baldwin 
957f6d434f1SJohn Baldwin static bool
958f6d434f1SJohn Baldwin nvmf_rescan_ns_cb(struct nvmf_softc *sc, uint32_t nsid,
959f6d434f1SJohn Baldwin     const struct nvme_namespace_data *data, void *arg)
960f6d434f1SJohn Baldwin {
961f6d434f1SJohn Baldwin 	uint32_t *last_nsid = arg;
962f6d434f1SJohn Baldwin 
963f6d434f1SJohn Baldwin 	/* Check for any gaps prior to this namespace. */
964f6d434f1SJohn Baldwin 	nvmf_purge_namespaces(sc, *last_nsid + 1, nsid);
965f6d434f1SJohn Baldwin 	*last_nsid = nsid;
966f6d434f1SJohn Baldwin 
967f6d434f1SJohn Baldwin 	nvmf_rescan_ns_1(sc, nsid, data);
968f6d434f1SJohn Baldwin 	return (true);
969f6d434f1SJohn Baldwin }
970f6d434f1SJohn Baldwin 
971f6d434f1SJohn Baldwin void
972f6d434f1SJohn Baldwin nvmf_rescan_all_ns(struct nvmf_softc *sc)
973f6d434f1SJohn Baldwin {
974f6d434f1SJohn Baldwin 	uint32_t last_nsid;
975f6d434f1SJohn Baldwin 
976f6d434f1SJohn Baldwin 	last_nsid = 0;
977f6d434f1SJohn Baldwin 	if (!nvmf_scan_active_namespaces(sc, nvmf_rescan_ns_cb, &last_nsid))
978f6d434f1SJohn Baldwin 		return;
979f6d434f1SJohn Baldwin 
980f6d434f1SJohn Baldwin 	/*
981f6d434f1SJohn Baldwin 	 * Check for any namespace devices after the last active
982f6d434f1SJohn Baldwin 	 * namespace.
983f6d434f1SJohn Baldwin 	 */
984f6d434f1SJohn Baldwin 	nvmf_purge_namespaces(sc, last_nsid + 1, sc->cdata->nn + 1);
985f6d434f1SJohn Baldwin }
986f6d434f1SJohn Baldwin 
987a1eda741SJohn Baldwin int
988a1eda741SJohn Baldwin nvmf_passthrough_cmd(struct nvmf_softc *sc, struct nvme_pt_command *pt,
989a1eda741SJohn Baldwin     bool admin)
990a1eda741SJohn Baldwin {
991a1eda741SJohn Baldwin 	struct nvmf_completion_status status;
992a1eda741SJohn Baldwin 	struct nvme_command cmd;
993a1eda741SJohn Baldwin 	struct memdesc mem;
994a1eda741SJohn Baldwin 	struct nvmf_host_qpair *qp;
995a1eda741SJohn Baldwin 	struct nvmf_request *req;
996a1eda741SJohn Baldwin 	void *buf;
997a1eda741SJohn Baldwin 	int error;
998a1eda741SJohn Baldwin 
999a1eda741SJohn Baldwin 	if (pt->len > sc->max_xfer_size)
1000a1eda741SJohn Baldwin 		return (EINVAL);
1001a1eda741SJohn Baldwin 
1002a1eda741SJohn Baldwin 	buf = NULL;
1003a1eda741SJohn Baldwin 	if (pt->len != 0) {
1004a1eda741SJohn Baldwin 		/*
1005a1eda741SJohn Baldwin 		 * XXX: Depending on the size we may want to pin the
1006a1eda741SJohn Baldwin 		 * user pages and use a memdesc with vm_page_t's
1007a1eda741SJohn Baldwin 		 * instead.
1008a1eda741SJohn Baldwin 		 */
1009a1eda741SJohn Baldwin 		buf = malloc(pt->len, M_NVMF, M_WAITOK);
1010a1eda741SJohn Baldwin 		if (pt->is_read == 0) {
1011a1eda741SJohn Baldwin 			error = copyin(pt->buf, buf, pt->len);
1012a1eda741SJohn Baldwin 			if (error != 0) {
1013a1eda741SJohn Baldwin 				free(buf, M_NVMF);
1014a1eda741SJohn Baldwin 				return (error);
1015a1eda741SJohn Baldwin 			}
1016a1eda741SJohn Baldwin 		} else {
1017a1eda741SJohn Baldwin 			/* Ensure no kernel data is leaked to userland. */
1018a1eda741SJohn Baldwin 			memset(buf, 0, pt->len);
1019a1eda741SJohn Baldwin 		}
1020a1eda741SJohn Baldwin 	}
1021a1eda741SJohn Baldwin 
1022a1eda741SJohn Baldwin 	memset(&cmd, 0, sizeof(cmd));
1023a1eda741SJohn Baldwin 	cmd.opc = pt->cmd.opc;
1024a1eda741SJohn Baldwin 	cmd.fuse = pt->cmd.fuse;
1025a1eda741SJohn Baldwin 	cmd.nsid = pt->cmd.nsid;
1026a1eda741SJohn Baldwin 	cmd.cdw10 = pt->cmd.cdw10;
1027a1eda741SJohn Baldwin 	cmd.cdw11 = pt->cmd.cdw11;
1028a1eda741SJohn Baldwin 	cmd.cdw12 = pt->cmd.cdw12;
1029a1eda741SJohn Baldwin 	cmd.cdw13 = pt->cmd.cdw13;
1030a1eda741SJohn Baldwin 	cmd.cdw14 = pt->cmd.cdw14;
1031a1eda741SJohn Baldwin 	cmd.cdw15 = pt->cmd.cdw15;
1032a1eda741SJohn Baldwin 
1033d1516ec3SJohn Baldwin 	sx_slock(&sc->connection_lock);
1034d1516ec3SJohn Baldwin 	if (sc->admin == NULL || sc->detaching) {
1035d1516ec3SJohn Baldwin 		device_printf(sc->dev,
1036d1516ec3SJohn Baldwin 		    "failed to send passthrough command\n");
1037d1516ec3SJohn Baldwin 		error = ECONNABORTED;
1038d1516ec3SJohn Baldwin 		sx_sunlock(&sc->connection_lock);
1039d1516ec3SJohn Baldwin 		goto error;
1040d1516ec3SJohn Baldwin 	}
1041a1eda741SJohn Baldwin 	if (admin)
1042a1eda741SJohn Baldwin 		qp = sc->admin;
1043a1eda741SJohn Baldwin 	else
1044a1eda741SJohn Baldwin 		qp = nvmf_select_io_queue(sc);
1045a1eda741SJohn Baldwin 	nvmf_status_init(&status);
1046a1eda741SJohn Baldwin 	req = nvmf_allocate_request(qp, &cmd, nvmf_complete, &status, M_WAITOK);
1047d1516ec3SJohn Baldwin 	sx_sunlock(&sc->connection_lock);
1048a1eda741SJohn Baldwin 	if (req == NULL) {
1049a1eda741SJohn Baldwin 		device_printf(sc->dev, "failed to send passthrough command\n");
1050a1eda741SJohn Baldwin 		error = ECONNABORTED;
1051a1eda741SJohn Baldwin 		goto error;
1052a1eda741SJohn Baldwin 	}
1053a1eda741SJohn Baldwin 
1054a1eda741SJohn Baldwin 	if (pt->len != 0) {
1055a1eda741SJohn Baldwin 		mem = memdesc_vaddr(buf, pt->len);
1056a1eda741SJohn Baldwin 		nvmf_capsule_append_data(req->nc, &mem, pt->len,
1057a1eda741SJohn Baldwin 		    pt->is_read == 0, nvmf_io_complete, &status);
1058a1eda741SJohn Baldwin 		nvmf_status_wait_io(&status);
1059a1eda741SJohn Baldwin 	}
1060a1eda741SJohn Baldwin 
1061a1eda741SJohn Baldwin 	nvmf_submit_request(req);
1062a1eda741SJohn Baldwin 	nvmf_wait_for_reply(&status);
1063a1eda741SJohn Baldwin 
1064a1eda741SJohn Baldwin 	memset(&pt->cpl, 0, sizeof(pt->cpl));
1065a1eda741SJohn Baldwin 	pt->cpl.cdw0 = status.cqe.cdw0;
1066a1eda741SJohn Baldwin 	pt->cpl.status = status.cqe.status;
1067a1eda741SJohn Baldwin 
1068a1eda741SJohn Baldwin 	error = status.io_error;
1069a1eda741SJohn Baldwin 	if (error == 0 && pt->len != 0 && pt->is_read != 0)
1070a1eda741SJohn Baldwin 		error = copyout(buf, pt->buf, pt->len);
1071a1eda741SJohn Baldwin error:
1072a1eda741SJohn Baldwin 	free(buf, M_NVMF);
1073a1eda741SJohn Baldwin 	return (error);
1074a1eda741SJohn Baldwin }
1075a1eda741SJohn Baldwin 
1076a1eda741SJohn Baldwin static int
1077365b89e8SJohn Baldwin nvmf_reconnect_params(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv)
1078365b89e8SJohn Baldwin {
1079365b89e8SJohn Baldwin 	int error;
1080365b89e8SJohn Baldwin 
1081365b89e8SJohn Baldwin 	sx_slock(&sc->connection_lock);
1082*8bba2c0fSJohn Baldwin 	error = nvmf_pack_ioc_nvlist(sc->rparams, nv);
1083365b89e8SJohn Baldwin 	sx_sunlock(&sc->connection_lock);
1084365b89e8SJohn Baldwin 
1085365b89e8SJohn Baldwin 	return (error);
1086365b89e8SJohn Baldwin }
1087365b89e8SJohn Baldwin 
1088365b89e8SJohn Baldwin static int
1089a1eda741SJohn Baldwin nvmf_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag,
1090a1eda741SJohn Baldwin     struct thread *td)
1091a1eda741SJohn Baldwin {
1092a1eda741SJohn Baldwin 	struct nvmf_softc *sc = cdev->si_drv1;
1093a1eda741SJohn Baldwin 	struct nvme_get_nsid *gnsid;
1094a1eda741SJohn Baldwin 	struct nvme_pt_command *pt;
1095365b89e8SJohn Baldwin 	struct nvmf_ioc_nv *nv;
1096a1eda741SJohn Baldwin 
1097a1eda741SJohn Baldwin 	switch (cmd) {
1098a1eda741SJohn Baldwin 	case NVME_PASSTHROUGH_CMD:
1099a1eda741SJohn Baldwin 		pt = (struct nvme_pt_command *)arg;
1100a1eda741SJohn Baldwin 		return (nvmf_passthrough_cmd(sc, pt, true));
1101a1eda741SJohn Baldwin 	case NVME_GET_NSID:
1102a1eda741SJohn Baldwin 		gnsid = (struct nvme_get_nsid *)arg;
1103da4230afSJohn Baldwin 		strlcpy(gnsid->cdev, device_get_nameunit(sc->dev),
1104a1eda741SJohn Baldwin 		    sizeof(gnsid->cdev));
1105a1eda741SJohn Baldwin 		gnsid->nsid = 0;
1106a1eda741SJohn Baldwin 		return (0);
1107a1eda741SJohn Baldwin 	case NVME_GET_MAX_XFER_SIZE:
1108a1eda741SJohn Baldwin 		*(uint64_t *)arg = sc->max_xfer_size;
1109a1eda741SJohn Baldwin 		return (0);
1110a1eda741SJohn Baldwin 	case NVMF_RECONNECT_PARAMS:
1111365b89e8SJohn Baldwin 		nv = (struct nvmf_ioc_nv *)arg;
1112365b89e8SJohn Baldwin 		return (nvmf_reconnect_params(sc, nv));
1113a1eda741SJohn Baldwin 	case NVMF_RECONNECT_HOST:
1114365b89e8SJohn Baldwin 		nv = (struct nvmf_ioc_nv *)arg;
1115365b89e8SJohn Baldwin 		return (nvmf_reconnect_host(sc, nv));
1116a1eda741SJohn Baldwin 	default:
1117a1eda741SJohn Baldwin 		return (ENOTTY);
1118a1eda741SJohn Baldwin 	}
1119a1eda741SJohn Baldwin }
1120a1eda741SJohn Baldwin 
1121a1eda741SJohn Baldwin static struct cdevsw nvmf_cdevsw = {
1122a1eda741SJohn Baldwin 	.d_version = D_VERSION,
1123a1eda741SJohn Baldwin 	.d_ioctl = nvmf_ioctl
1124a1eda741SJohn Baldwin };
1125a1eda741SJohn Baldwin 
1126a1eda741SJohn Baldwin static int
1127a1eda741SJohn Baldwin nvmf_modevent(module_t mod, int what, void *arg)
1128a1eda741SJohn Baldwin {
1129a1eda741SJohn Baldwin 	switch (what) {
1130a1eda741SJohn Baldwin 	case MOD_LOAD:
1131a1eda741SJohn Baldwin 		return (nvmf_ctl_load());
1132a1eda741SJohn Baldwin 	case MOD_QUIESCE:
1133a1eda741SJohn Baldwin 		return (0);
1134a1eda741SJohn Baldwin 	case MOD_UNLOAD:
1135a1eda741SJohn Baldwin 		nvmf_ctl_unload();
1136a1eda741SJohn Baldwin 		destroy_dev_drain(&nvmf_cdevsw);
1137a1eda741SJohn Baldwin 		return (0);
1138a1eda741SJohn Baldwin 	default:
1139a1eda741SJohn Baldwin 		return (EOPNOTSUPP);
1140a1eda741SJohn Baldwin 	}
1141a1eda741SJohn Baldwin }
1142a1eda741SJohn Baldwin 
1143a1eda741SJohn Baldwin static device_method_t nvmf_methods[] = {
1144a1eda741SJohn Baldwin 	/* Device interface */
1145a1eda741SJohn Baldwin 	DEVMETHOD(device_probe,     nvmf_probe),
1146a1eda741SJohn Baldwin 	DEVMETHOD(device_attach,    nvmf_attach),
1147a1eda741SJohn Baldwin 	DEVMETHOD(device_detach,    nvmf_detach),
1148a1eda741SJohn Baldwin 	DEVMETHOD_END
1149a1eda741SJohn Baldwin };
1150a1eda741SJohn Baldwin 
1151a1eda741SJohn Baldwin driver_t nvme_nvmf_driver = {
1152a1eda741SJohn Baldwin 	"nvme",
1153a1eda741SJohn Baldwin 	nvmf_methods,
1154a1eda741SJohn Baldwin 	sizeof(struct nvmf_softc),
1155a1eda741SJohn Baldwin };
1156a1eda741SJohn Baldwin 
1157a1eda741SJohn Baldwin DRIVER_MODULE(nvme, root, nvme_nvmf_driver, nvmf_modevent, NULL);
1158a1eda741SJohn Baldwin MODULE_DEPEND(nvmf, nvmf_transport, 1, 1, 1);
1159