ctl_backend_ramdisk.c revision 287500
1229997Sken/*-
2229997Sken * Copyright (c) 2003, 2008 Silicon Graphics International Corp.
3232604Strasz * Copyright (c) 2012 The FreeBSD Foundation
4229997Sken * All rights reserved.
5229997Sken *
6232604Strasz * Portions of this software were developed by Edward Tomasz Napierala
7232604Strasz * under sponsorship from the FreeBSD Foundation.
8232604Strasz *
9229997Sken * Redistribution and use in source and binary forms, with or without
10229997Sken * modification, are permitted provided that the following conditions
11229997Sken * are met:
12229997Sken * 1. Redistributions of source code must retain the above copyright
13229997Sken *    notice, this list of conditions, and the following disclaimer,
14229997Sken *    without modification.
15229997Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer
16229997Sken *    substantially similar to the "NO WARRANTY" disclaimer below
17229997Sken *    ("Disclaimer") and any redistribution must be conditioned upon
18229997Sken *    including a substantially similar Disclaimer requirement for further
19229997Sken *    binary redistribution.
20229997Sken *
21229997Sken * NO WARRANTY
22229997Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23229997Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24229997Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
25229997Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26229997Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
30229997Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
31229997Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32229997Sken * POSSIBILITY OF SUCH DAMAGES.
33229997Sken *
34229997Sken * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $
35229997Sken */
36229997Sken/*
37229997Sken * CAM Target Layer backend for a "fake" ramdisk.
38229997Sken *
39229997Sken * Author: Ken Merry <ken@FreeBSD.org>
40229997Sken */
41229997Sken
42229997Sken#include <sys/cdefs.h>
43229997Sken__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_backend_ramdisk.c 287500 2015-09-06 11:23:01Z mav $");
44229997Sken
45229997Sken#include <sys/param.h>
46229997Sken#include <sys/systm.h>
47229997Sken#include <sys/kernel.h>
48229997Sken#include <sys/condvar.h>
49229997Sken#include <sys/types.h>
50229997Sken#include <sys/lock.h>
51229997Sken#include <sys/mutex.h>
52229997Sken#include <sys/malloc.h>
53264886Smav#include <sys/taskqueue.h>
54229997Sken#include <sys/time.h>
55229997Sken#include <sys/queue.h>
56229997Sken#include <sys/conf.h>
57229997Sken#include <sys/ioccom.h>
58229997Sken#include <sys/module.h>
59229997Sken
60229997Sken#include <cam/scsi/scsi_all.h>
61229997Sken#include <cam/ctl/ctl_io.h>
62229997Sken#include <cam/ctl/ctl.h>
63229997Sken#include <cam/ctl/ctl_util.h>
64229997Sken#include <cam/ctl/ctl_backend.h>
65229997Sken#include <cam/ctl/ctl_debug.h>
66229997Sken#include <cam/ctl/ctl_ioctl.h>
67229997Sken#include <cam/ctl/ctl_error.h>
68229997Sken
69229997Skentypedef enum {
70229997Sken	CTL_BE_RAMDISK_LUN_UNCONFIGURED	= 0x01,
71229997Sken	CTL_BE_RAMDISK_LUN_CONFIG_ERR	= 0x02,
72229997Sken	CTL_BE_RAMDISK_LUN_WAITING	= 0x04
73229997Sken} ctl_be_ramdisk_lun_flags;
74229997Sken
75229997Skenstruct ctl_be_ramdisk_lun {
76287500Smav	struct ctl_lun_create_params params;
77264886Smav	char lunname[32];
78229997Sken	uint64_t size_bytes;
79229997Sken	uint64_t size_blocks;
80229997Sken	struct ctl_be_ramdisk_softc *softc;
81229997Sken	ctl_be_ramdisk_lun_flags flags;
82229997Sken	STAILQ_ENTRY(ctl_be_ramdisk_lun) links;
83287499Smav	struct ctl_be_lun cbe_lun;
84264886Smav	struct taskqueue *io_taskqueue;
85264886Smav	struct task io_task;
86264886Smav	STAILQ_HEAD(, ctl_io_hdr) cont_queue;
87267877Smav	struct mtx_padalign queue_lock;
88229997Sken};
89229997Sken
90229997Skenstruct ctl_be_ramdisk_softc {
91229997Sken	struct mtx lock;
92229997Sken	int rd_size;
93229997Sken#ifdef CTL_RAMDISK_PAGES
94229997Sken	uint8_t **ramdisk_pages;
95229997Sken	int num_pages;
96229997Sken#else
97229997Sken	uint8_t *ramdisk_buffer;
98229997Sken#endif
99229997Sken	int num_luns;
100229997Sken	STAILQ_HEAD(, ctl_be_ramdisk_lun) lun_list;
101229997Sken};
102229997Sken
103229997Skenstatic struct ctl_be_ramdisk_softc rd_softc;
104229997Sken
105229997Skenint ctl_backend_ramdisk_init(void);
106229997Skenvoid ctl_backend_ramdisk_shutdown(void);
107229997Skenstatic int ctl_backend_ramdisk_move_done(union ctl_io *io);
108229997Skenstatic int ctl_backend_ramdisk_submit(union ctl_io *io);
109264886Smavstatic void ctl_backend_ramdisk_continue(union ctl_io *io);
110229997Skenstatic int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd,
111229997Sken				     caddr_t addr, int flag, struct thread *td);
112229997Skenstatic int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc,
113229997Sken				  struct ctl_lun_req *req);
114229997Skenstatic int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
115287499Smav				      struct ctl_lun_req *req);
116232604Straszstatic int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc,
117232604Strasz				  struct ctl_lun_req *req);
118264886Smavstatic void ctl_backend_ramdisk_worker(void *context, int pending);
119229997Skenstatic void ctl_backend_ramdisk_lun_shutdown(void *be_lun);
120229997Skenstatic void ctl_backend_ramdisk_lun_config_status(void *be_lun,
121229997Sken						  ctl_lun_config_status status);
122229997Skenstatic int ctl_backend_ramdisk_config_write(union ctl_io *io);
123229997Skenstatic int ctl_backend_ramdisk_config_read(union ctl_io *io);
124229997Sken
125229997Skenstatic struct ctl_backend_driver ctl_be_ramdisk_driver =
126229997Sken{
127230334Sken	.name = "ramdisk",
128230334Sken	.flags = CTL_BE_FLAG_HAS_CONFIG,
129230334Sken	.init = ctl_backend_ramdisk_init,
130230334Sken	.data_submit = ctl_backend_ramdisk_submit,
131230334Sken	.data_move_done = ctl_backend_ramdisk_move_done,
132230334Sken	.config_read = ctl_backend_ramdisk_config_read,
133230334Sken	.config_write = ctl_backend_ramdisk_config_write,
134230334Sken	.ioctl = ctl_backend_ramdisk_ioctl
135229997Sken};
136229997Sken
137229997SkenMALLOC_DEFINE(M_RAMDISK, "ramdisk", "Memory used for CTL RAMdisk");
138229997SkenCTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver);
139229997Sken
140229997Skenint
141229997Skenctl_backend_ramdisk_init(void)
142229997Sken{
143229997Sken	struct ctl_be_ramdisk_softc *softc;
144229997Sken#ifdef CTL_RAMDISK_PAGES
145240993Strasz	int i;
146229997Sken#endif
147229997Sken
148229997Sken
149229997Sken	softc = &rd_softc;
150229997Sken
151229997Sken	memset(softc, 0, sizeof(*softc));
152229997Sken
153267877Smav	mtx_init(&softc->lock, "ctlramdisk", NULL, MTX_DEF);
154229997Sken
155229997Sken	STAILQ_INIT(&softc->lun_list);
156264886Smav	softc->rd_size = 1024 * 1024;
157229997Sken#ifdef CTL_RAMDISK_PAGES
158229997Sken	softc->num_pages = softc->rd_size / PAGE_SIZE;
159229997Sken	softc->ramdisk_pages = (uint8_t **)malloc(sizeof(uint8_t *) *
160229997Sken						  softc->num_pages, M_RAMDISK,
161229997Sken						  M_WAITOK);
162240993Strasz	for (i = 0; i < softc->num_pages; i++)
163229997Sken		softc->ramdisk_pages[i] = malloc(PAGE_SIZE, M_RAMDISK,M_WAITOK);
164229997Sken#else
165229997Sken	softc->ramdisk_buffer = (uint8_t *)malloc(softc->rd_size, M_RAMDISK,
166229997Sken						  M_WAITOK);
167229997Sken#endif
168229997Sken
169229997Sken	return (0);
170229997Sken}
171229997Sken
172229997Skenvoid
173229997Skenctl_backend_ramdisk_shutdown(void)
174229997Sken{
175229997Sken	struct ctl_be_ramdisk_softc *softc;
176229997Sken	struct ctl_be_ramdisk_lun *lun, *next_lun;
177229997Sken#ifdef CTL_RAMDISK_PAGES
178229997Sken	int i;
179229997Sken#endif
180229997Sken
181229997Sken	softc = &rd_softc;
182229997Sken
183229997Sken	mtx_lock(&softc->lock);
184229997Sken	for (lun = STAILQ_FIRST(&softc->lun_list); lun != NULL; lun = next_lun){
185229997Sken		/*
186229997Sken		 * Grab the next LUN.  The current LUN may get removed by
187229997Sken		 * ctl_invalidate_lun(), which will call our LUN shutdown
188229997Sken		 * routine, if there is no outstanding I/O for this LUN.
189229997Sken		 */
190229997Sken		next_lun = STAILQ_NEXT(lun, links);
191229997Sken
192229997Sken		/*
193229997Sken		 * Drop our lock here.  Since ctl_invalidate_lun() can call
194229997Sken		 * back into us, this could potentially lead to a recursive
195229997Sken		 * lock of the same mutex, which would cause a hang.
196229997Sken		 */
197229997Sken		mtx_unlock(&softc->lock);
198287499Smav		ctl_disable_lun(&lun->cbe_lun);
199287499Smav		ctl_invalidate_lun(&lun->cbe_lun);
200229997Sken		mtx_lock(&softc->lock);
201229997Sken	}
202229997Sken	mtx_unlock(&softc->lock);
203229997Sken
204229997Sken#ifdef CTL_RAMDISK_PAGES
205229997Sken	for (i = 0; i < softc->num_pages; i++)
206229997Sken		free(softc->ramdisk_pages[i], M_RAMDISK);
207229997Sken
208229997Sken	free(softc->ramdisk_pages, M_RAMDISK);
209229997Sken#else
210229997Sken	free(softc->ramdisk_buffer, M_RAMDISK);
211229997Sken#endif
212229997Sken
213229997Sken	if (ctl_backend_deregister(&ctl_be_ramdisk_driver) != 0) {
214229997Sken		printf("ctl_backend_ramdisk_shutdown: "
215229997Sken		       "ctl_backend_deregister() failed!\n");
216229997Sken	}
217229997Sken}
218229997Sken
219229997Skenstatic int
220229997Skenctl_backend_ramdisk_move_done(union ctl_io *io)
221229997Sken{
222287499Smav	struct ctl_be_lun *cbe_lun;
223264886Smav	struct ctl_be_ramdisk_lun *be_lun;
224229997Sken#ifdef CTL_TIME_IO
225229997Sken	struct bintime cur_bt;
226229997Sken#endif
227229997Sken
228229997Sken	CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n"));
229287499Smav	cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[
230264886Smav		CTL_PRIV_BACKEND_LUN].ptr;
231287499Smav	be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun->be_lun;
232264886Smav#ifdef CTL_TIME_IO
233264886Smav	getbintime(&cur_bt);
234264886Smav	bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt);
235264886Smav	bintime_add(&io->io_hdr.dma_bt, &cur_bt);
236264886Smav	io->io_hdr.num_dmas++;
237264886Smav#endif
238264886Smav	if (io->scsiio.kern_sg_entries > 0)
239264886Smav		free(io->scsiio.kern_data_ptr, M_RAMDISK);
240264886Smav	io->scsiio.kern_rel_offset += io->scsiio.kern_data_len;
241275058Smav	if (io->io_hdr.flags & CTL_FLAG_ABORT) {
242275058Smav		;
243275058Smav	} else if ((io->io_hdr.port_status == 0) &&
244275058Smav	    ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) {
245267519Smav		if (io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer > 0) {
246267877Smav			mtx_lock(&be_lun->queue_lock);
247264886Smav			STAILQ_INSERT_TAIL(&be_lun->cont_queue,
248264886Smav			    &io->io_hdr, links);
249267877Smav			mtx_unlock(&be_lun->queue_lock);
250264886Smav			taskqueue_enqueue(be_lun->io_taskqueue,
251264886Smav			    &be_lun->io_task);
252264886Smav			return (0);
253264886Smav		}
254275009Smav		ctl_set_success(&io->scsiio);
255275058Smav	} else if ((io->io_hdr.port_status != 0) &&
256275058Smav	    ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE ||
257275058Smav	     (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) {
258229997Sken		/*
259229997Sken		 * For hardware error sense keys, the sense key
260229997Sken		 * specific value is defined to be a retry count,
261229997Sken		 * but we use it to pass back an internal FETD
262229997Sken		 * error code.  XXX KDM  Hopefully the FETD is only
263229997Sken		 * using 16 bits for an error code, since that's
264229997Sken		 * all the space we have in the sks field.
265229997Sken		 */
266229997Sken		ctl_set_internal_failure(&io->scsiio,
267229997Sken					 /*sks_valid*/ 1,
268229997Sken					 /*retry_count*/
269229997Sken					 io->io_hdr.port_status);
270229997Sken	}
271267537Smav	ctl_data_submit_done(io);
272229997Sken	return(0);
273229997Sken}
274229997Sken
275229997Skenstatic int
276229997Skenctl_backend_ramdisk_submit(union ctl_io *io)
277229997Sken{
278287499Smav	struct ctl_be_lun *cbe_lun;
279267537Smav	struct ctl_lba_len_flags *lbalen;
280229997Sken
281287499Smav	cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[
282267519Smav		CTL_PRIV_BACKEND_LUN].ptr;
283267537Smav	lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN];
284267537Smav	if (lbalen->flags & CTL_LLF_VERIFY) {
285267537Smav		ctl_set_success(&io->scsiio);
286267537Smav		ctl_data_submit_done(io);
287267537Smav		return (CTL_RETVAL_COMPLETE);
288267537Smav	}
289267519Smav	io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer =
290287499Smav	    lbalen->len * cbe_lun->blocksize;
291264886Smav	ctl_backend_ramdisk_continue(io);
292264886Smav	return (CTL_RETVAL_COMPLETE);
293264886Smav}
294229997Sken
295264886Smavstatic void
296264886Smavctl_backend_ramdisk_continue(union ctl_io *io)
297264886Smav{
298264886Smav	struct ctl_be_ramdisk_softc *softc;
299264886Smav	int len, len_filled, sg_filled;
300264886Smav#ifdef CTL_RAMDISK_PAGES
301264886Smav	struct ctl_sg_entry *sg_entries;
302264886Smav	int i;
303264886Smav#endif
304229997Sken
305264886Smav	softc = &rd_softc;
306267519Smav	len = io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer;
307229997Sken#ifdef CTL_RAMDISK_PAGES
308264886Smav	sg_filled = min(btoc(len), softc->num_pages);
309264886Smav	if (sg_filled > 1) {
310229997Sken		io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) *
311264886Smav						  sg_filled, M_RAMDISK,
312229997Sken						  M_WAITOK);
313229997Sken		sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr;
314264886Smav		for (i = 0, len_filled = 0; i < sg_filled; i++) {
315229997Sken			sg_entries[i].addr = softc->ramdisk_pages[i];
316275953Smav			sg_entries[i].len = MIN(PAGE_SIZE, len - len_filled);
317264886Smav			len_filled += sg_entries[i].len;
318229997Sken		}
319264886Smav		io->io_hdr.flags |= CTL_FLAG_KDPTR_SGLIST;
320229997Sken	} else {
321264886Smav		sg_filled = 0;
322264886Smav		len_filled = len;
323229997Sken		io->scsiio.kern_data_ptr = softc->ramdisk_pages[0];
324264886Smav	}
325229997Sken#else
326264886Smav	sg_filled = 0;
327264886Smav	len_filled = min(len, softc->rd_size);
328264886Smav	io->scsiio.kern_data_ptr = softc->ramdisk_buffer;
329264886Smav#endif /* CTL_RAMDISK_PAGES */
330229997Sken
331267514Smav	io->scsiio.be_move_done = ctl_backend_ramdisk_move_done;
332267514Smav	io->scsiio.kern_data_resid = 0;
333264886Smav	io->scsiio.kern_data_len = len_filled;
334264886Smav	io->scsiio.kern_sg_entries = sg_filled;
335264886Smav	io->io_hdr.flags |= CTL_FLAG_ALLOCATED;
336267519Smav	io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer -= len_filled;
337229997Sken#ifdef CTL_TIME_IO
338229997Sken	getbintime(&io->io_hdr.dma_start_bt);
339229997Sken#endif
340229997Sken	ctl_datamove(io);
341264886Smav}
342229997Sken
343264886Smavstatic void
344264886Smavctl_backend_ramdisk_worker(void *context, int pending)
345264886Smav{
346264886Smav	struct ctl_be_ramdisk_softc *softc;
347264886Smav	struct ctl_be_ramdisk_lun *be_lun;
348264886Smav	union ctl_io *io;
349264886Smav
350264886Smav	be_lun = (struct ctl_be_ramdisk_lun *)context;
351264886Smav	softc = be_lun->softc;
352264886Smav
353267877Smav	mtx_lock(&be_lun->queue_lock);
354264886Smav	for (;;) {
355264886Smav		io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue);
356264886Smav		if (io != NULL) {
357264886Smav			STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr,
358264886Smav				      ctl_io_hdr, links);
359264886Smav
360267877Smav			mtx_unlock(&be_lun->queue_lock);
361264886Smav
362264886Smav			ctl_backend_ramdisk_continue(io);
363264886Smav
364267877Smav			mtx_lock(&be_lun->queue_lock);
365264886Smav			continue;
366264886Smav		}
367264886Smav
368264886Smav		/*
369264886Smav		 * If we get here, there is no work left in the queues, so
370264886Smav		 * just break out and let the task queue go to sleep.
371264886Smav		 */
372264886Smav		break;
373264886Smav	}
374267877Smav	mtx_unlock(&be_lun->queue_lock);
375229997Sken}
376229997Sken
377229997Skenstatic int
378229997Skenctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
379229997Sken			  int flag, struct thread *td)
380229997Sken{
381229997Sken	struct ctl_be_ramdisk_softc *softc;
382229997Sken	int retval;
383229997Sken
384229997Sken	retval = 0;
385229997Sken	softc = &rd_softc;
386229997Sken
387229997Sken	switch (cmd) {
388229997Sken	case CTL_LUN_REQ: {
389229997Sken		struct ctl_lun_req *lun_req;
390229997Sken
391229997Sken		lun_req = (struct ctl_lun_req *)addr;
392229997Sken
393229997Sken		switch (lun_req->reqtype) {
394229997Sken		case CTL_LUNREQ_CREATE:
395287499Smav			retval = ctl_backend_ramdisk_create(softc, lun_req);
396229997Sken			break;
397229997Sken		case CTL_LUNREQ_RM:
398229997Sken			retval = ctl_backend_ramdisk_rm(softc, lun_req);
399229997Sken			break;
400232604Strasz		case CTL_LUNREQ_MODIFY:
401232604Strasz			retval = ctl_backend_ramdisk_modify(softc, lun_req);
402232604Strasz			break;
403229997Sken		default:
404229997Sken			lun_req->status = CTL_LUN_ERROR;
405229997Sken			snprintf(lun_req->error_str, sizeof(lun_req->error_str),
406229997Sken				 "%s: invalid LUN request type %d", __func__,
407229997Sken				 lun_req->reqtype);
408229997Sken			break;
409229997Sken		}
410229997Sken		break;
411229997Sken	}
412229997Sken	default:
413229997Sken		retval = ENOTTY;
414229997Sken		break;
415229997Sken	}
416229997Sken
417229997Sken	return (retval);
418229997Sken}
419229997Sken
420229997Skenstatic int
421229997Skenctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc,
422229997Sken		       struct ctl_lun_req *req)
423229997Sken{
424229997Sken	struct ctl_be_ramdisk_lun *be_lun;
425229997Sken	struct ctl_lun_rm_params *params;
426229997Sken	int retval;
427229997Sken
428229997Sken
429229997Sken	retval = 0;
430229997Sken	params = &req->reqdata.rm;
431229997Sken
432229997Sken	be_lun = NULL;
433229997Sken
434229997Sken	mtx_lock(&softc->lock);
435229997Sken
436229997Sken	STAILQ_FOREACH(be_lun, &softc->lun_list, links) {
437287499Smav		if (be_lun->cbe_lun.lun_id == params->lun_id)
438229997Sken			break;
439229997Sken	}
440229997Sken	mtx_unlock(&softc->lock);
441229997Sken
442229997Sken	if (be_lun == NULL) {
443229997Sken		snprintf(req->error_str, sizeof(req->error_str),
444229997Sken			 "%s: LUN %u is not managed by the ramdisk backend",
445229997Sken			 __func__, params->lun_id);
446229997Sken		goto bailout_error;
447229997Sken	}
448229997Sken
449287499Smav	retval = ctl_disable_lun(&be_lun->cbe_lun);
450229997Sken
451229997Sken	if (retval != 0) {
452229997Sken		snprintf(req->error_str, sizeof(req->error_str),
453229997Sken			 "%s: error %d returned from ctl_disable_lun() for "
454229997Sken			 "LUN %d", __func__, retval, params->lun_id);
455229997Sken		goto bailout_error;
456229997Sken	}
457229997Sken
458229997Sken	/*
459229997Sken	 * Set the waiting flag before we invalidate the LUN.  Our shutdown
460229997Sken	 * routine can be called any time after we invalidate the LUN,
461229997Sken	 * and can be called from our context.
462229997Sken	 *
463229997Sken	 * This tells the shutdown routine that we're waiting, or we're
464229997Sken	 * going to wait for the shutdown to happen.
465229997Sken	 */
466229997Sken	mtx_lock(&softc->lock);
467229997Sken	be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING;
468229997Sken	mtx_unlock(&softc->lock);
469229997Sken
470287499Smav	retval = ctl_invalidate_lun(&be_lun->cbe_lun);
471229997Sken	if (retval != 0) {
472229997Sken		snprintf(req->error_str, sizeof(req->error_str),
473229997Sken			 "%s: error %d returned from ctl_invalidate_lun() for "
474229997Sken			 "LUN %d", __func__, retval, params->lun_id);
475252569Smav		mtx_lock(&softc->lock);
476252569Smav		be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
477252569Smav		mtx_unlock(&softc->lock);
478229997Sken		goto bailout_error;
479229997Sken	}
480229997Sken
481229997Sken	mtx_lock(&softc->lock);
482229997Sken
483229997Sken	while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) {
484229997Sken		retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0);
485229997Sken 		if (retval == EINTR)
486229997Sken			break;
487229997Sken	}
488229997Sken	be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
489229997Sken
490229997Sken	/*
491229997Sken	 * We only remove this LUN from the list and free it (below) if
492229997Sken	 * retval == 0.  If the user interrupted the wait, we just bail out
493229997Sken	 * without actually freeing the LUN.  We let the shutdown routine
494229997Sken	 * free the LUN if that happens.
495229997Sken	 */
496229997Sken	if (retval == 0) {
497229997Sken		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
498229997Sken			      links);
499229997Sken		softc->num_luns--;
500229997Sken	}
501229997Sken
502229997Sken	mtx_unlock(&softc->lock);
503229997Sken
504264886Smav	if (retval == 0) {
505264886Smav		taskqueue_drain(be_lun->io_taskqueue, &be_lun->io_task);
506264886Smav		taskqueue_free(be_lun->io_taskqueue);
507287499Smav		ctl_free_opts(&be_lun->cbe_lun.options);
508267877Smav		mtx_destroy(&be_lun->queue_lock);
509229997Sken		free(be_lun, M_RAMDISK);
510264886Smav	}
511229997Sken
512229997Sken	req->status = CTL_LUN_OK;
513229997Sken
514229997Sken	return (retval);
515229997Sken
516229997Skenbailout_error:
517229997Sken	req->status = CTL_LUN_ERROR;
518229997Sken
519229997Sken	return (0);
520229997Sken}
521229997Sken
522229997Skenstatic int
523229997Skenctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc,
524287499Smav			   struct ctl_lun_req *req)
525229997Sken{
526229997Sken	struct ctl_be_ramdisk_lun *be_lun;
527287499Smav	struct ctl_be_lun *cbe_lun;
528229997Sken	struct ctl_lun_create_params *params;
529267481Smav	char *value;
530229997Sken	char tmpstr[32];
531287499Smav	int retval;
532229997Sken
533229997Sken	retval = 0;
534229997Sken	params = &req->reqdata.create;
535229997Sken
536287499Smav	be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK);
537287499Smav	cbe_lun = &be_lun->cbe_lun;
538287499Smav	cbe_lun->be_lun = be_lun;
539287500Smav	be_lun->params = req->reqdata.create;
540287499Smav	be_lun->softc = softc;
541264886Smav	sprintf(be_lun->lunname, "cram%d", softc->num_luns);
542287499Smav	ctl_init_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args);
543229997Sken
544229997Sken	if (params->flags & CTL_LUN_FLAG_DEV_TYPE)
545287499Smav		cbe_lun->lun_type = params->device_type;
546229997Sken	else
547287499Smav		cbe_lun->lun_type = T_DIRECT;
548287499Smav	be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED;
549287499Smav	cbe_lun->flags = CTL_LUN_FLAG_PRIMARY;
550229997Sken
551287499Smav	if (cbe_lun->lun_type == T_DIRECT) {
552287499Smav		if (params->blocksize_bytes != 0)
553287499Smav			cbe_lun->blocksize = params->blocksize_bytes;
554287499Smav		else
555287499Smav			cbe_lun->blocksize = 512;
556287499Smav		if (params->lun_size_bytes < cbe_lun->blocksize) {
557229997Sken			snprintf(req->error_str, sizeof(req->error_str),
558229997Sken				 "%s: LUN size %ju < blocksize %u", __func__,
559287499Smav				 params->lun_size_bytes, cbe_lun->blocksize);
560229997Sken			goto bailout_error;
561229997Sken		}
562287499Smav		be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize;
563287499Smav		be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize;
564287499Smav		cbe_lun->maxlba = be_lun->size_blocks - 1;
565287499Smav		cbe_lun->atomicblock = UINT32_MAX;
566287499Smav		cbe_lun->opttxferlen = softc->rd_size / cbe_lun->blocksize;
567229997Sken	}
568229997Sken
569229997Sken	/* Tell the user the blocksize we ended up using */
570287499Smav	params->blocksize_bytes = cbe_lun->blocksize;
571229997Sken	params->lun_size_bytes = be_lun->size_bytes;
572229997Sken
573287499Smav	value = ctl_get_opt(&cbe_lun->options, "unmap");
574267481Smav	if (value != NULL && strcmp(value, "on") == 0)
575287499Smav		cbe_lun->flags |= CTL_LUN_FLAG_UNMAP;
576287499Smav	value = ctl_get_opt(&cbe_lun->options, "readonly");
577287499Smav	if (value != NULL && strcmp(value, "on") == 0)
578287499Smav		cbe_lun->flags |= CTL_LUN_FLAG_READONLY;
579287499Smav	cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
580287499Smav	value = ctl_get_opt(&cbe_lun->options, "serseq");
581287499Smav	if (value != NULL && strcmp(value, "on") == 0)
582287499Smav		cbe_lun->serseq = CTL_LUN_SERSEQ_ON;
583287499Smav	else if (value != NULL && strcmp(value, "read") == 0)
584287499Smav		cbe_lun->serseq = CTL_LUN_SERSEQ_READ;
585287499Smav	else if (value != NULL && strcmp(value, "off") == 0)
586287499Smav		cbe_lun->serseq = CTL_LUN_SERSEQ_OFF;
587254759Strasz
588229997Sken	if (params->flags & CTL_LUN_FLAG_ID_REQ) {
589287499Smav		cbe_lun->req_lun_id = params->req_lun_id;
590287499Smav		cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ;
591229997Sken	} else
592287499Smav		cbe_lun->req_lun_id = 0;
593229997Sken
594287499Smav	cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown;
595287499Smav	cbe_lun->lun_config_status = ctl_backend_ramdisk_lun_config_status;
596287499Smav	cbe_lun->be = &ctl_be_ramdisk_driver;
597229997Sken	if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) {
598229997Sken		snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d",
599229997Sken			 softc->num_luns);
600287499Smav		strncpy((char *)cbe_lun->serial_num, tmpstr,
601287499Smav			MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr)));
602229997Sken
603229997Sken		/* Tell the user what we used for a serial number */
604229997Sken		strncpy((char *)params->serial_num, tmpstr,
605275953Smav			MIN(sizeof(params->serial_num), sizeof(tmpstr)));
606229997Sken	} else {
607287499Smav		strncpy((char *)cbe_lun->serial_num, params->serial_num,
608287499Smav			MIN(sizeof(cbe_lun->serial_num),
609275953Smav			    sizeof(params->serial_num)));
610229997Sken	}
611229997Sken	if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) {
612229997Sken		snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns);
613287499Smav		strncpy((char *)cbe_lun->device_id, tmpstr,
614287499Smav			MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr)));
615229997Sken
616229997Sken		/* Tell the user what we used for a device ID */
617229997Sken		strncpy((char *)params->device_id, tmpstr,
618275953Smav			MIN(sizeof(params->device_id), sizeof(tmpstr)));
619229997Sken	} else {
620287499Smav		strncpy((char *)cbe_lun->device_id, params->device_id,
621287499Smav			MIN(sizeof(cbe_lun->device_id),
622275953Smav			    sizeof(params->device_id)));
623229997Sken	}
624229997Sken
625264886Smav	STAILQ_INIT(&be_lun->cont_queue);
626267877Smav	mtx_init(&be_lun->queue_lock, "cram queue lock", NULL, MTX_DEF);
627264886Smav	TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker,
628264886Smav	    be_lun);
629264886Smav
630264886Smav	be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK,
631264886Smav	    taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue);
632264886Smav	if (be_lun->io_taskqueue == NULL) {
633264886Smav		snprintf(req->error_str, sizeof(req->error_str),
634264886Smav			 "%s: Unable to create taskqueue", __func__);
635264886Smav		goto bailout_error;
636264886Smav	}
637264886Smav
638264886Smav	retval = taskqueue_start_threads(&be_lun->io_taskqueue,
639264886Smav					 /*num threads*/1,
640264886Smav					 /*priority*/PWAIT,
641264886Smav					 /*thread name*/
642264886Smav					 "%s taskq", be_lun->lunname);
643264886Smav	if (retval != 0)
644264886Smav		goto bailout_error;
645264886Smav
646229997Sken	mtx_lock(&softc->lock);
647229997Sken	softc->num_luns++;
648229997Sken	STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links);
649229997Sken
650229997Sken	mtx_unlock(&softc->lock);
651229997Sken
652287499Smav	retval = ctl_add_lun(&be_lun->cbe_lun);
653229997Sken	if (retval != 0) {
654229997Sken		mtx_lock(&softc->lock);
655229997Sken		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
656229997Sken			      links);
657229997Sken		softc->num_luns--;
658229997Sken		mtx_unlock(&softc->lock);
659229997Sken		snprintf(req->error_str, sizeof(req->error_str),
660229997Sken			 "%s: ctl_add_lun() returned error %d, see dmesg for "
661229997Sken			"details", __func__, retval);
662229997Sken		retval = 0;
663229997Sken		goto bailout_error;
664229997Sken	}
665229997Sken
666229997Sken	mtx_lock(&softc->lock);
667229997Sken
668229997Sken	/*
669229997Sken	 * Tell the config_status routine that we're waiting so it won't
670229997Sken	 * clean up the LUN in the event of an error.
671229997Sken	 */
672229997Sken	be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING;
673229997Sken
674229997Sken	while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) {
675229997Sken		retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0);
676229997Sken		if (retval == EINTR)
677229997Sken			break;
678229997Sken	}
679229997Sken	be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING;
680229997Sken
681229997Sken	if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) {
682229997Sken		snprintf(req->error_str, sizeof(req->error_str),
683229997Sken			 "%s: LUN configuration error, see dmesg for details",
684229997Sken			 __func__);
685229997Sken		STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun,
686229997Sken			      links);
687229997Sken		softc->num_luns--;
688229997Sken		mtx_unlock(&softc->lock);
689229997Sken		goto bailout_error;
690229997Sken	} else {
691287499Smav		params->req_lun_id = cbe_lun->lun_id;
692229997Sken	}
693229997Sken	mtx_unlock(&softc->lock);
694229997Sken
695229997Sken	req->status = CTL_LUN_OK;
696229997Sken
697229997Sken	return (retval);
698229997Sken
699229997Skenbailout_error:
700229997Sken	req->status = CTL_LUN_ERROR;
701264886Smav	if (be_lun != NULL) {
702264886Smav		if (be_lun->io_taskqueue != NULL) {
703264886Smav			taskqueue_free(be_lun->io_taskqueue);
704264886Smav		}
705287499Smav		ctl_free_opts(&cbe_lun->options);
706267877Smav		mtx_destroy(&be_lun->queue_lock);
707264886Smav		free(be_lun, M_RAMDISK);
708264886Smav	}
709229997Sken
710229997Sken	return (retval);
711229997Sken}
712229997Sken
713232604Straszstatic int
714232604Straszctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc,
715232604Strasz		       struct ctl_lun_req *req)
716232604Strasz{
717232604Strasz	struct ctl_be_ramdisk_lun *be_lun;
718287500Smav	struct ctl_be_lun *cbe_lun;
719232604Strasz	struct ctl_lun_modify_params *params;
720232604Strasz	uint32_t blocksize;
721232604Strasz
722232604Strasz	params = &req->reqdata.modify;
723232604Strasz
724232604Strasz	mtx_lock(&softc->lock);
725232604Strasz	STAILQ_FOREACH(be_lun, &softc->lun_list, links) {
726287499Smav		if (be_lun->cbe_lun.lun_id == params->lun_id)
727232604Strasz			break;
728232604Strasz	}
729232604Strasz	mtx_unlock(&softc->lock);
730232604Strasz
731232604Strasz	if (be_lun == NULL) {
732232604Strasz		snprintf(req->error_str, sizeof(req->error_str),
733232604Strasz			 "%s: LUN %u is not managed by the ramdisk backend",
734232604Strasz			 __func__, params->lun_id);
735232604Strasz		goto bailout_error;
736232604Strasz	}
737287500Smav	cbe_lun = &be_lun->cbe_lun;
738232604Strasz
739287500Smav	if (params->lun_size_bytes != 0)
740287500Smav		be_lun->params.lun_size_bytes = params->lun_size_bytes;
741287500Smav	ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args);
742287499Smav	blocksize = be_lun->cbe_lun.blocksize;
743232604Strasz
744287500Smav	if (be_lun->params.lun_size_bytes < blocksize) {
745232604Strasz		snprintf(req->error_str, sizeof(req->error_str),
746232604Strasz			"%s: LUN size %ju < blocksize %u", __func__,
747287500Smav			be_lun->params.lun_size_bytes, blocksize);
748232604Strasz		goto bailout_error;
749232604Strasz	}
750232604Strasz
751287500Smav	be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize;
752232604Strasz	be_lun->size_bytes = be_lun->size_blocks * blocksize;
753287499Smav	be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1;
754287499Smav	ctl_lun_capacity_changed(&be_lun->cbe_lun);
755232604Strasz
756232604Strasz	/* Tell the user the exact size we ended up using */
757232604Strasz	params->lun_size_bytes = be_lun->size_bytes;
758232604Strasz
759232604Strasz	req->status = CTL_LUN_OK;
760232604Strasz
761232604Strasz	return (0);
762232604Strasz
763232604Straszbailout_error:
764232604Strasz	req->status = CTL_LUN_ERROR;
765232604Strasz
766232604Strasz	return (0);
767232604Strasz}
768232604Strasz
769229997Skenstatic void
770229997Skenctl_backend_ramdisk_lun_shutdown(void *be_lun)
771229997Sken{
772229997Sken	struct ctl_be_ramdisk_lun *lun;
773229997Sken	struct ctl_be_ramdisk_softc *softc;
774229997Sken	int do_free;
775229997Sken
776229997Sken	lun = (struct ctl_be_ramdisk_lun *)be_lun;
777229997Sken	softc = lun->softc;
778229997Sken	do_free = 0;
779229997Sken
780229997Sken	mtx_lock(&softc->lock);
781229997Sken
782229997Sken	lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED;
783229997Sken
784229997Sken	if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) {
785229997Sken		wakeup(lun);
786229997Sken	} else {
787269058Smav		STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun,
788229997Sken			      links);
789229997Sken		softc->num_luns--;
790229997Sken		do_free = 1;
791229997Sken	}
792229997Sken
793229997Sken	mtx_unlock(&softc->lock);
794229997Sken
795229997Sken	if (do_free != 0)
796229997Sken		free(be_lun, M_RAMDISK);
797229997Sken}
798229997Sken
799229997Skenstatic void
800229997Skenctl_backend_ramdisk_lun_config_status(void *be_lun,
801229997Sken				      ctl_lun_config_status status)
802229997Sken{
803229997Sken	struct ctl_be_ramdisk_lun *lun;
804229997Sken	struct ctl_be_ramdisk_softc *softc;
805229997Sken
806229997Sken	lun = (struct ctl_be_ramdisk_lun *)be_lun;
807229997Sken	softc = lun->softc;
808229997Sken
809229997Sken	if (status == CTL_LUN_CONFIG_OK) {
810229997Sken		mtx_lock(&softc->lock);
811229997Sken		lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED;
812229997Sken		if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING)
813229997Sken			wakeup(lun);
814229997Sken		mtx_unlock(&softc->lock);
815229997Sken
816229997Sken		/*
817229997Sken		 * We successfully added the LUN, attempt to enable it.
818229997Sken		 */
819287499Smav		if (ctl_enable_lun(&lun->cbe_lun) != 0) {
820229997Sken			printf("%s: ctl_enable_lun() failed!\n", __func__);
821287499Smav			if (ctl_invalidate_lun(&lun->cbe_lun) != 0) {
822229997Sken				printf("%s: ctl_invalidate_lun() failed!\n",
823229997Sken				       __func__);
824229997Sken			}
825229997Sken		}
826229997Sken
827229997Sken		return;
828229997Sken	}
829229997Sken
830229997Sken
831229997Sken	mtx_lock(&softc->lock);
832229997Sken	lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED;
833229997Sken
834229997Sken	/*
835229997Sken	 * If we have a user waiting, let him handle the cleanup.  If not,
836229997Sken	 * clean things up here.
837229997Sken	 */
838229997Sken	if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) {
839229997Sken		lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR;
840229997Sken		wakeup(lun);
841229997Sken	} else {
842229997Sken		STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun,
843229997Sken			      links);
844229997Sken		softc->num_luns--;
845229997Sken		free(lun, M_RAMDISK);
846229997Sken	}
847229997Sken	mtx_unlock(&softc->lock);
848229997Sken}
849229997Sken
850229997Skenstatic int
851229997Skenctl_backend_ramdisk_config_write(union ctl_io *io)
852229997Sken{
853229997Sken	struct ctl_be_ramdisk_softc *softc;
854229997Sken	int retval;
855229997Sken
856229997Sken	retval = 0;
857229997Sken	softc = &rd_softc;
858229997Sken
859229997Sken	switch (io->scsiio.cdb[0]) {
860229997Sken	case SYNCHRONIZE_CACHE:
861229997Sken	case SYNCHRONIZE_CACHE_16:
862229997Sken		/*
863229997Sken		 * The upper level CTL code will filter out any CDBs with
864229997Sken		 * the immediate bit set and return the proper error.  It
865229997Sken		 * will also not allow a sync cache command to go to a LUN
866229997Sken		 * that is powered down.
867229997Sken		 *
868229997Sken		 * We don't really need to worry about what LBA range the
869229997Sken		 * user asked to be synced out.  When they issue a sync
870229997Sken		 * cache command, we'll sync out the whole thing.
871229997Sken		 *
872229997Sken		 * This is obviously just a stubbed out implementation.
873229997Sken		 * The real implementation will be in the RAIDCore/CTL
874229997Sken		 * interface, and can only really happen when RAIDCore
875229997Sken		 * implements a per-array cache sync.
876229997Sken		 */
877229997Sken		ctl_set_success(&io->scsiio);
878229997Sken		ctl_config_write_done(io);
879229997Sken		break;
880229997Sken	case START_STOP_UNIT: {
881229997Sken		struct scsi_start_stop_unit *cdb;
882287499Smav		struct ctl_be_lun *cbe_lun;
883229997Sken		struct ctl_be_ramdisk_lun *be_lun;
884229997Sken
885229997Sken		cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb;
886229997Sken
887287499Smav		cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[
888229997Sken			CTL_PRIV_BACKEND_LUN].ptr;
889287499Smav		be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun->be_lun;
890229997Sken
891229997Sken		if (cdb->how & SSS_START)
892287499Smav			retval = ctl_start_lun(cbe_lun);
893229997Sken		else {
894287499Smav			retval = ctl_stop_lun(cbe_lun);
895229997Sken#ifdef NEEDTOPORT
896229997Sken			if ((retval == 0)
897229997Sken			 && (cdb->byte2 & SSS_ONOFFLINE))
898287499Smav				retval = ctl_lun_offline(cbe_lun);
899229997Sken#endif
900229997Sken		}
901229997Sken
902229997Sken		/*
903229997Sken		 * In general, the above routines should not fail.  They
904229997Sken		 * just set state for the LUN.  So we've got something
905229997Sken		 * pretty wrong here if we can't start or stop the LUN.
906229997Sken		 */
907229997Sken		if (retval != 0) {
908229997Sken			ctl_set_internal_failure(&io->scsiio,
909229997Sken						 /*sks_valid*/ 1,
910229997Sken						 /*retry_count*/ 0xf051);
911229997Sken			retval = CTL_RETVAL_COMPLETE;
912229997Sken		} else {
913229997Sken			ctl_set_success(&io->scsiio);
914229997Sken		}
915229997Sken		ctl_config_write_done(io);
916229997Sken		break;
917229997Sken	}
918264274Smav	case WRITE_SAME_10:
919264274Smav	case WRITE_SAME_16:
920264274Smav	case UNMAP:
921264274Smav		ctl_set_success(&io->scsiio);
922264274Smav		ctl_config_write_done(io);
923264274Smav		break;
924229997Sken	default:
925229997Sken		ctl_set_invalid_opcode(&io->scsiio);
926229997Sken		ctl_config_write_done(io);
927229997Sken		retval = CTL_RETVAL_COMPLETE;
928229997Sken		break;
929229997Sken	}
930229997Sken
931229997Sken	return (retval);
932229997Sken}
933229997Sken
934229997Skenstatic int
935229997Skenctl_backend_ramdisk_config_read(union ctl_io *io)
936229997Sken{
937275474Smav	int retval = 0;
938275474Smav
939275474Smav	switch (io->scsiio.cdb[0]) {
940275474Smav	case SERVICE_ACTION_IN:
941275474Smav		if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) {
942275474Smav			/* We have nothing to tell, leave default data. */
943275474Smav			ctl_config_read_done(io);
944275474Smav			retval = CTL_RETVAL_COMPLETE;
945275474Smav			break;
946275474Smav		}
947275474Smav		ctl_set_invalid_field(&io->scsiio,
948275474Smav				      /*sks_valid*/ 1,
949275474Smav				      /*command*/ 1,
950275474Smav				      /*field*/ 1,
951275474Smav				      /*bit_valid*/ 1,
952275474Smav				      /*bit*/ 4);
953275474Smav		ctl_config_read_done(io);
954275474Smav		retval = CTL_RETVAL_COMPLETE;
955275474Smav		break;
956275474Smav	default:
957275474Smav		ctl_set_invalid_opcode(&io->scsiio);
958275474Smav		ctl_config_read_done(io);
959275474Smav		retval = CTL_RETVAL_COMPLETE;
960275474Smav		break;
961275474Smav	}
962275474Smav
963275474Smav	return (retval);
964229997Sken}
965