xref: /freebsd/sys/cam/ctl/ctl_backend_ramdisk.c (revision 95eb4b873b6a8b527c5bd78d7191975dfca38998)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2003, 2008 Silicon Graphics International Corp.
5  * Copyright (c) 2012 The FreeBSD Foundation
6  * Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org>
7  * All rights reserved.
8  *
9  * Portions of this software were developed by Edward Tomasz Napierala
10  * under sponsorship from the FreeBSD Foundation.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  *
24  * NO WARRANTY
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
34  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGES.
36  *
37  * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $
38  */
39 /*
40  * CAM Target Layer black hole and RAM disk backend.
41  *
42  * Author: Ken Merry <ken@FreeBSD.org>
43  */
44 
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/condvar.h>
49 #include <sys/types.h>
50 #include <sys/limits.h>
51 #include <sys/lock.h>
52 #include <sys/mutex.h>
53 #include <sys/malloc.h>
54 #include <sys/sx.h>
55 #include <sys/taskqueue.h>
56 #include <sys/time.h>
57 #include <sys/queue.h>
58 #include <sys/conf.h>
59 #include <sys/ioccom.h>
60 #include <sys/module.h>
61 #include <sys/sysctl.h>
62 #include <sys/nv.h>
63 #include <sys/dnv.h>
64 
65 #include <cam/scsi/scsi_all.h>
66 #include <cam/scsi/scsi_da.h>
67 #include <cam/ctl/ctl_io.h>
68 #include <cam/ctl/ctl.h>
69 #include <cam/ctl/ctl_util.h>
70 #include <cam/ctl/ctl_backend.h>
71 #include <cam/ctl/ctl_debug.h>
72 #include <cam/ctl/ctl_ioctl.h>
73 #include <cam/ctl/ctl_ha.h>
74 #include <cam/ctl/ctl_private.h>
75 #include <cam/ctl/ctl_error.h>
76 
77 #define PRIV(io)	\
78     ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND])
79 #define ARGS(io)	\
80     ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN])
81 
82 #define	PPP	(PAGE_SIZE / sizeof(uint8_t **))
83 #ifdef __LP64__
84 #define	PPPS	(PAGE_SHIFT - 3)
85 #else
86 #define	PPPS	(PAGE_SHIFT - 2)
87 #endif
88 #define	SGPP	(PAGE_SIZE / sizeof(struct ctl_sg_entry))
89 
90 #define	P_UNMAPPED	NULL			/* Page is unmapped. */
91 #define	P_ANCHORED	((void *)(uintptr_t)1)	/* Page is anchored. */
92 
93 typedef enum {
94 	GP_READ,	/* Return data page or zero page. */
95 	GP_WRITE,	/* Return data page, try allocate if none. */
96 	GP_ANCHOR,	/* Return data page, try anchor if none. */
97 	GP_OTHER,	/* Return what present, do not allocate/anchor. */
98 } getpage_op_t;
99 
100 typedef enum {
101 	CTL_BE_RAMDISK_LUN_UNCONFIGURED	= 0x01,
102 	CTL_BE_RAMDISK_LUN_WAITING	= 0x04
103 } ctl_be_ramdisk_lun_flags;
104 
105 struct ctl_be_ramdisk_lun {
106 	struct ctl_be_lun	cbe_lun;	/* Must be first element. */
107 	struct ctl_lun_create_params params;
108 	int			indir;
109 	uint8_t			**pages;
110 	uint8_t			*zero_page;
111 	struct sx		page_lock;
112 	u_int			pblocksize;
113 	u_int			pblockmul;
114 	uint64_t		size_bytes;
115 	uint64_t		size_blocks;
116 	uint64_t		cap_bytes;
117 	uint64_t		cap_used;
118 	struct ctl_be_ramdisk_softc *softc;
119 	ctl_be_ramdisk_lun_flags flags;
120 	SLIST_ENTRY(ctl_be_ramdisk_lun) links;
121 	struct taskqueue	*io_taskqueue;
122 	struct task		io_task;
123 	STAILQ_HEAD(, ctl_io_hdr) cont_queue;
124 	struct mtx_padalign	queue_lock;
125 };
126 
127 struct ctl_be_ramdisk_softc {
128 	struct sx modify_lock;
129 	struct mtx lock;
130 	int num_luns;
131 	SLIST_HEAD(, ctl_be_ramdisk_lun) lun_list;
132 };
133 
134 static struct ctl_be_ramdisk_softc rd_softc;
135 extern struct ctl_softc *control_softc;
136 
137 static int ctl_backend_ramdisk_init(void);
138 static int ctl_backend_ramdisk_shutdown(void);
139 static int ctl_backend_ramdisk_move_done(union ctl_io *io, bool samethr);
140 static void ctl_backend_ramdisk_compare(union ctl_io *io);
141 static void ctl_backend_ramdisk_rw(union ctl_io *io);
142 static int ctl_backend_ramdisk_submit(union ctl_io *io);
143 static void ctl_backend_ramdisk_worker(void *context, int pending);
144 static int ctl_backend_ramdisk_config_read(union ctl_io *io);
145 static int ctl_backend_ramdisk_config_write(union ctl_io *io);
146 static uint64_t ctl_backend_ramdisk_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname);
147 static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd,
148 				     caddr_t addr, int flag, struct thread *td);
149 static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc,
150 				  struct ctl_lun_req *req);
151 static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
152 				      struct ctl_lun_req *req);
153 static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc,
154 				  struct ctl_lun_req *req);
155 static void ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun *cbe_lun);
156 
157 static struct ctl_backend_driver ctl_be_ramdisk_driver =
158 {
159 	.name = "ramdisk",
160 	.flags = CTL_BE_FLAG_HAS_CONFIG,
161 	.init = ctl_backend_ramdisk_init,
162 	.shutdown = ctl_backend_ramdisk_shutdown,
163 	.data_submit = ctl_backend_ramdisk_submit,
164 	.config_read = ctl_backend_ramdisk_config_read,
165 	.config_write = ctl_backend_ramdisk_config_write,
166 	.ioctl = ctl_backend_ramdisk_ioctl,
167 	.lun_attr = ctl_backend_ramdisk_lun_attr,
168 };
169 
170 MALLOC_DEFINE(M_RAMDISK, "ctlramdisk", "Memory used for CTL RAMdisk");
171 CTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver);
172 
173 static int
174 ctl_backend_ramdisk_init(void)
175 {
176 	struct ctl_be_ramdisk_softc *softc = &rd_softc;
177 
178 	memset(softc, 0, sizeof(*softc));
179 	sx_init(&softc->modify_lock, "ctlrammod");
180 	mtx_init(&softc->lock, "ctlram", NULL, MTX_DEF);
181 	SLIST_INIT(&softc->lun_list);
182 	return (0);
183 }
184 
185 static int
186 ctl_backend_ramdisk_shutdown(void)
187 {
188 	struct ctl_be_ramdisk_softc *softc = &rd_softc;
189 	struct ctl_be_ramdisk_lun *lun;
190 
191 	mtx_lock(&softc->lock);
192 	while ((lun = SLIST_FIRST(&softc->lun_list)) != NULL) {
193 		SLIST_REMOVE_HEAD(&softc->lun_list, links);
194 		softc->num_luns--;
195 		/*
196 		 * Drop our lock here.  Since ctl_remove_lun() can call
197 		 * back into us, this could potentially lead to a recursive
198 		 * lock of the same mutex, which would cause a hang.
199 		 */
200 		mtx_unlock(&softc->lock);
201 		ctl_remove_lun(&lun->cbe_lun);
202 		mtx_lock(&softc->lock);
203 	}
204 	mtx_unlock(&softc->lock);
205 	mtx_destroy(&softc->lock);
206 	sx_destroy(&softc->modify_lock);
207 	return (0);
208 }
209 
210 static uint8_t *
211 ctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn,
212     getpage_op_t op)
213 {
214 	uint8_t **p, ***pp;
215 	off_t i;
216 	int s;
217 
218 	if (be_lun->cap_bytes == 0) {
219 		switch (op) {
220 		case GP_READ:
221 			return (be_lun->zero_page);
222 		case GP_WRITE:
223 			return ((uint8_t *)be_lun->pages);
224 		case GP_ANCHOR:
225 			return (P_ANCHORED);
226 		default:
227 			return (P_UNMAPPED);
228 		}
229 	}
230 	if (op == GP_WRITE || op == GP_ANCHOR) {
231 		sx_xlock(&be_lun->page_lock);
232 		pp = &be_lun->pages;
233 		for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
234 			if (*pp == NULL) {
235 				*pp = malloc(PAGE_SIZE, M_RAMDISK,
236 				    M_WAITOK|M_ZERO);
237 			}
238 			i = pn >> s;
239 			pp = (uint8_t ***)&(*pp)[i];
240 			pn -= i << s;
241 		}
242 		if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) {
243 			if (op == GP_WRITE) {
244 				*pp = malloc(be_lun->pblocksize, M_RAMDISK,
245 				    M_WAITOK|M_ZERO);
246 			} else
247 				*pp = P_ANCHORED;
248 			be_lun->cap_used += be_lun->pblocksize;
249 		} else if (*pp == P_ANCHORED && op == GP_WRITE) {
250 			*pp = malloc(be_lun->pblocksize, M_RAMDISK,
251 			    M_WAITOK|M_ZERO);
252 		}
253 		sx_xunlock(&be_lun->page_lock);
254 		return ((uint8_t *)*pp);
255 	} else {
256 		sx_slock(&be_lun->page_lock);
257 		p = be_lun->pages;
258 		for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
259 			if (p == NULL)
260 				break;
261 			i = pn >> s;
262 			p = (uint8_t **)p[i];
263 			pn -= i << s;
264 		}
265 		sx_sunlock(&be_lun->page_lock);
266 		if ((p == P_UNMAPPED || p == P_ANCHORED) && op == GP_READ)
267 			return (be_lun->zero_page);
268 		return ((uint8_t *)p);
269 	}
270 };
271 
272 static void
273 ctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun *be_lun, off_t pn)
274 {
275 	uint8_t ***pp;
276 	off_t i;
277 	int s;
278 
279 	if (be_lun->cap_bytes == 0)
280 		return;
281 	sx_xlock(&be_lun->page_lock);
282 	pp = &be_lun->pages;
283 	for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
284 		if (*pp == NULL)
285 			goto noindir;
286 		i = pn >> s;
287 		pp = (uint8_t ***)&(*pp)[i];
288 		pn -= i << s;
289 	}
290 	if (*pp == P_ANCHORED) {
291 		be_lun->cap_used -= be_lun->pblocksize;
292 		*pp = P_UNMAPPED;
293 	} else if (*pp != P_UNMAPPED) {
294 		free(*pp, M_RAMDISK);
295 		be_lun->cap_used -= be_lun->pblocksize;
296 		*pp = P_UNMAPPED;
297 	}
298 noindir:
299 	sx_xunlock(&be_lun->page_lock);
300 };
301 
302 static void
303 ctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn)
304 {
305 	uint8_t ***pp;
306 	off_t i;
307 	int s;
308 
309 	if (be_lun->cap_bytes == 0)
310 		return;
311 	sx_xlock(&be_lun->page_lock);
312 	pp = &be_lun->pages;
313 	for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
314 		if (*pp == NULL)
315 			goto noindir;
316 		i = pn >> s;
317 		pp = (uint8_t ***)&(*pp)[i];
318 		pn -= i << s;
319 	}
320 	if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) {
321 		be_lun->cap_used += be_lun->pblocksize;
322 		*pp = P_ANCHORED;
323 	} else if (*pp != P_ANCHORED) {
324 		free(*pp, M_RAMDISK);
325 		*pp = P_ANCHORED;
326 	}
327 noindir:
328 	sx_xunlock(&be_lun->page_lock);
329 };
330 
331 static void
332 ctl_backend_ramdisk_freeallpages(uint8_t **p, int indir)
333 {
334 	int i;
335 
336 	if (p == NULL)
337 		return;
338 	if (indir == 0) {
339 		free(p, M_RAMDISK);
340 		return;
341 	}
342 	for (i = 0; i < PPP; i++) {
343 		if (p[i] == NULL)
344 			continue;
345 		ctl_backend_ramdisk_freeallpages((uint8_t **)p[i], indir - 1);
346 	}
347 	free(p, M_RAMDISK);
348 };
349 
350 static size_t
351 cmp(uint8_t *a, uint8_t *b, size_t size)
352 {
353 	size_t i;
354 
355 	for (i = 0; i < size; i++) {
356 		if (a[i] != b[i])
357 			break;
358 	}
359 	return (i);
360 }
361 
362 static int
363 ctl_backend_ramdisk_cmp(union ctl_io *io)
364 {
365 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
366 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
367 	uint8_t *page;
368 	uint64_t lba;
369 	u_int lbaoff, lbas, res, off;
370 
371 	lbas = ctl_kern_data_len(io) / cbe_lun->blocksize;
372 	lba = ARGS(io)->lba + PRIV(io)->len - lbas;
373 	off = 0;
374 	for (; lbas > 0; lbas--, lba++) {
375 		page = ctl_backend_ramdisk_getpage(be_lun,
376 		    lba >> cbe_lun->pblockexp, GP_READ);
377 		lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
378 		page += lbaoff * cbe_lun->blocksize;
379 		res = cmp(ctl_kern_data_ptr(io) + off, page,
380 		    cbe_lun->blocksize);
381 		off += res;
382 		if (res < cbe_lun->blocksize)
383 			break;
384 	}
385 	free(io->scsiio.kern_data_ptr, M_RAMDISK);
386 	if (lbas > 0) {
387 		off += ctl_kern_rel_offset(io) - ctl_kern_data_len(io);
388 		ctl_io_set_compare_failure(io, off);
389 		return (1);
390 	}
391 	return (0);
392 }
393 
394 static int
395 ctl_backend_ramdisk_move_done(union ctl_io *io, bool samethr)
396 {
397 	struct ctl_be_ramdisk_lun *be_lun =
398 	    (struct ctl_be_ramdisk_lun *)CTL_BACKEND_LUN(io);
399 
400 	CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n"));
401 	if (ctl_kern_sg_entries(io) > 0)
402 		free(ctl_kern_data_ptr(io), M_RAMDISK);
403 	ctl_add_kern_rel_offset(io, ctl_kern_data_len(io));
404 	if ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0 &&
405 	    (io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE) {
406 		if (ARGS(io)->flags & CTL_LLF_COMPARE) {
407 			/* We have data block ready for comparison. */
408 			if (ctl_backend_ramdisk_cmp(io))
409 				goto done;
410 		}
411 		if (ARGS(io)->len > PRIV(io)->len) {
412 			mtx_lock(&be_lun->queue_lock);
413 			STAILQ_INSERT_TAIL(&be_lun->cont_queue,
414 			    &io->io_hdr, links);
415 			mtx_unlock(&be_lun->queue_lock);
416 			taskqueue_enqueue(be_lun->io_taskqueue,
417 			    &be_lun->io_task);
418 			return (0);
419 		}
420 		ctl_io_set_success(io);
421 	}
422 done:
423 	ctl_data_submit_done(io);
424 	return(0);
425 }
426 
427 static void
428 ctl_backend_ramdisk_compare(union ctl_io *io)
429 {
430 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
431 	u_int lbas, len;
432 
433 	lbas = ARGS(io)->len - PRIV(io)->len;
434 	lbas = MIN(lbas, 131072 / cbe_lun->blocksize);
435 	len = lbas * cbe_lun->blocksize;
436 
437 	ctl_set_be_move_done(io, ctl_backend_ramdisk_move_done);
438 	ctl_set_kern_data_ptr(io, malloc(len, M_RAMDISK, M_WAITOK));
439 	ctl_set_kern_data_len(io, len);
440 	ctl_set_kern_sg_entries(io, 0);
441 	io->io_hdr.flags |= CTL_FLAG_ALLOCATED;
442 	PRIV(io)->len += lbas;
443 	ctl_datamove(io);
444 }
445 
446 static void
447 ctl_backend_ramdisk_rw(union ctl_io *io)
448 {
449 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
450 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
451 	struct ctl_sg_entry *sg_entries;
452 	uint8_t *page;
453 	uint64_t lba;
454 	u_int i, len, lbaoff, lbas, sgs, off;
455 	getpage_op_t op;
456 
457 	lba = ARGS(io)->lba + PRIV(io)->len;
458 	lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
459 	lbas = ARGS(io)->len - PRIV(io)->len;
460 	lbas = MIN(lbas, (SGPP << cbe_lun->pblockexp) - lbaoff);
461 	sgs = (lbas + lbaoff + be_lun->pblockmul - 1) >> cbe_lun->pblockexp;
462 	off = lbaoff * cbe_lun->blocksize;
463 	op = (ARGS(io)->flags & CTL_LLF_WRITE) ? GP_WRITE : GP_READ;
464 	if (sgs > 1) {
465 		sg_entries = malloc(sizeof(struct ctl_sg_entry) * sgs,
466 		    M_RAMDISK, M_WAITOK);
467 		ctl_set_kern_data_ptr(io, sg_entries);
468 		len = lbas * cbe_lun->blocksize;
469 		for (i = 0; i < sgs; i++) {
470 			page = ctl_backend_ramdisk_getpage(be_lun,
471 			    (lba >> cbe_lun->pblockexp) + i, op);
472 			if (page == P_UNMAPPED || page == P_ANCHORED) {
473 				free(sg_entries, M_RAMDISK);
474 nospc:
475 				ctl_io_set_space_alloc_fail(io);
476 				ctl_data_submit_done(io);
477 				return;
478 			}
479 			sg_entries[i].addr = page + off;
480 			sg_entries[i].len = MIN(len, be_lun->pblocksize - off);
481 			len -= sg_entries[i].len;
482 			off = 0;
483 		}
484 	} else {
485 		page = ctl_backend_ramdisk_getpage(be_lun,
486 		    lba >> cbe_lun->pblockexp, op);
487 		if (page == P_UNMAPPED || page == P_ANCHORED)
488 			goto nospc;
489 		sgs = 0;
490 		ctl_set_kern_data_ptr(io, page + off);
491 	}
492 
493 	ctl_set_be_move_done(io, ctl_backend_ramdisk_move_done);
494 	ctl_set_kern_data_len(io, lbas * cbe_lun->blocksize);
495 	ctl_set_kern_sg_entries(io, sgs);
496 	io->io_hdr.flags |= CTL_FLAG_ALLOCATED;
497 	PRIV(io)->len += lbas;
498 	if ((ARGS(io)->flags & CTL_LLF_READ) &&
499 	    ARGS(io)->len <= PRIV(io)->len) {
500 		ctl_io_set_success(io);
501 		if (cbe_lun->serseq >= CTL_LUN_SERSEQ_SOFT)
502 			ctl_serseq_done(io);
503 	}
504 	ctl_datamove(io);
505 }
506 
507 static int
508 ctl_backend_ramdisk_submit(union ctl_io *io)
509 {
510 	struct ctl_lba_len_flags *lbalen = ARGS(io);
511 
512 	if (lbalen->flags & CTL_LLF_VERIFY) {
513 		ctl_io_set_success(io);
514 		ctl_data_submit_done(io);
515 		return (CTL_RETVAL_COMPLETE);
516 	}
517 	PRIV(io)->len = 0;
518 	if (lbalen->flags & CTL_LLF_COMPARE)
519 		ctl_backend_ramdisk_compare(io);
520 	else
521 		ctl_backend_ramdisk_rw(io);
522 	return (CTL_RETVAL_COMPLETE);
523 }
524 
525 static void
526 ctl_backend_ramdisk_worker(void *context, int pending)
527 {
528 	struct ctl_be_ramdisk_lun *be_lun;
529 	union ctl_io *io;
530 
531 	be_lun = (struct ctl_be_ramdisk_lun *)context;
532 	mtx_lock(&be_lun->queue_lock);
533 	for (;;) {
534 		io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue);
535 		if (io != NULL) {
536 			STAILQ_REMOVE_HEAD(&be_lun->cont_queue, links);
537 			mtx_unlock(&be_lun->queue_lock);
538 			if (ARGS(io)->flags & CTL_LLF_COMPARE)
539 				ctl_backend_ramdisk_compare(io);
540 			else
541 				ctl_backend_ramdisk_rw(io);
542 			mtx_lock(&be_lun->queue_lock);
543 			continue;
544 		}
545 
546 		/*
547 		 * If we get here, there is no work left in the queues, so
548 		 * just break out and let the task queue go to sleep.
549 		 */
550 		break;
551 	}
552 	mtx_unlock(&be_lun->queue_lock);
553 }
554 
555 static int
556 ctl_backend_ramdisk_gls(union ctl_io *io)
557 {
558 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
559 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
560 	struct scsi_get_lba_status_data *data;
561 	uint8_t *page;
562 	u_int lbaoff;
563 
564 	data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
565 	scsi_u64to8b(ARGS(io)->lba, data->descr[0].addr);
566 	lbaoff = ARGS(io)->lba & ~(UINT_MAX << cbe_lun->pblockexp);
567 	scsi_ulto4b(be_lun->pblockmul - lbaoff, data->descr[0].length);
568 	page = ctl_backend_ramdisk_getpage(be_lun,
569 	    ARGS(io)->lba >> cbe_lun->pblockexp, GP_OTHER);
570 	if (page == P_UNMAPPED)
571 		data->descr[0].status = 1;
572 	else if (page == P_ANCHORED)
573 		data->descr[0].status = 2;
574 	else
575 		data->descr[0].status = 0;
576 	ctl_config_read_done(io);
577 	return (CTL_RETVAL_COMPLETE);
578 }
579 
580 static int
581 ctl_backend_ramdisk_scsi_config_read(union ctl_io *io)
582 {
583 	int retval = 0;
584 
585 	switch (io->scsiio.cdb[0]) {
586 	case SERVICE_ACTION_IN:
587 		if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
588 			retval = ctl_backend_ramdisk_gls(io);
589 			break;
590 		}
591 		ctl_set_invalid_field(&io->scsiio,
592 				      /*sks_valid*/ 1,
593 				      /*command*/ 1,
594 				      /*field*/ 1,
595 				      /*bit_valid*/ 1,
596 				      /*bit*/ 4);
597 		ctl_config_read_done(io);
598 		retval = CTL_RETVAL_COMPLETE;
599 		break;
600 	default:
601 		ctl_set_invalid_opcode(&io->scsiio);
602 		ctl_config_read_done(io);
603 		retval = CTL_RETVAL_COMPLETE;
604 		break;
605 	}
606 	return (retval);
607 }
608 
609 static int
610 ramdisk_namespace_data(union ctl_io *io)
611 {
612 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
613 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
614 	struct nvme_namespace_data *nsdata;
615 
616 	if (io->nvmeio.kern_data_len != sizeof(struct nvme_namespace_data) ||
617 	    io->nvmeio.kern_sg_entries != 0)
618 		return (CTL_RETVAL_ERROR);
619 
620 	nsdata = (struct nvme_namespace_data *)io->nvmeio.kern_data_ptr;
621 	memset(nsdata, 0, sizeof(*nsdata));
622 	nsdata->nsze = htole64(be_lun->size_blocks);
623 	nsdata->ncap = htole64(be_lun->cap_bytes / cbe_lun->blocksize);
624 	nsdata->nuse = htole64(be_lun->cap_used / cbe_lun->blocksize);
625 	nsdata->nsfeat = NVMEM(NVME_NS_DATA_NSFEAT_THIN_PROV) |
626 	    NVMEM(NVME_NS_DATA_NSFEAT_DEALLOC);
627 	nsdata->nlbaf = 1 - 1;
628 	nsdata->dlfeat = NVMEM(NVME_NS_DATA_DLFEAT_DWZ) |
629 	    NVMEF(NVME_NS_DATA_DLFEAT_READ, NVME_NS_DATA_DLFEAT_READ_00);
630 	nsdata->flbas = NVMEF(NVME_NS_DATA_FLBAS_FORMAT, 0);
631 	nsdata->lbaf[0] = NVMEF(NVME_NS_DATA_LBAF_LBADS,
632 	    ffs(cbe_lun->blocksize) - 1);
633 
634 	ctl_lun_nsdata_ids(cbe_lun, nsdata);
635 	ctl_config_read_done(io);
636 	return (CTL_RETVAL_COMPLETE);
637 }
638 
639 static int
640 ramdisk_nvme_ids(union ctl_io *io)
641 {
642 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
643 
644 	if (io->nvmeio.kern_data_len != 4096 || io->nvmeio.kern_sg_entries != 0)
645 		return (CTL_RETVAL_ERROR);
646 
647 	ctl_lun_nvme_ids(cbe_lun, io->nvmeio.kern_data_ptr);
648 	ctl_config_read_done(io);
649 	return (CTL_RETVAL_COMPLETE);
650 }
651 
652 static int
653 ctl_backend_ramdisk_nvme_config_read(union ctl_io *io)
654 {
655 	switch (io->nvmeio.cmd.opc) {
656 	case NVME_OPC_IDENTIFY:
657 	{
658 		uint8_t cns;
659 
660 		cns = le32toh(io->nvmeio.cmd.cdw10) & 0xff;
661 		switch (cns) {
662 		case 0:
663 			return (ramdisk_namespace_data(io));
664 		case 3:
665 			return (ramdisk_nvme_ids(io));
666 		default:
667 			ctl_nvme_set_invalid_field(&io->nvmeio);
668 			ctl_config_read_done(io);
669 			return (CTL_RETVAL_COMPLETE);
670 		}
671 	}
672 	default:
673 		ctl_nvme_set_invalid_opcode(&io->nvmeio);
674 		ctl_config_read_done(io);
675 		return (CTL_RETVAL_COMPLETE);
676 	}
677 }
678 
679 static int
680 ctl_backend_ramdisk_config_read(union ctl_io *io)
681 {
682 	switch (io->io_hdr.io_type) {
683 	case CTL_IO_SCSI:
684 		return (ctl_backend_ramdisk_scsi_config_read(io));
685 	case CTL_IO_NVME_ADMIN:
686 		return (ctl_backend_ramdisk_nvme_config_read(io));
687 	default:
688 		__assert_unreachable();
689 	}
690 }
691 
692 static void
693 ctl_backend_ramdisk_delete(struct ctl_be_lun *cbe_lun, off_t lba, off_t len,
694     int anchor)
695 {
696 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
697 	uint8_t *page;
698 	uint64_t p, lp;
699 	u_int lbaoff;
700 	getpage_op_t op = anchor ? GP_ANCHOR : GP_OTHER;
701 
702 	/* Partially zero first partial page. */
703 	p = lba >> cbe_lun->pblockexp;
704 	lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
705 	if (lbaoff != 0) {
706 		page = ctl_backend_ramdisk_getpage(be_lun, p, op);
707 		if (page != P_UNMAPPED && page != P_ANCHORED) {
708 			memset(page + lbaoff * cbe_lun->blocksize, 0,
709 			    min(len, be_lun->pblockmul - lbaoff) *
710 			    cbe_lun->blocksize);
711 		}
712 		p++;
713 	}
714 
715 	/* Partially zero last partial page. */
716 	lp = (lba + len) >> cbe_lun->pblockexp;
717 	lbaoff = (lba + len) & ~(UINT_MAX << cbe_lun->pblockexp);
718 	if (p <= lp && lbaoff != 0) {
719 		page = ctl_backend_ramdisk_getpage(be_lun, lp, op);
720 		if (page != P_UNMAPPED && page != P_ANCHORED)
721 			memset(page, 0, lbaoff * cbe_lun->blocksize);
722 	}
723 
724 	/* Delete remaining full pages. */
725 	if (anchor) {
726 		for (; p < lp; p++)
727 			ctl_backend_ramdisk_anchorpage(be_lun, p);
728 	} else {
729 		for (; p < lp; p++)
730 			ctl_backend_ramdisk_unmappage(be_lun, p);
731 	}
732 }
733 
734 static void
735 ctl_backend_ramdisk_ws(union ctl_io *io)
736 {
737 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
738 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
739 	struct ctl_lba_len_flags *lbalen = ARGS(io);
740 	uint8_t *page;
741 	uint64_t lba;
742 	u_int lbaoff, lbas;
743 
744 	CTL_IO_ASSERT(io, SCSI);
745 
746 	if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB)) {
747 		ctl_set_invalid_field(&io->scsiio,
748 				      /*sks_valid*/ 1,
749 				      /*command*/ 1,
750 				      /*field*/ 1,
751 				      /*bit_valid*/ 0,
752 				      /*bit*/ 0);
753 		ctl_config_write_done(io);
754 		return;
755 	}
756 	if (lbalen->flags & SWS_UNMAP) {
757 		ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len,
758 		    (lbalen->flags & SWS_ANCHOR) != 0);
759 		ctl_set_success(&io->scsiio);
760 		ctl_config_write_done(io);
761 		return;
762 	}
763 
764 	for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) {
765 		page = ctl_backend_ramdisk_getpage(be_lun,
766 		    lba >> cbe_lun->pblockexp, GP_WRITE);
767 		if (page == P_UNMAPPED || page == P_ANCHORED) {
768 			ctl_set_space_alloc_fail(&io->scsiio);
769 			ctl_data_submit_done(io);
770 			return;
771 		}
772 		lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
773 		page += lbaoff * cbe_lun->blocksize;
774 		if (lbalen->flags & SWS_NDOB) {
775 			memset(page, 0, cbe_lun->blocksize);
776 		} else {
777 			memcpy(page, io->scsiio.kern_data_ptr,
778 			    cbe_lun->blocksize);
779 		}
780 		if (lbalen->flags & SWS_LBDATA)
781 			scsi_ulto4b(lba, page);
782 	}
783 	ctl_set_success(&io->scsiio);
784 	ctl_config_write_done(io);
785 }
786 
787 static void
788 ctl_backend_ramdisk_unmap(union ctl_io *io)
789 {
790 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
791 	struct ctl_ptr_len_flags *ptrlen = (struct ctl_ptr_len_flags *)ARGS(io);
792 	struct scsi_unmap_desc *buf, *end;
793 
794 	CTL_IO_ASSERT(io, SCSI);
795 
796 	if ((ptrlen->flags & ~SU_ANCHOR) != 0) {
797 		ctl_set_invalid_field(&io->scsiio,
798 				      /*sks_valid*/ 0,
799 				      /*command*/ 0,
800 				      /*field*/ 0,
801 				      /*bit_valid*/ 0,
802 				      /*bit*/ 0);
803 		ctl_config_write_done(io);
804 		return;
805 	}
806 
807 	buf = (struct scsi_unmap_desc *)ptrlen->ptr;
808 	end = buf + ptrlen->len / sizeof(*buf);
809 	for (; buf < end; buf++) {
810 		ctl_backend_ramdisk_delete(cbe_lun,
811 		    scsi_8btou64(buf->lba), scsi_4btoul(buf->length),
812 		    (ptrlen->flags & SU_ANCHOR) != 0);
813 	}
814 
815 	ctl_set_success(&io->scsiio);
816 	ctl_config_write_done(io);
817 }
818 
819 static int
820 ctl_backend_ramdisk_scsi_config_write(union ctl_io *io)
821 {
822 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
823 	int retval = 0;
824 
825 	switch (io->scsiio.cdb[0]) {
826 	case SYNCHRONIZE_CACHE:
827 	case SYNCHRONIZE_CACHE_16:
828 		/* We have no cache to flush. */
829 		ctl_set_success(&io->scsiio);
830 		ctl_config_write_done(io);
831 		break;
832 	case START_STOP_UNIT: {
833 		struct scsi_start_stop_unit *cdb;
834 
835 		cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb;
836 		if ((cdb->how & SSS_PC_MASK) != 0) {
837 			ctl_set_success(&io->scsiio);
838 			ctl_config_write_done(io);
839 			break;
840 		}
841 		if (cdb->how & SSS_START) {
842 			if (cdb->how & SSS_LOEJ)
843 				ctl_lun_has_media(cbe_lun);
844 			ctl_start_lun(cbe_lun);
845 		} else {
846 			ctl_stop_lun(cbe_lun);
847 			if (cdb->how & SSS_LOEJ)
848 				ctl_lun_ejected(cbe_lun);
849 		}
850 		ctl_set_success(&io->scsiio);
851 		ctl_config_write_done(io);
852 		break;
853 	}
854 	case PREVENT_ALLOW:
855 		ctl_set_success(&io->scsiio);
856 		ctl_config_write_done(io);
857 		break;
858 	case WRITE_SAME_10:
859 	case WRITE_SAME_16:
860 		ctl_backend_ramdisk_ws(io);
861 		break;
862 	case UNMAP:
863 		ctl_backend_ramdisk_unmap(io);
864 		break;
865 	default:
866 		ctl_set_invalid_opcode(&io->scsiio);
867 		ctl_config_write_done(io);
868 		retval = CTL_RETVAL_COMPLETE;
869 		break;
870 	}
871 
872 	return (retval);
873 }
874 
875 static void
876 ctl_backend_ramdisk_wu(union ctl_io *io)
877 {
878 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
879 	struct ctl_lba_len_flags *lbalen = ARGS(io);
880 
881 	CTL_IO_ASSERT(io, NVME);
882 
883 	/*
884 	 * XXX: Not quite right as reads will return zeroes rather
885 	 * than failing.
886 	 */
887 	ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 1);
888 	ctl_nvme_set_success(&io->nvmeio);
889 	ctl_config_write_done(io);
890 }
891 
892 static void
893 ctl_backend_ramdisk_wz(union ctl_io *io)
894 {
895 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
896 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
897 	struct ctl_lba_len_flags *lbalen = ARGS(io);
898 	uint8_t *page;
899 	uint64_t lba;
900 	u_int lbaoff, lbas;
901 
902 	CTL_IO_ASSERT(io, NVME);
903 
904 	if ((le32toh(io->nvmeio.cmd.cdw12) & (1U << 25)) != 0) {
905 		ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len,
906 		    0);
907 		ctl_nvme_set_success(&io->nvmeio);
908 		ctl_config_write_done(io);
909 		return;
910 	}
911 
912 	for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) {
913 		page = ctl_backend_ramdisk_getpage(be_lun,
914 		    lba >> cbe_lun->pblockexp, GP_WRITE);
915 		if (page == P_UNMAPPED || page == P_ANCHORED) {
916 			ctl_nvme_set_space_alloc_fail(&io->nvmeio);
917 			ctl_data_submit_done(io);
918 			return;
919 		}
920 		lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
921 		page += lbaoff * cbe_lun->blocksize;
922 		memset(page, 0, cbe_lun->blocksize);
923 	}
924 	ctl_nvme_set_success(&io->nvmeio);
925 	ctl_config_write_done(io);
926 }
927 
928 static void
929 ctl_backend_ramdisk_dsm(union ctl_io *io)
930 {
931 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
932 	struct nvme_dsm_range *r;
933 	uint64_t lba;
934 	uint32_t num_blocks;
935 	u_int i, ranges;
936 
937 	CTL_IO_ASSERT(io, NVME);
938 
939 	ranges = le32toh(io->nvmeio.cmd.cdw10) & 0xff;
940 	r = (struct nvme_dsm_range *)io->nvmeio.kern_data_ptr;
941 	for (i = 0; i < ranges; i++) {
942 		lba = le64toh(r[i].starting_lba);
943 		num_blocks = le32toh(r[i].length);
944 		if ((le32toh(r[i].attributes) & (1U << 2)) != 0)
945 			ctl_backend_ramdisk_delete(cbe_lun, lba, num_blocks, 0);
946 	}
947 
948 	ctl_nvme_set_success(&io->nvmeio);
949 	ctl_config_write_done(io);
950 }
951 
952 static int
953 ctl_backend_ramdisk_nvme_config_write(union ctl_io *io)
954 {
955 	switch (io->nvmeio.cmd.opc) {
956 	case NVME_OPC_FLUSH:
957 		/* We have no cache to flush. */
958 		ctl_nvme_set_success(&io->nvmeio);
959 		ctl_config_write_done(io);
960 		break;
961 	case NVME_OPC_WRITE_UNCORRECTABLE:
962 		ctl_backend_ramdisk_wu(io);
963 		break;
964 	case NVME_OPC_WRITE_ZEROES:
965 		ctl_backend_ramdisk_wz(io);
966 		break;
967 	case NVME_OPC_DATASET_MANAGEMENT:
968 		ctl_backend_ramdisk_dsm(io);
969 		break;
970 	default:
971 		ctl_nvme_set_invalid_opcode(&io->nvmeio);
972 		ctl_config_write_done(io);
973 		break;
974 	}
975 	return (CTL_RETVAL_COMPLETE);
976 }
977 
978 static int
979 ctl_backend_ramdisk_config_write(union ctl_io *io)
980 {
981 	switch (io->io_hdr.io_type) {
982 	case CTL_IO_SCSI:
983 		return (ctl_backend_ramdisk_scsi_config_write(io));
984 	case CTL_IO_NVME:
985 		return (ctl_backend_ramdisk_nvme_config_write(io));
986 	default:
987 		__assert_unreachable();
988 	}
989 }
990 
991 static uint64_t
992 ctl_backend_ramdisk_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname)
993 {
994 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
995 	uint64_t		val;
996 
997 	val = UINT64_MAX;
998 	if (be_lun->cap_bytes == 0)
999 		return (val);
1000 	sx_slock(&be_lun->page_lock);
1001 	if (strcmp(attrname, "blocksused") == 0) {
1002 		val = be_lun->cap_used / be_lun->cbe_lun.blocksize;
1003 	} else if (strcmp(attrname, "blocksavail") == 0) {
1004 		val = (be_lun->cap_bytes - be_lun->cap_used) /
1005 		    be_lun->cbe_lun.blocksize;
1006 	}
1007 	sx_sunlock(&be_lun->page_lock);
1008 	return (val);
1009 }
1010 
1011 static int
1012 ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
1013 			  int flag, struct thread *td)
1014 {
1015 	struct ctl_be_ramdisk_softc *softc = &rd_softc;
1016 	struct ctl_lun_req *lun_req;
1017 	int retval;
1018 
1019 	retval = 0;
1020 	switch (cmd) {
1021 	case CTL_LUN_REQ:
1022 		lun_req = (struct ctl_lun_req *)addr;
1023 		switch (lun_req->reqtype) {
1024 		case CTL_LUNREQ_CREATE:
1025 			retval = ctl_backend_ramdisk_create(softc, lun_req);
1026 			break;
1027 		case CTL_LUNREQ_RM:
1028 			retval = ctl_backend_ramdisk_rm(softc, lun_req);
1029 			break;
1030 		case CTL_LUNREQ_MODIFY:
1031 			retval = ctl_backend_ramdisk_modify(softc, lun_req);
1032 			break;
1033 		default:
1034 			lun_req->status = CTL_LUN_ERROR;
1035 			snprintf(lun_req->error_str, sizeof(lun_req->error_str),
1036 				 "%s: invalid LUN request type %d", __func__,
1037 				 lun_req->reqtype);
1038 			break;
1039 		}
1040 		break;
1041 	default:
1042 		retval = ENOTTY;
1043 		break;
1044 	}
1045 
1046 	return (retval);
1047 }
1048 
1049 static int
1050 ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc,
1051 		       struct ctl_lun_req *req)
1052 {
1053 	struct ctl_be_ramdisk_lun *be_lun;
1054 	struct ctl_lun_rm_params *params;
1055 	int retval;
1056 
1057 	params = &req->reqdata.rm;
1058 	sx_xlock(&softc->modify_lock);
1059 	mtx_lock(&softc->lock);
1060 	SLIST_FOREACH(be_lun, &softc->lun_list, links) {
1061 		if (be_lun->cbe_lun.lun_id == params->lun_id) {
1062 			SLIST_REMOVE(&softc->lun_list, be_lun,
1063 			    ctl_be_ramdisk_lun, links);
1064 			softc->num_luns--;
1065 			break;
1066 		}
1067 	}
1068 	mtx_unlock(&softc->lock);
1069 	sx_xunlock(&softc->modify_lock);
1070 	if (be_lun == NULL) {
1071 		snprintf(req->error_str, sizeof(req->error_str),
1072 			 "%s: LUN %u is not managed by the ramdisk backend",
1073 			 __func__, params->lun_id);
1074 		goto bailout_error;
1075 	}
1076 
1077 	/*
1078 	 * Set the waiting flag before we invalidate the LUN.  Our shutdown
1079 	 * routine can be called any time after we invalidate the LUN,
1080 	 * and can be called from our context.
1081 	 *
1082 	 * This tells the shutdown routine that we're waiting, or we're
1083 	 * going to wait for the shutdown to happen.
1084 	 */
1085 	mtx_lock(&softc->lock);
1086 	be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING;
1087 	mtx_unlock(&softc->lock);
1088 
1089 	retval = ctl_remove_lun(&be_lun->cbe_lun);
1090 	if (retval != 0) {
1091 		snprintf(req->error_str, sizeof(req->error_str),
1092 			 "%s: error %d returned from ctl_remove_lun() for "
1093 			 "LUN %d", __func__, retval, params->lun_id);
1094 		mtx_lock(&softc->lock);
1095 		be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
1096 		mtx_unlock(&softc->lock);
1097 		goto bailout_error;
1098 	}
1099 
1100 	mtx_lock(&softc->lock);
1101 	while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) {
1102 		retval = msleep(be_lun, &softc->lock, PCATCH, "ctlramrm", 0);
1103 		if (retval == EINTR)
1104 			break;
1105 	}
1106 	be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
1107 	if (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) {
1108 		mtx_unlock(&softc->lock);
1109 		free(be_lun, M_RAMDISK);
1110 	} else {
1111 		mtx_unlock(&softc->lock);
1112 		return (EINTR);
1113 	}
1114 
1115 	req->status = CTL_LUN_OK;
1116 	return (retval);
1117 
1118 bailout_error:
1119 	req->status = CTL_LUN_ERROR;
1120 	return (0);
1121 }
1122 
1123 static int
1124 ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
1125 			   struct ctl_lun_req *req)
1126 {
1127 	struct ctl_be_ramdisk_lun *be_lun;
1128 	struct ctl_be_lun *cbe_lun;
1129 	struct ctl_lun_create_params *params;
1130 	const char *value;
1131 	char tmpstr[32];
1132 	uint64_t t;
1133 	int retval;
1134 
1135 	retval = 0;
1136 	params = &req->reqdata.create;
1137 
1138 	be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK);
1139 	cbe_lun = &be_lun->cbe_lun;
1140 	cbe_lun->options = nvlist_clone(req->args_nvl);
1141 	be_lun->params = req->reqdata.create;
1142 	be_lun->softc = softc;
1143 
1144 	if (params->flags & CTL_LUN_FLAG_DEV_TYPE)
1145 		cbe_lun->lun_type = params->device_type;
1146 	else
1147 		cbe_lun->lun_type = T_DIRECT;
1148 	be_lun->flags = 0;
1149 	cbe_lun->flags = 0;
1150 	value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL);
1151 	if (value != NULL) {
1152 		if (strcmp(value, "primary") == 0)
1153 			cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1154 	} else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
1155 		cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1156 
1157 	be_lun->pblocksize = PAGE_SIZE;
1158 	value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL);
1159 	if (value != NULL) {
1160 		ctl_expand_number(value, &t);
1161 		be_lun->pblocksize = t;
1162 	}
1163 	if (be_lun->pblocksize < 512 || be_lun->pblocksize > 131072) {
1164 		snprintf(req->error_str, sizeof(req->error_str),
1165 			 "%s: unsupported pblocksize %u", __func__,
1166 			 be_lun->pblocksize);
1167 		goto bailout_error;
1168 	}
1169 
1170 	if (cbe_lun->lun_type == T_DIRECT ||
1171 	    cbe_lun->lun_type == T_CDROM) {
1172 		if (params->blocksize_bytes != 0)
1173 			cbe_lun->blocksize = params->blocksize_bytes;
1174 		else if (cbe_lun->lun_type == T_CDROM)
1175 			cbe_lun->blocksize = 2048;
1176 		else
1177 			cbe_lun->blocksize = 512;
1178 		be_lun->pblockmul = be_lun->pblocksize / cbe_lun->blocksize;
1179 		if (be_lun->pblockmul < 1 || !powerof2(be_lun->pblockmul)) {
1180 			snprintf(req->error_str, sizeof(req->error_str),
1181 				 "%s: pblocksize %u not exp2 of blocksize %u",
1182 				 __func__,
1183 				 be_lun->pblocksize, cbe_lun->blocksize);
1184 			goto bailout_error;
1185 		}
1186 		if (params->lun_size_bytes < cbe_lun->blocksize) {
1187 			snprintf(req->error_str, sizeof(req->error_str),
1188 				 "%s: LUN size %ju < blocksize %u", __func__,
1189 				 params->lun_size_bytes, cbe_lun->blocksize);
1190 			goto bailout_error;
1191 		}
1192 		be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize;
1193 		be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize;
1194 		be_lun->indir = 0;
1195 		t = be_lun->size_bytes / be_lun->pblocksize;
1196 		while (t > 1) {
1197 			t /= PPP;
1198 			be_lun->indir++;
1199 		}
1200 		cbe_lun->maxlba = be_lun->size_blocks - 1;
1201 		cbe_lun->pblockexp = fls(be_lun->pblockmul) - 1;
1202 		cbe_lun->pblockoff = 0;
1203 		cbe_lun->ublockexp = cbe_lun->pblockexp;
1204 		cbe_lun->ublockoff = 0;
1205 		cbe_lun->atomicblock = be_lun->pblocksize;
1206 		cbe_lun->opttxferlen = SGPP * be_lun->pblocksize;
1207 		value = dnvlist_get_string(cbe_lun->options, "capacity", NULL);
1208 		if (value != NULL)
1209 			ctl_expand_number(value, &be_lun->cap_bytes);
1210 	} else {
1211 		be_lun->pblockmul = 1;
1212 		cbe_lun->pblockexp = 0;
1213 	}
1214 
1215 	/* Tell the user the blocksize we ended up using */
1216 	params->blocksize_bytes = cbe_lun->blocksize;
1217 	params->lun_size_bytes = be_lun->size_bytes;
1218 
1219 	value = dnvlist_get_string(cbe_lun->options, "unmap", NULL);
1220 	if (value == NULL || strcmp(value, "off") != 0)
1221 		cbe_lun->flags |= CTL_LUN_FLAG_UNMAP;
1222 	value = dnvlist_get_string(cbe_lun->options, "readonly", NULL);
1223 	if (value != NULL) {
1224 		if (strcmp(value, "on") == 0)
1225 			cbe_lun->flags |= CTL_LUN_FLAG_READONLY;
1226 	} else if (cbe_lun->lun_type != T_DIRECT)
1227 		cbe_lun->flags |= CTL_LUN_FLAG_READONLY;
1228 	cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
1229 	value = dnvlist_get_string(cbe_lun->options, "serseq", NULL);
1230 	if (value != NULL && strcmp(value, "on") == 0)
1231 		cbe_lun->serseq = CTL_LUN_SERSEQ_ON;
1232 	else if (value != NULL && strcmp(value, "read") == 0)
1233 		cbe_lun->serseq = CTL_LUN_SERSEQ_READ;
1234 	else if (value != NULL && strcmp(value, "soft") == 0)
1235 		cbe_lun->serseq = CTL_LUN_SERSEQ_SOFT;
1236 	else if (value != NULL && strcmp(value, "off") == 0)
1237 		cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
1238 
1239 	if (params->flags & CTL_LUN_FLAG_ID_REQ) {
1240 		cbe_lun->req_lun_id = params->req_lun_id;
1241 		cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ;
1242 	} else
1243 		cbe_lun->req_lun_id = 0;
1244 
1245 	cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown;
1246 	cbe_lun->be = &ctl_be_ramdisk_driver;
1247 	if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) {
1248 		snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%04d",
1249 			 softc->num_luns);
1250 		strncpy((char *)cbe_lun->serial_num, tmpstr,
1251 			MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr)));
1252 
1253 		/* Tell the user what we used for a serial number */
1254 		strncpy((char *)params->serial_num, tmpstr,
1255 			MIN(sizeof(params->serial_num), sizeof(tmpstr)));
1256 	} else {
1257 		strncpy((char *)cbe_lun->serial_num, params->serial_num,
1258 			MIN(sizeof(cbe_lun->serial_num),
1259 			    sizeof(params->serial_num)));
1260 	}
1261 	if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) {
1262 		snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%04d", softc->num_luns);
1263 		strncpy((char *)cbe_lun->device_id, tmpstr,
1264 			MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr)));
1265 
1266 		/* Tell the user what we used for a device ID */
1267 		strncpy((char *)params->device_id, tmpstr,
1268 			MIN(sizeof(params->device_id), sizeof(tmpstr)));
1269 	} else {
1270 		strncpy((char *)cbe_lun->device_id, params->device_id,
1271 			MIN(sizeof(cbe_lun->device_id),
1272 			    sizeof(params->device_id)));
1273 	}
1274 
1275 	STAILQ_INIT(&be_lun->cont_queue);
1276 	sx_init(&be_lun->page_lock, "ctlram page");
1277 	if (be_lun->cap_bytes == 0) {
1278 		be_lun->indir = 0;
1279 		be_lun->pages = malloc(be_lun->pblocksize, M_RAMDISK, M_WAITOK);
1280 	}
1281 	be_lun->zero_page = malloc(be_lun->pblocksize, M_RAMDISK,
1282 	    M_WAITOK|M_ZERO);
1283 	mtx_init(&be_lun->queue_lock, "ctlram queue", NULL, MTX_DEF);
1284 	TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker,
1285 	    be_lun);
1286 
1287 	be_lun->io_taskqueue = taskqueue_create("ctlramtq", M_WAITOK,
1288 	    taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue);
1289 	if (be_lun->io_taskqueue == NULL) {
1290 		snprintf(req->error_str, sizeof(req->error_str),
1291 			 "%s: Unable to create taskqueue", __func__);
1292 		goto bailout_error;
1293 	}
1294 
1295 	retval = taskqueue_start_threads_in_proc(&be_lun->io_taskqueue,
1296 					 /*num threads*/1,
1297 					 /*priority*/PUSER,
1298 					 /*proc*/control_softc->ctl_proc,
1299 					 /*thread name*/"ramdisk");
1300 	if (retval != 0)
1301 		goto bailout_error;
1302 
1303 	retval = ctl_add_lun(&be_lun->cbe_lun);
1304 	if (retval != 0) {
1305 		snprintf(req->error_str, sizeof(req->error_str),
1306 			 "%s: ctl_add_lun() returned error %d, see dmesg for "
1307 			"details", __func__, retval);
1308 		retval = 0;
1309 		goto bailout_error;
1310 	}
1311 
1312 	mtx_lock(&softc->lock);
1313 	softc->num_luns++;
1314 	SLIST_INSERT_HEAD(&softc->lun_list, be_lun, links);
1315 	mtx_unlock(&softc->lock);
1316 
1317 	params->req_lun_id = cbe_lun->lun_id;
1318 
1319 	req->status = CTL_LUN_OK;
1320 	return (retval);
1321 
1322 bailout_error:
1323 	req->status = CTL_LUN_ERROR;
1324 	if (be_lun != NULL) {
1325 		if (be_lun->io_taskqueue != NULL)
1326 			taskqueue_free(be_lun->io_taskqueue);
1327 		nvlist_destroy(cbe_lun->options);
1328 		free(be_lun->zero_page, M_RAMDISK);
1329 		ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir);
1330 		sx_destroy(&be_lun->page_lock);
1331 		mtx_destroy(&be_lun->queue_lock);
1332 		free(be_lun, M_RAMDISK);
1333 	}
1334 	return (retval);
1335 }
1336 
1337 static int
1338 ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc,
1339 		       struct ctl_lun_req *req)
1340 {
1341 	struct ctl_be_ramdisk_lun *be_lun;
1342 	struct ctl_be_lun *cbe_lun;
1343 	struct ctl_lun_modify_params *params;
1344 	const char *value;
1345 	uint32_t blocksize;
1346 	int wasprim;
1347 
1348 	params = &req->reqdata.modify;
1349 	sx_xlock(&softc->modify_lock);
1350 	mtx_lock(&softc->lock);
1351 	SLIST_FOREACH(be_lun, &softc->lun_list, links) {
1352 		if (be_lun->cbe_lun.lun_id == params->lun_id)
1353 			break;
1354 	}
1355 	mtx_unlock(&softc->lock);
1356 	if (be_lun == NULL) {
1357 		snprintf(req->error_str, sizeof(req->error_str),
1358 			 "%s: LUN %u is not managed by the ramdisk backend",
1359 			 __func__, params->lun_id);
1360 		goto bailout_error;
1361 	}
1362 	cbe_lun = &be_lun->cbe_lun;
1363 
1364 	if (params->lun_size_bytes != 0)
1365 		be_lun->params.lun_size_bytes = params->lun_size_bytes;
1366 
1367 	if (req->args_nvl != NULL) {
1368 		nvlist_destroy(cbe_lun->options);
1369 		cbe_lun->options = nvlist_clone(req->args_nvl);
1370 	}
1371 
1372 	wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY);
1373 	value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL);
1374 	if (value != NULL) {
1375 		if (strcmp(value, "primary") == 0)
1376 			cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1377 		else
1378 			cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
1379 	} else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
1380 		cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1381 	else
1382 		cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
1383 	if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) {
1384 		if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)
1385 			ctl_lun_primary(cbe_lun);
1386 		else
1387 			ctl_lun_secondary(cbe_lun);
1388 	}
1389 
1390 	blocksize = be_lun->cbe_lun.blocksize;
1391 	if (be_lun->params.lun_size_bytes < blocksize) {
1392 		snprintf(req->error_str, sizeof(req->error_str),
1393 			"%s: LUN size %ju < blocksize %u", __func__,
1394 			be_lun->params.lun_size_bytes, blocksize);
1395 		goto bailout_error;
1396 	}
1397 	be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize;
1398 	be_lun->size_bytes = be_lun->size_blocks * blocksize;
1399 	be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1;
1400 	ctl_lun_capacity_changed(&be_lun->cbe_lun);
1401 
1402 	/* Tell the user the exact size we ended up using */
1403 	params->lun_size_bytes = be_lun->size_bytes;
1404 
1405 	sx_xunlock(&softc->modify_lock);
1406 	req->status = CTL_LUN_OK;
1407 	return (0);
1408 
1409 bailout_error:
1410 	sx_xunlock(&softc->modify_lock);
1411 	req->status = CTL_LUN_ERROR;
1412 	return (0);
1413 }
1414 
1415 static void
1416 ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun *cbe_lun)
1417 {
1418 	struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun;
1419 	struct ctl_be_ramdisk_softc *softc = be_lun->softc;
1420 
1421 	taskqueue_drain_all(be_lun->io_taskqueue);
1422 	taskqueue_free(be_lun->io_taskqueue);
1423 	nvlist_destroy(be_lun->cbe_lun.options);
1424 	free(be_lun->zero_page, M_RAMDISK);
1425 	ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir);
1426 	sx_destroy(&be_lun->page_lock);
1427 	mtx_destroy(&be_lun->queue_lock);
1428 
1429 	mtx_lock(&softc->lock);
1430 	be_lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED;
1431 	if (be_lun->flags & CTL_BE_RAMDISK_LUN_WAITING)
1432 		wakeup(be_lun);
1433 	else
1434 		free(be_lun, M_RAMDISK);
1435 	mtx_unlock(&softc->lock);
1436 }
1437