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/bio.h>
10a1eda741SJohn Baldwin #include <sys/bus.h>
11a1eda741SJohn Baldwin #include <sys/conf.h>
12a1eda741SJohn Baldwin #include <sys/disk.h>
13a1eda741SJohn Baldwin #include <sys/fcntl.h>
14a1eda741SJohn Baldwin #include <sys/lock.h>
15a1eda741SJohn Baldwin #include <sys/malloc.h>
16a1eda741SJohn Baldwin #include <sys/memdesc.h>
17a1eda741SJohn Baldwin #include <sys/mutex.h>
18a1eda741SJohn Baldwin #include <sys/proc.h>
19a1eda741SJohn Baldwin #include <sys/refcount.h>
20a1eda741SJohn Baldwin #include <sys/sbuf.h>
21a1eda741SJohn Baldwin #include <machine/stdarg.h>
22a1eda741SJohn Baldwin #include <dev/nvme/nvme.h>
23a1eda741SJohn Baldwin #include <dev/nvmf/host/nvmf_var.h>
24a1eda741SJohn Baldwin
25a1eda741SJohn Baldwin struct nvmf_namespace {
26a1eda741SJohn Baldwin struct nvmf_softc *sc;
27a1eda741SJohn Baldwin uint64_t size;
28a1eda741SJohn Baldwin uint32_t id;
29a1eda741SJohn Baldwin u_int flags;
30a1eda741SJohn Baldwin uint32_t lba_size;
31a1eda741SJohn Baldwin bool disconnected;
32*f46d4971SJohn Baldwin bool shutdown;
33a1eda741SJohn Baldwin
34a1eda741SJohn Baldwin TAILQ_HEAD(, bio) pending_bios;
35a1eda741SJohn Baldwin struct mtx lock;
36a1eda741SJohn Baldwin volatile u_int active_bios;
37a1eda741SJohn Baldwin
38a1eda741SJohn Baldwin struct cdev *cdev;
39a1eda741SJohn Baldwin };
40a1eda741SJohn Baldwin
41a1eda741SJohn Baldwin static void nvmf_ns_strategy(struct bio *bio);
42a1eda741SJohn Baldwin
43a1eda741SJohn Baldwin static void
ns_printf(struct nvmf_namespace * ns,const char * fmt,...)44a1eda741SJohn Baldwin ns_printf(struct nvmf_namespace *ns, const char *fmt, ...)
45a1eda741SJohn Baldwin {
46a1eda741SJohn Baldwin char buf[128];
47a1eda741SJohn Baldwin struct sbuf sb;
48a1eda741SJohn Baldwin va_list ap;
49a1eda741SJohn Baldwin
50a1eda741SJohn Baldwin sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
51a1eda741SJohn Baldwin sbuf_set_drain(&sb, sbuf_printf_drain, NULL);
52a1eda741SJohn Baldwin
53ce75bfcaSChuck Tuffli sbuf_printf(&sb, "%sn%u: ", device_get_nameunit(ns->sc->dev),
54a1eda741SJohn Baldwin ns->id);
55a1eda741SJohn Baldwin
56a1eda741SJohn Baldwin va_start(ap, fmt);
57a1eda741SJohn Baldwin sbuf_vprintf(&sb, fmt, ap);
58a1eda741SJohn Baldwin va_end(ap);
59a1eda741SJohn Baldwin
60a1eda741SJohn Baldwin sbuf_finish(&sb);
61a1eda741SJohn Baldwin sbuf_delete(&sb);
62a1eda741SJohn Baldwin }
63a1eda741SJohn Baldwin
64a1eda741SJohn Baldwin /*
65a1eda741SJohn Baldwin * The I/O completion may trigger after the received CQE if the I/O
66a1eda741SJohn Baldwin * used a zero-copy mbuf that isn't harvested until after the NIC
67a1eda741SJohn Baldwin * driver processes TX completions. Abuse bio_driver1 as a refcount.
68a1eda741SJohn Baldwin * Store I/O errors in bio_driver2.
69a1eda741SJohn Baldwin */
70a1eda741SJohn Baldwin static __inline u_int *
bio_refs(struct bio * bio)71a1eda741SJohn Baldwin bio_refs(struct bio *bio)
72a1eda741SJohn Baldwin {
73a1eda741SJohn Baldwin return ((u_int *)&bio->bio_driver1);
74a1eda741SJohn Baldwin }
75a1eda741SJohn Baldwin
76a1eda741SJohn Baldwin static void
nvmf_ns_biodone(struct bio * bio)77a1eda741SJohn Baldwin nvmf_ns_biodone(struct bio *bio)
78a1eda741SJohn Baldwin {
79a1eda741SJohn Baldwin struct nvmf_namespace *ns;
80a1eda741SJohn Baldwin int error;
81a1eda741SJohn Baldwin
82a1eda741SJohn Baldwin if (!refcount_release(bio_refs(bio)))
83a1eda741SJohn Baldwin return;
84a1eda741SJohn Baldwin
85a1eda741SJohn Baldwin ns = bio->bio_dev->si_drv1;
86a1eda741SJohn Baldwin
87a1eda741SJohn Baldwin /* If a request is aborted, resubmit or queue it for resubmission. */
88aacaeeeeSJohn Baldwin if (bio->bio_error == ECONNABORTED && !nvmf_fail_disconnect) {
89a1eda741SJohn Baldwin bio->bio_error = 0;
90a1eda741SJohn Baldwin bio->bio_driver2 = 0;
91a1eda741SJohn Baldwin mtx_lock(&ns->lock);
92a1eda741SJohn Baldwin if (ns->disconnected) {
93*f46d4971SJohn Baldwin if (nvmf_fail_disconnect || ns->shutdown) {
94a1eda741SJohn Baldwin mtx_unlock(&ns->lock);
95aacaeeeeSJohn Baldwin bio->bio_error = ECONNABORTED;
96aacaeeeeSJohn Baldwin bio->bio_flags |= BIO_ERROR;
97aacaeeeeSJohn Baldwin bio->bio_resid = bio->bio_bcount;
98aacaeeeeSJohn Baldwin biodone(bio);
99aacaeeeeSJohn Baldwin } else {
100aacaeeeeSJohn Baldwin TAILQ_INSERT_TAIL(&ns->pending_bios, bio,
101aacaeeeeSJohn Baldwin bio_queue);
102aacaeeeeSJohn Baldwin mtx_unlock(&ns->lock);
103aacaeeeeSJohn Baldwin }
104a1eda741SJohn Baldwin } else {
105a1eda741SJohn Baldwin mtx_unlock(&ns->lock);
106a1eda741SJohn Baldwin nvmf_ns_strategy(bio);
107a1eda741SJohn Baldwin }
108a1eda741SJohn Baldwin } else {
109a1eda741SJohn Baldwin /*
110a1eda741SJohn Baldwin * I/O errors take precedence over generic EIO from
111a1eda741SJohn Baldwin * CQE errors.
112a1eda741SJohn Baldwin */
113a1eda741SJohn Baldwin error = (intptr_t)bio->bio_driver2;
114a1eda741SJohn Baldwin if (error != 0)
115a1eda741SJohn Baldwin bio->bio_error = error;
116a1eda741SJohn Baldwin if (bio->bio_error != 0)
117a1eda741SJohn Baldwin bio->bio_flags |= BIO_ERROR;
118a1eda741SJohn Baldwin biodone(bio);
119a1eda741SJohn Baldwin }
120a1eda741SJohn Baldwin
121a1eda741SJohn Baldwin if (refcount_release(&ns->active_bios))
122a1eda741SJohn Baldwin wakeup(ns);
123a1eda741SJohn Baldwin }
124a1eda741SJohn Baldwin
125a1eda741SJohn Baldwin static void
nvmf_ns_io_complete(void * arg,size_t xfered,int error)126a1eda741SJohn Baldwin nvmf_ns_io_complete(void *arg, size_t xfered, int error)
127a1eda741SJohn Baldwin {
128a1eda741SJohn Baldwin struct bio *bio = arg;
129a1eda741SJohn Baldwin
130a1eda741SJohn Baldwin KASSERT(xfered <= bio->bio_bcount,
131a1eda741SJohn Baldwin ("%s: xfered > bio_bcount", __func__));
132a1eda741SJohn Baldwin
133a1eda741SJohn Baldwin bio->bio_driver2 = (void *)(intptr_t)error;
134a1eda741SJohn Baldwin bio->bio_resid = bio->bio_bcount - xfered;
135a1eda741SJohn Baldwin
136a1eda741SJohn Baldwin nvmf_ns_biodone(bio);
137a1eda741SJohn Baldwin }
138a1eda741SJohn Baldwin
139a1eda741SJohn Baldwin static void
nvmf_ns_delete_complete(void * arg,size_t xfered,int error)140a1eda741SJohn Baldwin nvmf_ns_delete_complete(void *arg, size_t xfered, int error)
141a1eda741SJohn Baldwin {
142a1eda741SJohn Baldwin struct bio *bio = arg;
143a1eda741SJohn Baldwin
144a1eda741SJohn Baldwin if (error != 0)
145a1eda741SJohn Baldwin bio->bio_resid = bio->bio_bcount;
146a1eda741SJohn Baldwin else
147a1eda741SJohn Baldwin bio->bio_resid = 0;
148a1eda741SJohn Baldwin
149a1eda741SJohn Baldwin free(bio->bio_driver2, M_NVMF);
150a1eda741SJohn Baldwin bio->bio_driver2 = (void *)(intptr_t)error;
151a1eda741SJohn Baldwin
152a1eda741SJohn Baldwin nvmf_ns_biodone(bio);
153a1eda741SJohn Baldwin }
154a1eda741SJohn Baldwin
155a1eda741SJohn Baldwin static void
nvmf_ns_bio_complete(void * arg,const struct nvme_completion * cqe)156a1eda741SJohn Baldwin nvmf_ns_bio_complete(void *arg, const struct nvme_completion *cqe)
157a1eda741SJohn Baldwin {
158a1eda741SJohn Baldwin struct bio *bio = arg;
159a1eda741SJohn Baldwin
160a1eda741SJohn Baldwin if (nvmf_cqe_aborted(cqe))
161a1eda741SJohn Baldwin bio->bio_error = ECONNABORTED;
162a1eda741SJohn Baldwin else if (cqe->status != 0)
163a1eda741SJohn Baldwin bio->bio_error = EIO;
164a1eda741SJohn Baldwin
165a1eda741SJohn Baldwin nvmf_ns_biodone(bio);
166a1eda741SJohn Baldwin }
167a1eda741SJohn Baldwin
168a1eda741SJohn Baldwin static int
nvmf_ns_submit_bio(struct nvmf_namespace * ns,struct bio * bio)169a1eda741SJohn Baldwin nvmf_ns_submit_bio(struct nvmf_namespace *ns, struct bio *bio)
170a1eda741SJohn Baldwin {
171a1eda741SJohn Baldwin struct nvme_command cmd;
172a1eda741SJohn Baldwin struct nvmf_request *req;
173a1eda741SJohn Baldwin struct nvme_dsm_range *dsm_range;
174a1eda741SJohn Baldwin struct memdesc mem;
175a1eda741SJohn Baldwin uint64_t lba, lba_count;
176aacaeeeeSJohn Baldwin int error;
177a1eda741SJohn Baldwin
178a1eda741SJohn Baldwin dsm_range = NULL;
179a1eda741SJohn Baldwin memset(&cmd, 0, sizeof(cmd));
180a1eda741SJohn Baldwin switch (bio->bio_cmd) {
181a1eda741SJohn Baldwin case BIO_READ:
182a1eda741SJohn Baldwin lba = bio->bio_offset / ns->lba_size;
183a1eda741SJohn Baldwin lba_count = bio->bio_bcount / ns->lba_size;
184a1eda741SJohn Baldwin nvme_ns_read_cmd(&cmd, ns->id, lba, lba_count);
185a1eda741SJohn Baldwin break;
186a1eda741SJohn Baldwin case BIO_WRITE:
187a1eda741SJohn Baldwin lba = bio->bio_offset / ns->lba_size;
188a1eda741SJohn Baldwin lba_count = bio->bio_bcount / ns->lba_size;
189a1eda741SJohn Baldwin nvme_ns_write_cmd(&cmd, ns->id, lba, lba_count);
190a1eda741SJohn Baldwin break;
191a1eda741SJohn Baldwin case BIO_FLUSH:
192a1eda741SJohn Baldwin nvme_ns_flush_cmd(&cmd, ns->id);
193a1eda741SJohn Baldwin break;
194a1eda741SJohn Baldwin case BIO_DELETE:
195a1eda741SJohn Baldwin dsm_range = malloc(sizeof(*dsm_range), M_NVMF, M_NOWAIT |
196a1eda741SJohn Baldwin M_ZERO);
197a1eda741SJohn Baldwin if (dsm_range == NULL)
198a1eda741SJohn Baldwin return (ENOMEM);
199a1eda741SJohn Baldwin lba = bio->bio_offset / ns->lba_size;
200a1eda741SJohn Baldwin lba_count = bio->bio_bcount / ns->lba_size;
201a1eda741SJohn Baldwin dsm_range->starting_lba = htole64(lba);
202a1eda741SJohn Baldwin dsm_range->length = htole32(lba_count);
203a1eda741SJohn Baldwin
204a1eda741SJohn Baldwin cmd.opc = NVME_OPC_DATASET_MANAGEMENT;
205a1eda741SJohn Baldwin cmd.nsid = htole32(ns->id);
206a1eda741SJohn Baldwin cmd.cdw10 = htole32(0); /* 1 range */
207a1eda741SJohn Baldwin cmd.cdw11 = htole32(NVME_DSM_ATTR_DEALLOCATE);
208a1eda741SJohn Baldwin break;
209a1eda741SJohn Baldwin default:
210a1eda741SJohn Baldwin return (EOPNOTSUPP);
211a1eda741SJohn Baldwin }
212a1eda741SJohn Baldwin
213a1eda741SJohn Baldwin mtx_lock(&ns->lock);
214a1eda741SJohn Baldwin if (ns->disconnected) {
215*f46d4971SJohn Baldwin if (nvmf_fail_disconnect || ns->shutdown) {
216aacaeeeeSJohn Baldwin error = ECONNABORTED;
217aacaeeeeSJohn Baldwin } else {
218a1eda741SJohn Baldwin TAILQ_INSERT_TAIL(&ns->pending_bios, bio, bio_queue);
219aacaeeeeSJohn Baldwin error = 0;
220aacaeeeeSJohn Baldwin }
221a1eda741SJohn Baldwin mtx_unlock(&ns->lock);
222a1eda741SJohn Baldwin free(dsm_range, M_NVMF);
223aacaeeeeSJohn Baldwin return (error);
224a1eda741SJohn Baldwin }
225a1eda741SJohn Baldwin
226a1eda741SJohn Baldwin req = nvmf_allocate_request(nvmf_select_io_queue(ns->sc), &cmd,
227a1eda741SJohn Baldwin nvmf_ns_bio_complete, bio, M_NOWAIT);
228a1eda741SJohn Baldwin if (req == NULL) {
229a1eda741SJohn Baldwin mtx_unlock(&ns->lock);
230a1eda741SJohn Baldwin free(dsm_range, M_NVMF);
231a1eda741SJohn Baldwin return (ENOMEM);
232a1eda741SJohn Baldwin }
233a1eda741SJohn Baldwin
234a1eda741SJohn Baldwin switch (bio->bio_cmd) {
235a1eda741SJohn Baldwin case BIO_READ:
236a1eda741SJohn Baldwin case BIO_WRITE:
237a1eda741SJohn Baldwin refcount_init(bio_refs(bio), 2);
238a1eda741SJohn Baldwin mem = memdesc_bio(bio);
239a1eda741SJohn Baldwin nvmf_capsule_append_data(req->nc, &mem, bio->bio_bcount,
240a1eda741SJohn Baldwin bio->bio_cmd == BIO_WRITE, nvmf_ns_io_complete, bio);
241a1eda741SJohn Baldwin break;
242a1eda741SJohn Baldwin case BIO_DELETE:
243a1eda741SJohn Baldwin refcount_init(bio_refs(bio), 2);
244a1eda741SJohn Baldwin mem = memdesc_vaddr(dsm_range, sizeof(*dsm_range));
245a1eda741SJohn Baldwin nvmf_capsule_append_data(req->nc, &mem, sizeof(*dsm_range),
246a1eda741SJohn Baldwin true, nvmf_ns_delete_complete, bio);
247a1eda741SJohn Baldwin bio->bio_driver2 = dsm_range;
248a1eda741SJohn Baldwin break;
249a1eda741SJohn Baldwin default:
250a1eda741SJohn Baldwin refcount_init(bio_refs(bio), 1);
251a1eda741SJohn Baldwin KASSERT(bio->bio_resid == 0,
252a1eda741SJohn Baldwin ("%s: input bio_resid != 0", __func__));
253a1eda741SJohn Baldwin break;
254a1eda741SJohn Baldwin }
255a1eda741SJohn Baldwin
256a1eda741SJohn Baldwin refcount_acquire(&ns->active_bios);
257a1eda741SJohn Baldwin nvmf_submit_request(req);
258a1eda741SJohn Baldwin mtx_unlock(&ns->lock);
259a1eda741SJohn Baldwin return (0);
260a1eda741SJohn Baldwin }
261a1eda741SJohn Baldwin
262a1eda741SJohn Baldwin static int
nvmf_ns_ioctl(struct cdev * dev,u_long cmd,caddr_t arg,int flag,struct thread * td)263a1eda741SJohn Baldwin nvmf_ns_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag,
264a1eda741SJohn Baldwin struct thread *td)
265a1eda741SJohn Baldwin {
266a1eda741SJohn Baldwin struct nvmf_namespace *ns = dev->si_drv1;
267a1eda741SJohn Baldwin struct nvme_get_nsid *gnsid;
268a1eda741SJohn Baldwin struct nvme_pt_command *pt;
269a1eda741SJohn Baldwin
270a1eda741SJohn Baldwin switch (cmd) {
271a1eda741SJohn Baldwin case NVME_PASSTHROUGH_CMD:
272a1eda741SJohn Baldwin pt = (struct nvme_pt_command *)arg;
273a1eda741SJohn Baldwin pt->cmd.nsid = htole32(ns->id);
274a1eda741SJohn Baldwin return (nvmf_passthrough_cmd(ns->sc, pt, false));
275a1eda741SJohn Baldwin case NVME_GET_NSID:
276a1eda741SJohn Baldwin gnsid = (struct nvme_get_nsid *)arg;
277da4230afSJohn Baldwin strlcpy(gnsid->cdev, device_get_nameunit(ns->sc->dev),
278a1eda741SJohn Baldwin sizeof(gnsid->cdev));
279a1eda741SJohn Baldwin gnsid->nsid = ns->id;
280a1eda741SJohn Baldwin return (0);
281a1eda741SJohn Baldwin case DIOCGMEDIASIZE:
282a1eda741SJohn Baldwin *(off_t *)arg = ns->size;
283a1eda741SJohn Baldwin return (0);
284a1eda741SJohn Baldwin case DIOCGSECTORSIZE:
285a1eda741SJohn Baldwin *(u_int *)arg = ns->lba_size;
286a1eda741SJohn Baldwin return (0);
287a1eda741SJohn Baldwin default:
288a1eda741SJohn Baldwin return (ENOTTY);
289a1eda741SJohn Baldwin }
290a1eda741SJohn Baldwin }
291a1eda741SJohn Baldwin
292a1eda741SJohn Baldwin static int
nvmf_ns_open(struct cdev * dev,int oflags,int devtype,struct thread * td)293a1eda741SJohn Baldwin nvmf_ns_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
294a1eda741SJohn Baldwin {
295a1eda741SJohn Baldwin int error;
296a1eda741SJohn Baldwin
297a1eda741SJohn Baldwin error = 0;
298a1eda741SJohn Baldwin if ((oflags & FWRITE) != 0)
299a1eda741SJohn Baldwin error = securelevel_gt(td->td_ucred, 0);
300a1eda741SJohn Baldwin return (error);
301a1eda741SJohn Baldwin }
302a1eda741SJohn Baldwin
303a1eda741SJohn Baldwin void
nvmf_ns_strategy(struct bio * bio)304a1eda741SJohn Baldwin nvmf_ns_strategy(struct bio *bio)
305a1eda741SJohn Baldwin {
306a1eda741SJohn Baldwin struct nvmf_namespace *ns;
307a1eda741SJohn Baldwin int error;
308a1eda741SJohn Baldwin
309a1eda741SJohn Baldwin ns = bio->bio_dev->si_drv1;
310a1eda741SJohn Baldwin
311a1eda741SJohn Baldwin error = nvmf_ns_submit_bio(ns, bio);
312a1eda741SJohn Baldwin if (error != 0) {
313a1eda741SJohn Baldwin bio->bio_error = error;
314a1eda741SJohn Baldwin bio->bio_flags |= BIO_ERROR;
315a1eda741SJohn Baldwin bio->bio_resid = bio->bio_bcount;
316a1eda741SJohn Baldwin biodone(bio);
317a1eda741SJohn Baldwin }
318a1eda741SJohn Baldwin }
319a1eda741SJohn Baldwin
320a1eda741SJohn Baldwin static struct cdevsw nvmf_ns_cdevsw = {
321a1eda741SJohn Baldwin .d_version = D_VERSION,
322a1eda741SJohn Baldwin .d_flags = D_DISK,
323a1eda741SJohn Baldwin .d_open = nvmf_ns_open,
324a1eda741SJohn Baldwin .d_read = physread,
325a1eda741SJohn Baldwin .d_write = physwrite,
326a1eda741SJohn Baldwin .d_strategy = nvmf_ns_strategy,
327a1eda741SJohn Baldwin .d_ioctl = nvmf_ns_ioctl
328a1eda741SJohn Baldwin };
329a1eda741SJohn Baldwin
330a1eda741SJohn Baldwin struct nvmf_namespace *
nvmf_init_ns(struct nvmf_softc * sc,uint32_t id,const struct nvme_namespace_data * data)331a1eda741SJohn Baldwin nvmf_init_ns(struct nvmf_softc *sc, uint32_t id,
332bed59babSJohn Baldwin const struct nvme_namespace_data *data)
333a1eda741SJohn Baldwin {
334a1eda741SJohn Baldwin struct make_dev_args mda;
335a1eda741SJohn Baldwin struct nvmf_namespace *ns;
336a1eda741SJohn Baldwin int error;
337a1eda741SJohn Baldwin uint8_t lbads, lbaf;
338a1eda741SJohn Baldwin
339a1eda741SJohn Baldwin ns = malloc(sizeof(*ns), M_NVMF, M_WAITOK | M_ZERO);
340a1eda741SJohn Baldwin ns->sc = sc;
341a1eda741SJohn Baldwin ns->id = id;
342a1eda741SJohn Baldwin TAILQ_INIT(&ns->pending_bios);
343a1eda741SJohn Baldwin mtx_init(&ns->lock, "nvmf ns", NULL, MTX_DEF);
344a1eda741SJohn Baldwin
345a1eda741SJohn Baldwin /* One dummy bio avoids dropping to 0 until destroy. */
346a1eda741SJohn Baldwin refcount_init(&ns->active_bios, 1);
347a1eda741SJohn Baldwin
348a1eda741SJohn Baldwin if (NVMEV(NVME_NS_DATA_DPS_PIT, data->dps) != 0) {
349a1eda741SJohn Baldwin ns_printf(ns, "End-to-end data protection not supported\n");
350a1eda741SJohn Baldwin goto fail;
351a1eda741SJohn Baldwin }
352a1eda741SJohn Baldwin
353a1eda741SJohn Baldwin lbaf = NVMEV(NVME_NS_DATA_FLBAS_FORMAT, data->flbas);
354a1eda741SJohn Baldwin if (lbaf > data->nlbaf) {
355a1eda741SJohn Baldwin ns_printf(ns, "Invalid LBA format index\n");
356a1eda741SJohn Baldwin goto fail;
357a1eda741SJohn Baldwin }
358a1eda741SJohn Baldwin
359a1eda741SJohn Baldwin if (NVMEV(NVME_NS_DATA_LBAF_MS, data->lbaf[lbaf]) != 0) {
360a1eda741SJohn Baldwin ns_printf(ns, "Namespaces with metadata are not supported\n");
361a1eda741SJohn Baldwin goto fail;
362a1eda741SJohn Baldwin }
363a1eda741SJohn Baldwin
364a1eda741SJohn Baldwin lbads = NVMEV(NVME_NS_DATA_LBAF_LBADS, data->lbaf[lbaf]);
365a1eda741SJohn Baldwin if (lbads == 0) {
366a1eda741SJohn Baldwin ns_printf(ns, "Invalid LBA format index\n");
367a1eda741SJohn Baldwin goto fail;
368a1eda741SJohn Baldwin }
369a1eda741SJohn Baldwin
370a1eda741SJohn Baldwin ns->lba_size = 1 << lbads;
371a1eda741SJohn Baldwin ns->size = data->nsze * ns->lba_size;
372a1eda741SJohn Baldwin
373a1eda741SJohn Baldwin if (nvme_ctrlr_has_dataset_mgmt(sc->cdata))
374a1eda741SJohn Baldwin ns->flags |= NVME_NS_DEALLOCATE_SUPPORTED;
375a1eda741SJohn Baldwin
376a1eda741SJohn Baldwin if (NVMEV(NVME_CTRLR_DATA_VWC_PRESENT, sc->cdata->vwc) != 0)
377a1eda741SJohn Baldwin ns->flags |= NVME_NS_FLUSH_SUPPORTED;
378a1eda741SJohn Baldwin
379a1eda741SJohn Baldwin /*
380a1eda741SJohn Baldwin * XXX: Does any of the boundary splitting for NOIOB make any
381a1eda741SJohn Baldwin * sense for Fabrics?
382a1eda741SJohn Baldwin */
383a1eda741SJohn Baldwin
384a1eda741SJohn Baldwin make_dev_args_init(&mda);
385a1eda741SJohn Baldwin mda.mda_devsw = &nvmf_ns_cdevsw;
386a1eda741SJohn Baldwin mda.mda_uid = UID_ROOT;
387a1eda741SJohn Baldwin mda.mda_gid = GID_WHEEL;
388a1eda741SJohn Baldwin mda.mda_mode = 0600;
389a1eda741SJohn Baldwin mda.mda_si_drv1 = ns;
390ce75bfcaSChuck Tuffli error = make_dev_s(&mda, &ns->cdev, "%sn%u",
391a1eda741SJohn Baldwin device_get_nameunit(sc->dev), id);
392a1eda741SJohn Baldwin if (error != 0)
393a1eda741SJohn Baldwin goto fail;
394ce75bfcaSChuck Tuffli ns->cdev->si_drv2 = make_dev_alias(ns->cdev, "%sns%u",
395ce75bfcaSChuck Tuffli device_get_nameunit(sc->dev), id);
396a1eda741SJohn Baldwin
397a1eda741SJohn Baldwin ns->cdev->si_flags |= SI_UNMAPPED;
398a1eda741SJohn Baldwin
399a1eda741SJohn Baldwin return (ns);
400a1eda741SJohn Baldwin fail:
401a1eda741SJohn Baldwin mtx_destroy(&ns->lock);
402a1eda741SJohn Baldwin free(ns, M_NVMF);
403a1eda741SJohn Baldwin return (NULL);
404a1eda741SJohn Baldwin }
405a1eda741SJohn Baldwin
406a1eda741SJohn Baldwin void
nvmf_disconnect_ns(struct nvmf_namespace * ns)407a1eda741SJohn Baldwin nvmf_disconnect_ns(struct nvmf_namespace *ns)
408a1eda741SJohn Baldwin {
409a1eda741SJohn Baldwin mtx_lock(&ns->lock);
410a1eda741SJohn Baldwin ns->disconnected = true;
411a1eda741SJohn Baldwin mtx_unlock(&ns->lock);
412a1eda741SJohn Baldwin }
413a1eda741SJohn Baldwin
414a1eda741SJohn Baldwin void
nvmf_reconnect_ns(struct nvmf_namespace * ns)415a1eda741SJohn Baldwin nvmf_reconnect_ns(struct nvmf_namespace *ns)
416a1eda741SJohn Baldwin {
417a1eda741SJohn Baldwin TAILQ_HEAD(, bio) bios;
418a1eda741SJohn Baldwin struct bio *bio;
419a1eda741SJohn Baldwin
420a1eda741SJohn Baldwin mtx_lock(&ns->lock);
421a1eda741SJohn Baldwin ns->disconnected = false;
422a1eda741SJohn Baldwin TAILQ_INIT(&bios);
423a1eda741SJohn Baldwin TAILQ_CONCAT(&bios, &ns->pending_bios, bio_queue);
424a1eda741SJohn Baldwin mtx_unlock(&ns->lock);
425a1eda741SJohn Baldwin
426a1eda741SJohn Baldwin while (!TAILQ_EMPTY(&bios)) {
427a1eda741SJohn Baldwin bio = TAILQ_FIRST(&bios);
428a1eda741SJohn Baldwin TAILQ_REMOVE(&bios, bio, bio_queue);
429a1eda741SJohn Baldwin nvmf_ns_strategy(bio);
430a1eda741SJohn Baldwin }
431a1eda741SJohn Baldwin }
432a1eda741SJohn Baldwin
433a1eda741SJohn Baldwin void
nvmf_shutdown_ns(struct nvmf_namespace * ns)434*f46d4971SJohn Baldwin nvmf_shutdown_ns(struct nvmf_namespace *ns)
435*f46d4971SJohn Baldwin {
436*f46d4971SJohn Baldwin TAILQ_HEAD(, bio) bios;
437*f46d4971SJohn Baldwin struct bio *bio;
438*f46d4971SJohn Baldwin
439*f46d4971SJohn Baldwin mtx_lock(&ns->lock);
440*f46d4971SJohn Baldwin ns->shutdown = true;
441*f46d4971SJohn Baldwin TAILQ_INIT(&bios);
442*f46d4971SJohn Baldwin TAILQ_CONCAT(&bios, &ns->pending_bios, bio_queue);
443*f46d4971SJohn Baldwin mtx_unlock(&ns->lock);
444*f46d4971SJohn Baldwin
445*f46d4971SJohn Baldwin while (!TAILQ_EMPTY(&bios)) {
446*f46d4971SJohn Baldwin bio = TAILQ_FIRST(&bios);
447*f46d4971SJohn Baldwin TAILQ_REMOVE(&bios, bio, bio_queue);
448*f46d4971SJohn Baldwin bio->bio_error = ECONNABORTED;
449*f46d4971SJohn Baldwin bio->bio_flags |= BIO_ERROR;
450*f46d4971SJohn Baldwin bio->bio_resid = bio->bio_bcount;
451*f46d4971SJohn Baldwin biodone(bio);
452*f46d4971SJohn Baldwin }
453*f46d4971SJohn Baldwin }
454*f46d4971SJohn Baldwin
455*f46d4971SJohn Baldwin void
nvmf_destroy_ns(struct nvmf_namespace * ns)456a1eda741SJohn Baldwin nvmf_destroy_ns(struct nvmf_namespace *ns)
457a1eda741SJohn Baldwin {
458a1eda741SJohn Baldwin TAILQ_HEAD(, bio) bios;
459a1eda741SJohn Baldwin struct bio *bio;
460a1eda741SJohn Baldwin
461ce75bfcaSChuck Tuffli if (ns->cdev->si_drv2 != NULL)
462ce75bfcaSChuck Tuffli destroy_dev(ns->cdev->si_drv2);
463a1eda741SJohn Baldwin destroy_dev(ns->cdev);
464a1eda741SJohn Baldwin
465a1eda741SJohn Baldwin /*
466a1eda741SJohn Baldwin * Wait for active I/O requests to drain. The release drops
467a1eda741SJohn Baldwin * the reference on the "dummy bio" when the namespace is
468a1eda741SJohn Baldwin * created.
469a1eda741SJohn Baldwin */
470a1eda741SJohn Baldwin mtx_lock(&ns->lock);
471a1eda741SJohn Baldwin if (!refcount_release(&ns->active_bios)) {
472a1eda741SJohn Baldwin while (ns->active_bios != 0)
473a1eda741SJohn Baldwin mtx_sleep(ns, &ns->lock, 0, "nvmfrmns", 0);
474a1eda741SJohn Baldwin }
475a1eda741SJohn Baldwin
476a1eda741SJohn Baldwin /* Abort any pending I/O requests. */
477a1eda741SJohn Baldwin TAILQ_INIT(&bios);
478a1eda741SJohn Baldwin TAILQ_CONCAT(&bios, &ns->pending_bios, bio_queue);
479a1eda741SJohn Baldwin mtx_unlock(&ns->lock);
480a1eda741SJohn Baldwin
481a1eda741SJohn Baldwin while (!TAILQ_EMPTY(&bios)) {
482a1eda741SJohn Baldwin bio = TAILQ_FIRST(&bios);
483a1eda741SJohn Baldwin TAILQ_REMOVE(&bios, bio, bio_queue);
484a1eda741SJohn Baldwin bio->bio_error = ECONNABORTED;
485a1eda741SJohn Baldwin bio->bio_flags |= BIO_ERROR;
486a1eda741SJohn Baldwin bio->bio_resid = bio->bio_bcount;
487a1eda741SJohn Baldwin biodone(bio);
488a1eda741SJohn Baldwin }
489a1eda741SJohn Baldwin
490a1eda741SJohn Baldwin mtx_destroy(&ns->lock);
491a1eda741SJohn Baldwin free(ns, M_NVMF);
492a1eda741SJohn Baldwin }
493a1eda741SJohn Baldwin
494a1eda741SJohn Baldwin bool
nvmf_update_ns(struct nvmf_namespace * ns,const struct nvme_namespace_data * data)495bed59babSJohn Baldwin nvmf_update_ns(struct nvmf_namespace *ns,
496bed59babSJohn Baldwin const struct nvme_namespace_data *data)
497a1eda741SJohn Baldwin {
498a1eda741SJohn Baldwin uint8_t lbads, lbaf;
499a1eda741SJohn Baldwin
500a1eda741SJohn Baldwin if (NVMEV(NVME_NS_DATA_DPS_PIT, data->dps) != 0) {
501a1eda741SJohn Baldwin ns_printf(ns, "End-to-end data protection not supported\n");
502a1eda741SJohn Baldwin return (false);
503a1eda741SJohn Baldwin }
504a1eda741SJohn Baldwin
505a1eda741SJohn Baldwin lbaf = NVMEV(NVME_NS_DATA_FLBAS_FORMAT, data->flbas);
506a1eda741SJohn Baldwin if (lbaf > data->nlbaf) {
507a1eda741SJohn Baldwin ns_printf(ns, "Invalid LBA format index\n");
508a1eda741SJohn Baldwin return (false);
509a1eda741SJohn Baldwin }
510a1eda741SJohn Baldwin
511a1eda741SJohn Baldwin if (NVMEV(NVME_NS_DATA_LBAF_MS, data->lbaf[lbaf]) != 0) {
512a1eda741SJohn Baldwin ns_printf(ns, "Namespaces with metadata are not supported\n");
513a1eda741SJohn Baldwin return (false);
514a1eda741SJohn Baldwin }
515a1eda741SJohn Baldwin
516a1eda741SJohn Baldwin lbads = NVMEV(NVME_NS_DATA_LBAF_LBADS, data->lbaf[lbaf]);
517a1eda741SJohn Baldwin if (lbads == 0) {
518a1eda741SJohn Baldwin ns_printf(ns, "Invalid LBA format index\n");
519a1eda741SJohn Baldwin return (false);
520a1eda741SJohn Baldwin }
521a1eda741SJohn Baldwin
522a1eda741SJohn Baldwin ns->lba_size = 1 << lbads;
523a1eda741SJohn Baldwin ns->size = data->nsze * ns->lba_size;
524a1eda741SJohn Baldwin return (true);
525a1eda741SJohn Baldwin }
526