1130f4520SKenneth D. Merry /*- 2130f4520SKenneth D. Merry * Copyright (c) 2003, 2008 Silicon Graphics International Corp. 381177295SEdward Tomasz Napierala * Copyright (c) 2012 The FreeBSD Foundation 4130f4520SKenneth D. Merry * All rights reserved. 5130f4520SKenneth D. Merry * 681177295SEdward Tomasz Napierala * Portions of this software were developed by Edward Tomasz Napierala 781177295SEdward Tomasz Napierala * under sponsorship from the FreeBSD Foundation. 881177295SEdward Tomasz Napierala * 9130f4520SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 10130f4520SKenneth D. Merry * modification, are permitted provided that the following conditions 11130f4520SKenneth D. Merry * are met: 12130f4520SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 13130f4520SKenneth D. Merry * notice, this list of conditions, and the following disclaimer, 14130f4520SKenneth D. Merry * without modification. 15130f4520SKenneth D. Merry * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16130f4520SKenneth D. Merry * substantially similar to the "NO WARRANTY" disclaimer below 17130f4520SKenneth D. Merry * ("Disclaimer") and any redistribution must be conditioned upon 18130f4520SKenneth D. Merry * including a substantially similar Disclaimer requirement for further 19130f4520SKenneth D. Merry * binary redistribution. 20130f4520SKenneth D. Merry * 21130f4520SKenneth D. Merry * NO WARRANTY 22130f4520SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23130f4520SKenneth D. Merry * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24130f4520SKenneth D. Merry * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 25130f4520SKenneth D. Merry * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26130f4520SKenneth D. Merry * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27130f4520SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28130f4520SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29130f4520SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30130f4520SKenneth D. Merry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 31130f4520SKenneth D. Merry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32130f4520SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGES. 33130f4520SKenneth D. Merry * 34130f4520SKenneth D. Merry * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $ 35130f4520SKenneth D. Merry */ 36130f4520SKenneth D. Merry /* 37130f4520SKenneth D. Merry * CAM Target Layer backend for a "fake" ramdisk. 38130f4520SKenneth D. Merry * 39130f4520SKenneth D. Merry * Author: Ken Merry <ken@FreeBSD.org> 40130f4520SKenneth D. Merry */ 41130f4520SKenneth D. Merry 42130f4520SKenneth D. Merry #include <sys/cdefs.h> 43130f4520SKenneth D. Merry __FBSDID("$FreeBSD$"); 44130f4520SKenneth D. Merry 45130f4520SKenneth D. Merry #include <sys/param.h> 46130f4520SKenneth D. Merry #include <sys/systm.h> 47130f4520SKenneth D. Merry #include <sys/kernel.h> 48130f4520SKenneth D. Merry #include <sys/condvar.h> 49130f4520SKenneth D. Merry #include <sys/types.h> 50130f4520SKenneth D. Merry #include <sys/lock.h> 51130f4520SKenneth D. Merry #include <sys/mutex.h> 52130f4520SKenneth D. Merry #include <sys/malloc.h> 5308a7cce5SAlexander Motin #include <sys/taskqueue.h> 54130f4520SKenneth D. Merry #include <sys/time.h> 55130f4520SKenneth D. Merry #include <sys/queue.h> 56130f4520SKenneth D. Merry #include <sys/conf.h> 57130f4520SKenneth D. Merry #include <sys/ioccom.h> 58130f4520SKenneth D. Merry #include <sys/module.h> 59130f4520SKenneth D. Merry 60130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 61130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 62130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 63130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h> 64130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h> 65130f4520SKenneth D. Merry #include <cam/ctl/ctl_frontend_internal.h> 66130f4520SKenneth D. Merry #include <cam/ctl/ctl_debug.h> 67130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h> 68130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h> 69130f4520SKenneth D. Merry 70130f4520SKenneth D. Merry typedef enum { 71130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_UNCONFIGURED = 0x01, 72130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_CONFIG_ERR = 0x02, 73130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_WAITING = 0x04 74130f4520SKenneth D. Merry } ctl_be_ramdisk_lun_flags; 75130f4520SKenneth D. Merry 76130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun { 7708a7cce5SAlexander Motin char lunname[32]; 78130f4520SKenneth D. Merry uint64_t size_bytes; 79130f4520SKenneth D. Merry uint64_t size_blocks; 80130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 81130f4520SKenneth D. Merry ctl_be_ramdisk_lun_flags flags; 82130f4520SKenneth D. Merry STAILQ_ENTRY(ctl_be_ramdisk_lun) links; 83130f4520SKenneth D. Merry struct ctl_be_lun ctl_be_lun; 8408a7cce5SAlexander Motin struct taskqueue *io_taskqueue; 8508a7cce5SAlexander Motin struct task io_task; 8608a7cce5SAlexander Motin STAILQ_HEAD(, ctl_io_hdr) cont_queue; 8775c7a1d3SAlexander Motin struct mtx_padalign queue_lock; 88130f4520SKenneth D. Merry }; 89130f4520SKenneth D. Merry 90130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc { 91130f4520SKenneth D. Merry struct mtx lock; 92130f4520SKenneth D. Merry int rd_size; 93130f4520SKenneth D. Merry #ifdef CTL_RAMDISK_PAGES 94130f4520SKenneth D. Merry uint8_t **ramdisk_pages; 95130f4520SKenneth D. Merry int num_pages; 96130f4520SKenneth D. Merry #else 97130f4520SKenneth D. Merry uint8_t *ramdisk_buffer; 98130f4520SKenneth D. Merry #endif 99130f4520SKenneth D. Merry int num_luns; 100130f4520SKenneth D. Merry STAILQ_HEAD(, ctl_be_ramdisk_lun) lun_list; 101130f4520SKenneth D. Merry }; 102130f4520SKenneth D. Merry 103130f4520SKenneth D. Merry static struct ctl_be_ramdisk_softc rd_softc; 104130f4520SKenneth D. Merry 105130f4520SKenneth D. Merry int ctl_backend_ramdisk_init(void); 106130f4520SKenneth D. Merry void ctl_backend_ramdisk_shutdown(void); 107130f4520SKenneth D. Merry static int ctl_backend_ramdisk_move_done(union ctl_io *io); 108130f4520SKenneth D. Merry static int ctl_backend_ramdisk_submit(union ctl_io *io); 10908a7cce5SAlexander Motin static void ctl_backend_ramdisk_continue(union ctl_io *io); 110130f4520SKenneth D. Merry static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, 111130f4520SKenneth D. Merry caddr_t addr, int flag, struct thread *td); 112130f4520SKenneth D. Merry static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 113130f4520SKenneth D. Merry struct ctl_lun_req *req); 114130f4520SKenneth D. Merry static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 115130f4520SKenneth D. Merry struct ctl_lun_req *req, int do_wait); 11681177295SEdward Tomasz Napierala static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 11781177295SEdward Tomasz Napierala struct ctl_lun_req *req); 11808a7cce5SAlexander Motin static void ctl_backend_ramdisk_worker(void *context, int pending); 119130f4520SKenneth D. Merry static void ctl_backend_ramdisk_lun_shutdown(void *be_lun); 120130f4520SKenneth D. Merry static void ctl_backend_ramdisk_lun_config_status(void *be_lun, 121130f4520SKenneth D. Merry ctl_lun_config_status status); 122130f4520SKenneth D. Merry static int ctl_backend_ramdisk_config_write(union ctl_io *io); 123130f4520SKenneth D. Merry static int ctl_backend_ramdisk_config_read(union ctl_io *io); 124130f4520SKenneth D. Merry 125130f4520SKenneth D. Merry static struct ctl_backend_driver ctl_be_ramdisk_driver = 126130f4520SKenneth D. Merry { 1272a2443d8SKenneth D. Merry .name = "ramdisk", 1282a2443d8SKenneth D. Merry .flags = CTL_BE_FLAG_HAS_CONFIG, 1292a2443d8SKenneth D. Merry .init = ctl_backend_ramdisk_init, 1302a2443d8SKenneth D. Merry .data_submit = ctl_backend_ramdisk_submit, 1312a2443d8SKenneth D. Merry .data_move_done = ctl_backend_ramdisk_move_done, 1322a2443d8SKenneth D. Merry .config_read = ctl_backend_ramdisk_config_read, 1332a2443d8SKenneth D. Merry .config_write = ctl_backend_ramdisk_config_write, 1342a2443d8SKenneth D. Merry .ioctl = ctl_backend_ramdisk_ioctl 135130f4520SKenneth D. Merry }; 136130f4520SKenneth D. Merry 137130f4520SKenneth D. Merry MALLOC_DEFINE(M_RAMDISK, "ramdisk", "Memory used for CTL RAMdisk"); 138130f4520SKenneth D. Merry CTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver); 139130f4520SKenneth D. Merry 140130f4520SKenneth D. Merry int 141130f4520SKenneth D. Merry ctl_backend_ramdisk_init(void) 142130f4520SKenneth D. Merry { 143130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 144130f4520SKenneth D. Merry #ifdef CTL_RAMDISK_PAGES 145a0a6ff82SEdward Tomasz Napierala int i; 146130f4520SKenneth D. Merry #endif 147130f4520SKenneth D. Merry 148130f4520SKenneth D. Merry 149130f4520SKenneth D. Merry softc = &rd_softc; 150130f4520SKenneth D. Merry 151130f4520SKenneth D. Merry memset(softc, 0, sizeof(*softc)); 152130f4520SKenneth D. Merry 15375c7a1d3SAlexander Motin mtx_init(&softc->lock, "ctlramdisk", NULL, MTX_DEF); 154130f4520SKenneth D. Merry 155130f4520SKenneth D. Merry STAILQ_INIT(&softc->lun_list); 15608a7cce5SAlexander Motin softc->rd_size = 1024 * 1024; 157130f4520SKenneth D. Merry #ifdef CTL_RAMDISK_PAGES 158130f4520SKenneth D. Merry softc->num_pages = softc->rd_size / PAGE_SIZE; 159130f4520SKenneth D. Merry softc->ramdisk_pages = (uint8_t **)malloc(sizeof(uint8_t *) * 160130f4520SKenneth D. Merry softc->num_pages, M_RAMDISK, 161130f4520SKenneth D. Merry M_WAITOK); 162a0a6ff82SEdward Tomasz Napierala for (i = 0; i < softc->num_pages; i++) 163130f4520SKenneth D. Merry softc->ramdisk_pages[i] = malloc(PAGE_SIZE, M_RAMDISK,M_WAITOK); 164130f4520SKenneth D. Merry #else 165130f4520SKenneth D. Merry softc->ramdisk_buffer = (uint8_t *)malloc(softc->rd_size, M_RAMDISK, 166130f4520SKenneth D. Merry M_WAITOK); 167130f4520SKenneth D. Merry #endif 168130f4520SKenneth D. Merry 169130f4520SKenneth D. Merry return (0); 170130f4520SKenneth D. Merry } 171130f4520SKenneth D. Merry 172130f4520SKenneth D. Merry void 173130f4520SKenneth D. Merry ctl_backend_ramdisk_shutdown(void) 174130f4520SKenneth D. Merry { 175130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 176130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun, *next_lun; 177130f4520SKenneth D. Merry #ifdef CTL_RAMDISK_PAGES 178130f4520SKenneth D. Merry int i; 179130f4520SKenneth D. Merry #endif 180130f4520SKenneth D. Merry 181130f4520SKenneth D. Merry softc = &rd_softc; 182130f4520SKenneth D. Merry 183130f4520SKenneth D. Merry mtx_lock(&softc->lock); 184130f4520SKenneth D. Merry for (lun = STAILQ_FIRST(&softc->lun_list); lun != NULL; lun = next_lun){ 185130f4520SKenneth D. Merry /* 186130f4520SKenneth D. Merry * Grab the next LUN. The current LUN may get removed by 187130f4520SKenneth D. Merry * ctl_invalidate_lun(), which will call our LUN shutdown 188130f4520SKenneth D. Merry * routine, if there is no outstanding I/O for this LUN. 189130f4520SKenneth D. Merry */ 190130f4520SKenneth D. Merry next_lun = STAILQ_NEXT(lun, links); 191130f4520SKenneth D. Merry 192130f4520SKenneth D. Merry /* 193130f4520SKenneth D. Merry * Drop our lock here. Since ctl_invalidate_lun() can call 194130f4520SKenneth D. Merry * back into us, this could potentially lead to a recursive 195130f4520SKenneth D. Merry * lock of the same mutex, which would cause a hang. 196130f4520SKenneth D. Merry */ 197130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 198130f4520SKenneth D. Merry ctl_disable_lun(&lun->ctl_be_lun); 199130f4520SKenneth D. Merry ctl_invalidate_lun(&lun->ctl_be_lun); 200130f4520SKenneth D. Merry mtx_lock(&softc->lock); 201130f4520SKenneth D. Merry } 202130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 203130f4520SKenneth D. Merry 204130f4520SKenneth D. Merry #ifdef CTL_RAMDISK_PAGES 205130f4520SKenneth D. Merry for (i = 0; i < softc->num_pages; i++) 206130f4520SKenneth D. Merry free(softc->ramdisk_pages[i], M_RAMDISK); 207130f4520SKenneth D. Merry 208130f4520SKenneth D. Merry free(softc->ramdisk_pages, M_RAMDISK); 209130f4520SKenneth D. Merry #else 210130f4520SKenneth D. Merry free(softc->ramdisk_buffer, M_RAMDISK); 211130f4520SKenneth D. Merry #endif 212130f4520SKenneth D. Merry 213130f4520SKenneth D. Merry if (ctl_backend_deregister(&ctl_be_ramdisk_driver) != 0) { 214130f4520SKenneth D. Merry printf("ctl_backend_ramdisk_shutdown: " 215130f4520SKenneth D. Merry "ctl_backend_deregister() failed!\n"); 216130f4520SKenneth D. Merry } 217130f4520SKenneth D. Merry } 218130f4520SKenneth D. Merry 219130f4520SKenneth D. Merry static int 220130f4520SKenneth D. Merry ctl_backend_ramdisk_move_done(union ctl_io *io) 221130f4520SKenneth D. Merry { 22208a7cce5SAlexander Motin struct ctl_be_lun *ctl_be_lun; 22308a7cce5SAlexander Motin struct ctl_be_ramdisk_lun *be_lun; 224130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 225130f4520SKenneth D. Merry struct bintime cur_bt; 226130f4520SKenneth D. Merry #endif 227130f4520SKenneth D. Merry 228130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); 22908a7cce5SAlexander Motin ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 23008a7cce5SAlexander Motin CTL_PRIV_BACKEND_LUN].ptr; 23108a7cce5SAlexander Motin be_lun = (struct ctl_be_ramdisk_lun *)ctl_be_lun->be_lun; 23208a7cce5SAlexander Motin #ifdef CTL_TIME_IO 23308a7cce5SAlexander Motin getbintime(&cur_bt); 23408a7cce5SAlexander Motin bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 23508a7cce5SAlexander Motin bintime_add(&io->io_hdr.dma_bt, &cur_bt); 23608a7cce5SAlexander Motin io->io_hdr.num_dmas++; 23708a7cce5SAlexander Motin #endif 23808a7cce5SAlexander Motin if (io->scsiio.kern_sg_entries > 0) 23908a7cce5SAlexander Motin free(io->scsiio.kern_data_ptr, M_RAMDISK); 24008a7cce5SAlexander Motin io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 241130f4520SKenneth D. Merry if ((io->io_hdr.port_status == 0) 242130f4520SKenneth D. Merry && ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0) 24308a7cce5SAlexander Motin && ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 244e86a4142SAlexander Motin if (io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer > 0) { 24575c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 24608a7cce5SAlexander Motin STAILQ_INSERT_TAIL(&be_lun->cont_queue, 24708a7cce5SAlexander Motin &io->io_hdr, links); 24875c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 24908a7cce5SAlexander Motin taskqueue_enqueue(be_lun->io_taskqueue, 25008a7cce5SAlexander Motin &be_lun->io_task); 25108a7cce5SAlexander Motin return (0); 25208a7cce5SAlexander Motin } 253130f4520SKenneth D. Merry io->io_hdr.status = CTL_SUCCESS; 25408a7cce5SAlexander Motin } else if ((io->io_hdr.port_status != 0) 255130f4520SKenneth D. Merry && ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0) 256130f4520SKenneth D. Merry && ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)){ 257130f4520SKenneth D. Merry /* 258130f4520SKenneth D. Merry * For hardware error sense keys, the sense key 259130f4520SKenneth D. Merry * specific value is defined to be a retry count, 260130f4520SKenneth D. Merry * but we use it to pass back an internal FETD 261130f4520SKenneth D. Merry * error code. XXX KDM Hopefully the FETD is only 262130f4520SKenneth D. Merry * using 16 bits for an error code, since that's 263130f4520SKenneth D. Merry * all the space we have in the sks field. 264130f4520SKenneth D. Merry */ 265130f4520SKenneth D. Merry ctl_set_internal_failure(&io->scsiio, 266130f4520SKenneth D. Merry /*sks_valid*/ 1, 267130f4520SKenneth D. Merry /*retry_count*/ 268130f4520SKenneth D. Merry io->io_hdr.port_status); 269130f4520SKenneth D. Merry } 27011b569f7SAlexander Motin ctl_data_submit_done(io); 271130f4520SKenneth D. Merry return(0); 272130f4520SKenneth D. Merry } 273130f4520SKenneth D. Merry 274130f4520SKenneth D. Merry static int 275130f4520SKenneth D. Merry ctl_backend_ramdisk_submit(union ctl_io *io) 276130f4520SKenneth D. Merry { 277e86a4142SAlexander Motin struct ctl_be_lun *ctl_be_lun; 27811b569f7SAlexander Motin struct ctl_lba_len_flags *lbalen; 279130f4520SKenneth D. Merry 280e86a4142SAlexander Motin ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 281e86a4142SAlexander Motin CTL_PRIV_BACKEND_LUN].ptr; 28211b569f7SAlexander Motin lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 28311b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_VERIFY) { 28411b569f7SAlexander Motin ctl_set_success(&io->scsiio); 28511b569f7SAlexander Motin ctl_data_submit_done(io); 28611b569f7SAlexander Motin return (CTL_RETVAL_COMPLETE); 28711b569f7SAlexander Motin } 288e86a4142SAlexander Motin io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer = 289e86a4142SAlexander Motin lbalen->len * ctl_be_lun->blocksize; 29008a7cce5SAlexander Motin ctl_backend_ramdisk_continue(io); 291130f4520SKenneth D. Merry return (CTL_RETVAL_COMPLETE); 292130f4520SKenneth D. Merry } 293130f4520SKenneth D. Merry 29408a7cce5SAlexander Motin static void 29508a7cce5SAlexander Motin ctl_backend_ramdisk_continue(union ctl_io *io) 29608a7cce5SAlexander Motin { 29708a7cce5SAlexander Motin struct ctl_be_ramdisk_softc *softc; 29808a7cce5SAlexander Motin int len, len_filled, sg_filled; 299130f4520SKenneth D. Merry #ifdef CTL_RAMDISK_PAGES 30008a7cce5SAlexander Motin struct ctl_sg_entry *sg_entries; 30108a7cce5SAlexander Motin int i; 30208a7cce5SAlexander Motin #endif 303130f4520SKenneth D. Merry 30408a7cce5SAlexander Motin softc = &rd_softc; 305e86a4142SAlexander Motin len = io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer; 30608a7cce5SAlexander Motin #ifdef CTL_RAMDISK_PAGES 30708a7cce5SAlexander Motin sg_filled = min(btoc(len), softc->num_pages); 30808a7cce5SAlexander Motin if (sg_filled > 1) { 309130f4520SKenneth D. Merry io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) * 31008a7cce5SAlexander Motin sg_filled, M_RAMDISK, 311130f4520SKenneth D. Merry M_WAITOK); 312130f4520SKenneth D. Merry sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 31308a7cce5SAlexander Motin for (i = 0, len_filled = 0; i < sg_filled; i++) { 314130f4520SKenneth D. Merry sg_entries[i].addr = softc->ramdisk_pages[i]; 315130f4520SKenneth D. Merry sg_entries[i].len = ctl_min(PAGE_SIZE, 316130f4520SKenneth D. Merry len - len_filled); 31708a7cce5SAlexander Motin len_filled += sg_entries[i].len; 318130f4520SKenneth D. Merry } 31908a7cce5SAlexander Motin io->io_hdr.flags |= CTL_FLAG_KDPTR_SGLIST; 320130f4520SKenneth D. Merry } else { 32108a7cce5SAlexander Motin sg_filled = 0; 32208a7cce5SAlexander Motin len_filled = len; 323130f4520SKenneth D. Merry io->scsiio.kern_data_ptr = softc->ramdisk_pages[0]; 324130f4520SKenneth D. Merry } 32508a7cce5SAlexander Motin #else 32608a7cce5SAlexander Motin sg_filled = 0; 32708a7cce5SAlexander Motin len_filled = min(len, softc->rd_size); 32808a7cce5SAlexander Motin io->scsiio.kern_data_ptr = softc->ramdisk_buffer; 32908a7cce5SAlexander Motin #endif /* CTL_RAMDISK_PAGES */ 330130f4520SKenneth D. Merry 3319c71cd5aSAlexander Motin io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 3329c71cd5aSAlexander Motin io->scsiio.kern_data_resid = 0; 33308a7cce5SAlexander Motin io->scsiio.kern_data_len = len_filled; 33408a7cce5SAlexander Motin io->scsiio.kern_sg_entries = sg_filled; 33508a7cce5SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 336e86a4142SAlexander Motin io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer -= len_filled; 337130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 338130f4520SKenneth D. Merry getbintime(&io->io_hdr.dma_start_bt); 339130f4520SKenneth D. Merry #endif 340130f4520SKenneth D. Merry ctl_datamove(io); 34108a7cce5SAlexander Motin } 342130f4520SKenneth D. Merry 34308a7cce5SAlexander Motin static void 34408a7cce5SAlexander Motin ctl_backend_ramdisk_worker(void *context, int pending) 34508a7cce5SAlexander Motin { 34608a7cce5SAlexander Motin struct ctl_be_ramdisk_softc *softc; 34708a7cce5SAlexander Motin struct ctl_be_ramdisk_lun *be_lun; 34808a7cce5SAlexander Motin union ctl_io *io; 34908a7cce5SAlexander Motin 35008a7cce5SAlexander Motin be_lun = (struct ctl_be_ramdisk_lun *)context; 35108a7cce5SAlexander Motin softc = be_lun->softc; 35208a7cce5SAlexander Motin 35375c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 35408a7cce5SAlexander Motin for (;;) { 35508a7cce5SAlexander Motin io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); 35608a7cce5SAlexander Motin if (io != NULL) { 35708a7cce5SAlexander Motin STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr, 35808a7cce5SAlexander Motin ctl_io_hdr, links); 35908a7cce5SAlexander Motin 36075c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 36108a7cce5SAlexander Motin 36208a7cce5SAlexander Motin ctl_backend_ramdisk_continue(io); 36308a7cce5SAlexander Motin 36475c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 36508a7cce5SAlexander Motin continue; 36608a7cce5SAlexander Motin } 36708a7cce5SAlexander Motin 36808a7cce5SAlexander Motin /* 36908a7cce5SAlexander Motin * If we get here, there is no work left in the queues, so 37008a7cce5SAlexander Motin * just break out and let the task queue go to sleep. 37108a7cce5SAlexander Motin */ 37208a7cce5SAlexander Motin break; 37308a7cce5SAlexander Motin } 37475c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 375130f4520SKenneth D. Merry } 376130f4520SKenneth D. Merry 377130f4520SKenneth D. Merry static int 378130f4520SKenneth D. Merry ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 379130f4520SKenneth D. Merry int flag, struct thread *td) 380130f4520SKenneth D. Merry { 381130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 382130f4520SKenneth D. Merry int retval; 383130f4520SKenneth D. Merry 384130f4520SKenneth D. Merry retval = 0; 385130f4520SKenneth D. Merry softc = &rd_softc; 386130f4520SKenneth D. Merry 387130f4520SKenneth D. Merry switch (cmd) { 388130f4520SKenneth D. Merry case CTL_LUN_REQ: { 389130f4520SKenneth D. Merry struct ctl_lun_req *lun_req; 390130f4520SKenneth D. Merry 391130f4520SKenneth D. Merry lun_req = (struct ctl_lun_req *)addr; 392130f4520SKenneth D. Merry 393130f4520SKenneth D. Merry switch (lun_req->reqtype) { 394130f4520SKenneth D. Merry case CTL_LUNREQ_CREATE: 395130f4520SKenneth D. Merry retval = ctl_backend_ramdisk_create(softc, lun_req, 396130f4520SKenneth D. Merry /*do_wait*/ 1); 397130f4520SKenneth D. Merry break; 398130f4520SKenneth D. Merry case CTL_LUNREQ_RM: 399130f4520SKenneth D. Merry retval = ctl_backend_ramdisk_rm(softc, lun_req); 400130f4520SKenneth D. Merry break; 40181177295SEdward Tomasz Napierala case CTL_LUNREQ_MODIFY: 40281177295SEdward Tomasz Napierala retval = ctl_backend_ramdisk_modify(softc, lun_req); 40381177295SEdward Tomasz Napierala break; 404130f4520SKenneth D. Merry default: 405130f4520SKenneth D. Merry lun_req->status = CTL_LUN_ERROR; 406130f4520SKenneth D. Merry snprintf(lun_req->error_str, sizeof(lun_req->error_str), 407130f4520SKenneth D. Merry "%s: invalid LUN request type %d", __func__, 408130f4520SKenneth D. Merry lun_req->reqtype); 409130f4520SKenneth D. Merry break; 410130f4520SKenneth D. Merry } 411130f4520SKenneth D. Merry break; 412130f4520SKenneth D. Merry } 413130f4520SKenneth D. Merry default: 414130f4520SKenneth D. Merry retval = ENOTTY; 415130f4520SKenneth D. Merry break; 416130f4520SKenneth D. Merry } 417130f4520SKenneth D. Merry 418130f4520SKenneth D. Merry return (retval); 419130f4520SKenneth D. Merry } 420130f4520SKenneth D. Merry 421130f4520SKenneth D. Merry static int 422130f4520SKenneth D. Merry ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 423130f4520SKenneth D. Merry struct ctl_lun_req *req) 424130f4520SKenneth D. Merry { 425130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 426130f4520SKenneth D. Merry struct ctl_lun_rm_params *params; 427130f4520SKenneth D. Merry int retval; 428130f4520SKenneth D. Merry 429130f4520SKenneth D. Merry 430130f4520SKenneth D. Merry retval = 0; 431130f4520SKenneth D. Merry params = &req->reqdata.rm; 432130f4520SKenneth D. Merry 433130f4520SKenneth D. Merry be_lun = NULL; 434130f4520SKenneth D. Merry 435130f4520SKenneth D. Merry mtx_lock(&softc->lock); 436130f4520SKenneth D. Merry 437130f4520SKenneth D. Merry STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 438130f4520SKenneth D. Merry if (be_lun->ctl_be_lun.lun_id == params->lun_id) 439130f4520SKenneth D. Merry break; 440130f4520SKenneth D. Merry } 441130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 442130f4520SKenneth D. Merry 443130f4520SKenneth D. Merry if (be_lun == NULL) { 444130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 445130f4520SKenneth D. Merry "%s: LUN %u is not managed by the ramdisk backend", 446130f4520SKenneth D. Merry __func__, params->lun_id); 447130f4520SKenneth D. Merry goto bailout_error; 448130f4520SKenneth D. Merry } 449130f4520SKenneth D. Merry 450130f4520SKenneth D. Merry retval = ctl_disable_lun(&be_lun->ctl_be_lun); 451130f4520SKenneth D. Merry 452130f4520SKenneth D. Merry if (retval != 0) { 453130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 454130f4520SKenneth D. Merry "%s: error %d returned from ctl_disable_lun() for " 455130f4520SKenneth D. Merry "LUN %d", __func__, retval, params->lun_id); 456130f4520SKenneth D. Merry goto bailout_error; 457130f4520SKenneth D. Merry } 458130f4520SKenneth D. Merry 459130f4520SKenneth D. Merry /* 460130f4520SKenneth D. Merry * Set the waiting flag before we invalidate the LUN. Our shutdown 461130f4520SKenneth D. Merry * routine can be called any time after we invalidate the LUN, 462130f4520SKenneth D. Merry * and can be called from our context. 463130f4520SKenneth D. Merry * 464130f4520SKenneth D. Merry * This tells the shutdown routine that we're waiting, or we're 465130f4520SKenneth D. Merry * going to wait for the shutdown to happen. 466130f4520SKenneth D. Merry */ 467130f4520SKenneth D. Merry mtx_lock(&softc->lock); 468130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 469130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 470130f4520SKenneth D. Merry 471130f4520SKenneth D. Merry retval = ctl_invalidate_lun(&be_lun->ctl_be_lun); 472130f4520SKenneth D. Merry if (retval != 0) { 473130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 474130f4520SKenneth D. Merry "%s: error %d returned from ctl_invalidate_lun() for " 475130f4520SKenneth D. Merry "LUN %d", __func__, retval, params->lun_id); 476ce300fbfSAlexander Motin mtx_lock(&softc->lock); 477ce300fbfSAlexander Motin be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 478ce300fbfSAlexander Motin mtx_unlock(&softc->lock); 479130f4520SKenneth D. Merry goto bailout_error; 480130f4520SKenneth D. Merry } 481130f4520SKenneth D. Merry 482130f4520SKenneth D. Merry mtx_lock(&softc->lock); 483130f4520SKenneth D. Merry 484130f4520SKenneth D. Merry while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) { 485130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 486130f4520SKenneth D. Merry if (retval == EINTR) 487130f4520SKenneth D. Merry break; 488130f4520SKenneth D. Merry } 489130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 490130f4520SKenneth D. Merry 491130f4520SKenneth D. Merry /* 492130f4520SKenneth D. Merry * We only remove this LUN from the list and free it (below) if 493130f4520SKenneth D. Merry * retval == 0. If the user interrupted the wait, we just bail out 494130f4520SKenneth D. Merry * without actually freeing the LUN. We let the shutdown routine 495130f4520SKenneth D. Merry * free the LUN if that happens. 496130f4520SKenneth D. Merry */ 497130f4520SKenneth D. Merry if (retval == 0) { 498130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 499130f4520SKenneth D. Merry links); 500130f4520SKenneth D. Merry softc->num_luns--; 501130f4520SKenneth D. Merry } 502130f4520SKenneth D. Merry 503130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 504130f4520SKenneth D. Merry 50508a7cce5SAlexander Motin if (retval == 0) { 50608a7cce5SAlexander Motin taskqueue_drain(be_lun->io_taskqueue, &be_lun->io_task); 50708a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 50843fb3a65SAlexander Motin ctl_free_opts(&be_lun->ctl_be_lun.options); 50975c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 510130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 51108a7cce5SAlexander Motin } 512130f4520SKenneth D. Merry 513130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 514130f4520SKenneth D. Merry 515130f4520SKenneth D. Merry return (retval); 516130f4520SKenneth D. Merry 517130f4520SKenneth D. Merry bailout_error: 518130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 519130f4520SKenneth D. Merry 520130f4520SKenneth D. Merry return (0); 521130f4520SKenneth D. Merry } 522130f4520SKenneth D. Merry 523130f4520SKenneth D. Merry static int 524130f4520SKenneth D. Merry ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 525130f4520SKenneth D. Merry struct ctl_lun_req *req, int do_wait) 526130f4520SKenneth D. Merry { 527130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 528130f4520SKenneth D. Merry struct ctl_lun_create_params *params; 529130f4520SKenneth D. Merry uint32_t blocksize; 53057a5db13SAlexander Motin char *value; 531130f4520SKenneth D. Merry char tmpstr[32]; 53257a5db13SAlexander Motin int retval, unmap; 533130f4520SKenneth D. Merry 534130f4520SKenneth D. Merry retval = 0; 535130f4520SKenneth D. Merry params = &req->reqdata.create; 536130f4520SKenneth D. Merry if (params->blocksize_bytes != 0) 537130f4520SKenneth D. Merry blocksize = params->blocksize_bytes; 538130f4520SKenneth D. Merry else 539130f4520SKenneth D. Merry blocksize = 512; 540130f4520SKenneth D. Merry 541130f4520SKenneth D. Merry be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | (do_wait ? 542130f4520SKenneth D. Merry M_WAITOK : M_NOWAIT)); 543130f4520SKenneth D. Merry 544130f4520SKenneth D. Merry if (be_lun == NULL) { 545130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 546130f4520SKenneth D. Merry "%s: error allocating %zd bytes", __func__, 547130f4520SKenneth D. Merry sizeof(*be_lun)); 548130f4520SKenneth D. Merry goto bailout_error; 549130f4520SKenneth D. Merry } 55008a7cce5SAlexander Motin sprintf(be_lun->lunname, "cram%d", softc->num_luns); 55143fb3a65SAlexander Motin ctl_init_opts(&be_lun->ctl_be_lun.options, 55243fb3a65SAlexander Motin req->num_be_args, req->kern_be_args); 553130f4520SKenneth D. Merry 554130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 555130f4520SKenneth D. Merry be_lun->ctl_be_lun.lun_type = params->device_type; 556130f4520SKenneth D. Merry else 557130f4520SKenneth D. Merry be_lun->ctl_be_lun.lun_type = T_DIRECT; 558130f4520SKenneth D. Merry 559130f4520SKenneth D. Merry if (be_lun->ctl_be_lun.lun_type == T_DIRECT) { 560130f4520SKenneth D. Merry 561130f4520SKenneth D. Merry if (params->lun_size_bytes < blocksize) { 562130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 563130f4520SKenneth D. Merry "%s: LUN size %ju < blocksize %u", __func__, 564130f4520SKenneth D. Merry params->lun_size_bytes, blocksize); 565130f4520SKenneth D. Merry goto bailout_error; 566130f4520SKenneth D. Merry } 567130f4520SKenneth D. Merry 568130f4520SKenneth D. Merry be_lun->size_blocks = params->lun_size_bytes / blocksize; 569130f4520SKenneth D. Merry be_lun->size_bytes = be_lun->size_blocks * blocksize; 570130f4520SKenneth D. Merry 571130f4520SKenneth D. Merry be_lun->ctl_be_lun.maxlba = be_lun->size_blocks - 1; 572130f4520SKenneth D. Merry } else { 573130f4520SKenneth D. Merry be_lun->ctl_be_lun.maxlba = 0; 574130f4520SKenneth D. Merry blocksize = 0; 575130f4520SKenneth D. Merry be_lun->size_bytes = 0; 576130f4520SKenneth D. Merry be_lun->size_blocks = 0; 577130f4520SKenneth D. Merry } 578130f4520SKenneth D. Merry 579130f4520SKenneth D. Merry be_lun->ctl_be_lun.blocksize = blocksize; 580130f4520SKenneth D. Merry 581130f4520SKenneth D. Merry /* Tell the user the blocksize we ended up using */ 582130f4520SKenneth D. Merry params->blocksize_bytes = blocksize; 583130f4520SKenneth D. Merry 584130f4520SKenneth D. Merry /* Tell the user the exact size we ended up using */ 585130f4520SKenneth D. Merry params->lun_size_bytes = be_lun->size_bytes; 586130f4520SKenneth D. Merry 587130f4520SKenneth D. Merry be_lun->softc = softc; 588130f4520SKenneth D. Merry 589f7ad1c46SAlexander Motin unmap = 0; 59043fb3a65SAlexander Motin value = ctl_get_opt(&be_lun->ctl_be_lun.options, "unmap"); 59157a5db13SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 592ee7f31c0SAlexander Motin unmap = 1; 59381a2151dSEdward Tomasz Napierala 594130f4520SKenneth D. Merry be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED; 595130f4520SKenneth D. Merry be_lun->ctl_be_lun.flags = CTL_LUN_FLAG_PRIMARY; 596ee7f31c0SAlexander Motin if (unmap) 597f7ad1c46SAlexander Motin be_lun->ctl_be_lun.flags |= CTL_LUN_FLAG_UNMAP; 598130f4520SKenneth D. Merry be_lun->ctl_be_lun.be_lun = be_lun; 599130f4520SKenneth D. Merry 600130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_ID_REQ) { 601130f4520SKenneth D. Merry be_lun->ctl_be_lun.req_lun_id = params->req_lun_id; 602130f4520SKenneth D. Merry be_lun->ctl_be_lun.flags |= CTL_LUN_FLAG_ID_REQ; 603130f4520SKenneth D. Merry } else 604130f4520SKenneth D. Merry be_lun->ctl_be_lun.req_lun_id = 0; 605130f4520SKenneth D. Merry 606130f4520SKenneth D. Merry be_lun->ctl_be_lun.lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 607130f4520SKenneth D. Merry be_lun->ctl_be_lun.lun_config_status = 608130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_config_status; 609130f4520SKenneth D. Merry be_lun->ctl_be_lun.be = &ctl_be_ramdisk_driver; 610130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 611130f4520SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 612130f4520SKenneth D. Merry softc->num_luns); 613130f4520SKenneth D. Merry strncpy((char *)be_lun->ctl_be_lun.serial_num, tmpstr, 614130f4520SKenneth D. Merry ctl_min(sizeof(be_lun->ctl_be_lun.serial_num), 615130f4520SKenneth D. Merry sizeof(tmpstr))); 616130f4520SKenneth D. Merry 617130f4520SKenneth D. Merry /* Tell the user what we used for a serial number */ 618130f4520SKenneth D. Merry strncpy((char *)params->serial_num, tmpstr, 619130f4520SKenneth D. Merry ctl_min(sizeof(params->serial_num), sizeof(tmpstr))); 620130f4520SKenneth D. Merry } else { 621130f4520SKenneth D. Merry strncpy((char *)be_lun->ctl_be_lun.serial_num, 622130f4520SKenneth D. Merry params->serial_num, 623130f4520SKenneth D. Merry ctl_min(sizeof(be_lun->ctl_be_lun.serial_num), 624130f4520SKenneth D. Merry sizeof(params->serial_num))); 625130f4520SKenneth D. Merry } 626130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 627130f4520SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 628130f4520SKenneth D. Merry strncpy((char *)be_lun->ctl_be_lun.device_id, tmpstr, 629130f4520SKenneth D. Merry ctl_min(sizeof(be_lun->ctl_be_lun.device_id), 630130f4520SKenneth D. Merry sizeof(tmpstr))); 631130f4520SKenneth D. Merry 632130f4520SKenneth D. Merry /* Tell the user what we used for a device ID */ 633130f4520SKenneth D. Merry strncpy((char *)params->device_id, tmpstr, 634130f4520SKenneth D. Merry ctl_min(sizeof(params->device_id), sizeof(tmpstr))); 635130f4520SKenneth D. Merry } else { 636130f4520SKenneth D. Merry strncpy((char *)be_lun->ctl_be_lun.device_id, 637130f4520SKenneth D. Merry params->device_id, 638130f4520SKenneth D. Merry ctl_min(sizeof(be_lun->ctl_be_lun.device_id), 639130f4520SKenneth D. Merry sizeof(params->device_id))); 640130f4520SKenneth D. Merry } 641130f4520SKenneth D. Merry 64208a7cce5SAlexander Motin STAILQ_INIT(&be_lun->cont_queue); 64375c7a1d3SAlexander Motin mtx_init(&be_lun->queue_lock, "cram queue lock", NULL, MTX_DEF); 64408a7cce5SAlexander Motin TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 64508a7cce5SAlexander Motin be_lun); 64608a7cce5SAlexander Motin 64708a7cce5SAlexander Motin be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 64808a7cce5SAlexander Motin taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 64908a7cce5SAlexander Motin if (be_lun->io_taskqueue == NULL) { 65008a7cce5SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 65108a7cce5SAlexander Motin "%s: Unable to create taskqueue", __func__); 65208a7cce5SAlexander Motin goto bailout_error; 65308a7cce5SAlexander Motin } 65408a7cce5SAlexander Motin 65508a7cce5SAlexander Motin retval = taskqueue_start_threads(&be_lun->io_taskqueue, 65608a7cce5SAlexander Motin /*num threads*/1, 65708a7cce5SAlexander Motin /*priority*/PWAIT, 65808a7cce5SAlexander Motin /*thread name*/ 65908a7cce5SAlexander Motin "%s taskq", be_lun->lunname); 66008a7cce5SAlexander Motin if (retval != 0) 66108a7cce5SAlexander Motin goto bailout_error; 66208a7cce5SAlexander Motin 663130f4520SKenneth D. Merry mtx_lock(&softc->lock); 664130f4520SKenneth D. Merry softc->num_luns++; 665130f4520SKenneth D. Merry STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 666130f4520SKenneth D. Merry 667130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 668130f4520SKenneth D. Merry 669130f4520SKenneth D. Merry retval = ctl_add_lun(&be_lun->ctl_be_lun); 670130f4520SKenneth D. Merry if (retval != 0) { 671130f4520SKenneth D. Merry mtx_lock(&softc->lock); 672130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 673130f4520SKenneth D. Merry links); 674130f4520SKenneth D. Merry softc->num_luns--; 675130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 676130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 677130f4520SKenneth D. Merry "%s: ctl_add_lun() returned error %d, see dmesg for " 678130f4520SKenneth D. Merry "details", __func__, retval); 679130f4520SKenneth D. Merry retval = 0; 680130f4520SKenneth D. Merry goto bailout_error; 681130f4520SKenneth D. Merry } 682130f4520SKenneth D. Merry 683130f4520SKenneth D. Merry if (do_wait == 0) 684130f4520SKenneth D. Merry return (retval); 685130f4520SKenneth D. Merry 686130f4520SKenneth D. Merry mtx_lock(&softc->lock); 687130f4520SKenneth D. Merry 688130f4520SKenneth D. Merry /* 689130f4520SKenneth D. Merry * Tell the config_status routine that we're waiting so it won't 690130f4520SKenneth D. Merry * clean up the LUN in the event of an error. 691130f4520SKenneth D. Merry */ 692130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 693130f4520SKenneth D. Merry 694130f4520SKenneth D. Merry while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 695130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 696130f4520SKenneth D. Merry if (retval == EINTR) 697130f4520SKenneth D. Merry break; 698130f4520SKenneth D. Merry } 699130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 700130f4520SKenneth D. Merry 701130f4520SKenneth D. Merry if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) { 702130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 703130f4520SKenneth D. Merry "%s: LUN configuration error, see dmesg for details", 704130f4520SKenneth D. Merry __func__); 705130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 706130f4520SKenneth D. Merry links); 707130f4520SKenneth D. Merry softc->num_luns--; 708130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 709130f4520SKenneth D. Merry goto bailout_error; 710130f4520SKenneth D. Merry } else { 711130f4520SKenneth D. Merry params->req_lun_id = be_lun->ctl_be_lun.lun_id; 712130f4520SKenneth D. Merry } 713130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 714130f4520SKenneth D. Merry 715130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 716130f4520SKenneth D. Merry 717130f4520SKenneth D. Merry return (retval); 718130f4520SKenneth D. Merry 719130f4520SKenneth D. Merry bailout_error: 720130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 72108a7cce5SAlexander Motin if (be_lun != NULL) { 72208a7cce5SAlexander Motin if (be_lun->io_taskqueue != NULL) { 72308a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 72408a7cce5SAlexander Motin } 72543fb3a65SAlexander Motin ctl_free_opts(&be_lun->ctl_be_lun.options); 72675c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 727130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 72808a7cce5SAlexander Motin } 729130f4520SKenneth D. Merry 730130f4520SKenneth D. Merry return (retval); 731130f4520SKenneth D. Merry } 732130f4520SKenneth D. Merry 73381177295SEdward Tomasz Napierala static int 73481177295SEdward Tomasz Napierala ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 73581177295SEdward Tomasz Napierala struct ctl_lun_req *req) 73681177295SEdward Tomasz Napierala { 73781177295SEdward Tomasz Napierala struct ctl_be_ramdisk_lun *be_lun; 73881177295SEdward Tomasz Napierala struct ctl_lun_modify_params *params; 73981177295SEdward Tomasz Napierala uint32_t blocksize; 74081177295SEdward Tomasz Napierala 74181177295SEdward Tomasz Napierala params = &req->reqdata.modify; 74281177295SEdward Tomasz Napierala 74381177295SEdward Tomasz Napierala be_lun = NULL; 74481177295SEdward Tomasz Napierala 74581177295SEdward Tomasz Napierala mtx_lock(&softc->lock); 74681177295SEdward Tomasz Napierala STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 74781177295SEdward Tomasz Napierala if (be_lun->ctl_be_lun.lun_id == params->lun_id) 74881177295SEdward Tomasz Napierala break; 74981177295SEdward Tomasz Napierala } 75081177295SEdward Tomasz Napierala mtx_unlock(&softc->lock); 75181177295SEdward Tomasz Napierala 75281177295SEdward Tomasz Napierala if (be_lun == NULL) { 75381177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 75481177295SEdward Tomasz Napierala "%s: LUN %u is not managed by the ramdisk backend", 75581177295SEdward Tomasz Napierala __func__, params->lun_id); 75681177295SEdward Tomasz Napierala goto bailout_error; 75781177295SEdward Tomasz Napierala } 75881177295SEdward Tomasz Napierala 75981177295SEdward Tomasz Napierala if (params->lun_size_bytes == 0) { 76081177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 76181177295SEdward Tomasz Napierala "%s: LUN size \"auto\" not supported " 76281177295SEdward Tomasz Napierala "by the ramdisk backend", __func__); 76381177295SEdward Tomasz Napierala goto bailout_error; 76481177295SEdward Tomasz Napierala } 76581177295SEdward Tomasz Napierala 76681177295SEdward Tomasz Napierala blocksize = be_lun->ctl_be_lun.blocksize; 76781177295SEdward Tomasz Napierala 76881177295SEdward Tomasz Napierala if (params->lun_size_bytes < blocksize) { 76981177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 77081177295SEdward Tomasz Napierala "%s: LUN size %ju < blocksize %u", __func__, 77181177295SEdward Tomasz Napierala params->lun_size_bytes, blocksize); 77281177295SEdward Tomasz Napierala goto bailout_error; 77381177295SEdward Tomasz Napierala } 77481177295SEdward Tomasz Napierala 77581177295SEdward Tomasz Napierala be_lun->size_blocks = params->lun_size_bytes / blocksize; 77681177295SEdward Tomasz Napierala be_lun->size_bytes = be_lun->size_blocks * blocksize; 77781177295SEdward Tomasz Napierala 77881177295SEdward Tomasz Napierala /* 77981177295SEdward Tomasz Napierala * The maximum LBA is the size - 1. 78081177295SEdward Tomasz Napierala * 78181177295SEdward Tomasz Napierala * XXX: Note that this field is being updated without locking, 78281177295SEdward Tomasz Napierala * which might cause problems on 32-bit architectures. 78381177295SEdward Tomasz Napierala */ 78481177295SEdward Tomasz Napierala be_lun->ctl_be_lun.maxlba = be_lun->size_blocks - 1; 78581177295SEdward Tomasz Napierala ctl_lun_capacity_changed(&be_lun->ctl_be_lun); 78681177295SEdward Tomasz Napierala 78781177295SEdward Tomasz Napierala /* Tell the user the exact size we ended up using */ 78881177295SEdward Tomasz Napierala params->lun_size_bytes = be_lun->size_bytes; 78981177295SEdward Tomasz Napierala 79081177295SEdward Tomasz Napierala req->status = CTL_LUN_OK; 79181177295SEdward Tomasz Napierala 79281177295SEdward Tomasz Napierala return (0); 79381177295SEdward Tomasz Napierala 79481177295SEdward Tomasz Napierala bailout_error: 79581177295SEdward Tomasz Napierala req->status = CTL_LUN_ERROR; 79681177295SEdward Tomasz Napierala 79781177295SEdward Tomasz Napierala return (0); 79881177295SEdward Tomasz Napierala } 79981177295SEdward Tomasz Napierala 800130f4520SKenneth D. Merry static void 801130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_shutdown(void *be_lun) 802130f4520SKenneth D. Merry { 803130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun; 804130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 805130f4520SKenneth D. Merry int do_free; 806130f4520SKenneth D. Merry 807130f4520SKenneth D. Merry lun = (struct ctl_be_ramdisk_lun *)be_lun; 808130f4520SKenneth D. Merry softc = lun->softc; 809130f4520SKenneth D. Merry do_free = 0; 810130f4520SKenneth D. Merry 811130f4520SKenneth D. Merry mtx_lock(&softc->lock); 812130f4520SKenneth D. Merry 813130f4520SKenneth D. Merry lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 814130f4520SKenneth D. Merry 815130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 816130f4520SKenneth D. Merry wakeup(lun); 817130f4520SKenneth D. Merry } else { 818e2507751SAlexander Motin STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 819130f4520SKenneth D. Merry links); 820130f4520SKenneth D. Merry softc->num_luns--; 821130f4520SKenneth D. Merry do_free = 1; 822130f4520SKenneth D. Merry } 823130f4520SKenneth D. Merry 824130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 825130f4520SKenneth D. Merry 826130f4520SKenneth D. Merry if (do_free != 0) 827130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 828130f4520SKenneth D. Merry } 829130f4520SKenneth D. Merry 830130f4520SKenneth D. Merry static void 831130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_config_status(void *be_lun, 832130f4520SKenneth D. Merry ctl_lun_config_status status) 833130f4520SKenneth D. Merry { 834130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun; 835130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 836130f4520SKenneth D. Merry 837130f4520SKenneth D. Merry lun = (struct ctl_be_ramdisk_lun *)be_lun; 838130f4520SKenneth D. Merry softc = lun->softc; 839130f4520SKenneth D. Merry 840130f4520SKenneth D. Merry if (status == CTL_LUN_CONFIG_OK) { 841130f4520SKenneth D. Merry mtx_lock(&softc->lock); 842130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 843130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 844130f4520SKenneth D. Merry wakeup(lun); 845130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 846130f4520SKenneth D. Merry 847130f4520SKenneth D. Merry /* 848130f4520SKenneth D. Merry * We successfully added the LUN, attempt to enable it. 849130f4520SKenneth D. Merry */ 850130f4520SKenneth D. Merry if (ctl_enable_lun(&lun->ctl_be_lun) != 0) { 851130f4520SKenneth D. Merry printf("%s: ctl_enable_lun() failed!\n", __func__); 852130f4520SKenneth D. Merry if (ctl_invalidate_lun(&lun->ctl_be_lun) != 0) { 853130f4520SKenneth D. Merry printf("%s: ctl_invalidate_lun() failed!\n", 854130f4520SKenneth D. Merry __func__); 855130f4520SKenneth D. Merry } 856130f4520SKenneth D. Merry } 857130f4520SKenneth D. Merry 858130f4520SKenneth D. Merry return; 859130f4520SKenneth D. Merry } 860130f4520SKenneth D. Merry 861130f4520SKenneth D. Merry 862130f4520SKenneth D. Merry mtx_lock(&softc->lock); 863130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 864130f4520SKenneth D. Merry 865130f4520SKenneth D. Merry /* 866130f4520SKenneth D. Merry * If we have a user waiting, let him handle the cleanup. If not, 867130f4520SKenneth D. Merry * clean things up here. 868130f4520SKenneth D. Merry */ 869130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 870130f4520SKenneth D. Merry lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR; 871130f4520SKenneth D. Merry wakeup(lun); 872130f4520SKenneth D. Merry } else { 873130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 874130f4520SKenneth D. Merry links); 875130f4520SKenneth D. Merry softc->num_luns--; 876130f4520SKenneth D. Merry free(lun, M_RAMDISK); 877130f4520SKenneth D. Merry } 878130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 879130f4520SKenneth D. Merry } 880130f4520SKenneth D. Merry 881130f4520SKenneth D. Merry static int 882130f4520SKenneth D. Merry ctl_backend_ramdisk_config_write(union ctl_io *io) 883130f4520SKenneth D. Merry { 884130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 885130f4520SKenneth D. Merry int retval; 886130f4520SKenneth D. Merry 887130f4520SKenneth D. Merry retval = 0; 888130f4520SKenneth D. Merry softc = &rd_softc; 889130f4520SKenneth D. Merry 890130f4520SKenneth D. Merry switch (io->scsiio.cdb[0]) { 891130f4520SKenneth D. Merry case SYNCHRONIZE_CACHE: 892130f4520SKenneth D. Merry case SYNCHRONIZE_CACHE_16: 893130f4520SKenneth D. Merry /* 894130f4520SKenneth D. Merry * The upper level CTL code will filter out any CDBs with 895130f4520SKenneth D. Merry * the immediate bit set and return the proper error. It 896130f4520SKenneth D. Merry * will also not allow a sync cache command to go to a LUN 897130f4520SKenneth D. Merry * that is powered down. 898130f4520SKenneth D. Merry * 899130f4520SKenneth D. Merry * We don't really need to worry about what LBA range the 900130f4520SKenneth D. Merry * user asked to be synced out. When they issue a sync 901130f4520SKenneth D. Merry * cache command, we'll sync out the whole thing. 902130f4520SKenneth D. Merry * 903130f4520SKenneth D. Merry * This is obviously just a stubbed out implementation. 904130f4520SKenneth D. Merry * The real implementation will be in the RAIDCore/CTL 905130f4520SKenneth D. Merry * interface, and can only really happen when RAIDCore 906130f4520SKenneth D. Merry * implements a per-array cache sync. 907130f4520SKenneth D. Merry */ 908130f4520SKenneth D. Merry ctl_set_success(&io->scsiio); 909130f4520SKenneth D. Merry ctl_config_write_done(io); 910130f4520SKenneth D. Merry break; 911130f4520SKenneth D. Merry case START_STOP_UNIT: { 912130f4520SKenneth D. Merry struct scsi_start_stop_unit *cdb; 913130f4520SKenneth D. Merry struct ctl_be_lun *ctl_be_lun; 914130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 915130f4520SKenneth D. Merry 916130f4520SKenneth D. Merry cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 917130f4520SKenneth D. Merry 918130f4520SKenneth D. Merry ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 919130f4520SKenneth D. Merry CTL_PRIV_BACKEND_LUN].ptr; 920130f4520SKenneth D. Merry be_lun = (struct ctl_be_ramdisk_lun *)ctl_be_lun->be_lun; 921130f4520SKenneth D. Merry 922130f4520SKenneth D. Merry if (cdb->how & SSS_START) 923130f4520SKenneth D. Merry retval = ctl_start_lun(ctl_be_lun); 924130f4520SKenneth D. Merry else { 925130f4520SKenneth D. Merry retval = ctl_stop_lun(ctl_be_lun); 926130f4520SKenneth D. Merry #ifdef NEEDTOPORT 927130f4520SKenneth D. Merry if ((retval == 0) 928130f4520SKenneth D. Merry && (cdb->byte2 & SSS_ONOFFLINE)) 929130f4520SKenneth D. Merry retval = ctl_lun_offline(ctl_be_lun); 930130f4520SKenneth D. Merry #endif 931130f4520SKenneth D. Merry } 932130f4520SKenneth D. Merry 933130f4520SKenneth D. Merry /* 934130f4520SKenneth D. Merry * In general, the above routines should not fail. They 935130f4520SKenneth D. Merry * just set state for the LUN. So we've got something 936130f4520SKenneth D. Merry * pretty wrong here if we can't start or stop the LUN. 937130f4520SKenneth D. Merry */ 938130f4520SKenneth D. Merry if (retval != 0) { 939130f4520SKenneth D. Merry ctl_set_internal_failure(&io->scsiio, 940130f4520SKenneth D. Merry /*sks_valid*/ 1, 941130f4520SKenneth D. Merry /*retry_count*/ 0xf051); 942130f4520SKenneth D. Merry retval = CTL_RETVAL_COMPLETE; 943130f4520SKenneth D. Merry } else { 944130f4520SKenneth D. Merry ctl_set_success(&io->scsiio); 945130f4520SKenneth D. Merry } 946130f4520SKenneth D. Merry ctl_config_write_done(io); 947130f4520SKenneth D. Merry break; 948130f4520SKenneth D. Merry } 949ee7f31c0SAlexander Motin case WRITE_SAME_10: 950ee7f31c0SAlexander Motin case WRITE_SAME_16: 951ee7f31c0SAlexander Motin case UNMAP: 952ee7f31c0SAlexander Motin ctl_set_success(&io->scsiio); 953ee7f31c0SAlexander Motin ctl_config_write_done(io); 954ee7f31c0SAlexander Motin break; 955130f4520SKenneth D. Merry default: 956130f4520SKenneth D. Merry ctl_set_invalid_opcode(&io->scsiio); 957130f4520SKenneth D. Merry ctl_config_write_done(io); 958130f4520SKenneth D. Merry retval = CTL_RETVAL_COMPLETE; 959130f4520SKenneth D. Merry break; 960130f4520SKenneth D. Merry } 961130f4520SKenneth D. Merry 962130f4520SKenneth D. Merry return (retval); 963130f4520SKenneth D. Merry } 964130f4520SKenneth D. Merry 965130f4520SKenneth D. Merry static int 966130f4520SKenneth D. Merry ctl_backend_ramdisk_config_read(union ctl_io *io) 967130f4520SKenneth D. Merry { 968130f4520SKenneth D. Merry /* 969130f4520SKenneth D. Merry * XXX KDM need to implement!! 970130f4520SKenneth D. Merry */ 971130f4520SKenneth D. Merry return (0); 972130f4520SKenneth D. Merry } 973