xref: /freebsd/sys/cam/ctl/ctl_backend_ramdisk.c (revision 2fb36370)
1130f4520SKenneth D. Merry /*-
2130f4520SKenneth D. Merry  * Copyright (c) 2003, 2008 Silicon Graphics International Corp.
381177295SEdward Tomasz Napierala  * Copyright (c) 2012 The FreeBSD Foundation
4e7037673SAlexander Motin  * Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org>
5130f4520SKenneth D. Merry  * All rights reserved.
6130f4520SKenneth D. Merry  *
781177295SEdward Tomasz Napierala  * Portions of this software were developed by Edward Tomasz Napierala
881177295SEdward Tomasz Napierala  * under sponsorship from the FreeBSD Foundation.
981177295SEdward Tomasz Napierala  *
10130f4520SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
11130f4520SKenneth D. Merry  * modification, are permitted provided that the following conditions
12130f4520SKenneth D. Merry  * are met:
13130f4520SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright
14130f4520SKenneth D. Merry  *    notice, this list of conditions, and the following disclaimer,
15130f4520SKenneth D. Merry  *    without modification.
16130f4520SKenneth D. Merry  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17130f4520SKenneth D. Merry  *    substantially similar to the "NO WARRANTY" disclaimer below
18130f4520SKenneth D. Merry  *    ("Disclaimer") and any redistribution must be conditioned upon
19130f4520SKenneth D. Merry  *    including a substantially similar Disclaimer requirement for further
20130f4520SKenneth D. Merry  *    binary redistribution.
21130f4520SKenneth D. Merry  *
22130f4520SKenneth D. Merry  * NO WARRANTY
23130f4520SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24130f4520SKenneth D. Merry  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25130f4520SKenneth D. Merry  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
26130f4520SKenneth D. Merry  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27130f4520SKenneth D. Merry  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28130f4520SKenneth D. Merry  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29130f4520SKenneth D. Merry  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30130f4520SKenneth D. Merry  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31130f4520SKenneth D. Merry  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32130f4520SKenneth D. Merry  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33130f4520SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGES.
34130f4520SKenneth D. Merry  *
35130f4520SKenneth D. Merry  * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $
36130f4520SKenneth D. Merry  */
37130f4520SKenneth D. Merry /*
38e7037673SAlexander Motin  * CAM Target Layer black hole and RAM disk backend.
39130f4520SKenneth D. Merry  *
40130f4520SKenneth D. Merry  * Author: Ken Merry <ken@FreeBSD.org>
41130f4520SKenneth D. Merry  */
42130f4520SKenneth D. Merry 
43130f4520SKenneth D. Merry #include <sys/cdefs.h>
44130f4520SKenneth D. Merry __FBSDID("$FreeBSD$");
45130f4520SKenneth D. Merry 
46130f4520SKenneth D. Merry #include <sys/param.h>
47130f4520SKenneth D. Merry #include <sys/systm.h>
48130f4520SKenneth D. Merry #include <sys/kernel.h>
49130f4520SKenneth D. Merry #include <sys/condvar.h>
50130f4520SKenneth D. Merry #include <sys/types.h>
51e7037673SAlexander Motin #include <sys/limits.h>
52130f4520SKenneth D. Merry #include <sys/lock.h>
53130f4520SKenneth D. Merry #include <sys/mutex.h>
54130f4520SKenneth D. Merry #include <sys/malloc.h>
55e7037673SAlexander Motin #include <sys/sx.h>
5608a7cce5SAlexander Motin #include <sys/taskqueue.h>
57130f4520SKenneth D. Merry #include <sys/time.h>
58130f4520SKenneth D. Merry #include <sys/queue.h>
59130f4520SKenneth D. Merry #include <sys/conf.h>
60130f4520SKenneth D. Merry #include <sys/ioccom.h>
61130f4520SKenneth D. Merry #include <sys/module.h>
627ac58230SAlexander Motin #include <sys/sysctl.h>
63130f4520SKenneth D. Merry 
64130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h>
657ac58230SAlexander Motin #include <cam/scsi/scsi_da.h>
66130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h>
67130f4520SKenneth D. Merry #include <cam/ctl/ctl.h>
68130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h>
69130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h>
70130f4520SKenneth D. Merry #include <cam/ctl/ctl_debug.h>
71130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h>
727ac58230SAlexander Motin #include <cam/ctl/ctl_ha.h>
737ac58230SAlexander Motin #include <cam/ctl/ctl_private.h>
74130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h>
75130f4520SKenneth D. Merry 
76e7037673SAlexander Motin #define PRIV(io)	\
77e7037673SAlexander Motin     ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND])
78e7037673SAlexander Motin #define ARGS(io)	\
79e7037673SAlexander Motin     ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN])
80e7037673SAlexander Motin 
81e7037673SAlexander Motin #define	PPP	(PAGE_SIZE / sizeof(uint8_t **))
82e7037673SAlexander Motin #ifdef __LP64__
83e7037673SAlexander Motin #define	PPPS	(PAGE_SHIFT - 3)
84e7037673SAlexander Motin #else
85e7037673SAlexander Motin #define	PPPS	(PAGE_SHIFT - 2)
86e7037673SAlexander Motin #endif
87e7037673SAlexander Motin #define	SGPP	(PAGE_SIZE / sizeof(struct ctl_sg_entry))
88e7037673SAlexander Motin 
89e7037673SAlexander Motin #define	P_UNMAPPED	NULL			/* Page is unmapped. */
90e7037673SAlexander Motin #define	P_ANCHORED	((void *)(uintptr_t)1)	/* Page is anchored. */
91e7037673SAlexander Motin 
92e7037673SAlexander Motin typedef enum {
93e7037673SAlexander Motin 	GP_READ,	/* Return data page or zero page. */
94e7037673SAlexander Motin 	GP_WRITE,	/* Return data page, try allocate if none. */
95e7037673SAlexander Motin 	GP_ANCHOR,	/* Return data page, try anchor if none. */
96e7037673SAlexander Motin 	GP_OTHER,	/* Return what present, do not allocate/anchor. */
97e7037673SAlexander Motin } getpage_op_t;
98e7037673SAlexander Motin 
99130f4520SKenneth D. Merry typedef enum {
100130f4520SKenneth D. Merry 	CTL_BE_RAMDISK_LUN_UNCONFIGURED	= 0x01,
101130f4520SKenneth D. Merry 	CTL_BE_RAMDISK_LUN_CONFIG_ERR	= 0x02,
102130f4520SKenneth D. Merry 	CTL_BE_RAMDISK_LUN_WAITING	= 0x04
103130f4520SKenneth D. Merry } ctl_be_ramdisk_lun_flags;
104130f4520SKenneth D. Merry 
105130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun {
106a3977beaSAlexander Motin 	struct ctl_lun_create_params params;
10708a7cce5SAlexander Motin 	char			lunname[32];
108e7037673SAlexander Motin 	int			indir;
109e7037673SAlexander Motin 	uint8_t			**pages;
110e7037673SAlexander Motin 	uint8_t			*zero_page;
111e7037673SAlexander Motin 	struct sx		page_lock;
112e7037673SAlexander Motin 	u_int			pblocksize;
113e7037673SAlexander Motin 	u_int			pblockmul;
114130f4520SKenneth D. Merry 	uint64_t		size_bytes;
115130f4520SKenneth D. Merry 	uint64_t		size_blocks;
116e7037673SAlexander Motin 	uint64_t		cap_bytes;
117e7037673SAlexander Motin 	uint64_t		cap_used;
118130f4520SKenneth D. Merry 	struct ctl_be_ramdisk_softc *softc;
119130f4520SKenneth D. Merry 	ctl_be_ramdisk_lun_flags flags;
120130f4520SKenneth D. Merry 	STAILQ_ENTRY(ctl_be_ramdisk_lun) links;
1210bcd4ab6SAlexander Motin 	struct ctl_be_lun	cbe_lun;
12208a7cce5SAlexander Motin 	struct taskqueue	*io_taskqueue;
12308a7cce5SAlexander Motin 	struct task		io_task;
12408a7cce5SAlexander Motin 	STAILQ_HEAD(, ctl_io_hdr) cont_queue;
12575c7a1d3SAlexander Motin 	struct mtx_padalign	queue_lock;
126130f4520SKenneth D. Merry };
127130f4520SKenneth D. Merry 
128130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc {
129130f4520SKenneth D. Merry 	struct mtx lock;
130130f4520SKenneth D. Merry 	int num_luns;
131130f4520SKenneth D. Merry 	STAILQ_HEAD(, ctl_be_ramdisk_lun) lun_list;
132130f4520SKenneth D. Merry };
133130f4520SKenneth D. Merry 
134130f4520SKenneth D. Merry static struct ctl_be_ramdisk_softc rd_softc;
1357ac58230SAlexander Motin extern struct ctl_softc *control_softc;
136130f4520SKenneth D. Merry 
1370c629e28SAlexander Motin static int ctl_backend_ramdisk_init(void);
1380c629e28SAlexander Motin static int ctl_backend_ramdisk_shutdown(void);
139130f4520SKenneth D. Merry static int ctl_backend_ramdisk_move_done(union ctl_io *io);
140e7037673SAlexander Motin static void ctl_backend_ramdisk_compare(union ctl_io *io);
141e7037673SAlexander Motin static void ctl_backend_ramdisk_rw(union ctl_io *io);
142130f4520SKenneth D. Merry static int ctl_backend_ramdisk_submit(union ctl_io *io);
143e7037673SAlexander Motin static void ctl_backend_ramdisk_worker(void *context, int pending);
144e7037673SAlexander Motin static int ctl_backend_ramdisk_config_read(union ctl_io *io);
145e7037673SAlexander Motin static int ctl_backend_ramdisk_config_write(union ctl_io *io);
146e7037673SAlexander Motin static uint64_t ctl_backend_ramdisk_lun_attr(void *be_lun, const char *attrname);
147130f4520SKenneth D. Merry static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd,
148130f4520SKenneth D. Merry 				     caddr_t addr, int flag, struct thread *td);
149130f4520SKenneth D. Merry static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc,
150130f4520SKenneth D. Merry 				  struct ctl_lun_req *req);
151130f4520SKenneth D. Merry static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
1520bcd4ab6SAlexander Motin 				      struct ctl_lun_req *req);
15381177295SEdward Tomasz Napierala static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc,
15481177295SEdward Tomasz Napierala 				  struct ctl_lun_req *req);
155130f4520SKenneth D. Merry static void ctl_backend_ramdisk_lun_shutdown(void *be_lun);
156130f4520SKenneth D. Merry static void ctl_backend_ramdisk_lun_config_status(void *be_lun,
157130f4520SKenneth D. Merry 						  ctl_lun_config_status status);
158130f4520SKenneth D. Merry 
159130f4520SKenneth D. Merry static struct ctl_backend_driver ctl_be_ramdisk_driver =
160130f4520SKenneth D. Merry {
1612a2443d8SKenneth D. Merry 	.name = "ramdisk",
1622a2443d8SKenneth D. Merry 	.flags = CTL_BE_FLAG_HAS_CONFIG,
1632a2443d8SKenneth D. Merry 	.init = ctl_backend_ramdisk_init,
1640c629e28SAlexander Motin 	.shutdown = ctl_backend_ramdisk_shutdown,
1652a2443d8SKenneth D. Merry 	.data_submit = ctl_backend_ramdisk_submit,
1662a2443d8SKenneth D. Merry 	.data_move_done = ctl_backend_ramdisk_move_done,
1672a2443d8SKenneth D. Merry 	.config_read = ctl_backend_ramdisk_config_read,
1682a2443d8SKenneth D. Merry 	.config_write = ctl_backend_ramdisk_config_write,
169e7037673SAlexander Motin 	.ioctl = ctl_backend_ramdisk_ioctl,
170e7037673SAlexander Motin 	.lun_attr = ctl_backend_ramdisk_lun_attr,
171130f4520SKenneth D. Merry };
172130f4520SKenneth D. Merry 
173130f4520SKenneth D. Merry MALLOC_DEFINE(M_RAMDISK, "ramdisk", "Memory used for CTL RAMdisk");
174130f4520SKenneth D. Merry CTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver);
175130f4520SKenneth D. Merry 
176e7037673SAlexander Motin static int
177130f4520SKenneth D. Merry ctl_backend_ramdisk_init(void)
178130f4520SKenneth D. Merry {
17967cc546dSAlexander Motin 	struct ctl_be_ramdisk_softc *softc = &rd_softc;
180130f4520SKenneth D. Merry 
181130f4520SKenneth D. Merry 	memset(softc, 0, sizeof(*softc));
18275c7a1d3SAlexander Motin 	mtx_init(&softc->lock, "ctlramdisk", NULL, MTX_DEF);
183130f4520SKenneth D. Merry 	STAILQ_INIT(&softc->lun_list);
184130f4520SKenneth D. Merry 	return (0);
185130f4520SKenneth D. Merry }
186130f4520SKenneth D. Merry 
1870c629e28SAlexander Motin static int
188130f4520SKenneth D. Merry ctl_backend_ramdisk_shutdown(void)
189130f4520SKenneth D. Merry {
19067cc546dSAlexander Motin 	struct ctl_be_ramdisk_softc *softc = &rd_softc;
191130f4520SKenneth D. Merry 	struct ctl_be_ramdisk_lun *lun, *next_lun;
192130f4520SKenneth D. Merry 
193130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
194f5a2bbe6SAlexander Motin 	STAILQ_FOREACH_SAFE(lun, &softc->lun_list, links, next_lun) {
195130f4520SKenneth D. Merry 		/*
196130f4520SKenneth D. Merry 		 * Drop our lock here.  Since ctl_invalidate_lun() can call
197130f4520SKenneth D. Merry 		 * back into us, this could potentially lead to a recursive
198130f4520SKenneth D. Merry 		 * lock of the same mutex, which would cause a hang.
199130f4520SKenneth D. Merry 		 */
200130f4520SKenneth D. Merry 		mtx_unlock(&softc->lock);
2010bcd4ab6SAlexander Motin 		ctl_disable_lun(&lun->cbe_lun);
2020bcd4ab6SAlexander Motin 		ctl_invalidate_lun(&lun->cbe_lun);
203130f4520SKenneth D. Merry 		mtx_lock(&softc->lock);
204130f4520SKenneth D. Merry 	}
205130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
2060c629e28SAlexander Motin 	mtx_destroy(&softc->lock);
2070c629e28SAlexander Motin 	return (0);
208130f4520SKenneth D. Merry }
209130f4520SKenneth D. Merry 
210e7037673SAlexander Motin static uint8_t *
211e7037673SAlexander Motin ctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn,
212e7037673SAlexander Motin     getpage_op_t op)
213e7037673SAlexander Motin {
214e7037673SAlexander Motin 	uint8_t **p, ***pp;
215e7037673SAlexander Motin 	off_t i;
216e7037673SAlexander Motin 	int s;
217e7037673SAlexander Motin 
218e7037673SAlexander Motin 	if (be_lun->cap_bytes == 0) {
219e7037673SAlexander Motin 		switch (op) {
220e7037673SAlexander Motin 		case GP_READ:
221e7037673SAlexander Motin 			return (be_lun->zero_page);
222e7037673SAlexander Motin 		case GP_WRITE:
223e7037673SAlexander Motin 			return ((uint8_t *)be_lun->pages);
224e7037673SAlexander Motin 		case GP_ANCHOR:
225e7037673SAlexander Motin 			return (P_ANCHORED);
226e7037673SAlexander Motin 		default:
227e7037673SAlexander Motin 			return (P_UNMAPPED);
228e7037673SAlexander Motin 		}
229e7037673SAlexander Motin 	}
230e7037673SAlexander Motin 	if (op == GP_WRITE || op == GP_ANCHOR) {
231e7037673SAlexander Motin 		sx_xlock(&be_lun->page_lock);
232e7037673SAlexander Motin 		pp = &be_lun->pages;
233e7037673SAlexander Motin 		for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
234e7037673SAlexander Motin 			if (*pp == NULL) {
235e7037673SAlexander Motin 				*pp = malloc(PAGE_SIZE, M_RAMDISK,
236e7037673SAlexander Motin 				    M_WAITOK|M_ZERO);
237e7037673SAlexander Motin 			}
238e7037673SAlexander Motin 			i = pn >> s;
239e7037673SAlexander Motin 			pp = (uint8_t ***)&(*pp)[i];
240e7037673SAlexander Motin 			pn -= i << s;
241e7037673SAlexander Motin 		}
242e7037673SAlexander Motin 		if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) {
243e7037673SAlexander Motin 			if (op == GP_WRITE) {
244e7037673SAlexander Motin 				*pp = malloc(be_lun->pblocksize, M_RAMDISK,
245e7037673SAlexander Motin 				    M_WAITOK|M_ZERO);
246e7037673SAlexander Motin 			} else
247e7037673SAlexander Motin 				*pp = P_ANCHORED;
248e7037673SAlexander Motin 			be_lun->cap_used += be_lun->pblocksize;
249e7037673SAlexander Motin 		} else if (*pp == P_ANCHORED && op == GP_WRITE) {
250e7037673SAlexander Motin 			*pp = malloc(be_lun->pblocksize, M_RAMDISK,
251e7037673SAlexander Motin 			    M_WAITOK|M_ZERO);
252e7037673SAlexander Motin 		}
253e7037673SAlexander Motin 		sx_xunlock(&be_lun->page_lock);
254e7037673SAlexander Motin 		return ((uint8_t *)*pp);
255e7037673SAlexander Motin 	} else {
256e7037673SAlexander Motin 		sx_slock(&be_lun->page_lock);
257e7037673SAlexander Motin 		p = be_lun->pages;
258e7037673SAlexander Motin 		for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
259e7037673SAlexander Motin 			if (p == NULL)
260e7037673SAlexander Motin 				break;
261e7037673SAlexander Motin 			i = pn >> s;
262e7037673SAlexander Motin 			p = (uint8_t **)p[i];
263e7037673SAlexander Motin 			pn -= i << s;
264e7037673SAlexander Motin 		}
265e7037673SAlexander Motin 		sx_sunlock(&be_lun->page_lock);
266e7037673SAlexander Motin 		if ((p == P_UNMAPPED || p == P_ANCHORED) && op == GP_READ)
267e7037673SAlexander Motin 			return (be_lun->zero_page);
268e7037673SAlexander Motin 		return ((uint8_t *)p);
269e7037673SAlexander Motin 	}
270e7037673SAlexander Motin };
271e7037673SAlexander Motin 
272e7037673SAlexander Motin static void
273e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun *be_lun, off_t pn)
274e7037673SAlexander Motin {
275e7037673SAlexander Motin 	uint8_t ***pp;
276e7037673SAlexander Motin 	off_t i;
277e7037673SAlexander Motin 	int s;
278e7037673SAlexander Motin 
279e7037673SAlexander Motin 	if (be_lun->cap_bytes == 0)
280e7037673SAlexander Motin 		return;
281e7037673SAlexander Motin 	sx_xlock(&be_lun->page_lock);
282e7037673SAlexander Motin 	pp = &be_lun->pages;
283e7037673SAlexander Motin 	for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
284e7037673SAlexander Motin 		if (*pp == NULL)
285e7037673SAlexander Motin 			goto noindir;
286e7037673SAlexander Motin 		i = pn >> s;
287e7037673SAlexander Motin 		pp = (uint8_t ***)&(*pp)[i];
288e7037673SAlexander Motin 		pn -= i << s;
289e7037673SAlexander Motin 	}
290e7037673SAlexander Motin 	if (*pp == P_ANCHORED) {
291e7037673SAlexander Motin 		be_lun->cap_used -= be_lun->pblocksize;
292e7037673SAlexander Motin 		*pp = P_UNMAPPED;
293e7037673SAlexander Motin 	} else if (*pp != P_UNMAPPED) {
294e7037673SAlexander Motin 		free(*pp, M_RAMDISK);
295e7037673SAlexander Motin 		be_lun->cap_used -= be_lun->pblocksize;
296e7037673SAlexander Motin 		*pp = P_UNMAPPED;
297e7037673SAlexander Motin 	}
298e7037673SAlexander Motin noindir:
299e7037673SAlexander Motin 	sx_xunlock(&be_lun->page_lock);
300e7037673SAlexander Motin };
301e7037673SAlexander Motin 
302e7037673SAlexander Motin static void
303e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn)
304e7037673SAlexander Motin {
305e7037673SAlexander Motin 	uint8_t ***pp;
306e7037673SAlexander Motin 	off_t i;
307e7037673SAlexander Motin 	int s;
308e7037673SAlexander Motin 
309e7037673SAlexander Motin 	if (be_lun->cap_bytes == 0)
310e7037673SAlexander Motin 		return;
311e7037673SAlexander Motin 	sx_xlock(&be_lun->page_lock);
312e7037673SAlexander Motin 	pp = &be_lun->pages;
313e7037673SAlexander Motin 	for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
314e7037673SAlexander Motin 		if (*pp == NULL)
315e7037673SAlexander Motin 			goto noindir;
316e7037673SAlexander Motin 		i = pn >> s;
317e7037673SAlexander Motin 		pp = (uint8_t ***)&(*pp)[i];
318e7037673SAlexander Motin 		pn -= i << s;
319e7037673SAlexander Motin 	}
320e7037673SAlexander Motin 	if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) {
321e7037673SAlexander Motin 		be_lun->cap_used += be_lun->pblocksize;
322e7037673SAlexander Motin 		*pp = P_ANCHORED;
323e7037673SAlexander Motin 	} else if (*pp != P_ANCHORED) {
324e7037673SAlexander Motin 		free(*pp, M_RAMDISK);
325e7037673SAlexander Motin 		*pp = P_ANCHORED;
326e7037673SAlexander Motin 	}
327e7037673SAlexander Motin noindir:
328e7037673SAlexander Motin 	sx_xunlock(&be_lun->page_lock);
329e7037673SAlexander Motin };
330e7037673SAlexander Motin 
331e7037673SAlexander Motin static void
332e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(uint8_t **p, int indir)
333e7037673SAlexander Motin {
334e7037673SAlexander Motin 	int i;
335e7037673SAlexander Motin 
336e7037673SAlexander Motin 	if (p == NULL)
337e7037673SAlexander Motin 		return;
338e7037673SAlexander Motin 	if (indir == 0) {
339e7037673SAlexander Motin 		free(p, M_RAMDISK);
340e7037673SAlexander Motin 		return;
341e7037673SAlexander Motin 	}
342e7037673SAlexander Motin 	for (i = 0; i < PPP; i++) {
343e7037673SAlexander Motin 		if (p[i] == NULL)
344e7037673SAlexander Motin 			continue;
345e7037673SAlexander Motin 		ctl_backend_ramdisk_freeallpages((uint8_t **)p[i], indir - 1);
346e7037673SAlexander Motin 	}
347e7037673SAlexander Motin 	free(p, M_RAMDISK);
348e7037673SAlexander Motin };
349e7037673SAlexander Motin 
350e7037673SAlexander Motin static size_t
351e7037673SAlexander Motin cmp(uint8_t *a, uint8_t *b, size_t size)
352e7037673SAlexander Motin {
353e7037673SAlexander Motin 	size_t i;
354e7037673SAlexander Motin 
355e7037673SAlexander Motin 	for (i = 0; i < size; i++) {
356e7037673SAlexander Motin 		if (a[i] != b[i])
357e7037673SAlexander Motin 			break;
358e7037673SAlexander Motin 	}
359e7037673SAlexander Motin 	return (i);
360e7037673SAlexander Motin }
361e7037673SAlexander Motin 
362e7037673SAlexander Motin static int
363e7037673SAlexander Motin ctl_backend_ramdisk_cmp(union ctl_io *io)
364e7037673SAlexander Motin {
365e7037673SAlexander Motin 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
366e7037673SAlexander Motin 	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
367e7037673SAlexander Motin 	uint8_t *page;
368e7037673SAlexander Motin 	uint8_t info[8];
369e7037673SAlexander Motin 	uint64_t lba;
370e7037673SAlexander Motin 	u_int lbaoff, lbas, res, off;
371e7037673SAlexander Motin 
372e7037673SAlexander Motin 	lbas = io->scsiio.kern_data_len / cbe_lun->blocksize;
373e7037673SAlexander Motin 	lba = ARGS(io)->lba + PRIV(io)->len - lbas;
374e7037673SAlexander Motin 	off = 0;
375e7037673SAlexander Motin 	for (; lbas > 0; lbas--, lba++) {
376e7037673SAlexander Motin 		page = ctl_backend_ramdisk_getpage(be_lun,
377e7037673SAlexander Motin 		    lba >> cbe_lun->pblockexp, GP_READ);
378e7037673SAlexander Motin 		lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
379e7037673SAlexander Motin 		page += lbaoff * cbe_lun->blocksize;
380e7037673SAlexander Motin 		res = cmp(io->scsiio.kern_data_ptr + off, page,
381e7037673SAlexander Motin 		    cbe_lun->blocksize);
382e7037673SAlexander Motin 		off += res;
383e7037673SAlexander Motin 		if (res < cbe_lun->blocksize)
384e7037673SAlexander Motin 			break;
385e7037673SAlexander Motin 	}
386e7037673SAlexander Motin 	if (lbas > 0) {
387e7037673SAlexander Motin 		off += io->scsiio.kern_rel_offset - io->scsiio.kern_data_len;
388e7037673SAlexander Motin 		scsi_u64to8b(off, info);
389e7037673SAlexander Motin 		ctl_set_sense(&io->scsiio, /*current_error*/ 1,
390e7037673SAlexander Motin 		    /*sense_key*/ SSD_KEY_MISCOMPARE,
391e7037673SAlexander Motin 		    /*asc*/ 0x1D, /*ascq*/ 0x00,
392e7037673SAlexander Motin 		    /*type*/ SSD_ELEM_INFO,
393e7037673SAlexander Motin 		    /*size*/ sizeof(info), /*data*/ &info,
394e7037673SAlexander Motin 		    /*type*/ SSD_ELEM_NONE);
395e7037673SAlexander Motin 		return (1);
396e7037673SAlexander Motin 	}
397e7037673SAlexander Motin 	return (0);
398e7037673SAlexander Motin }
399e7037673SAlexander Motin 
400130f4520SKenneth D. Merry static int
401130f4520SKenneth D. Merry ctl_backend_ramdisk_move_done(union ctl_io *io)
402130f4520SKenneth D. Merry {
403e7037673SAlexander Motin 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
404e7037673SAlexander Motin 	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
405130f4520SKenneth D. Merry #ifdef CTL_TIME_IO
406130f4520SKenneth D. Merry 	struct bintime cur_bt;
407130f4520SKenneth D. Merry #endif
408130f4520SKenneth D. Merry 
409130f4520SKenneth D. Merry 	CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n"));
41008a7cce5SAlexander Motin #ifdef CTL_TIME_IO
411e675024aSAlexander Motin 	getbinuptime(&cur_bt);
41208a7cce5SAlexander Motin 	bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt);
41308a7cce5SAlexander Motin 	bintime_add(&io->io_hdr.dma_bt, &cur_bt);
41408a7cce5SAlexander Motin #endif
415e675024aSAlexander Motin 	io->io_hdr.num_dmas++;
41608a7cce5SAlexander Motin 	if (io->scsiio.kern_sg_entries > 0)
41708a7cce5SAlexander Motin 		free(io->scsiio.kern_data_ptr, M_RAMDISK);
41808a7cce5SAlexander Motin 	io->scsiio.kern_rel_offset += io->scsiio.kern_data_len;
419f7241cceSAlexander Motin 	if (io->io_hdr.flags & CTL_FLAG_ABORT) {
420f7241cceSAlexander Motin 		;
421eb6ac6f9SAlexander Motin 	} else if (io->io_hdr.port_status != 0 &&
422eb6ac6f9SAlexander Motin 	    ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE ||
423eb6ac6f9SAlexander Motin 	     (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) {
424eb6ac6f9SAlexander Motin 		ctl_set_internal_failure(&io->scsiio, /*sks_valid*/ 1,
425eb6ac6f9SAlexander Motin 		    /*retry_count*/ io->io_hdr.port_status);
426eb6ac6f9SAlexander Motin 	} else if (io->scsiio.kern_data_resid != 0 &&
427eb6ac6f9SAlexander Motin 	    (io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_OUT &&
428eb6ac6f9SAlexander Motin 	    ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE ||
429eb6ac6f9SAlexander Motin 	     (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) {
430eb6ac6f9SAlexander Motin 		ctl_set_invalid_field_ciu(&io->scsiio);
431f7241cceSAlexander Motin 	} else if ((io->io_hdr.port_status == 0) &&
432f7241cceSAlexander Motin 	    ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) {
433e7037673SAlexander Motin 		if (ARGS(io)->flags & CTL_LLF_COMPARE) {
434e7037673SAlexander Motin 			/* We have data block ready for comparison. */
435e7037673SAlexander Motin 			if (ctl_backend_ramdisk_cmp(io))
436e7037673SAlexander Motin 				goto done;
437e7037673SAlexander Motin 		}
438e7037673SAlexander Motin 		if (ARGS(io)->len > PRIV(io)->len) {
43975c7a1d3SAlexander Motin 			mtx_lock(&be_lun->queue_lock);
44008a7cce5SAlexander Motin 			STAILQ_INSERT_TAIL(&be_lun->cont_queue,
44108a7cce5SAlexander Motin 			    &io->io_hdr, links);
44275c7a1d3SAlexander Motin 			mtx_unlock(&be_lun->queue_lock);
44308a7cce5SAlexander Motin 			taskqueue_enqueue(be_lun->io_taskqueue,
44408a7cce5SAlexander Motin 			    &be_lun->io_task);
44508a7cce5SAlexander Motin 			return (0);
44608a7cce5SAlexander Motin 		}
4474a286345SAlexander Motin 		ctl_set_success(&io->scsiio);
448130f4520SKenneth D. Merry 	}
449e7037673SAlexander Motin done:
45011b569f7SAlexander Motin 	ctl_data_submit_done(io);
451130f4520SKenneth D. Merry 	return(0);
452130f4520SKenneth D. Merry }
453130f4520SKenneth D. Merry 
454e7037673SAlexander Motin static void
455e7037673SAlexander Motin ctl_backend_ramdisk_compare(union ctl_io *io)
456e7037673SAlexander Motin {
457e7037673SAlexander Motin 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
458e7037673SAlexander Motin 	u_int lbas, len;
459e7037673SAlexander Motin 
460e7037673SAlexander Motin 	lbas = ARGS(io)->len - PRIV(io)->len;
461e7037673SAlexander Motin 	lbas = MIN(lbas, 131072 / cbe_lun->blocksize);
462e7037673SAlexander Motin 	len = lbas * cbe_lun->blocksize;
463e7037673SAlexander Motin 
464e7037673SAlexander Motin 	io->scsiio.be_move_done = ctl_backend_ramdisk_move_done;
465e7037673SAlexander Motin 	io->scsiio.kern_data_ptr = malloc(len, M_RAMDISK, M_WAITOK);
466e7037673SAlexander Motin 	io->scsiio.kern_data_len = len;
467e7037673SAlexander Motin 	io->scsiio.kern_sg_entries = 0;
468e7037673SAlexander Motin 	io->io_hdr.flags |= CTL_FLAG_ALLOCATED;
469e7037673SAlexander Motin 	PRIV(io)->len += lbas;
470e7037673SAlexander Motin #ifdef CTL_TIME_IO
471e7037673SAlexander Motin 	getbinuptime(&io->io_hdr.dma_start_bt);
472e7037673SAlexander Motin #endif
473e7037673SAlexander Motin 	ctl_datamove(io);
474e7037673SAlexander Motin }
475e7037673SAlexander Motin 
476e7037673SAlexander Motin static void
477e7037673SAlexander Motin ctl_backend_ramdisk_rw(union ctl_io *io)
478e7037673SAlexander Motin {
479e7037673SAlexander Motin 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
480e7037673SAlexander Motin 	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
481e7037673SAlexander Motin 	struct ctl_sg_entry *sg_entries;
482e7037673SAlexander Motin 	uint8_t *page;
483e7037673SAlexander Motin 	uint64_t lba;
484e7037673SAlexander Motin 	u_int i, len, lbaoff, lbas, sgs, off;
485e7037673SAlexander Motin 	getpage_op_t op;
486e7037673SAlexander Motin 
487e7037673SAlexander Motin 	lba = ARGS(io)->lba + PRIV(io)->len;
488e7037673SAlexander Motin 	lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
489e7037673SAlexander Motin 	lbas = ARGS(io)->len - PRIV(io)->len;
490e7037673SAlexander Motin 	lbas = MIN(lbas, (SGPP << cbe_lun->pblockexp) - lbaoff);
491e7037673SAlexander Motin 	sgs = (lbas + lbaoff + be_lun->pblockmul - 1) >> cbe_lun->pblockexp;
492e7037673SAlexander Motin 	off = lbaoff * cbe_lun->blocksize;
493e7037673SAlexander Motin 	op = (ARGS(io)->flags & CTL_LLF_WRITE) ? GP_WRITE : GP_READ;
494e7037673SAlexander Motin 	if (sgs > 1) {
495e7037673SAlexander Motin 		io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) *
496e7037673SAlexander Motin 		    sgs, M_RAMDISK, M_WAITOK);
497e7037673SAlexander Motin 		sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
498e7037673SAlexander Motin 		len = lbas * cbe_lun->blocksize;
499e7037673SAlexander Motin 		for (i = 0; i < sgs; i++) {
500e7037673SAlexander Motin 			page = ctl_backend_ramdisk_getpage(be_lun,
501e7037673SAlexander Motin 			    (lba >> cbe_lun->pblockexp) + i, op);
502e7037673SAlexander Motin 			if (page == P_UNMAPPED || page == P_ANCHORED) {
503e7037673SAlexander Motin 				free(io->scsiio.kern_data_ptr, M_RAMDISK);
504e7037673SAlexander Motin nospc:
505e7037673SAlexander Motin 				ctl_set_space_alloc_fail(&io->scsiio);
506e7037673SAlexander Motin 				ctl_data_submit_done(io);
507e7037673SAlexander Motin 				return;
508e7037673SAlexander Motin 			}
509e7037673SAlexander Motin 			sg_entries[i].addr = page + off;
510e7037673SAlexander Motin 			sg_entries[i].len = MIN(len, be_lun->pblocksize - off);
511e7037673SAlexander Motin 			len -= sg_entries[i].len;
512e7037673SAlexander Motin 			off = 0;
513e7037673SAlexander Motin 		}
514e7037673SAlexander Motin 	} else {
515e7037673SAlexander Motin 		page = ctl_backend_ramdisk_getpage(be_lun,
516e7037673SAlexander Motin 		    lba >> cbe_lun->pblockexp, op);
517e7037673SAlexander Motin 		if (page == P_UNMAPPED || page == P_ANCHORED)
518e7037673SAlexander Motin 			goto nospc;
519e7037673SAlexander Motin 		sgs = 0;
520e7037673SAlexander Motin 		io->scsiio.kern_data_ptr = page + off;
521e7037673SAlexander Motin 	}
522e7037673SAlexander Motin 
523e7037673SAlexander Motin 	io->scsiio.be_move_done = ctl_backend_ramdisk_move_done;
524e7037673SAlexander Motin 	io->scsiio.kern_data_len = lbas * cbe_lun->blocksize;
525e7037673SAlexander Motin 	io->scsiio.kern_sg_entries = sgs;
526e7037673SAlexander Motin 	io->io_hdr.flags |= CTL_FLAG_ALLOCATED;
527e7037673SAlexander Motin 	PRIV(io)->len += lbas;
528e7037673SAlexander Motin #ifdef CTL_TIME_IO
529e7037673SAlexander Motin 	getbinuptime(&io->io_hdr.dma_start_bt);
530e7037673SAlexander Motin #endif
531e7037673SAlexander Motin 	ctl_datamove(io);
532e7037673SAlexander Motin }
533e7037673SAlexander Motin 
534130f4520SKenneth D. Merry static int
535130f4520SKenneth D. Merry ctl_backend_ramdisk_submit(union ctl_io *io)
536130f4520SKenneth D. Merry {
537e7037673SAlexander Motin 	struct ctl_lba_len_flags *lbalen = ARGS(io);
538130f4520SKenneth D. Merry 
53911b569f7SAlexander Motin 	if (lbalen->flags & CTL_LLF_VERIFY) {
54011b569f7SAlexander Motin 		ctl_set_success(&io->scsiio);
54111b569f7SAlexander Motin 		ctl_data_submit_done(io);
54211b569f7SAlexander Motin 		return (CTL_RETVAL_COMPLETE);
54311b569f7SAlexander Motin 	}
544e7037673SAlexander Motin 	PRIV(io)->len = 0;
545e7037673SAlexander Motin 	if (lbalen->flags & CTL_LLF_COMPARE)
546e7037673SAlexander Motin 		ctl_backend_ramdisk_compare(io);
547e7037673SAlexander Motin 	else
548e7037673SAlexander Motin 		ctl_backend_ramdisk_rw(io);
549130f4520SKenneth D. Merry 	return (CTL_RETVAL_COMPLETE);
550130f4520SKenneth D. Merry }
551130f4520SKenneth D. Merry 
55208a7cce5SAlexander Motin static void
55308a7cce5SAlexander Motin ctl_backend_ramdisk_worker(void *context, int pending)
55408a7cce5SAlexander Motin {
55508a7cce5SAlexander Motin 	struct ctl_be_ramdisk_lun *be_lun;
55608a7cce5SAlexander Motin 	union ctl_io *io;
55708a7cce5SAlexander Motin 
55808a7cce5SAlexander Motin 	be_lun = (struct ctl_be_ramdisk_lun *)context;
55975c7a1d3SAlexander Motin 	mtx_lock(&be_lun->queue_lock);
56008a7cce5SAlexander Motin 	for (;;) {
56108a7cce5SAlexander Motin 		io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue);
56208a7cce5SAlexander Motin 		if (io != NULL) {
56308a7cce5SAlexander Motin 			STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr,
56408a7cce5SAlexander Motin 				      ctl_io_hdr, links);
56575c7a1d3SAlexander Motin 			mtx_unlock(&be_lun->queue_lock);
566e7037673SAlexander Motin 			if (ARGS(io)->flags & CTL_LLF_COMPARE)
567e7037673SAlexander Motin 				ctl_backend_ramdisk_compare(io);
568e7037673SAlexander Motin 			else
569e7037673SAlexander Motin 				ctl_backend_ramdisk_rw(io);
57075c7a1d3SAlexander Motin 			mtx_lock(&be_lun->queue_lock);
57108a7cce5SAlexander Motin 			continue;
57208a7cce5SAlexander Motin 		}
57308a7cce5SAlexander Motin 
57408a7cce5SAlexander Motin 		/*
57508a7cce5SAlexander Motin 		 * If we get here, there is no work left in the queues, so
57608a7cce5SAlexander Motin 		 * just break out and let the task queue go to sleep.
57708a7cce5SAlexander Motin 		 */
57808a7cce5SAlexander Motin 		break;
57908a7cce5SAlexander Motin 	}
58075c7a1d3SAlexander Motin 	mtx_unlock(&be_lun->queue_lock);
581130f4520SKenneth D. Merry }
582130f4520SKenneth D. Merry 
583130f4520SKenneth D. Merry static int
584e7037673SAlexander Motin ctl_backend_ramdisk_gls(union ctl_io *io)
585e7037673SAlexander Motin {
586e7037673SAlexander Motin 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
587e7037673SAlexander Motin 	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
588e7037673SAlexander Motin 	struct scsi_get_lba_status_data *data;
589e7037673SAlexander Motin 	uint8_t *page;
590e7037673SAlexander Motin 	u_int lbaoff;
591e7037673SAlexander Motin 
592e7037673SAlexander Motin 	data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
593e7037673SAlexander Motin 	scsi_u64to8b(ARGS(io)->lba, data->descr[0].addr);
594e7037673SAlexander Motin 	lbaoff = ARGS(io)->lba & ~(UINT_MAX << cbe_lun->pblockexp);
595e7037673SAlexander Motin 	scsi_ulto4b(be_lun->pblockmul - lbaoff, data->descr[0].length);
596e7037673SAlexander Motin 	page = ctl_backend_ramdisk_getpage(be_lun,
597e7037673SAlexander Motin 	    ARGS(io)->lba >> cbe_lun->pblockexp, GP_OTHER);
598e7037673SAlexander Motin 	if (page == P_UNMAPPED)
599e7037673SAlexander Motin 		data->descr[0].status = 1;
600e7037673SAlexander Motin 	else if (page == P_ANCHORED)
601e7037673SAlexander Motin 		data->descr[0].status = 2;
602e7037673SAlexander Motin 	else
603e7037673SAlexander Motin 		data->descr[0].status = 0;
604e7037673SAlexander Motin 	ctl_config_read_done(io);
605e7037673SAlexander Motin 	return (CTL_RETVAL_COMPLETE);
606e7037673SAlexander Motin }
607e7037673SAlexander Motin 
608e7037673SAlexander Motin static int
609e7037673SAlexander Motin ctl_backend_ramdisk_config_read(union ctl_io *io)
610e7037673SAlexander Motin {
611e7037673SAlexander Motin 	int retval = 0;
612e7037673SAlexander Motin 
613e7037673SAlexander Motin 	switch (io->scsiio.cdb[0]) {
614e7037673SAlexander Motin 	case SERVICE_ACTION_IN:
615e7037673SAlexander Motin 		if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
616e7037673SAlexander Motin 			retval = ctl_backend_ramdisk_gls(io);
617e7037673SAlexander Motin 			break;
618e7037673SAlexander Motin 		}
619e7037673SAlexander Motin 		ctl_set_invalid_field(&io->scsiio,
620e7037673SAlexander Motin 				      /*sks_valid*/ 1,
621e7037673SAlexander Motin 				      /*command*/ 1,
622e7037673SAlexander Motin 				      /*field*/ 1,
623e7037673SAlexander Motin 				      /*bit_valid*/ 1,
624e7037673SAlexander Motin 				      /*bit*/ 4);
625e7037673SAlexander Motin 		ctl_config_read_done(io);
626e7037673SAlexander Motin 		retval = CTL_RETVAL_COMPLETE;
627e7037673SAlexander Motin 		break;
628e7037673SAlexander Motin 	default:
629e7037673SAlexander Motin 		ctl_set_invalid_opcode(&io->scsiio);
630e7037673SAlexander Motin 		ctl_config_read_done(io);
631e7037673SAlexander Motin 		retval = CTL_RETVAL_COMPLETE;
632e7037673SAlexander Motin 		break;
633e7037673SAlexander Motin 	}
634e7037673SAlexander Motin 	return (retval);
635e7037673SAlexander Motin }
636e7037673SAlexander Motin 
637e7037673SAlexander Motin static void
638e7037673SAlexander Motin ctl_backend_ramdisk_delete(struct ctl_be_lun *cbe_lun, off_t lba, off_t len,
639e7037673SAlexander Motin     int anchor)
640e7037673SAlexander Motin {
641e7037673SAlexander Motin 	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
642e7037673SAlexander Motin 	uint8_t *page;
643e7037673SAlexander Motin 	uint64_t p, lp;
644e7037673SAlexander Motin 	u_int lbaoff;
645e7037673SAlexander Motin 	getpage_op_t op = anchor ? GP_ANCHOR : GP_OTHER;
646e7037673SAlexander Motin 
647e7037673SAlexander Motin 	/* Partially zero first partial page. */
648e7037673SAlexander Motin 	p = lba >> cbe_lun->pblockexp;
649e7037673SAlexander Motin 	lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
650e7037673SAlexander Motin 	if (lbaoff != 0) {
651e7037673SAlexander Motin 		page = ctl_backend_ramdisk_getpage(be_lun, p, op);
652e7037673SAlexander Motin 		if (page != P_UNMAPPED && page != P_ANCHORED) {
653e7037673SAlexander Motin 			memset(page + lbaoff * cbe_lun->blocksize, 0,
654e7037673SAlexander Motin 			    min(len, be_lun->pblockmul - lbaoff) *
655e7037673SAlexander Motin 			    cbe_lun->blocksize);
656e7037673SAlexander Motin 		}
657e7037673SAlexander Motin 		p++;
658e7037673SAlexander Motin 	}
659e7037673SAlexander Motin 
660e7037673SAlexander Motin 	/* Partially zero last partial page. */
661e7037673SAlexander Motin 	lp = (lba + len) >> cbe_lun->pblockexp;
662e7037673SAlexander Motin 	lbaoff = (lba + len) & ~(UINT_MAX << cbe_lun->pblockexp);
663e7037673SAlexander Motin 	if (p <= lp && lbaoff != 0) {
664e7037673SAlexander Motin 		page = ctl_backend_ramdisk_getpage(be_lun, lp, op);
665e7037673SAlexander Motin 		if (page != P_UNMAPPED && page != P_ANCHORED)
666e7037673SAlexander Motin 			memset(page, 0, lbaoff * cbe_lun->blocksize);
667e7037673SAlexander Motin 	}
668e7037673SAlexander Motin 
669e7037673SAlexander Motin 	/* Delete remaining full pages. */
670e7037673SAlexander Motin 	if (anchor) {
671e7037673SAlexander Motin 		for (; p < lp; p++)
672e7037673SAlexander Motin 			ctl_backend_ramdisk_anchorpage(be_lun, p);
673e7037673SAlexander Motin 	} else {
674e7037673SAlexander Motin 		for (; p < lp; p++)
675e7037673SAlexander Motin 			ctl_backend_ramdisk_unmappage(be_lun, p);
676e7037673SAlexander Motin 	}
677e7037673SAlexander Motin }
678e7037673SAlexander Motin 
679e7037673SAlexander Motin static void
680e7037673SAlexander Motin ctl_backend_ramdisk_ws(union ctl_io *io)
681e7037673SAlexander Motin {
682e7037673SAlexander Motin 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
683e7037673SAlexander Motin 	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
684e7037673SAlexander Motin 	struct ctl_lba_len_flags *lbalen = ARGS(io);
685e7037673SAlexander Motin 	uint8_t *page;
686e7037673SAlexander Motin 	uint64_t lba;
687e7037673SAlexander Motin 	u_int lbaoff, lbas;
688e7037673SAlexander Motin 
689e7037673SAlexander Motin 	if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB)) {
690e7037673SAlexander Motin 		ctl_set_invalid_field(&io->scsiio,
691e7037673SAlexander Motin 				      /*sks_valid*/ 1,
692e7037673SAlexander Motin 				      /*command*/ 1,
693e7037673SAlexander Motin 				      /*field*/ 1,
694e7037673SAlexander Motin 				      /*bit_valid*/ 0,
695e7037673SAlexander Motin 				      /*bit*/ 0);
696e7037673SAlexander Motin 		ctl_config_write_done(io);
697e7037673SAlexander Motin 		return;
698e7037673SAlexander Motin 	}
699e7037673SAlexander Motin 	if (lbalen->flags & SWS_UNMAP) {
700e7037673SAlexander Motin 		ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len,
701e7037673SAlexander Motin 		    (lbalen->flags & SWS_ANCHOR) != 0);
702e7037673SAlexander Motin 		ctl_set_success(&io->scsiio);
703e7037673SAlexander Motin 		ctl_config_write_done(io);
704e7037673SAlexander Motin 		return;
705e7037673SAlexander Motin 	}
706e7037673SAlexander Motin 
707e7037673SAlexander Motin 	for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) {
708e7037673SAlexander Motin 		page = ctl_backend_ramdisk_getpage(be_lun,
709e7037673SAlexander Motin 		    lba >> cbe_lun->pblockexp, GP_WRITE);
710e7037673SAlexander Motin 		if (page == P_UNMAPPED || page == P_ANCHORED) {
711e7037673SAlexander Motin 			ctl_set_space_alloc_fail(&io->scsiio);
712e7037673SAlexander Motin 			ctl_data_submit_done(io);
713e7037673SAlexander Motin 			return;
714e7037673SAlexander Motin 		}
715e7037673SAlexander Motin 		lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
716e7037673SAlexander Motin 		page += lbaoff * cbe_lun->blocksize;
717e7037673SAlexander Motin 		if (lbalen->flags & SWS_NDOB) {
718e7037673SAlexander Motin 			memset(page, 0, cbe_lun->blocksize);
719e7037673SAlexander Motin 		} else {
720e7037673SAlexander Motin 			memcpy(page, io->scsiio.kern_data_ptr,
721e7037673SAlexander Motin 			    cbe_lun->blocksize);
722e7037673SAlexander Motin 		}
723e7037673SAlexander Motin 		if (lbalen->flags & SWS_LBDATA)
724e7037673SAlexander Motin 			scsi_ulto4b(lba, page);
725e7037673SAlexander Motin 	}
726e7037673SAlexander Motin 	ctl_set_success(&io->scsiio);
727e7037673SAlexander Motin 	ctl_config_write_done(io);
728e7037673SAlexander Motin }
729e7037673SAlexander Motin 
730e7037673SAlexander Motin static void
731e7037673SAlexander Motin ctl_backend_ramdisk_unmap(union ctl_io *io)
732e7037673SAlexander Motin {
733e7037673SAlexander Motin 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
734e7037673SAlexander Motin 	struct ctl_ptr_len_flags *ptrlen = (struct ctl_ptr_len_flags *)ARGS(io);
735e7037673SAlexander Motin 	struct scsi_unmap_desc *buf, *end;
736e7037673SAlexander Motin 
737e7037673SAlexander Motin 	if ((ptrlen->flags & ~SU_ANCHOR) != 0) {
738e7037673SAlexander Motin 		ctl_set_invalid_field(&io->scsiio,
739e7037673SAlexander Motin 				      /*sks_valid*/ 0,
740e7037673SAlexander Motin 				      /*command*/ 0,
741e7037673SAlexander Motin 				      /*field*/ 0,
742e7037673SAlexander Motin 				      /*bit_valid*/ 0,
743e7037673SAlexander Motin 				      /*bit*/ 0);
744e7037673SAlexander Motin 		ctl_config_write_done(io);
745e7037673SAlexander Motin 		return;
746e7037673SAlexander Motin 	}
747e7037673SAlexander Motin 
748e7037673SAlexander Motin 	buf = (struct scsi_unmap_desc *)ptrlen->ptr;
749e7037673SAlexander Motin 	end = buf + ptrlen->len / sizeof(*buf);
750e7037673SAlexander Motin 	for (; buf < end; buf++) {
751e7037673SAlexander Motin 		ctl_backend_ramdisk_delete(cbe_lun,
752e7037673SAlexander Motin 		    scsi_8btou64(buf->lba), scsi_4btoul(buf->length),
753e7037673SAlexander Motin 		    (ptrlen->flags & SU_ANCHOR) != 0);
754e7037673SAlexander Motin 	}
755e7037673SAlexander Motin 
756e7037673SAlexander Motin 	ctl_set_success(&io->scsiio);
757e7037673SAlexander Motin 	ctl_config_write_done(io);
758e7037673SAlexander Motin }
759e7037673SAlexander Motin 
760e7037673SAlexander Motin static int
761e7037673SAlexander Motin ctl_backend_ramdisk_config_write(union ctl_io *io)
762e7037673SAlexander Motin {
763e7037673SAlexander Motin 	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
764e7037673SAlexander Motin 	int retval = 0;
765e7037673SAlexander Motin 
766e7037673SAlexander Motin 	switch (io->scsiio.cdb[0]) {
767e7037673SAlexander Motin 	case SYNCHRONIZE_CACHE:
768e7037673SAlexander Motin 	case SYNCHRONIZE_CACHE_16:
769e7037673SAlexander Motin 		/* We have no cache to flush. */
770e7037673SAlexander Motin 		ctl_set_success(&io->scsiio);
771e7037673SAlexander Motin 		ctl_config_write_done(io);
772e7037673SAlexander Motin 		break;
773e7037673SAlexander Motin 	case START_STOP_UNIT: {
774e7037673SAlexander Motin 		struct scsi_start_stop_unit *cdb;
775e7037673SAlexander Motin 
776e7037673SAlexander Motin 		cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb;
777e7037673SAlexander Motin 		if ((cdb->how & SSS_PC_MASK) != 0) {
778e7037673SAlexander Motin 			ctl_set_success(&io->scsiio);
779e7037673SAlexander Motin 			ctl_config_write_done(io);
780e7037673SAlexander Motin 			break;
781e7037673SAlexander Motin 		}
782e7037673SAlexander Motin 		if (cdb->how & SSS_START) {
783e7037673SAlexander Motin 			if (cdb->how & SSS_LOEJ)
784e7037673SAlexander Motin 				ctl_lun_has_media(cbe_lun);
785e7037673SAlexander Motin 			ctl_start_lun(cbe_lun);
786e7037673SAlexander Motin 		} else {
787e7037673SAlexander Motin 			ctl_stop_lun(cbe_lun);
788e7037673SAlexander Motin 			if (cdb->how & SSS_LOEJ)
789e7037673SAlexander Motin 				ctl_lun_ejected(cbe_lun);
790e7037673SAlexander Motin 		}
791e7037673SAlexander Motin 		ctl_set_success(&io->scsiio);
792e7037673SAlexander Motin 		ctl_config_write_done(io);
793e7037673SAlexander Motin 		break;
794e7037673SAlexander Motin 	}
795e7037673SAlexander Motin 	case PREVENT_ALLOW:
796e7037673SAlexander Motin 		ctl_set_success(&io->scsiio);
797e7037673SAlexander Motin 		ctl_config_write_done(io);
798e7037673SAlexander Motin 		break;
799e7037673SAlexander Motin 	case WRITE_SAME_10:
800e7037673SAlexander Motin 	case WRITE_SAME_16:
801e7037673SAlexander Motin 		ctl_backend_ramdisk_ws(io);
802e7037673SAlexander Motin 		break;
803e7037673SAlexander Motin 	case UNMAP:
804e7037673SAlexander Motin 		ctl_backend_ramdisk_unmap(io);
805e7037673SAlexander Motin 		break;
806e7037673SAlexander Motin 	default:
807e7037673SAlexander Motin 		ctl_set_invalid_opcode(&io->scsiio);
808e7037673SAlexander Motin 		ctl_config_write_done(io);
809e7037673SAlexander Motin 		retval = CTL_RETVAL_COMPLETE;
810e7037673SAlexander Motin 		break;
811e7037673SAlexander Motin 	}
812e7037673SAlexander Motin 
813e7037673SAlexander Motin 	return (retval);
814e7037673SAlexander Motin }
815e7037673SAlexander Motin 
816e7037673SAlexander Motin static uint64_t
817e7037673SAlexander Motin ctl_backend_ramdisk_lun_attr(void *arg, const char *attrname)
818e7037673SAlexander Motin {
819e7037673SAlexander Motin 	struct ctl_be_ramdisk_lun *be_lun = arg;
820e7037673SAlexander Motin 	uint64_t		val;
821e7037673SAlexander Motin 
822e7037673SAlexander Motin 	val = UINT64_MAX;
823e7037673SAlexander Motin 	if (be_lun->cap_bytes == 0)
824e7037673SAlexander Motin 		return (val);
825e7037673SAlexander Motin 	sx_slock(&be_lun->page_lock);
826e7037673SAlexander Motin 	if (strcmp(attrname, "blocksused") == 0) {
827e7037673SAlexander Motin 		val = be_lun->cap_used / be_lun->cbe_lun.blocksize;
828e7037673SAlexander Motin 	} else if (strcmp(attrname, "blocksavail") == 0) {
829e7037673SAlexander Motin 		val = (be_lun->cap_bytes - be_lun->cap_used) /
830e7037673SAlexander Motin 		    be_lun->cbe_lun.blocksize;
831e7037673SAlexander Motin 	}
832e7037673SAlexander Motin 	sx_sunlock(&be_lun->page_lock);
833e7037673SAlexander Motin 	return (val);
834e7037673SAlexander Motin }
835e7037673SAlexander Motin 
836e7037673SAlexander Motin static int
837130f4520SKenneth D. Merry ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
838130f4520SKenneth D. Merry 			  int flag, struct thread *td)
839130f4520SKenneth D. Merry {
84067cc546dSAlexander Motin 	struct ctl_be_ramdisk_softc *softc = &rd_softc;
84167cc546dSAlexander Motin 	struct ctl_lun_req *lun_req;
842130f4520SKenneth D. Merry 	int retval;
843130f4520SKenneth D. Merry 
844130f4520SKenneth D. Merry 	retval = 0;
845130f4520SKenneth D. Merry 	switch (cmd) {
84667cc546dSAlexander Motin 	case CTL_LUN_REQ:
847130f4520SKenneth D. Merry 		lun_req = (struct ctl_lun_req *)addr;
848130f4520SKenneth D. Merry 		switch (lun_req->reqtype) {
849130f4520SKenneth D. Merry 		case CTL_LUNREQ_CREATE:
8500bcd4ab6SAlexander Motin 			retval = ctl_backend_ramdisk_create(softc, lun_req);
851130f4520SKenneth D. Merry 			break;
852130f4520SKenneth D. Merry 		case CTL_LUNREQ_RM:
853130f4520SKenneth D. Merry 			retval = ctl_backend_ramdisk_rm(softc, lun_req);
854130f4520SKenneth D. Merry 			break;
85581177295SEdward Tomasz Napierala 		case CTL_LUNREQ_MODIFY:
85681177295SEdward Tomasz Napierala 			retval = ctl_backend_ramdisk_modify(softc, lun_req);
85781177295SEdward Tomasz Napierala 			break;
858130f4520SKenneth D. Merry 		default:
859130f4520SKenneth D. Merry 			lun_req->status = CTL_LUN_ERROR;
860130f4520SKenneth D. Merry 			snprintf(lun_req->error_str, sizeof(lun_req->error_str),
861130f4520SKenneth D. Merry 				 "%s: invalid LUN request type %d", __func__,
862130f4520SKenneth D. Merry 				 lun_req->reqtype);
863130f4520SKenneth D. Merry 			break;
864130f4520SKenneth D. Merry 		}
865130f4520SKenneth D. Merry 		break;
866130f4520SKenneth D. Merry 	default:
867130f4520SKenneth D. Merry 		retval = ENOTTY;
868130f4520SKenneth D. Merry 		break;
869130f4520SKenneth D. Merry 	}
870130f4520SKenneth D. Merry 
871130f4520SKenneth D. Merry 	return (retval);
872130f4520SKenneth D. Merry }
873130f4520SKenneth D. Merry 
874130f4520SKenneth D. Merry static int
875130f4520SKenneth D. Merry ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc,
876130f4520SKenneth D. Merry 		       struct ctl_lun_req *req)
877130f4520SKenneth D. Merry {
878130f4520SKenneth D. Merry 	struct ctl_be_ramdisk_lun *be_lun;
879130f4520SKenneth D. Merry 	struct ctl_lun_rm_params *params;
880130f4520SKenneth D. Merry 	int retval;
881130f4520SKenneth D. Merry 
882130f4520SKenneth D. Merry 	params = &req->reqdata.rm;
883130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
884130f4520SKenneth D. Merry 	STAILQ_FOREACH(be_lun, &softc->lun_list, links) {
8850bcd4ab6SAlexander Motin 		if (be_lun->cbe_lun.lun_id == params->lun_id)
886130f4520SKenneth D. Merry 			break;
887130f4520SKenneth D. Merry 	}
888130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
889130f4520SKenneth D. Merry 	if (be_lun == NULL) {
890130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
891130f4520SKenneth D. Merry 			 "%s: LUN %u is not managed by the ramdisk backend",
892130f4520SKenneth D. Merry 			 __func__, params->lun_id);
893130f4520SKenneth D. Merry 		goto bailout_error;
894130f4520SKenneth D. Merry 	}
895130f4520SKenneth D. Merry 
8960bcd4ab6SAlexander Motin 	retval = ctl_disable_lun(&be_lun->cbe_lun);
897130f4520SKenneth D. Merry 	if (retval != 0) {
898130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
899130f4520SKenneth D. Merry 			 "%s: error %d returned from ctl_disable_lun() for "
900130f4520SKenneth D. Merry 			 "LUN %d", __func__, retval, params->lun_id);
901130f4520SKenneth D. Merry 		goto bailout_error;
902130f4520SKenneth D. Merry 	}
903130f4520SKenneth D. Merry 
904130f4520SKenneth D. Merry 	/*
905130f4520SKenneth D. Merry 	 * Set the waiting flag before we invalidate the LUN.  Our shutdown
906130f4520SKenneth D. Merry 	 * routine can be called any time after we invalidate the LUN,
907130f4520SKenneth D. Merry 	 * and can be called from our context.
908130f4520SKenneth D. Merry 	 *
909130f4520SKenneth D. Merry 	 * This tells the shutdown routine that we're waiting, or we're
910130f4520SKenneth D. Merry 	 * going to wait for the shutdown to happen.
911130f4520SKenneth D. Merry 	 */
912130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
913130f4520SKenneth D. Merry 	be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING;
914130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
915130f4520SKenneth D. Merry 
9160bcd4ab6SAlexander Motin 	retval = ctl_invalidate_lun(&be_lun->cbe_lun);
917130f4520SKenneth D. Merry 	if (retval != 0) {
918130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
919130f4520SKenneth D. Merry 			 "%s: error %d returned from ctl_invalidate_lun() for "
920130f4520SKenneth D. Merry 			 "LUN %d", __func__, retval, params->lun_id);
921ce300fbfSAlexander Motin 		mtx_lock(&softc->lock);
922ce300fbfSAlexander Motin 		be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
923ce300fbfSAlexander Motin 		mtx_unlock(&softc->lock);
924130f4520SKenneth D. Merry 		goto bailout_error;
925130f4520SKenneth D. Merry 	}
926130f4520SKenneth D. Merry 
927130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
928130f4520SKenneth D. Merry 	while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) {
929130f4520SKenneth D. Merry 		retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0);
930130f4520SKenneth D. Merry 		if (retval == EINTR)
931130f4520SKenneth D. Merry 			break;
932130f4520SKenneth D. Merry 	}
933130f4520SKenneth D. Merry 	be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
934130f4520SKenneth D. Merry 
935130f4520SKenneth D. Merry 	/*
936130f4520SKenneth D. Merry 	 * We only remove this LUN from the list and free it (below) if
937130f4520SKenneth D. Merry 	 * retval == 0.  If the user interrupted the wait, we just bail out
938130f4520SKenneth D. Merry 	 * without actually freeing the LUN.  We let the shutdown routine
939130f4520SKenneth D. Merry 	 * free the LUN if that happens.
940130f4520SKenneth D. Merry 	 */
941130f4520SKenneth D. Merry 	if (retval == 0) {
942130f4520SKenneth D. Merry 		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
943130f4520SKenneth D. Merry 			      links);
944130f4520SKenneth D. Merry 		softc->num_luns--;
945130f4520SKenneth D. Merry 	}
946130f4520SKenneth D. Merry 
947130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
948130f4520SKenneth D. Merry 
94908a7cce5SAlexander Motin 	if (retval == 0) {
950ee4ad294SAlexander Motin 		taskqueue_drain_all(be_lun->io_taskqueue);
95108a7cce5SAlexander Motin 		taskqueue_free(be_lun->io_taskqueue);
9520bcd4ab6SAlexander Motin 		ctl_free_opts(&be_lun->cbe_lun.options);
953e7037673SAlexander Motin 		free(be_lun->zero_page, M_RAMDISK);
954e7037673SAlexander Motin 		ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir);
955e7037673SAlexander Motin 		sx_destroy(&be_lun->page_lock);
95675c7a1d3SAlexander Motin 		mtx_destroy(&be_lun->queue_lock);
957130f4520SKenneth D. Merry 		free(be_lun, M_RAMDISK);
95808a7cce5SAlexander Motin 	}
959130f4520SKenneth D. Merry 
960130f4520SKenneth D. Merry 	req->status = CTL_LUN_OK;
961130f4520SKenneth D. Merry 	return (retval);
962130f4520SKenneth D. Merry 
963130f4520SKenneth D. Merry bailout_error:
964130f4520SKenneth D. Merry 	req->status = CTL_LUN_ERROR;
965130f4520SKenneth D. Merry 	return (0);
966130f4520SKenneth D. Merry }
967130f4520SKenneth D. Merry 
968130f4520SKenneth D. Merry static int
969130f4520SKenneth D. Merry ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
9700bcd4ab6SAlexander Motin 			   struct ctl_lun_req *req)
971130f4520SKenneth D. Merry {
972130f4520SKenneth D. Merry 	struct ctl_be_ramdisk_lun *be_lun;
9730bcd4ab6SAlexander Motin 	struct ctl_be_lun *cbe_lun;
974130f4520SKenneth D. Merry 	struct ctl_lun_create_params *params;
97557a5db13SAlexander Motin 	char *value;
976130f4520SKenneth D. Merry 	char tmpstr[32];
977e7037673SAlexander Motin 	uint64_t t;
9780bcd4ab6SAlexander Motin 	int retval;
979130f4520SKenneth D. Merry 
980130f4520SKenneth D. Merry 	retval = 0;
981130f4520SKenneth D. Merry 	params = &req->reqdata.create;
982130f4520SKenneth D. Merry 
9830bcd4ab6SAlexander Motin 	be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK);
9840bcd4ab6SAlexander Motin 	cbe_lun = &be_lun->cbe_lun;
9850bcd4ab6SAlexander Motin 	cbe_lun->be_lun = be_lun;
986a3977beaSAlexander Motin 	be_lun->params = req->reqdata.create;
9870bcd4ab6SAlexander Motin 	be_lun->softc = softc;
98808a7cce5SAlexander Motin 	sprintf(be_lun->lunname, "cram%d", softc->num_luns);
9890bcd4ab6SAlexander Motin 	ctl_init_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args);
990130f4520SKenneth D. Merry 
991130f4520SKenneth D. Merry 	if (params->flags & CTL_LUN_FLAG_DEV_TYPE)
9920bcd4ab6SAlexander Motin 		cbe_lun->lun_type = params->device_type;
993130f4520SKenneth D. Merry 	else
9940bcd4ab6SAlexander Motin 		cbe_lun->lun_type = T_DIRECT;
9950bcd4ab6SAlexander Motin 	be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED;
9967ac58230SAlexander Motin 	cbe_lun->flags = 0;
9977ac58230SAlexander Motin 	value = ctl_get_opt(&cbe_lun->options, "ha_role");
9987ac58230SAlexander Motin 	if (value != NULL) {
9997ac58230SAlexander Motin 		if (strcmp(value, "primary") == 0)
10007ac58230SAlexander Motin 			cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
10017ac58230SAlexander Motin 	} else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
10027ac58230SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1003130f4520SKenneth D. Merry 
1004e7037673SAlexander Motin 	be_lun->pblocksize = PAGE_SIZE;
1005e7037673SAlexander Motin 	value = ctl_get_opt(&cbe_lun->options, "pblocksize");
1006e7037673SAlexander Motin 	if (value != NULL) {
1007e7037673SAlexander Motin 		ctl_expand_number(value, &t);
1008e7037673SAlexander Motin 		be_lun->pblocksize = t;
1009e7037673SAlexander Motin 	}
1010e7037673SAlexander Motin 	if (be_lun->pblocksize < 512 || be_lun->pblocksize > 131072) {
1011e7037673SAlexander Motin 		snprintf(req->error_str, sizeof(req->error_str),
1012e7037673SAlexander Motin 			 "%s: unsupported pblocksize %u", __func__,
1013e7037673SAlexander Motin 			 be_lun->pblocksize);
1014e7037673SAlexander Motin 		goto bailout_error;
1015e7037673SAlexander Motin 	}
1016e7037673SAlexander Motin 
101791be33dcSAlexander Motin 	if (cbe_lun->lun_type == T_DIRECT ||
101891be33dcSAlexander Motin 	    cbe_lun->lun_type == T_CDROM) {
10190bcd4ab6SAlexander Motin 		if (params->blocksize_bytes != 0)
10200bcd4ab6SAlexander Motin 			cbe_lun->blocksize = params->blocksize_bytes;
102191be33dcSAlexander Motin 		else if (cbe_lun->lun_type == T_CDROM)
102291be33dcSAlexander Motin 			cbe_lun->blocksize = 2048;
10230bcd4ab6SAlexander Motin 		else
10240bcd4ab6SAlexander Motin 			cbe_lun->blocksize = 512;
1025e7037673SAlexander Motin 		be_lun->pblockmul = be_lun->pblocksize / cbe_lun->blocksize;
1026e7037673SAlexander Motin 		if (be_lun->pblockmul < 1 || !powerof2(be_lun->pblockmul)) {
1027e7037673SAlexander Motin 			snprintf(req->error_str, sizeof(req->error_str),
1028e7037673SAlexander Motin 				 "%s: pblocksize %u not exp2 of blocksize %u",
1029e7037673SAlexander Motin 				 __func__,
1030e7037673SAlexander Motin 				 be_lun->pblocksize, cbe_lun->blocksize);
1031e7037673SAlexander Motin 			goto bailout_error;
1032e7037673SAlexander Motin 		}
10330bcd4ab6SAlexander Motin 		if (params->lun_size_bytes < cbe_lun->blocksize) {
1034130f4520SKenneth D. Merry 			snprintf(req->error_str, sizeof(req->error_str),
1035130f4520SKenneth D. Merry 				 "%s: LUN size %ju < blocksize %u", __func__,
10360bcd4ab6SAlexander Motin 				 params->lun_size_bytes, cbe_lun->blocksize);
1037130f4520SKenneth D. Merry 			goto bailout_error;
1038130f4520SKenneth D. Merry 		}
10390bcd4ab6SAlexander Motin 		be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize;
10400bcd4ab6SAlexander Motin 		be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize;
1041e7037673SAlexander Motin 		be_lun->indir = 0;
1042e7037673SAlexander Motin 		t = be_lun->size_bytes / be_lun->pblocksize;
1043e7037673SAlexander Motin 		while (t > 1) {
1044e7037673SAlexander Motin 			t /= PPP;
1045e7037673SAlexander Motin 			be_lun->indir++;
1046e7037673SAlexander Motin 		}
10470bcd4ab6SAlexander Motin 		cbe_lun->maxlba = be_lun->size_blocks - 1;
1048e7037673SAlexander Motin 		cbe_lun->pblockexp = fls(be_lun->pblockmul) - 1;
1049e7037673SAlexander Motin 		cbe_lun->pblockoff = 0;
1050e7037673SAlexander Motin 		cbe_lun->ublockexp = cbe_lun->pblockexp;
1051e7037673SAlexander Motin 		cbe_lun->ublockoff = 0;
1052e7037673SAlexander Motin 		cbe_lun->atomicblock = be_lun->pblocksize;
1053e7037673SAlexander Motin 		cbe_lun->opttxferlen = SGPP * be_lun->pblocksize;
1054e7037673SAlexander Motin 		value = ctl_get_opt(&cbe_lun->options, "capacity");
1055e7037673SAlexander Motin 		if (value != NULL)
1056e7037673SAlexander Motin 			ctl_expand_number(value, &be_lun->cap_bytes);
1057e7037673SAlexander Motin 	} else {
1058e7037673SAlexander Motin 		be_lun->pblockmul = 1;
1059e7037673SAlexander Motin 		cbe_lun->pblockexp = 0;
1060130f4520SKenneth D. Merry 	}
1061130f4520SKenneth D. Merry 
1062130f4520SKenneth D. Merry 	/* Tell the user the blocksize we ended up using */
10630bcd4ab6SAlexander Motin 	params->blocksize_bytes = cbe_lun->blocksize;
1064130f4520SKenneth D. Merry 	params->lun_size_bytes = be_lun->size_bytes;
1065130f4520SKenneth D. Merry 
10660bcd4ab6SAlexander Motin 	value = ctl_get_opt(&cbe_lun->options, "unmap");
1067e7037673SAlexander Motin 	if (value == NULL || strcmp(value, "off") != 0)
10680bcd4ab6SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_UNMAP;
10690bcd4ab6SAlexander Motin 	value = ctl_get_opt(&cbe_lun->options, "readonly");
107091be33dcSAlexander Motin 	if (value != NULL) {
107191be33dcSAlexander Motin 		if (strcmp(value, "on") == 0)
107291be33dcSAlexander Motin 			cbe_lun->flags |= CTL_LUN_FLAG_READONLY;
107391be33dcSAlexander Motin 	} else if (cbe_lun->lun_type != T_DIRECT)
10740bcd4ab6SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_READONLY;
10750bcd4ab6SAlexander Motin 	cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
10760bcd4ab6SAlexander Motin 	value = ctl_get_opt(&cbe_lun->options, "serseq");
10770bcd4ab6SAlexander Motin 	if (value != NULL && strcmp(value, "on") == 0)
10780bcd4ab6SAlexander Motin 		cbe_lun->serseq = CTL_LUN_SERSEQ_ON;
10790bcd4ab6SAlexander Motin 	else if (value != NULL && strcmp(value, "read") == 0)
10800bcd4ab6SAlexander Motin 		cbe_lun->serseq = CTL_LUN_SERSEQ_READ;
10810bcd4ab6SAlexander Motin 	else if (value != NULL && strcmp(value, "off") == 0)
10820bcd4ab6SAlexander Motin 		cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
1083130f4520SKenneth D. Merry 
1084130f4520SKenneth D. Merry 	if (params->flags & CTL_LUN_FLAG_ID_REQ) {
10850bcd4ab6SAlexander Motin 		cbe_lun->req_lun_id = params->req_lun_id;
10860bcd4ab6SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ;
1087130f4520SKenneth D. Merry 	} else
10880bcd4ab6SAlexander Motin 		cbe_lun->req_lun_id = 0;
1089130f4520SKenneth D. Merry 
10900bcd4ab6SAlexander Motin 	cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown;
10910bcd4ab6SAlexander Motin 	cbe_lun->lun_config_status = ctl_backend_ramdisk_lun_config_status;
10920bcd4ab6SAlexander Motin 	cbe_lun->be = &ctl_be_ramdisk_driver;
1093130f4520SKenneth D. Merry 	if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) {
1094130f4520SKenneth D. Merry 		snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d",
1095130f4520SKenneth D. Merry 			 softc->num_luns);
10960bcd4ab6SAlexander Motin 		strncpy((char *)cbe_lun->serial_num, tmpstr,
10970bcd4ab6SAlexander Motin 			MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr)));
1098130f4520SKenneth D. Merry 
1099130f4520SKenneth D. Merry 		/* Tell the user what we used for a serial number */
1100130f4520SKenneth D. Merry 		strncpy((char *)params->serial_num, tmpstr,
1101e7038eb7SAlexander Motin 			MIN(sizeof(params->serial_num), sizeof(tmpstr)));
1102130f4520SKenneth D. Merry 	} else {
11030bcd4ab6SAlexander Motin 		strncpy((char *)cbe_lun->serial_num, params->serial_num,
11040bcd4ab6SAlexander Motin 			MIN(sizeof(cbe_lun->serial_num),
1105130f4520SKenneth D. Merry 			    sizeof(params->serial_num)));
1106130f4520SKenneth D. Merry 	}
1107130f4520SKenneth D. Merry 	if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) {
1108130f4520SKenneth D. Merry 		snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns);
11090bcd4ab6SAlexander Motin 		strncpy((char *)cbe_lun->device_id, tmpstr,
11100bcd4ab6SAlexander Motin 			MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr)));
1111130f4520SKenneth D. Merry 
1112130f4520SKenneth D. Merry 		/* Tell the user what we used for a device ID */
1113130f4520SKenneth D. Merry 		strncpy((char *)params->device_id, tmpstr,
1114e7038eb7SAlexander Motin 			MIN(sizeof(params->device_id), sizeof(tmpstr)));
1115130f4520SKenneth D. Merry 	} else {
11160bcd4ab6SAlexander Motin 		strncpy((char *)cbe_lun->device_id, params->device_id,
11170bcd4ab6SAlexander Motin 			MIN(sizeof(cbe_lun->device_id),
1118130f4520SKenneth D. Merry 			    sizeof(params->device_id)));
1119130f4520SKenneth D. Merry 	}
1120130f4520SKenneth D. Merry 
112108a7cce5SAlexander Motin 	STAILQ_INIT(&be_lun->cont_queue);
1122e7037673SAlexander Motin 	sx_init(&be_lun->page_lock, "cram page lock");
11232fb36370SAlexander Motin 	if (be_lun->cap_bytes == 0) {
11242fb36370SAlexander Motin 		be_lun->indir = 0;
1125e7037673SAlexander Motin 		be_lun->pages = malloc(be_lun->pblocksize, M_RAMDISK, M_WAITOK);
11262fb36370SAlexander Motin 	}
1127e7037673SAlexander Motin 	be_lun->zero_page = malloc(be_lun->pblocksize, M_RAMDISK,
1128e7037673SAlexander Motin 	    M_WAITOK|M_ZERO);
112975c7a1d3SAlexander Motin 	mtx_init(&be_lun->queue_lock, "cram queue lock", NULL, MTX_DEF);
113008a7cce5SAlexander Motin 	TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker,
113108a7cce5SAlexander Motin 	    be_lun);
113208a7cce5SAlexander Motin 
113308a7cce5SAlexander Motin 	be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK,
113408a7cce5SAlexander Motin 	    taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue);
113508a7cce5SAlexander Motin 	if (be_lun->io_taskqueue == NULL) {
113608a7cce5SAlexander Motin 		snprintf(req->error_str, sizeof(req->error_str),
113708a7cce5SAlexander Motin 			 "%s: Unable to create taskqueue", __func__);
113808a7cce5SAlexander Motin 		goto bailout_error;
113908a7cce5SAlexander Motin 	}
114008a7cce5SAlexander Motin 
114108a7cce5SAlexander Motin 	retval = taskqueue_start_threads(&be_lun->io_taskqueue,
114208a7cce5SAlexander Motin 					 /*num threads*/1,
114308a7cce5SAlexander Motin 					 /*priority*/PWAIT,
114408a7cce5SAlexander Motin 					 /*thread name*/
114508a7cce5SAlexander Motin 					 "%s taskq", be_lun->lunname);
114608a7cce5SAlexander Motin 	if (retval != 0)
114708a7cce5SAlexander Motin 		goto bailout_error;
114808a7cce5SAlexander Motin 
1149130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
1150130f4520SKenneth D. Merry 	softc->num_luns++;
1151130f4520SKenneth D. Merry 	STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links);
1152130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
1153130f4520SKenneth D. Merry 
11540bcd4ab6SAlexander Motin 	retval = ctl_add_lun(&be_lun->cbe_lun);
1155130f4520SKenneth D. Merry 	if (retval != 0) {
1156130f4520SKenneth D. Merry 		mtx_lock(&softc->lock);
1157130f4520SKenneth D. Merry 		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
1158130f4520SKenneth D. Merry 			      links);
1159130f4520SKenneth D. Merry 		softc->num_luns--;
1160130f4520SKenneth D. Merry 		mtx_unlock(&softc->lock);
1161130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
1162130f4520SKenneth D. Merry 			 "%s: ctl_add_lun() returned error %d, see dmesg for "
1163130f4520SKenneth D. Merry 			"details", __func__, retval);
1164130f4520SKenneth D. Merry 		retval = 0;
1165130f4520SKenneth D. Merry 		goto bailout_error;
1166130f4520SKenneth D. Merry 	}
1167130f4520SKenneth D. Merry 
1168130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
1169130f4520SKenneth D. Merry 
1170130f4520SKenneth D. Merry 	/*
1171130f4520SKenneth D. Merry 	 * Tell the config_status routine that we're waiting so it won't
1172130f4520SKenneth D. Merry 	 * clean up the LUN in the event of an error.
1173130f4520SKenneth D. Merry 	 */
1174130f4520SKenneth D. Merry 	be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING;
1175130f4520SKenneth D. Merry 
1176130f4520SKenneth D. Merry 	while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) {
1177130f4520SKenneth D. Merry 		retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0);
1178130f4520SKenneth D. Merry 		if (retval == EINTR)
1179130f4520SKenneth D. Merry 			break;
1180130f4520SKenneth D. Merry 	}
1181130f4520SKenneth D. Merry 	be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
1182130f4520SKenneth D. Merry 
1183130f4520SKenneth D. Merry 	if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) {
1184130f4520SKenneth D. Merry 		snprintf(req->error_str, sizeof(req->error_str),
1185130f4520SKenneth D. Merry 			 "%s: LUN configuration error, see dmesg for details",
1186130f4520SKenneth D. Merry 			 __func__);
1187130f4520SKenneth D. Merry 		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
1188130f4520SKenneth D. Merry 			      links);
1189130f4520SKenneth D. Merry 		softc->num_luns--;
1190130f4520SKenneth D. Merry 		mtx_unlock(&softc->lock);
1191130f4520SKenneth D. Merry 		goto bailout_error;
1192130f4520SKenneth D. Merry 	} else {
11930bcd4ab6SAlexander Motin 		params->req_lun_id = cbe_lun->lun_id;
1194130f4520SKenneth D. Merry 	}
1195130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
1196130f4520SKenneth D. Merry 
1197130f4520SKenneth D. Merry 	req->status = CTL_LUN_OK;
1198130f4520SKenneth D. Merry 	return (retval);
1199130f4520SKenneth D. Merry 
1200130f4520SKenneth D. Merry bailout_error:
1201130f4520SKenneth D. Merry 	req->status = CTL_LUN_ERROR;
120208a7cce5SAlexander Motin 	if (be_lun != NULL) {
1203e7037673SAlexander Motin 		if (be_lun->io_taskqueue != NULL)
120408a7cce5SAlexander Motin 			taskqueue_free(be_lun->io_taskqueue);
12050bcd4ab6SAlexander Motin 		ctl_free_opts(&cbe_lun->options);
1206e7037673SAlexander Motin 		free(be_lun->zero_page, M_RAMDISK);
1207e7037673SAlexander Motin 		ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir);
1208e7037673SAlexander Motin 		sx_destroy(&be_lun->page_lock);
120975c7a1d3SAlexander Motin 		mtx_destroy(&be_lun->queue_lock);
1210130f4520SKenneth D. Merry 		free(be_lun, M_RAMDISK);
121108a7cce5SAlexander Motin 	}
1212130f4520SKenneth D. Merry 	return (retval);
1213130f4520SKenneth D. Merry }
1214130f4520SKenneth D. Merry 
121581177295SEdward Tomasz Napierala static int
121681177295SEdward Tomasz Napierala ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc,
121781177295SEdward Tomasz Napierala 		       struct ctl_lun_req *req)
121881177295SEdward Tomasz Napierala {
121981177295SEdward Tomasz Napierala 	struct ctl_be_ramdisk_lun *be_lun;
1220a3977beaSAlexander Motin 	struct ctl_be_lun *cbe_lun;
122181177295SEdward Tomasz Napierala 	struct ctl_lun_modify_params *params;
12227ac58230SAlexander Motin 	char *value;
122381177295SEdward Tomasz Napierala 	uint32_t blocksize;
12247ac58230SAlexander Motin 	int wasprim;
122581177295SEdward Tomasz Napierala 
122681177295SEdward Tomasz Napierala 	params = &req->reqdata.modify;
122781177295SEdward Tomasz Napierala 
122881177295SEdward Tomasz Napierala 	mtx_lock(&softc->lock);
122981177295SEdward Tomasz Napierala 	STAILQ_FOREACH(be_lun, &softc->lun_list, links) {
12300bcd4ab6SAlexander Motin 		if (be_lun->cbe_lun.lun_id == params->lun_id)
123181177295SEdward Tomasz Napierala 			break;
123281177295SEdward Tomasz Napierala 	}
123381177295SEdward Tomasz Napierala 	mtx_unlock(&softc->lock);
123481177295SEdward Tomasz Napierala 	if (be_lun == NULL) {
123581177295SEdward Tomasz Napierala 		snprintf(req->error_str, sizeof(req->error_str),
123681177295SEdward Tomasz Napierala 			 "%s: LUN %u is not managed by the ramdisk backend",
123781177295SEdward Tomasz Napierala 			 __func__, params->lun_id);
123881177295SEdward Tomasz Napierala 		goto bailout_error;
123981177295SEdward Tomasz Napierala 	}
1240a3977beaSAlexander Motin 	cbe_lun = &be_lun->cbe_lun;
124181177295SEdward Tomasz Napierala 
1242a3977beaSAlexander Motin 	if (params->lun_size_bytes != 0)
1243a3977beaSAlexander Motin 		be_lun->params.lun_size_bytes = params->lun_size_bytes;
1244a3977beaSAlexander Motin 	ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args);
124581177295SEdward Tomasz Napierala 
12467ac58230SAlexander Motin 	wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY);
12477ac58230SAlexander Motin 	value = ctl_get_opt(&cbe_lun->options, "ha_role");
12487ac58230SAlexander Motin 	if (value != NULL) {
12497ac58230SAlexander Motin 		if (strcmp(value, "primary") == 0)
12507ac58230SAlexander Motin 			cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
12517ac58230SAlexander Motin 		else
12527ac58230SAlexander Motin 			cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
12537ac58230SAlexander Motin 	} else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
12547ac58230SAlexander Motin 		cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
12557ac58230SAlexander Motin 	else
12567ac58230SAlexander Motin 		cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
12577ac58230SAlexander Motin 	if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) {
12587ac58230SAlexander Motin 		if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)
12597ac58230SAlexander Motin 			ctl_lun_primary(cbe_lun);
12607ac58230SAlexander Motin 		else
12617ac58230SAlexander Motin 			ctl_lun_secondary(cbe_lun);
12627ac58230SAlexander Motin 	}
12637ac58230SAlexander Motin 
12647ac58230SAlexander Motin 	blocksize = be_lun->cbe_lun.blocksize;
1265a3977beaSAlexander Motin 	if (be_lun->params.lun_size_bytes < blocksize) {
126681177295SEdward Tomasz Napierala 		snprintf(req->error_str, sizeof(req->error_str),
126781177295SEdward Tomasz Napierala 			"%s: LUN size %ju < blocksize %u", __func__,
1268a3977beaSAlexander Motin 			be_lun->params.lun_size_bytes, blocksize);
126981177295SEdward Tomasz Napierala 		goto bailout_error;
127081177295SEdward Tomasz Napierala 	}
1271a3977beaSAlexander Motin 	be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize;
127281177295SEdward Tomasz Napierala 	be_lun->size_bytes = be_lun->size_blocks * blocksize;
12730bcd4ab6SAlexander Motin 	be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1;
12740bcd4ab6SAlexander Motin 	ctl_lun_capacity_changed(&be_lun->cbe_lun);
127581177295SEdward Tomasz Napierala 
127681177295SEdward Tomasz Napierala 	/* Tell the user the exact size we ended up using */
127781177295SEdward Tomasz Napierala 	params->lun_size_bytes = be_lun->size_bytes;
127881177295SEdward Tomasz Napierala 
127981177295SEdward Tomasz Napierala 	req->status = CTL_LUN_OK;
128081177295SEdward Tomasz Napierala 	return (0);
128181177295SEdward Tomasz Napierala 
128281177295SEdward Tomasz Napierala bailout_error:
128381177295SEdward Tomasz Napierala 	req->status = CTL_LUN_ERROR;
128481177295SEdward Tomasz Napierala 	return (0);
128581177295SEdward Tomasz Napierala }
128681177295SEdward Tomasz Napierala 
1287130f4520SKenneth D. Merry static void
1288130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_shutdown(void *be_lun)
1289130f4520SKenneth D. Merry {
1290130f4520SKenneth D. Merry 	struct ctl_be_ramdisk_lun *lun;
1291130f4520SKenneth D. Merry 	struct ctl_be_ramdisk_softc *softc;
1292130f4520SKenneth D. Merry 	int do_free;
1293130f4520SKenneth D. Merry 
1294130f4520SKenneth D. Merry 	lun = (struct ctl_be_ramdisk_lun *)be_lun;
1295130f4520SKenneth D. Merry 	softc = lun->softc;
1296130f4520SKenneth D. Merry 	do_free = 0;
1297130f4520SKenneth D. Merry 
1298130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
1299130f4520SKenneth D. Merry 	lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED;
1300130f4520SKenneth D. Merry 	if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) {
1301130f4520SKenneth D. Merry 		wakeup(lun);
1302130f4520SKenneth D. Merry 	} else {
1303e2507751SAlexander Motin 		STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun,
1304130f4520SKenneth D. Merry 			      links);
1305130f4520SKenneth D. Merry 		softc->num_luns--;
1306130f4520SKenneth D. Merry 		do_free = 1;
1307130f4520SKenneth D. Merry 	}
1308130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
1309130f4520SKenneth D. Merry 
1310130f4520SKenneth D. Merry 	if (do_free != 0)
1311130f4520SKenneth D. Merry 		free(be_lun, M_RAMDISK);
1312130f4520SKenneth D. Merry }
1313130f4520SKenneth D. Merry 
1314130f4520SKenneth D. Merry static void
1315130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_config_status(void *be_lun,
1316130f4520SKenneth D. Merry 				      ctl_lun_config_status status)
1317130f4520SKenneth D. Merry {
1318130f4520SKenneth D. Merry 	struct ctl_be_ramdisk_lun *lun;
1319130f4520SKenneth D. Merry 	struct ctl_be_ramdisk_softc *softc;
1320130f4520SKenneth D. Merry 
1321130f4520SKenneth D. Merry 	lun = (struct ctl_be_ramdisk_lun *)be_lun;
1322130f4520SKenneth D. Merry 	softc = lun->softc;
1323130f4520SKenneth D. Merry 
1324130f4520SKenneth D. Merry 	if (status == CTL_LUN_CONFIG_OK) {
1325130f4520SKenneth D. Merry 		mtx_lock(&softc->lock);
1326130f4520SKenneth D. Merry 		lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED;
1327130f4520SKenneth D. Merry 		if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING)
1328130f4520SKenneth D. Merry 			wakeup(lun);
1329130f4520SKenneth D. Merry 		mtx_unlock(&softc->lock);
1330130f4520SKenneth D. Merry 
1331130f4520SKenneth D. Merry 		/*
1332130f4520SKenneth D. Merry 		 * We successfully added the LUN, attempt to enable it.
1333130f4520SKenneth D. Merry 		 */
13340bcd4ab6SAlexander Motin 		if (ctl_enable_lun(&lun->cbe_lun) != 0) {
1335130f4520SKenneth D. Merry 			printf("%s: ctl_enable_lun() failed!\n", __func__);
13360bcd4ab6SAlexander Motin 			if (ctl_invalidate_lun(&lun->cbe_lun) != 0) {
1337130f4520SKenneth D. Merry 				printf("%s: ctl_invalidate_lun() failed!\n",
1338130f4520SKenneth D. Merry 				       __func__);
1339130f4520SKenneth D. Merry 			}
1340130f4520SKenneth D. Merry 		}
1341130f4520SKenneth D. Merry 
1342130f4520SKenneth D. Merry 		return;
1343130f4520SKenneth D. Merry 	}
1344130f4520SKenneth D. Merry 
1345130f4520SKenneth D. Merry 
1346130f4520SKenneth D. Merry 	mtx_lock(&softc->lock);
1347130f4520SKenneth D. Merry 	lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED;
1348130f4520SKenneth D. Merry 
1349130f4520SKenneth D. Merry 	/*
1350130f4520SKenneth D. Merry 	 * If we have a user waiting, let him handle the cleanup.  If not,
1351130f4520SKenneth D. Merry 	 * clean things up here.
1352130f4520SKenneth D. Merry 	 */
1353130f4520SKenneth D. Merry 	if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) {
1354130f4520SKenneth D. Merry 		lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR;
1355130f4520SKenneth D. Merry 		wakeup(lun);
1356130f4520SKenneth D. Merry 	} else {
1357130f4520SKenneth D. Merry 		STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun,
1358130f4520SKenneth D. Merry 			      links);
1359130f4520SKenneth D. Merry 		softc->num_luns--;
1360130f4520SKenneth D. Merry 		free(lun, M_RAMDISK);
1361130f4520SKenneth D. Merry 	}
1362130f4520SKenneth D. Merry 	mtx_unlock(&softc->lock);
1363130f4520SKenneth D. Merry }
1364