1229997Sken/*-
2229997Sken * Copyright (c) 2003, 2008 Silicon Graphics International Corp.
3232604Strasz * Copyright (c) 2012 The FreeBSD Foundation
4313371Smav * Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org>
5229997Sken * All rights reserved.
6229997Sken *
7232604Strasz * Portions of this software were developed by Edward Tomasz Napierala
8232604Strasz * under sponsorship from the FreeBSD Foundation.
9232604Strasz *
10229997Sken * Redistribution and use in source and binary forms, with or without
11229997Sken * modification, are permitted provided that the following conditions
12229997Sken * are met:
13229997Sken * 1. Redistributions of source code must retain the above copyright
14229997Sken *    notice, this list of conditions, and the following disclaimer,
15229997Sken *    without modification.
16229997Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17229997Sken *    substantially similar to the "NO WARRANTY" disclaimer below
18229997Sken *    ("Disclaimer") and any redistribution must be conditioned upon
19229997Sken *    including a substantially similar Disclaimer requirement for further
20229997Sken *    binary redistribution.
21229997Sken *
22229997Sken * NO WARRANTY
23229997Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24229997Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25229997Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
26229997Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27229997Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31229997Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32229997Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33229997Sken * POSSIBILITY OF SUCH DAMAGES.
34229997Sken *
35229997Sken * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $
36229997Sken */
37229997Sken/*
38313371Smav * CAM Target Layer black hole and RAM disk backend.
39229997Sken *
40229997Sken * Author: Ken Merry <ken@FreeBSD.org>
41229997Sken */
42229997Sken
43229997Sken#include <sys/cdefs.h>
44229997Sken__FBSDID("$FreeBSD: stable/10/sys/cam/ctl/ctl_backend_ramdisk.c 314026 2017-02-21 05:13:16Z mav $");
45229997Sken
46229997Sken#include <sys/param.h>
47229997Sken#include <sys/systm.h>
48229997Sken#include <sys/kernel.h>
49229997Sken#include <sys/condvar.h>
50229997Sken#include <sys/types.h>
51313371Smav#include <sys/limits.h>
52229997Sken#include <sys/lock.h>
53229997Sken#include <sys/mutex.h>
54229997Sken#include <sys/malloc.h>
55313371Smav#include <sys/sx.h>
56265642Smav#include <sys/taskqueue.h>
57229997Sken#include <sys/time.h>
58229997Sken#include <sys/queue.h>
59229997Sken#include <sys/conf.h>
60229997Sken#include <sys/ioccom.h>
61229997Sken#include <sys/module.h>
62288732Smav#include <sys/sysctl.h>
63229997Sken
64229997Sken#include <cam/scsi/scsi_all.h>
65288732Smav#include <cam/scsi/scsi_da.h>
66229997Sken#include <cam/ctl/ctl_io.h>
67229997Sken#include <cam/ctl/ctl.h>
68229997Sken#include <cam/ctl/ctl_util.h>
69229997Sken#include <cam/ctl/ctl_backend.h>
70229997Sken#include <cam/ctl/ctl_debug.h>
71229997Sken#include <cam/ctl/ctl_ioctl.h>
72288732Smav#include <cam/ctl/ctl_ha.h>
73288732Smav#include <cam/ctl/ctl_private.h>
74229997Sken#include <cam/ctl/ctl_error.h>
75229997Sken
76313371Smav#define PRIV(io)	\
77313371Smav    ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND])
78313371Smav#define ARGS(io)	\
79313371Smav    ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN])
80313371Smav
81313371Smav#define	PPP	(PAGE_SIZE / sizeof(uint8_t **))
82313371Smav#ifdef __LP64__
83313371Smav#define	PPPS	(PAGE_SHIFT - 3)
84313371Smav#else
85313371Smav#define	PPPS	(PAGE_SHIFT - 2)
86313371Smav#endif
87313371Smav#define	SGPP	(PAGE_SIZE / sizeof(struct ctl_sg_entry))
88313371Smav
89313371Smav#define	P_UNMAPPED	NULL			/* Page is unmapped. */
90313371Smav#define	P_ANCHORED	((void *)(uintptr_t)1)	/* Page is anchored. */
91313371Smav
92229997Skentypedef enum {
93313371Smav	GP_READ,	/* Return data page or zero page. */
94313371Smav	GP_WRITE,	/* Return data page, try allocate if none. */
95313371Smav	GP_ANCHOR,	/* Return data page, try anchor if none. */
96313371Smav	GP_OTHER,	/* Return what present, do not allocate/anchor. */
97313371Smav} getpage_op_t;
98313371Smav
99313371Smavtypedef enum {
100229997Sken	CTL_BE_RAMDISK_LUN_UNCONFIGURED	= 0x01,
101229997Sken	CTL_BE_RAMDISK_LUN_CONFIG_ERR	= 0x02,
102229997Sken	CTL_BE_RAMDISK_LUN_WAITING	= 0x04
103229997Sken} ctl_be_ramdisk_lun_flags;
104229997Sken
105229997Skenstruct ctl_be_ramdisk_lun {
106288728Smav	struct ctl_lun_create_params params;
107313371Smav	char			lunname[32];
108313371Smav	int			indir;
109313371Smav	uint8_t			**pages;
110313371Smav	uint8_t			*zero_page;
111313371Smav	struct sx		page_lock;
112313371Smav	u_int			pblocksize;
113313371Smav	u_int			pblockmul;
114313371Smav	uint64_t		size_bytes;
115313371Smav	uint64_t		size_blocks;
116313371Smav	uint64_t		cap_bytes;
117313371Smav	uint64_t		cap_used;
118229997Sken	struct ctl_be_ramdisk_softc *softc;
119229997Sken	ctl_be_ramdisk_lun_flags flags;
120229997Sken	STAILQ_ENTRY(ctl_be_ramdisk_lun) links;
121313371Smav	struct ctl_be_lun	cbe_lun;
122313371Smav	struct taskqueue	*io_taskqueue;
123313371Smav	struct task		io_task;
124265642Smav	STAILQ_HEAD(, ctl_io_hdr) cont_queue;
125313371Smav	struct mtx_padalign	queue_lock;
126229997Sken};
127229997Sken
128229997Skenstruct ctl_be_ramdisk_softc {
129229997Sken	struct mtx lock;
130229997Sken	int num_luns;
131229997Sken	STAILQ_HEAD(, ctl_be_ramdisk_lun) lun_list;
132229997Sken};
133229997Sken
134229997Skenstatic struct ctl_be_ramdisk_softc rd_softc;
135288732Smavextern struct ctl_softc *control_softc;
136229997Sken
137313369Smavstatic int ctl_backend_ramdisk_init(void);
138313369Smavstatic int ctl_backend_ramdisk_shutdown(void);
139229997Skenstatic int ctl_backend_ramdisk_move_done(union ctl_io *io);
140313371Smavstatic void ctl_backend_ramdisk_compare(union ctl_io *io);
141313371Smavstatic void ctl_backend_ramdisk_rw(union ctl_io *io);
142229997Skenstatic int ctl_backend_ramdisk_submit(union ctl_io *io);
143313371Smavstatic void ctl_backend_ramdisk_worker(void *context, int pending);
144313371Smavstatic int ctl_backend_ramdisk_config_read(union ctl_io *io);
145313371Smavstatic int ctl_backend_ramdisk_config_write(union ctl_io *io);
146313371Smavstatic uint64_t ctl_backend_ramdisk_lun_attr(void *be_lun, const char *attrname);
147229997Skenstatic int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd,
148229997Sken				     caddr_t addr, int flag, struct thread *td);
149229997Skenstatic int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc,
150229997Sken				  struct ctl_lun_req *req);
151229997Skenstatic int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
152288727Smav				      struct ctl_lun_req *req);
153232604Straszstatic int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc,
154232604Strasz				  struct ctl_lun_req *req);
155229997Skenstatic void ctl_backend_ramdisk_lun_shutdown(void *be_lun);
156229997Skenstatic void ctl_backend_ramdisk_lun_config_status(void *be_lun,
157229997Sken						  ctl_lun_config_status status);
158229997Sken
159229997Skenstatic struct ctl_backend_driver ctl_be_ramdisk_driver =
160229997Sken{
161230334Sken	.name = "ramdisk",
162230334Sken	.flags = CTL_BE_FLAG_HAS_CONFIG,
163230334Sken	.init = ctl_backend_ramdisk_init,
164313369Smav	.shutdown = ctl_backend_ramdisk_shutdown,
165230334Sken	.data_submit = ctl_backend_ramdisk_submit,
166230334Sken	.data_move_done = ctl_backend_ramdisk_move_done,
167230334Sken	.config_read = ctl_backend_ramdisk_config_read,
168230334Sken	.config_write = ctl_backend_ramdisk_config_write,
169313371Smav	.ioctl = ctl_backend_ramdisk_ioctl,
170313371Smav	.lun_attr = ctl_backend_ramdisk_lun_attr,
171229997Sken};
172229997Sken
173229997SkenMALLOC_DEFINE(M_RAMDISK, "ramdisk", "Memory used for CTL RAMdisk");
174229997SkenCTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver);
175229997Sken
176313371Smavstatic int
177229997Skenctl_backend_ramdisk_init(void)
178229997Sken{
179288799Smav	struct ctl_be_ramdisk_softc *softc = &rd_softc;
180229997Sken
181229997Sken	memset(softc, 0, sizeof(*softc));
182268549Smav	mtx_init(&softc->lock, "ctlramdisk", NULL, MTX_DEF);
183229997Sken	STAILQ_INIT(&softc->lun_list);
184229997Sken	return (0);
185229997Sken}
186229997Sken
187313369Smavstatic int
188229997Skenctl_backend_ramdisk_shutdown(void)
189229997Sken{
190288799Smav	struct ctl_be_ramdisk_softc *softc = &rd_softc;
191229997Sken	struct ctl_be_ramdisk_lun *lun, *next_lun;
192229997Sken
193229997Sken	mtx_lock(&softc->lock);
194288818Smav	STAILQ_FOREACH_SAFE(lun, &softc->lun_list, links, next_lun) {
195229997Sken		/*
196229997Sken		 * Drop our lock here.  Since ctl_invalidate_lun() can call
197229997Sken		 * back into us, this could potentially lead to a recursive
198229997Sken		 * lock of the same mutex, which would cause a hang.
199229997Sken		 */
200229997Sken		mtx_unlock(&softc->lock);
201288727Smav		ctl_disable_lun(&lun->cbe_lun);
202288727Smav		ctl_invalidate_lun(&lun->cbe_lun);
203229997Sken		mtx_lock(&softc->lock);
204229997Sken	}
205229997Sken	mtx_unlock(&softc->lock);
206313369Smav	mtx_destroy(&softc->lock);
207313369Smav	return (0);
208229997Sken}
209229997Sken
210313371Smavstatic uint8_t *
211313371Smavctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn,
212313371Smav    getpage_op_t op)
213313371Smav{
214313371Smav	uint8_t **p, ***pp;
215313371Smav	off_t i;
216313371Smav	int s;
217313371Smav
218313371Smav	if (be_lun->cap_bytes == 0) {
219313371Smav		switch (op) {
220313371Smav		case GP_READ:
221313371Smav			return (be_lun->zero_page);
222313371Smav		case GP_WRITE:
223313371Smav			return ((uint8_t *)be_lun->pages);
224313371Smav		case GP_ANCHOR:
225313371Smav			return (P_ANCHORED);
226313371Smav		default:
227313371Smav			return (P_UNMAPPED);
228313371Smav		}
229313371Smav	}
230313371Smav	if (op == GP_WRITE || op == GP_ANCHOR) {
231313371Smav		sx_xlock(&be_lun->page_lock);
232313371Smav		pp = &be_lun->pages;
233313371Smav		for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
234313371Smav			if (*pp == NULL) {
235313371Smav				*pp = malloc(PAGE_SIZE, M_RAMDISK,
236313371Smav				    M_WAITOK|M_ZERO);
237313371Smav			}
238313371Smav			i = pn >> s;
239313371Smav			pp = (uint8_t ***)&(*pp)[i];
240313371Smav			pn -= i << s;
241313371Smav		}
242313371Smav		if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) {
243313371Smav			if (op == GP_WRITE) {
244313371Smav				*pp = malloc(be_lun->pblocksize, M_RAMDISK,
245313371Smav				    M_WAITOK|M_ZERO);
246313371Smav			} else
247313371Smav				*pp = P_ANCHORED;
248313371Smav			be_lun->cap_used += be_lun->pblocksize;
249313371Smav		} else if (*pp == P_ANCHORED && op == GP_WRITE) {
250313371Smav			*pp = malloc(be_lun->pblocksize, M_RAMDISK,
251313371Smav			    M_WAITOK|M_ZERO);
252313371Smav		}
253313371Smav		sx_xunlock(&be_lun->page_lock);
254313371Smav		return ((uint8_t *)*pp);
255313371Smav	} else {
256313371Smav		sx_slock(&be_lun->page_lock);
257313371Smav		p = be_lun->pages;
258313371Smav		for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
259313371Smav			if (p == NULL)
260313371Smav				break;
261313371Smav			i = pn >> s;
262313371Smav			p = (uint8_t **)p[i];
263313371Smav			pn -= i << s;
264313371Smav		}
265313371Smav		sx_sunlock(&be_lun->page_lock);
266313371Smav		if ((p == P_UNMAPPED || p == P_ANCHORED) && op == GP_READ)
267313371Smav			return (be_lun->zero_page);
268313371Smav		return ((uint8_t *)p);
269313371Smav	}
270313371Smav};
271313371Smav
272313371Smavstatic void
273313371Smavctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun *be_lun, off_t pn)
274313371Smav{
275313371Smav	uint8_t ***pp;
276313371Smav	off_t i;
277313371Smav	int s;
278313371Smav
279313371Smav	if (be_lun->cap_bytes == 0)
280313371Smav		return;
281313371Smav	sx_xlock(&be_lun->page_lock);
282313371Smav	pp = &be_lun->pages;
283313371Smav	for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
284313371Smav		if (*pp == NULL)
285313371Smav			goto noindir;
286313371Smav		i = pn >> s;
287313371Smav		pp = (uint8_t ***)&(*pp)[i];
288313371Smav		pn -= i << s;
289313371Smav	}
290313371Smav	if (*pp == P_ANCHORED) {
291313371Smav		be_lun->cap_used -= be_lun->pblocksize;
292313371Smav		*pp = P_UNMAPPED;
293313371Smav	} else if (*pp != P_UNMAPPED) {
294313371Smav		free(*pp, M_RAMDISK);
295313371Smav		be_lun->cap_used -= be_lun->pblocksize;
296313371Smav		*pp = P_UNMAPPED;
297313371Smav	}
298313371Smavnoindir:
299313371Smav	sx_xunlock(&be_lun->page_lock);
300313371Smav};
301313371Smav
302313371Smavstatic void
303313371Smavctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn)
304313371Smav{
305313371Smav	uint8_t ***pp;
306313371Smav	off_t i;
307313371Smav	int s;
308313371Smav
309313371Smav	if (be_lun->cap_bytes == 0)
310313371Smav		return;
311313371Smav	sx_xlock(&be_lun->page_lock);
312313371Smav	pp = &be_lun->pages;
313313371Smav	for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) {
314313371Smav		if (*pp == NULL)
315313371Smav			goto noindir;
316313371Smav		i = pn >> s;
317313371Smav		pp = (uint8_t ***)&(*pp)[i];
318313371Smav		pn -= i << s;
319313371Smav	}
320313371Smav	if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) {
321313371Smav		be_lun->cap_used += be_lun->pblocksize;
322313371Smav		*pp = P_ANCHORED;
323313371Smav	} else if (*pp != P_ANCHORED) {
324313371Smav		free(*pp, M_RAMDISK);
325313371Smav		*pp = P_ANCHORED;
326313371Smav	}
327313371Smavnoindir:
328313371Smav	sx_xunlock(&be_lun->page_lock);
329313371Smav};
330313371Smav
331313371Smavstatic void
332313371Smavctl_backend_ramdisk_freeallpages(uint8_t **p, int indir)
333313371Smav{
334313371Smav	int i;
335313371Smav
336313371Smav	if (p == NULL)
337313371Smav		return;
338313371Smav	if (indir == 0) {
339313371Smav		free(p, M_RAMDISK);
340313371Smav		return;
341313371Smav	}
342313371Smav	for (i = 0; i < PPP; i++) {
343313371Smav		if (p[i] == NULL)
344313371Smav			continue;
345313371Smav		ctl_backend_ramdisk_freeallpages((uint8_t **)p[i], indir - 1);
346313371Smav	}
347313371Smav	free(p, M_RAMDISK);
348313371Smav};
349313371Smav
350313371Smavstatic size_t
351313371Smavcmp(uint8_t *a, uint8_t *b, size_t size)
352313371Smav{
353313371Smav	size_t i;
354313371Smav
355313371Smav	for (i = 0; i < size; i++) {
356313371Smav		if (a[i] != b[i])
357313371Smav			break;
358313371Smav	}
359313371Smav	return (i);
360313371Smav}
361313371Smav
362229997Skenstatic int
363313371Smavctl_backend_ramdisk_cmp(union ctl_io *io)
364313371Smav{
365313371Smav	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
366313371Smav	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
367313371Smav	uint8_t *page;
368313371Smav	uint8_t info[8];
369313371Smav	uint64_t lba;
370313371Smav	u_int lbaoff, lbas, res, off;
371313371Smav
372313371Smav	lbas = io->scsiio.kern_data_len / cbe_lun->blocksize;
373313371Smav	lba = ARGS(io)->lba + PRIV(io)->len - lbas;
374313371Smav	off = 0;
375313371Smav	for (; lbas > 0; lbas--, lba++) {
376313371Smav		page = ctl_backend_ramdisk_getpage(be_lun,
377313371Smav		    lba >> cbe_lun->pblockexp, GP_READ);
378313371Smav		lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
379313371Smav		page += lbaoff * cbe_lun->blocksize;
380313371Smav		res = cmp(io->scsiio.kern_data_ptr + off, page,
381313371Smav		    cbe_lun->blocksize);
382313371Smav		off += res;
383313371Smav		if (res < cbe_lun->blocksize)
384313371Smav			break;
385313371Smav	}
386313371Smav	if (lbas > 0) {
387313371Smav		off += io->scsiio.kern_rel_offset - io->scsiio.kern_data_len;
388313371Smav		scsi_u64to8b(off, info);
389313371Smav		ctl_set_sense(&io->scsiio, /*current_error*/ 1,
390313371Smav		    /*sense_key*/ SSD_KEY_MISCOMPARE,
391313371Smav		    /*asc*/ 0x1D, /*ascq*/ 0x00,
392313371Smav		    /*type*/ SSD_ELEM_INFO,
393313371Smav		    /*size*/ sizeof(info), /*data*/ &info,
394313371Smav		    /*type*/ SSD_ELEM_NONE);
395313371Smav		return (1);
396313371Smav	}
397313371Smav	return (0);
398313371Smav}
399313371Smav
400313371Smavstatic int
401229997Skenctl_backend_ramdisk_move_done(union ctl_io *io)
402229997Sken{
403313371Smav	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
404313371Smav	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
405229997Sken#ifdef CTL_TIME_IO
406229997Sken	struct bintime cur_bt;
407229997Sken#endif
408229997Sken
409229997Sken	CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n"));
410265642Smav#ifdef CTL_TIME_IO
411288798Smav	getbinuptime(&cur_bt);
412265642Smav	bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt);
413265642Smav	bintime_add(&io->io_hdr.dma_bt, &cur_bt);
414288798Smav#endif
415265642Smav	io->io_hdr.num_dmas++;
416265642Smav	if (io->scsiio.kern_sg_entries > 0)
417265642Smav		free(io->scsiio.kern_data_ptr, M_RAMDISK);
418265642Smav	io->scsiio.kern_rel_offset += io->scsiio.kern_data_len;
419275881Smav	if (io->io_hdr.flags & CTL_FLAG_ABORT) {
420275881Smav		;
421313365Smav	} else if (io->io_hdr.port_status != 0 &&
422313365Smav	    ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE ||
423313365Smav	     (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) {
424313365Smav		ctl_set_internal_failure(&io->scsiio, /*sks_valid*/ 1,
425313365Smav		    /*retry_count*/ io->io_hdr.port_status);
426313365Smav	} else if (io->scsiio.kern_data_resid != 0 &&
427313365Smav	    (io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_OUT &&
428313365Smav	    ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE ||
429313365Smav	     (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) {
430313365Smav		ctl_set_invalid_field_ciu(&io->scsiio);
431275881Smav	} else if ((io->io_hdr.port_status == 0) &&
432275881Smav	    ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) {
433313371Smav		if (ARGS(io)->flags & CTL_LLF_COMPARE) {
434313371Smav			/* We have data block ready for comparison. */
435313371Smav			if (ctl_backend_ramdisk_cmp(io))
436313371Smav				goto done;
437313371Smav		}
438313371Smav		if (ARGS(io)->len > PRIV(io)->len) {
439268549Smav			mtx_lock(&be_lun->queue_lock);
440265642Smav			STAILQ_INSERT_TAIL(&be_lun->cont_queue,
441265642Smav			    &io->io_hdr, links);
442268549Smav			mtx_unlock(&be_lun->queue_lock);
443265642Smav			taskqueue_enqueue(be_lun->io_taskqueue,
444265642Smav			    &be_lun->io_task);
445265642Smav			return (0);
446265642Smav		}
447275879Smav		ctl_set_success(&io->scsiio);
448229997Sken	}
449313371Smavdone:
450268151Smav	ctl_data_submit_done(io);
451229997Sken	return(0);
452229997Sken}
453229997Sken
454313371Smavstatic void
455313371Smavctl_backend_ramdisk_compare(union ctl_io *io)
456229997Sken{
457313371Smav	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
458313371Smav	u_int lbas, len;
459229997Sken
460313371Smav	lbas = ARGS(io)->len - PRIV(io)->len;
461313371Smav	lbas = MIN(lbas, 131072 / cbe_lun->blocksize);
462313371Smav	len = lbas * cbe_lun->blocksize;
463313371Smav
464313371Smav	io->scsiio.be_move_done = ctl_backend_ramdisk_move_done;
465313371Smav	io->scsiio.kern_data_ptr = malloc(len, M_RAMDISK, M_WAITOK);
466313371Smav	io->scsiio.kern_data_len = len;
467313371Smav	io->scsiio.kern_sg_entries = 0;
468313371Smav	io->io_hdr.flags |= CTL_FLAG_ALLOCATED;
469313371Smav	PRIV(io)->len += lbas;
470313371Smav#ifdef CTL_TIME_IO
471313371Smav	getbinuptime(&io->io_hdr.dma_start_bt);
472313371Smav#endif
473313371Smav	ctl_datamove(io);
474265642Smav}
475229997Sken
476265642Smavstatic void
477313371Smavctl_backend_ramdisk_rw(union ctl_io *io)
478265642Smav{
479313371Smav	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
480313371Smav	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
481265642Smav	struct ctl_sg_entry *sg_entries;
482313371Smav	uint8_t *page;
483313371Smav	uint64_t lba;
484313371Smav	u_int i, len, lbaoff, lbas, sgs, off;
485313371Smav	getpage_op_t op;
486229997Sken
487313371Smav	lba = ARGS(io)->lba + PRIV(io)->len;
488313371Smav	lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
489313371Smav	lbas = ARGS(io)->len - PRIV(io)->len;
490313371Smav	lbas = MIN(lbas, (SGPP << cbe_lun->pblockexp) - lbaoff);
491313371Smav	sgs = (lbas + lbaoff + be_lun->pblockmul - 1) >> cbe_lun->pblockexp;
492313371Smav	off = lbaoff * cbe_lun->blocksize;
493313371Smav	op = (ARGS(io)->flags & CTL_LLF_WRITE) ? GP_WRITE : GP_READ;
494313371Smav	if (sgs > 1) {
495229997Sken		io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) *
496313371Smav		    sgs, M_RAMDISK, M_WAITOK);
497229997Sken		sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
498313371Smav		len = lbas * cbe_lun->blocksize;
499313371Smav		for (i = 0; i < sgs; i++) {
500313371Smav			page = ctl_backend_ramdisk_getpage(be_lun,
501313371Smav			    (lba >> cbe_lun->pblockexp) + i, op);
502313371Smav			if (page == P_UNMAPPED || page == P_ANCHORED) {
503313371Smav				free(io->scsiio.kern_data_ptr, M_RAMDISK);
504313371Smavnospc:
505313371Smav				ctl_set_space_alloc_fail(&io->scsiio);
506313371Smav				ctl_data_submit_done(io);
507313371Smav				return;
508313371Smav			}
509313371Smav			sg_entries[i].addr = page + off;
510313371Smav			sg_entries[i].len = MIN(len, be_lun->pblocksize - off);
511313371Smav			len -= sg_entries[i].len;
512313371Smav			off = 0;
513229997Sken		}
514229997Sken	} else {
515313371Smav		page = ctl_backend_ramdisk_getpage(be_lun,
516313371Smav		    lba >> cbe_lun->pblockexp, op);
517313371Smav		if (page == P_UNMAPPED || page == P_ANCHORED)
518313371Smav			goto nospc;
519313371Smav		sgs = 0;
520313371Smav		io->scsiio.kern_data_ptr = page + off;
521265642Smav	}
522229997Sken
523268148Smav	io->scsiio.be_move_done = ctl_backend_ramdisk_move_done;
524313371Smav	io->scsiio.kern_data_len = lbas * cbe_lun->blocksize;
525313371Smav	io->scsiio.kern_sg_entries = sgs;
526265642Smav	io->io_hdr.flags |= CTL_FLAG_ALLOCATED;
527313371Smav	PRIV(io)->len += lbas;
528229997Sken#ifdef CTL_TIME_IO
529288798Smav	getbinuptime(&io->io_hdr.dma_start_bt);
530229997Sken#endif
531229997Sken	ctl_datamove(io);
532265642Smav}
533229997Sken
534313371Smavstatic int
535313371Smavctl_backend_ramdisk_submit(union ctl_io *io)
536313371Smav{
537313371Smav	struct ctl_lba_len_flags *lbalen = ARGS(io);
538313371Smav
539313371Smav	if (lbalen->flags & CTL_LLF_VERIFY) {
540313371Smav		ctl_set_success(&io->scsiio);
541313371Smav		ctl_data_submit_done(io);
542313371Smav		return (CTL_RETVAL_COMPLETE);
543313371Smav	}
544313371Smav	PRIV(io)->len = 0;
545313371Smav	if (lbalen->flags & CTL_LLF_COMPARE)
546313371Smav		ctl_backend_ramdisk_compare(io);
547313371Smav	else
548313371Smav		ctl_backend_ramdisk_rw(io);
549313371Smav	return (CTL_RETVAL_COMPLETE);
550313371Smav}
551313371Smav
552265642Smavstatic void
553265642Smavctl_backend_ramdisk_worker(void *context, int pending)
554265642Smav{
555265642Smav	struct ctl_be_ramdisk_lun *be_lun;
556265642Smav	union ctl_io *io;
557265642Smav
558265642Smav	be_lun = (struct ctl_be_ramdisk_lun *)context;
559268549Smav	mtx_lock(&be_lun->queue_lock);
560265642Smav	for (;;) {
561265642Smav		io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue);
562265642Smav		if (io != NULL) {
563265642Smav			STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr,
564265642Smav				      ctl_io_hdr, links);
565268549Smav			mtx_unlock(&be_lun->queue_lock);
566313371Smav			if (ARGS(io)->flags & CTL_LLF_COMPARE)
567313371Smav				ctl_backend_ramdisk_compare(io);
568313371Smav			else
569313371Smav				ctl_backend_ramdisk_rw(io);
570268549Smav			mtx_lock(&be_lun->queue_lock);
571265642Smav			continue;
572265642Smav		}
573265642Smav
574265642Smav		/*
575265642Smav		 * If we get here, there is no work left in the queues, so
576265642Smav		 * just break out and let the task queue go to sleep.
577265642Smav		 */
578265642Smav		break;
579265642Smav	}
580268549Smav	mtx_unlock(&be_lun->queue_lock);
581229997Sken}
582229997Sken
583229997Skenstatic int
584313371Smavctl_backend_ramdisk_gls(union ctl_io *io)
585313371Smav{
586313371Smav	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
587313371Smav	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
588313371Smav	struct scsi_get_lba_status_data *data;
589313371Smav	uint8_t *page;
590313371Smav	u_int lbaoff;
591313371Smav
592313371Smav	data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr;
593313371Smav	scsi_u64to8b(ARGS(io)->lba, data->descr[0].addr);
594313371Smav	lbaoff = ARGS(io)->lba & ~(UINT_MAX << cbe_lun->pblockexp);
595313371Smav	scsi_ulto4b(be_lun->pblockmul - lbaoff, data->descr[0].length);
596313371Smav	page = ctl_backend_ramdisk_getpage(be_lun,
597313371Smav	    ARGS(io)->lba >> cbe_lun->pblockexp, GP_OTHER);
598313371Smav	if (page == P_UNMAPPED)
599313371Smav		data->descr[0].status = 1;
600313371Smav	else if (page == P_ANCHORED)
601313371Smav		data->descr[0].status = 2;
602313371Smav	else
603313371Smav		data->descr[0].status = 0;
604313371Smav	ctl_config_read_done(io);
605313371Smav	return (CTL_RETVAL_COMPLETE);
606313371Smav}
607313371Smav
608313371Smavstatic int
609313371Smavctl_backend_ramdisk_config_read(union ctl_io *io)
610313371Smav{
611313371Smav	int retval = 0;
612313371Smav
613313371Smav	switch (io->scsiio.cdb[0]) {
614313371Smav	case SERVICE_ACTION_IN:
615313371Smav		if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
616313371Smav			retval = ctl_backend_ramdisk_gls(io);
617313371Smav			break;
618313371Smav		}
619313371Smav		ctl_set_invalid_field(&io->scsiio,
620313371Smav				      /*sks_valid*/ 1,
621313371Smav				      /*command*/ 1,
622313371Smav				      /*field*/ 1,
623313371Smav				      /*bit_valid*/ 1,
624313371Smav				      /*bit*/ 4);
625313371Smav		ctl_config_read_done(io);
626313371Smav		retval = CTL_RETVAL_COMPLETE;
627313371Smav		break;
628313371Smav	default:
629313371Smav		ctl_set_invalid_opcode(&io->scsiio);
630313371Smav		ctl_config_read_done(io);
631313371Smav		retval = CTL_RETVAL_COMPLETE;
632313371Smav		break;
633313371Smav	}
634313371Smav	return (retval);
635313371Smav}
636313371Smav
637313371Smavstatic void
638313371Smavctl_backend_ramdisk_delete(struct ctl_be_lun *cbe_lun, off_t lba, off_t len,
639313371Smav    int anchor)
640313371Smav{
641313371Smav	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
642313371Smav	uint8_t *page;
643313371Smav	uint64_t p, lp;
644313371Smav	u_int lbaoff;
645313371Smav	getpage_op_t op = anchor ? GP_ANCHOR : GP_OTHER;
646313371Smav
647313371Smav	/* Partially zero first partial page. */
648313371Smav	p = lba >> cbe_lun->pblockexp;
649313371Smav	lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
650313371Smav	if (lbaoff != 0) {
651313371Smav		page = ctl_backend_ramdisk_getpage(be_lun, p, op);
652313371Smav		if (page != P_UNMAPPED && page != P_ANCHORED) {
653313371Smav			memset(page + lbaoff * cbe_lun->blocksize, 0,
654313371Smav			    min(len, be_lun->pblockmul - lbaoff) *
655313371Smav			    cbe_lun->blocksize);
656313371Smav		}
657313371Smav		p++;
658313371Smav	}
659313371Smav
660313371Smav	/* Partially zero last partial page. */
661313371Smav	lp = (lba + len) >> cbe_lun->pblockexp;
662313371Smav	lbaoff = (lba + len) & ~(UINT_MAX << cbe_lun->pblockexp);
663313371Smav	if (p <= lp && lbaoff != 0) {
664313371Smav		page = ctl_backend_ramdisk_getpage(be_lun, lp, op);
665313371Smav		if (page != P_UNMAPPED && page != P_ANCHORED)
666313371Smav			memset(page, 0, lbaoff * cbe_lun->blocksize);
667313371Smav	}
668313371Smav
669313371Smav	/* Delete remaining full pages. */
670313371Smav	if (anchor) {
671313371Smav		for (; p < lp; p++)
672313371Smav			ctl_backend_ramdisk_anchorpage(be_lun, p);
673313371Smav	} else {
674313371Smav		for (; p < lp; p++)
675313371Smav			ctl_backend_ramdisk_unmappage(be_lun, p);
676313371Smav	}
677313371Smav}
678313371Smav
679313371Smavstatic void
680313371Smavctl_backend_ramdisk_ws(union ctl_io *io)
681313371Smav{
682313371Smav	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
683313371Smav	struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun;
684313371Smav	struct ctl_lba_len_flags *lbalen = ARGS(io);
685313371Smav	uint8_t *page;
686313371Smav	uint64_t lba;
687313371Smav	u_int lbaoff, lbas;
688313371Smav
689313371Smav	if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB)) {
690313371Smav		ctl_set_invalid_field(&io->scsiio,
691313371Smav				      /*sks_valid*/ 1,
692313371Smav				      /*command*/ 1,
693313371Smav				      /*field*/ 1,
694313371Smav				      /*bit_valid*/ 0,
695313371Smav				      /*bit*/ 0);
696313371Smav		ctl_config_write_done(io);
697313371Smav		return;
698313371Smav	}
699313371Smav	if (lbalen->flags & SWS_UNMAP) {
700313371Smav		ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len,
701313371Smav		    (lbalen->flags & SWS_ANCHOR) != 0);
702313371Smav		ctl_set_success(&io->scsiio);
703313371Smav		ctl_config_write_done(io);
704313371Smav		return;
705313371Smav	}
706313371Smav
707313371Smav	for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) {
708313371Smav		page = ctl_backend_ramdisk_getpage(be_lun,
709313371Smav		    lba >> cbe_lun->pblockexp, GP_WRITE);
710313371Smav		if (page == P_UNMAPPED || page == P_ANCHORED) {
711313371Smav			ctl_set_space_alloc_fail(&io->scsiio);
712313371Smav			ctl_data_submit_done(io);
713313371Smav			return;
714313371Smav		}
715313371Smav		lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp);
716313371Smav		page += lbaoff * cbe_lun->blocksize;
717313371Smav		if (lbalen->flags & SWS_NDOB) {
718313371Smav			memset(page, 0, cbe_lun->blocksize);
719313371Smav		} else {
720313371Smav			memcpy(page, io->scsiio.kern_data_ptr,
721313371Smav			    cbe_lun->blocksize);
722313371Smav		}
723313371Smav		if (lbalen->flags & SWS_LBDATA)
724313371Smav			scsi_ulto4b(lba, page);
725313371Smav	}
726313371Smav	ctl_set_success(&io->scsiio);
727313371Smav	ctl_config_write_done(io);
728313371Smav}
729313371Smav
730313371Smavstatic void
731313371Smavctl_backend_ramdisk_unmap(union ctl_io *io)
732313371Smav{
733313371Smav	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
734313371Smav	struct ctl_ptr_len_flags *ptrlen = (struct ctl_ptr_len_flags *)ARGS(io);
735313371Smav	struct scsi_unmap_desc *buf, *end;
736313371Smav
737313371Smav	if ((ptrlen->flags & ~SU_ANCHOR) != 0) {
738313371Smav		ctl_set_invalid_field(&io->scsiio,
739313371Smav				      /*sks_valid*/ 0,
740313371Smav				      /*command*/ 0,
741313371Smav				      /*field*/ 0,
742313371Smav				      /*bit_valid*/ 0,
743313371Smav				      /*bit*/ 0);
744313371Smav		ctl_config_write_done(io);
745313371Smav		return;
746313371Smav	}
747313371Smav
748313371Smav	buf = (struct scsi_unmap_desc *)ptrlen->ptr;
749313371Smav	end = buf + ptrlen->len / sizeof(*buf);
750313371Smav	for (; buf < end; buf++) {
751313371Smav		ctl_backend_ramdisk_delete(cbe_lun,
752313371Smav		    scsi_8btou64(buf->lba), scsi_4btoul(buf->length),
753313371Smav		    (ptrlen->flags & SU_ANCHOR) != 0);
754313371Smav	}
755313371Smav
756313371Smav	ctl_set_success(&io->scsiio);
757313371Smav	ctl_config_write_done(io);
758313371Smav}
759313371Smav
760313371Smavstatic int
761313371Smavctl_backend_ramdisk_config_write(union ctl_io *io)
762313371Smav{
763313371Smav	struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io);
764313371Smav	int retval = 0;
765313371Smav
766313371Smav	switch (io->scsiio.cdb[0]) {
767313371Smav	case SYNCHRONIZE_CACHE:
768313371Smav	case SYNCHRONIZE_CACHE_16:
769313371Smav		/* We have no cache to flush. */
770313371Smav		ctl_set_success(&io->scsiio);
771313371Smav		ctl_config_write_done(io);
772313371Smav		break;
773313371Smav	case START_STOP_UNIT: {
774313371Smav		struct scsi_start_stop_unit *cdb;
775313371Smav
776313371Smav		cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb;
777313371Smav		if ((cdb->how & SSS_PC_MASK) != 0) {
778313371Smav			ctl_set_success(&io->scsiio);
779313371Smav			ctl_config_write_done(io);
780313371Smav			break;
781313371Smav		}
782313371Smav		if (cdb->how & SSS_START) {
783313371Smav			if (cdb->how & SSS_LOEJ)
784313371Smav				ctl_lun_has_media(cbe_lun);
785313371Smav			ctl_start_lun(cbe_lun);
786313371Smav		} else {
787313371Smav			ctl_stop_lun(cbe_lun);
788313371Smav			if (cdb->how & SSS_LOEJ)
789313371Smav				ctl_lun_ejected(cbe_lun);
790313371Smav		}
791313371Smav		ctl_set_success(&io->scsiio);
792313371Smav		ctl_config_write_done(io);
793313371Smav		break;
794313371Smav	}
795313371Smav	case PREVENT_ALLOW:
796313371Smav		ctl_set_success(&io->scsiio);
797313371Smav		ctl_config_write_done(io);
798313371Smav		break;
799313371Smav	case WRITE_SAME_10:
800313371Smav	case WRITE_SAME_16:
801313371Smav		ctl_backend_ramdisk_ws(io);
802313371Smav		break;
803313371Smav	case UNMAP:
804313371Smav		ctl_backend_ramdisk_unmap(io);
805313371Smav		break;
806313371Smav	default:
807313371Smav		ctl_set_invalid_opcode(&io->scsiio);
808313371Smav		ctl_config_write_done(io);
809313371Smav		retval = CTL_RETVAL_COMPLETE;
810313371Smav		break;
811313371Smav	}
812313371Smav
813313371Smav	return (retval);
814313371Smav}
815313371Smav
816313371Smavstatic uint64_t
817313371Smavctl_backend_ramdisk_lun_attr(void *arg, const char *attrname)
818313371Smav{
819313371Smav	struct ctl_be_ramdisk_lun *be_lun = arg;
820313371Smav	uint64_t		val;
821313371Smav
822313371Smav	val = UINT64_MAX;
823313371Smav	if (be_lun->cap_bytes == 0)
824313371Smav		return (val);
825313371Smav	sx_slock(&be_lun->page_lock);
826313371Smav	if (strcmp(attrname, "blocksused") == 0) {
827313371Smav		val = be_lun->cap_used / be_lun->cbe_lun.blocksize;
828313371Smav	} else if (strcmp(attrname, "blocksavail") == 0) {
829313371Smav		val = (be_lun->cap_bytes - be_lun->cap_used) /
830313371Smav		    be_lun->cbe_lun.blocksize;
831313371Smav	}
832313371Smav	sx_sunlock(&be_lun->page_lock);
833313371Smav	return (val);
834313371Smav}
835313371Smav
836313371Smavstatic int
837229997Skenctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
838229997Sken			  int flag, struct thread *td)
839229997Sken{
840288799Smav	struct ctl_be_ramdisk_softc *softc = &rd_softc;
841288799Smav	struct ctl_lun_req *lun_req;
842229997Sken	int retval;
843229997Sken
844229997Sken	retval = 0;
845229997Sken	switch (cmd) {
846288799Smav	case CTL_LUN_REQ:
847229997Sken		lun_req = (struct ctl_lun_req *)addr;
848229997Sken		switch (lun_req->reqtype) {
849229997Sken		case CTL_LUNREQ_CREATE:
850288727Smav			retval = ctl_backend_ramdisk_create(softc, lun_req);
851229997Sken			break;
852229997Sken		case CTL_LUNREQ_RM:
853229997Sken			retval = ctl_backend_ramdisk_rm(softc, lun_req);
854229997Sken			break;
855232604Strasz		case CTL_LUNREQ_MODIFY:
856232604Strasz			retval = ctl_backend_ramdisk_modify(softc, lun_req);
857232604Strasz			break;
858229997Sken		default:
859229997Sken			lun_req->status = CTL_LUN_ERROR;
860229997Sken			snprintf(lun_req->error_str, sizeof(lun_req->error_str),
861229997Sken				 "%s: invalid LUN request type %d", __func__,
862229997Sken				 lun_req->reqtype);
863229997Sken			break;
864229997Sken		}
865229997Sken		break;
866229997Sken	default:
867229997Sken		retval = ENOTTY;
868229997Sken		break;
869229997Sken	}
870229997Sken
871229997Sken	return (retval);
872229997Sken}
873229997Sken
874229997Skenstatic int
875229997Skenctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc,
876229997Sken		       struct ctl_lun_req *req)
877229997Sken{
878229997Sken	struct ctl_be_ramdisk_lun *be_lun;
879229997Sken	struct ctl_lun_rm_params *params;
880229997Sken	int retval;
881229997Sken
882229997Sken	params = &req->reqdata.rm;
883229997Sken	mtx_lock(&softc->lock);
884229997Sken	STAILQ_FOREACH(be_lun, &softc->lun_list, links) {
885288727Smav		if (be_lun->cbe_lun.lun_id == params->lun_id)
886229997Sken			break;
887229997Sken	}
888229997Sken	mtx_unlock(&softc->lock);
889229997Sken	if (be_lun == NULL) {
890229997Sken		snprintf(req->error_str, sizeof(req->error_str),
891229997Sken			 "%s: LUN %u is not managed by the ramdisk backend",
892229997Sken			 __func__, params->lun_id);
893229997Sken		goto bailout_error;
894229997Sken	}
895229997Sken
896288727Smav	retval = ctl_disable_lun(&be_lun->cbe_lun);
897229997Sken	if (retval != 0) {
898229997Sken		snprintf(req->error_str, sizeof(req->error_str),
899229997Sken			 "%s: error %d returned from ctl_disable_lun() for "
900229997Sken			 "LUN %d", __func__, retval, params->lun_id);
901229997Sken		goto bailout_error;
902229997Sken	}
903229997Sken
904229997Sken	/*
905229997Sken	 * Set the waiting flag before we invalidate the LUN.  Our shutdown
906229997Sken	 * routine can be called any time after we invalidate the LUN,
907229997Sken	 * and can be called from our context.
908229997Sken	 *
909229997Sken	 * This tells the shutdown routine that we're waiting, or we're
910229997Sken	 * going to wait for the shutdown to happen.
911229997Sken	 */
912229997Sken	mtx_lock(&softc->lock);
913229997Sken	be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING;
914229997Sken	mtx_unlock(&softc->lock);
915229997Sken
916288727Smav	retval = ctl_invalidate_lun(&be_lun->cbe_lun);
917229997Sken	if (retval != 0) {
918229997Sken		snprintf(req->error_str, sizeof(req->error_str),
919229997Sken			 "%s: error %d returned from ctl_invalidate_lun() for "
920229997Sken			 "LUN %d", __func__, retval, params->lun_id);
921252569Smav		mtx_lock(&softc->lock);
922252569Smav		be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
923252569Smav		mtx_unlock(&softc->lock);
924229997Sken		goto bailout_error;
925229997Sken	}
926229997Sken
927229997Sken	mtx_lock(&softc->lock);
928229997Sken	while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) {
929229997Sken		retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0);
930288799Smav		if (retval == EINTR)
931229997Sken			break;
932229997Sken	}
933229997Sken	be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
934229997Sken
935229997Sken	/*
936229997Sken	 * We only remove this LUN from the list and free it (below) if
937229997Sken	 * retval == 0.  If the user interrupted the wait, we just bail out
938229997Sken	 * without actually freeing the LUN.  We let the shutdown routine
939229997Sken	 * free the LUN if that happens.
940229997Sken	 */
941229997Sken	if (retval == 0) {
942229997Sken		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
943229997Sken			      links);
944229997Sken		softc->num_luns--;
945229997Sken	}
946229997Sken
947229997Sken	mtx_unlock(&softc->lock);
948229997Sken
949265642Smav	if (retval == 0) {
950288734Smav		taskqueue_drain_all(be_lun->io_taskqueue);
951265642Smav		taskqueue_free(be_lun->io_taskqueue);
952288727Smav		ctl_free_opts(&be_lun->cbe_lun.options);
953313371Smav		free(be_lun->zero_page, M_RAMDISK);
954313371Smav		ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir);
955313371Smav		sx_destroy(&be_lun->page_lock);
956268549Smav		mtx_destroy(&be_lun->queue_lock);
957229997Sken		free(be_lun, M_RAMDISK);
958265642Smav	}
959229997Sken
960229997Sken	req->status = CTL_LUN_OK;
961229997Sken	return (retval);
962229997Sken
963229997Skenbailout_error:
964229997Sken	req->status = CTL_LUN_ERROR;
965229997Sken	return (0);
966229997Sken}
967229997Sken
968229997Skenstatic int
969229997Skenctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
970288727Smav			   struct ctl_lun_req *req)
971229997Sken{
972229997Sken	struct ctl_be_ramdisk_lun *be_lun;
973288727Smav	struct ctl_be_lun *cbe_lun;
974229997Sken	struct ctl_lun_create_params *params;
975268143Smav	char *value;
976229997Sken	char tmpstr[32];
977313371Smav	uint64_t t;
978288727Smav	int retval;
979229997Sken
980229997Sken	retval = 0;
981229997Sken	params = &req->reqdata.create;
982229997Sken
983288727Smav	be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK);
984288727Smav	cbe_lun = &be_lun->cbe_lun;
985288727Smav	cbe_lun->be_lun = be_lun;
986288728Smav	be_lun->params = req->reqdata.create;
987288727Smav	be_lun->softc = softc;
988265642Smav	sprintf(be_lun->lunname, "cram%d", softc->num_luns);
989288727Smav	ctl_init_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args);
990229997Sken
991229997Sken	if (params->flags & CTL_LUN_FLAG_DEV_TYPE)
992288727Smav		cbe_lun->lun_type = params->device_type;
993229997Sken	else
994288727Smav		cbe_lun->lun_type = T_DIRECT;
995288727Smav	be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED;
996288732Smav	cbe_lun->flags = 0;
997288732Smav	value = ctl_get_opt(&cbe_lun->options, "ha_role");
998288732Smav	if (value != NULL) {
999288732Smav		if (strcmp(value, "primary") == 0)
1000288732Smav			cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1001288732Smav	} else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
1002288732Smav		cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1003229997Sken
1004313371Smav	be_lun->pblocksize = PAGE_SIZE;
1005313371Smav	value = ctl_get_opt(&cbe_lun->options, "pblocksize");
1006313371Smav	if (value != NULL) {
1007313371Smav		ctl_expand_number(value, &t);
1008313371Smav		be_lun->pblocksize = t;
1009313371Smav	}
1010313371Smav	if (be_lun->pblocksize < 512 || be_lun->pblocksize > 131072) {
1011313371Smav		snprintf(req->error_str, sizeof(req->error_str),
1012313371Smav			 "%s: unsupported pblocksize %u", __func__,
1013313371Smav			 be_lun->pblocksize);
1014313371Smav		goto bailout_error;
1015313371Smav	}
1016313371Smav
1017288810Smav	if (cbe_lun->lun_type == T_DIRECT ||
1018288810Smav	    cbe_lun->lun_type == T_CDROM) {
1019288727Smav		if (params->blocksize_bytes != 0)
1020288727Smav			cbe_lun->blocksize = params->blocksize_bytes;
1021288810Smav		else if (cbe_lun->lun_type == T_CDROM)
1022288810Smav			cbe_lun->blocksize = 2048;
1023288727Smav		else
1024288727Smav			cbe_lun->blocksize = 512;
1025313371Smav		be_lun->pblockmul = be_lun->pblocksize / cbe_lun->blocksize;
1026313371Smav		if (be_lun->pblockmul < 1 || !powerof2(be_lun->pblockmul)) {
1027313371Smav			snprintf(req->error_str, sizeof(req->error_str),
1028313371Smav				 "%s: pblocksize %u not exp2 of blocksize %u",
1029313371Smav				 __func__,
1030313371Smav				 be_lun->pblocksize, cbe_lun->blocksize);
1031313371Smav			goto bailout_error;
1032313371Smav		}
1033288727Smav		if (params->lun_size_bytes < cbe_lun->blocksize) {
1034229997Sken			snprintf(req->error_str, sizeof(req->error_str),
1035229997Sken				 "%s: LUN size %ju < blocksize %u", __func__,
1036288727Smav				 params->lun_size_bytes, cbe_lun->blocksize);
1037229997Sken			goto bailout_error;
1038229997Sken		}
1039288727Smav		be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize;
1040288727Smav		be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize;
1041313371Smav		be_lun->indir = 0;
1042313371Smav		t = be_lun->size_bytes / be_lun->pblocksize;
1043313371Smav		while (t > 1) {
1044313371Smav			t /= PPP;
1045313371Smav			be_lun->indir++;
1046313371Smav		}
1047288727Smav		cbe_lun->maxlba = be_lun->size_blocks - 1;
1048313371Smav		cbe_lun->pblockexp = fls(be_lun->pblockmul) - 1;
1049313371Smav		cbe_lun->pblockoff = 0;
1050313371Smav		cbe_lun->ublockexp = cbe_lun->pblockexp;
1051313371Smav		cbe_lun->ublockoff = 0;
1052313371Smav		cbe_lun->atomicblock = be_lun->pblocksize;
1053313371Smav		cbe_lun->opttxferlen = SGPP * be_lun->pblocksize;
1054313371Smav		value = ctl_get_opt(&cbe_lun->options, "capacity");
1055313371Smav		if (value != NULL)
1056313371Smav			ctl_expand_number(value, &be_lun->cap_bytes);
1057313371Smav	} else {
1058313371Smav		be_lun->pblockmul = 1;
1059313371Smav		cbe_lun->pblockexp = 0;
1060229997Sken	}
1061229997Sken
1062229997Sken	/* Tell the user the blocksize we ended up using */
1063288727Smav	params->blocksize_bytes = cbe_lun->blocksize;
1064229997Sken	params->lun_size_bytes = be_lun->size_bytes;
1065229997Sken
1066288727Smav	value = ctl_get_opt(&cbe_lun->options, "unmap");
1067313371Smav	if (value == NULL || strcmp(value, "off") != 0)
1068288727Smav		cbe_lun->flags |= CTL_LUN_FLAG_UNMAP;
1069288727Smav	value = ctl_get_opt(&cbe_lun->options, "readonly");
1070288810Smav	if (value != NULL) {
1071288810Smav		if (strcmp(value, "on") == 0)
1072288810Smav			cbe_lun->flags |= CTL_LUN_FLAG_READONLY;
1073288810Smav	} else if (cbe_lun->lun_type != T_DIRECT)
1074288727Smav		cbe_lun->flags |= CTL_LUN_FLAG_READONLY;
1075288727Smav	cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
1076288727Smav	value = ctl_get_opt(&cbe_lun->options, "serseq");
1077288727Smav	if (value != NULL && strcmp(value, "on") == 0)
1078288727Smav		cbe_lun->serseq = CTL_LUN_SERSEQ_ON;
1079288727Smav	else if (value != NULL && strcmp(value, "read") == 0)
1080288727Smav		cbe_lun->serseq = CTL_LUN_SERSEQ_READ;
1081288727Smav	else if (value != NULL && strcmp(value, "off") == 0)
1082288727Smav		cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
1083254759Strasz
1084229997Sken	if (params->flags & CTL_LUN_FLAG_ID_REQ) {
1085288727Smav		cbe_lun->req_lun_id = params->req_lun_id;
1086288727Smav		cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ;
1087229997Sken	} else
1088288727Smav		cbe_lun->req_lun_id = 0;
1089229997Sken
1090288727Smav	cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown;
1091288727Smav	cbe_lun->lun_config_status = ctl_backend_ramdisk_lun_config_status;
1092288727Smav	cbe_lun->be = &ctl_be_ramdisk_driver;
1093229997Sken	if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) {
1094229997Sken		snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d",
1095229997Sken			 softc->num_luns);
1096288727Smav		strncpy((char *)cbe_lun->serial_num, tmpstr,
1097288727Smav			MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr)));
1098229997Sken
1099229997Sken		/* Tell the user what we used for a serial number */
1100229997Sken		strncpy((char *)params->serial_num, tmpstr,
1101276616Smav			MIN(sizeof(params->serial_num), sizeof(tmpstr)));
1102229997Sken	} else {
1103288727Smav		strncpy((char *)cbe_lun->serial_num, params->serial_num,
1104288727Smav			MIN(sizeof(cbe_lun->serial_num),
1105276616Smav			    sizeof(params->serial_num)));
1106229997Sken	}
1107229997Sken	if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) {
1108229997Sken		snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns);
1109288727Smav		strncpy((char *)cbe_lun->device_id, tmpstr,
1110288727Smav			MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr)));
1111229997Sken
1112229997Sken		/* Tell the user what we used for a device ID */
1113229997Sken		strncpy((char *)params->device_id, tmpstr,
1114276616Smav			MIN(sizeof(params->device_id), sizeof(tmpstr)));
1115229997Sken	} else {
1116288727Smav		strncpy((char *)cbe_lun->device_id, params->device_id,
1117288727Smav			MIN(sizeof(cbe_lun->device_id),
1118276616Smav			    sizeof(params->device_id)));
1119229997Sken	}
1120229997Sken
1121265642Smav	STAILQ_INIT(&be_lun->cont_queue);
1122313371Smav	sx_init(&be_lun->page_lock, "cram page lock");
1123314026Smav	if (be_lun->cap_bytes == 0) {
1124314026Smav		be_lun->indir = 0;
1125313371Smav		be_lun->pages = malloc(be_lun->pblocksize, M_RAMDISK, M_WAITOK);
1126314026Smav	}
1127313371Smav	be_lun->zero_page = malloc(be_lun->pblocksize, M_RAMDISK,
1128313371Smav	    M_WAITOK|M_ZERO);
1129268549Smav	mtx_init(&be_lun->queue_lock, "cram queue lock", NULL, MTX_DEF);
1130265642Smav	TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker,
1131265642Smav	    be_lun);
1132265642Smav
1133265642Smav	be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK,
1134265642Smav	    taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue);
1135265642Smav	if (be_lun->io_taskqueue == NULL) {
1136265642Smav		snprintf(req->error_str, sizeof(req->error_str),
1137265642Smav			 "%s: Unable to create taskqueue", __func__);
1138265642Smav		goto bailout_error;
1139265642Smav	}
1140265642Smav
1141265642Smav	retval = taskqueue_start_threads(&be_lun->io_taskqueue,
1142265642Smav					 /*num threads*/1,
1143265642Smav					 /*priority*/PWAIT,
1144265642Smav					 /*thread name*/
1145265642Smav					 "%s taskq", be_lun->lunname);
1146265642Smav	if (retval != 0)
1147265642Smav		goto bailout_error;
1148265642Smav
1149229997Sken	mtx_lock(&softc->lock);
1150229997Sken	softc->num_luns++;
1151229997Sken	STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links);
1152229997Sken	mtx_unlock(&softc->lock);
1153229997Sken
1154288727Smav	retval = ctl_add_lun(&be_lun->cbe_lun);
1155229997Sken	if (retval != 0) {
1156229997Sken		mtx_lock(&softc->lock);
1157229997Sken		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
1158229997Sken			      links);
1159229997Sken		softc->num_luns--;
1160229997Sken		mtx_unlock(&softc->lock);
1161229997Sken		snprintf(req->error_str, sizeof(req->error_str),
1162229997Sken			 "%s: ctl_add_lun() returned error %d, see dmesg for "
1163229997Sken			"details", __func__, retval);
1164229997Sken		retval = 0;
1165229997Sken		goto bailout_error;
1166229997Sken	}
1167229997Sken
1168229997Sken	mtx_lock(&softc->lock);
1169229997Sken
1170229997Sken	/*
1171229997Sken	 * Tell the config_status routine that we're waiting so it won't
1172229997Sken	 * clean up the LUN in the event of an error.
1173229997Sken	 */
1174229997Sken	be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING;
1175229997Sken
1176229997Sken	while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) {
1177229997Sken		retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0);
1178229997Sken		if (retval == EINTR)
1179229997Sken			break;
1180229997Sken	}
1181229997Sken	be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
1182229997Sken
1183229997Sken	if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) {
1184229997Sken		snprintf(req->error_str, sizeof(req->error_str),
1185229997Sken			 "%s: LUN configuration error, see dmesg for details",
1186229997Sken			 __func__);
1187229997Sken		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
1188229997Sken			      links);
1189229997Sken		softc->num_luns--;
1190229997Sken		mtx_unlock(&softc->lock);
1191229997Sken		goto bailout_error;
1192229997Sken	} else {
1193288727Smav		params->req_lun_id = cbe_lun->lun_id;
1194229997Sken	}
1195229997Sken	mtx_unlock(&softc->lock);
1196229997Sken
1197229997Sken	req->status = CTL_LUN_OK;
1198229997Sken	return (retval);
1199229997Sken
1200229997Skenbailout_error:
1201229997Sken	req->status = CTL_LUN_ERROR;
1202265642Smav	if (be_lun != NULL) {
1203313371Smav		if (be_lun->io_taskqueue != NULL)
1204265642Smav			taskqueue_free(be_lun->io_taskqueue);
1205288727Smav		ctl_free_opts(&cbe_lun->options);
1206313371Smav		free(be_lun->zero_page, M_RAMDISK);
1207313371Smav		ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir);
1208313371Smav		sx_destroy(&be_lun->page_lock);
1209268549Smav		mtx_destroy(&be_lun->queue_lock);
1210265642Smav		free(be_lun, M_RAMDISK);
1211265642Smav	}
1212229997Sken	return (retval);
1213229997Sken}
1214229997Sken
1215232604Straszstatic int
1216232604Straszctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc,
1217232604Strasz		       struct ctl_lun_req *req)
1218232604Strasz{
1219232604Strasz	struct ctl_be_ramdisk_lun *be_lun;
1220288728Smav	struct ctl_be_lun *cbe_lun;
1221232604Strasz	struct ctl_lun_modify_params *params;
1222288732Smav	char *value;
1223232604Strasz	uint32_t blocksize;
1224288732Smav	int wasprim;
1225232604Strasz
1226232604Strasz	params = &req->reqdata.modify;
1227232604Strasz
1228232604Strasz	mtx_lock(&softc->lock);
1229232604Strasz	STAILQ_FOREACH(be_lun, &softc->lun_list, links) {
1230288727Smav		if (be_lun->cbe_lun.lun_id == params->lun_id)
1231232604Strasz			break;
1232232604Strasz	}
1233232604Strasz	mtx_unlock(&softc->lock);
1234232604Strasz	if (be_lun == NULL) {
1235232604Strasz		snprintf(req->error_str, sizeof(req->error_str),
1236232604Strasz			 "%s: LUN %u is not managed by the ramdisk backend",
1237232604Strasz			 __func__, params->lun_id);
1238232604Strasz		goto bailout_error;
1239232604Strasz	}
1240288728Smav	cbe_lun = &be_lun->cbe_lun;
1241232604Strasz
1242288728Smav	if (params->lun_size_bytes != 0)
1243288728Smav		be_lun->params.lun_size_bytes = params->lun_size_bytes;
1244288728Smav	ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args);
1245288732Smav
1246288732Smav	wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY);
1247288732Smav	value = ctl_get_opt(&cbe_lun->options, "ha_role");
1248288732Smav	if (value != NULL) {
1249288732Smav		if (strcmp(value, "primary") == 0)
1250288732Smav			cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1251288732Smav		else
1252288732Smav			cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
1253288732Smav	} else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF)
1254288732Smav		cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY;
1255288732Smav	else
1256288732Smav		cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY;
1257288732Smav	if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) {
1258288732Smav		if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)
1259288732Smav			ctl_lun_primary(cbe_lun);
1260288732Smav		else
1261288732Smav			ctl_lun_secondary(cbe_lun);
1262288732Smav	}
1263288732Smav
1264288727Smav	blocksize = be_lun->cbe_lun.blocksize;
1265288728Smav	if (be_lun->params.lun_size_bytes < blocksize) {
1266232604Strasz		snprintf(req->error_str, sizeof(req->error_str),
1267232604Strasz			"%s: LUN size %ju < blocksize %u", __func__,
1268288728Smav			be_lun->params.lun_size_bytes, blocksize);
1269232604Strasz		goto bailout_error;
1270232604Strasz	}
1271288728Smav	be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize;
1272232604Strasz	be_lun->size_bytes = be_lun->size_blocks * blocksize;
1273288727Smav	be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1;
1274288727Smav	ctl_lun_capacity_changed(&be_lun->cbe_lun);
1275232604Strasz
1276232604Strasz	/* Tell the user the exact size we ended up using */
1277232604Strasz	params->lun_size_bytes = be_lun->size_bytes;
1278232604Strasz
1279232604Strasz	req->status = CTL_LUN_OK;
1280232604Strasz	return (0);
1281232604Strasz
1282232604Straszbailout_error:
1283232604Strasz	req->status = CTL_LUN_ERROR;
1284232604Strasz	return (0);
1285232604Strasz}
1286232604Strasz
1287229997Skenstatic void
1288229997Skenctl_backend_ramdisk_lun_shutdown(void *be_lun)
1289229997Sken{
1290229997Sken	struct ctl_be_ramdisk_lun *lun;
1291229997Sken	struct ctl_be_ramdisk_softc *softc;
1292229997Sken	int do_free;
1293229997Sken
1294229997Sken	lun = (struct ctl_be_ramdisk_lun *)be_lun;
1295229997Sken	softc = lun->softc;
1296229997Sken	do_free = 0;
1297229997Sken
1298229997Sken	mtx_lock(&softc->lock);
1299229997Sken	lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED;
1300229997Sken	if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) {
1301229997Sken		wakeup(lun);
1302229997Sken	} else {
1303269151Smav		STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun,
1304229997Sken			      links);
1305229997Sken		softc->num_luns--;
1306229997Sken		do_free = 1;
1307229997Sken	}
1308229997Sken	mtx_unlock(&softc->lock);
1309229997Sken
1310229997Sken	if (do_free != 0)
1311229997Sken		free(be_lun, M_RAMDISK);
1312229997Sken}
1313229997Sken
1314229997Skenstatic void
1315229997Skenctl_backend_ramdisk_lun_config_status(void *be_lun,
1316229997Sken				      ctl_lun_config_status status)
1317229997Sken{
1318229997Sken	struct ctl_be_ramdisk_lun *lun;
1319229997Sken	struct ctl_be_ramdisk_softc *softc;
1320229997Sken
1321229997Sken	lun = (struct ctl_be_ramdisk_lun *)be_lun;
1322229997Sken	softc = lun->softc;
1323229997Sken
1324229997Sken	if (status == CTL_LUN_CONFIG_OK) {
1325229997Sken		mtx_lock(&softc->lock);
1326229997Sken		lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED;
1327229997Sken		if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING)
1328229997Sken			wakeup(lun);
1329229997Sken		mtx_unlock(&softc->lock);
1330229997Sken
1331229997Sken		/*
1332229997Sken		 * We successfully added the LUN, attempt to enable it.
1333229997Sken		 */
1334288727Smav		if (ctl_enable_lun(&lun->cbe_lun) != 0) {
1335229997Sken			printf("%s: ctl_enable_lun() failed!\n", __func__);
1336288727Smav			if (ctl_invalidate_lun(&lun->cbe_lun) != 0) {
1337229997Sken				printf("%s: ctl_invalidate_lun() failed!\n",
1338229997Sken				       __func__);
1339229997Sken			}
1340229997Sken		}
1341229997Sken
1342229997Sken		return;
1343229997Sken	}
1344229997Sken
1345229997Sken
1346229997Sken	mtx_lock(&softc->lock);
1347229997Sken	lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED;
1348229997Sken
1349229997Sken	/*
1350229997Sken	 * If we have a user waiting, let him handle the cleanup.  If not,
1351229997Sken	 * clean things up here.
1352229997Sken	 */
1353229997Sken	if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) {
1354229997Sken		lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR;
1355229997Sken		wakeup(lun);
1356229997Sken	} else {
1357229997Sken		STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun,
1358229997Sken			      links);
1359229997Sken		softc->num_luns--;
1360229997Sken		free(lun, M_RAMDISK);
1361229997Sken	}
1362229997Sken	mtx_unlock(&softc->lock);
1363229997Sken}
1364