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); 50857a5db13SAlexander Motin ctl_free_opts(&be_lun->ctl_be_lun); 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); 55157a5db13SAlexander Motin ctl_init_opts(&be_lun->ctl_be_lun, req); 552130f4520SKenneth D. Merry 553130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 554130f4520SKenneth D. Merry be_lun->ctl_be_lun.lun_type = params->device_type; 555130f4520SKenneth D. Merry else 556130f4520SKenneth D. Merry be_lun->ctl_be_lun.lun_type = T_DIRECT; 557130f4520SKenneth D. Merry 558130f4520SKenneth D. Merry if (be_lun->ctl_be_lun.lun_type == T_DIRECT) { 559130f4520SKenneth D. Merry 560130f4520SKenneth D. Merry if (params->lun_size_bytes < blocksize) { 561130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 562130f4520SKenneth D. Merry "%s: LUN size %ju < blocksize %u", __func__, 563130f4520SKenneth D. Merry params->lun_size_bytes, blocksize); 564130f4520SKenneth D. Merry goto bailout_error; 565130f4520SKenneth D. Merry } 566130f4520SKenneth D. Merry 567130f4520SKenneth D. Merry be_lun->size_blocks = params->lun_size_bytes / blocksize; 568130f4520SKenneth D. Merry be_lun->size_bytes = be_lun->size_blocks * blocksize; 569130f4520SKenneth D. Merry 570130f4520SKenneth D. Merry be_lun->ctl_be_lun.maxlba = be_lun->size_blocks - 1; 571130f4520SKenneth D. Merry } else { 572130f4520SKenneth D. Merry be_lun->ctl_be_lun.maxlba = 0; 573130f4520SKenneth D. Merry blocksize = 0; 574130f4520SKenneth D. Merry be_lun->size_bytes = 0; 575130f4520SKenneth D. Merry be_lun->size_blocks = 0; 576130f4520SKenneth D. Merry } 577130f4520SKenneth D. Merry 578130f4520SKenneth D. Merry be_lun->ctl_be_lun.blocksize = blocksize; 579130f4520SKenneth D. Merry 580130f4520SKenneth D. Merry /* Tell the user the blocksize we ended up using */ 581130f4520SKenneth D. Merry params->blocksize_bytes = blocksize; 582130f4520SKenneth D. Merry 583130f4520SKenneth D. Merry /* Tell the user the exact size we ended up using */ 584130f4520SKenneth D. Merry params->lun_size_bytes = be_lun->size_bytes; 585130f4520SKenneth D. Merry 586130f4520SKenneth D. Merry be_lun->softc = softc; 587130f4520SKenneth D. Merry 588f7ad1c46SAlexander Motin unmap = 0; 58957a5db13SAlexander Motin value = ctl_get_opt(&be_lun->ctl_be_lun, "unmap"); 59057a5db13SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 591ee7f31c0SAlexander Motin unmap = 1; 59281a2151dSEdward Tomasz Napierala 593130f4520SKenneth D. Merry be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED; 594130f4520SKenneth D. Merry be_lun->ctl_be_lun.flags = CTL_LUN_FLAG_PRIMARY; 595ee7f31c0SAlexander Motin if (unmap) 596f7ad1c46SAlexander Motin be_lun->ctl_be_lun.flags |= CTL_LUN_FLAG_UNMAP; 597130f4520SKenneth D. Merry be_lun->ctl_be_lun.be_lun = be_lun; 598130f4520SKenneth D. Merry 599130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_ID_REQ) { 600130f4520SKenneth D. Merry be_lun->ctl_be_lun.req_lun_id = params->req_lun_id; 601130f4520SKenneth D. Merry be_lun->ctl_be_lun.flags |= CTL_LUN_FLAG_ID_REQ; 602130f4520SKenneth D. Merry } else 603130f4520SKenneth D. Merry be_lun->ctl_be_lun.req_lun_id = 0; 604130f4520SKenneth D. Merry 605130f4520SKenneth D. Merry be_lun->ctl_be_lun.lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 606130f4520SKenneth D. Merry be_lun->ctl_be_lun.lun_config_status = 607130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_config_status; 608130f4520SKenneth D. Merry be_lun->ctl_be_lun.be = &ctl_be_ramdisk_driver; 609130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 610130f4520SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 611130f4520SKenneth D. Merry softc->num_luns); 612130f4520SKenneth D. Merry strncpy((char *)be_lun->ctl_be_lun.serial_num, tmpstr, 613130f4520SKenneth D. Merry ctl_min(sizeof(be_lun->ctl_be_lun.serial_num), 614130f4520SKenneth D. Merry sizeof(tmpstr))); 615130f4520SKenneth D. Merry 616130f4520SKenneth D. Merry /* Tell the user what we used for a serial number */ 617130f4520SKenneth D. Merry strncpy((char *)params->serial_num, tmpstr, 618130f4520SKenneth D. Merry ctl_min(sizeof(params->serial_num), sizeof(tmpstr))); 619130f4520SKenneth D. Merry } else { 620130f4520SKenneth D. Merry strncpy((char *)be_lun->ctl_be_lun.serial_num, 621130f4520SKenneth D. Merry params->serial_num, 622130f4520SKenneth D. Merry ctl_min(sizeof(be_lun->ctl_be_lun.serial_num), 623130f4520SKenneth D. Merry sizeof(params->serial_num))); 624130f4520SKenneth D. Merry } 625130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 626130f4520SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 627130f4520SKenneth D. Merry strncpy((char *)be_lun->ctl_be_lun.device_id, tmpstr, 628130f4520SKenneth D. Merry ctl_min(sizeof(be_lun->ctl_be_lun.device_id), 629130f4520SKenneth D. Merry sizeof(tmpstr))); 630130f4520SKenneth D. Merry 631130f4520SKenneth D. Merry /* Tell the user what we used for a device ID */ 632130f4520SKenneth D. Merry strncpy((char *)params->device_id, tmpstr, 633130f4520SKenneth D. Merry ctl_min(sizeof(params->device_id), sizeof(tmpstr))); 634130f4520SKenneth D. Merry } else { 635130f4520SKenneth D. Merry strncpy((char *)be_lun->ctl_be_lun.device_id, 636130f4520SKenneth D. Merry params->device_id, 637130f4520SKenneth D. Merry ctl_min(sizeof(be_lun->ctl_be_lun.device_id), 638130f4520SKenneth D. Merry sizeof(params->device_id))); 639130f4520SKenneth D. Merry } 640130f4520SKenneth D. Merry 64108a7cce5SAlexander Motin STAILQ_INIT(&be_lun->cont_queue); 64275c7a1d3SAlexander Motin mtx_init(&be_lun->queue_lock, "cram queue lock", NULL, MTX_DEF); 64308a7cce5SAlexander Motin TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 64408a7cce5SAlexander Motin be_lun); 64508a7cce5SAlexander Motin 64608a7cce5SAlexander Motin be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 64708a7cce5SAlexander Motin taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 64808a7cce5SAlexander Motin if (be_lun->io_taskqueue == NULL) { 64908a7cce5SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 65008a7cce5SAlexander Motin "%s: Unable to create taskqueue", __func__); 65108a7cce5SAlexander Motin goto bailout_error; 65208a7cce5SAlexander Motin } 65308a7cce5SAlexander Motin 65408a7cce5SAlexander Motin retval = taskqueue_start_threads(&be_lun->io_taskqueue, 65508a7cce5SAlexander Motin /*num threads*/1, 65608a7cce5SAlexander Motin /*priority*/PWAIT, 65708a7cce5SAlexander Motin /*thread name*/ 65808a7cce5SAlexander Motin "%s taskq", be_lun->lunname); 65908a7cce5SAlexander Motin if (retval != 0) 66008a7cce5SAlexander Motin goto bailout_error; 66108a7cce5SAlexander Motin 662130f4520SKenneth D. Merry mtx_lock(&softc->lock); 663130f4520SKenneth D. Merry softc->num_luns++; 664130f4520SKenneth D. Merry STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 665130f4520SKenneth D. Merry 666130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 667130f4520SKenneth D. Merry 668130f4520SKenneth D. Merry retval = ctl_add_lun(&be_lun->ctl_be_lun); 669130f4520SKenneth D. Merry if (retval != 0) { 670130f4520SKenneth D. Merry mtx_lock(&softc->lock); 671130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 672130f4520SKenneth D. Merry links); 673130f4520SKenneth D. Merry softc->num_luns--; 674130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 675130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 676130f4520SKenneth D. Merry "%s: ctl_add_lun() returned error %d, see dmesg for " 677130f4520SKenneth D. Merry "details", __func__, retval); 678130f4520SKenneth D. Merry retval = 0; 679130f4520SKenneth D. Merry goto bailout_error; 680130f4520SKenneth D. Merry } 681130f4520SKenneth D. Merry 682130f4520SKenneth D. Merry if (do_wait == 0) 683130f4520SKenneth D. Merry return (retval); 684130f4520SKenneth D. Merry 685130f4520SKenneth D. Merry mtx_lock(&softc->lock); 686130f4520SKenneth D. Merry 687130f4520SKenneth D. Merry /* 688130f4520SKenneth D. Merry * Tell the config_status routine that we're waiting so it won't 689130f4520SKenneth D. Merry * clean up the LUN in the event of an error. 690130f4520SKenneth D. Merry */ 691130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 692130f4520SKenneth D. Merry 693130f4520SKenneth D. Merry while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 694130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 695130f4520SKenneth D. Merry if (retval == EINTR) 696130f4520SKenneth D. Merry break; 697130f4520SKenneth D. Merry } 698130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 699130f4520SKenneth D. Merry 700130f4520SKenneth D. Merry if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) { 701130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 702130f4520SKenneth D. Merry "%s: LUN configuration error, see dmesg for details", 703130f4520SKenneth D. Merry __func__); 704130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 705130f4520SKenneth D. Merry links); 706130f4520SKenneth D. Merry softc->num_luns--; 707130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 708130f4520SKenneth D. Merry goto bailout_error; 709130f4520SKenneth D. Merry } else { 710130f4520SKenneth D. Merry params->req_lun_id = be_lun->ctl_be_lun.lun_id; 711130f4520SKenneth D. Merry } 712130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 713130f4520SKenneth D. Merry 714130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 715130f4520SKenneth D. Merry 716130f4520SKenneth D. Merry return (retval); 717130f4520SKenneth D. Merry 718130f4520SKenneth D. Merry bailout_error: 719130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 72008a7cce5SAlexander Motin if (be_lun != NULL) { 72108a7cce5SAlexander Motin if (be_lun->io_taskqueue != NULL) { 72208a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 72308a7cce5SAlexander Motin } 72457a5db13SAlexander Motin ctl_free_opts(&be_lun->ctl_be_lun); 72575c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 726130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 72708a7cce5SAlexander Motin } 728130f4520SKenneth D. Merry 729130f4520SKenneth D. Merry return (retval); 730130f4520SKenneth D. Merry } 731130f4520SKenneth D. Merry 73281177295SEdward Tomasz Napierala static int 73381177295SEdward Tomasz Napierala ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 73481177295SEdward Tomasz Napierala struct ctl_lun_req *req) 73581177295SEdward Tomasz Napierala { 73681177295SEdward Tomasz Napierala struct ctl_be_ramdisk_lun *be_lun; 73781177295SEdward Tomasz Napierala struct ctl_lun_modify_params *params; 73881177295SEdward Tomasz Napierala uint32_t blocksize; 73981177295SEdward Tomasz Napierala 74081177295SEdward Tomasz Napierala params = &req->reqdata.modify; 74181177295SEdward Tomasz Napierala 74281177295SEdward Tomasz Napierala be_lun = NULL; 74381177295SEdward Tomasz Napierala 74481177295SEdward Tomasz Napierala mtx_lock(&softc->lock); 74581177295SEdward Tomasz Napierala STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 74681177295SEdward Tomasz Napierala if (be_lun->ctl_be_lun.lun_id == params->lun_id) 74781177295SEdward Tomasz Napierala break; 74881177295SEdward Tomasz Napierala } 74981177295SEdward Tomasz Napierala mtx_unlock(&softc->lock); 75081177295SEdward Tomasz Napierala 75181177295SEdward Tomasz Napierala if (be_lun == NULL) { 75281177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 75381177295SEdward Tomasz Napierala "%s: LUN %u is not managed by the ramdisk backend", 75481177295SEdward Tomasz Napierala __func__, params->lun_id); 75581177295SEdward Tomasz Napierala goto bailout_error; 75681177295SEdward Tomasz Napierala } 75781177295SEdward Tomasz Napierala 75881177295SEdward Tomasz Napierala if (params->lun_size_bytes == 0) { 75981177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 76081177295SEdward Tomasz Napierala "%s: LUN size \"auto\" not supported " 76181177295SEdward Tomasz Napierala "by the ramdisk backend", __func__); 76281177295SEdward Tomasz Napierala goto bailout_error; 76381177295SEdward Tomasz Napierala } 76481177295SEdward Tomasz Napierala 76581177295SEdward Tomasz Napierala blocksize = be_lun->ctl_be_lun.blocksize; 76681177295SEdward Tomasz Napierala 76781177295SEdward Tomasz Napierala if (params->lun_size_bytes < blocksize) { 76881177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 76981177295SEdward Tomasz Napierala "%s: LUN size %ju < blocksize %u", __func__, 77081177295SEdward Tomasz Napierala params->lun_size_bytes, blocksize); 77181177295SEdward Tomasz Napierala goto bailout_error; 77281177295SEdward Tomasz Napierala } 77381177295SEdward Tomasz Napierala 77481177295SEdward Tomasz Napierala be_lun->size_blocks = params->lun_size_bytes / blocksize; 77581177295SEdward Tomasz Napierala be_lun->size_bytes = be_lun->size_blocks * blocksize; 77681177295SEdward Tomasz Napierala 77781177295SEdward Tomasz Napierala /* 77881177295SEdward Tomasz Napierala * The maximum LBA is the size - 1. 77981177295SEdward Tomasz Napierala * 78081177295SEdward Tomasz Napierala * XXX: Note that this field is being updated without locking, 78181177295SEdward Tomasz Napierala * which might cause problems on 32-bit architectures. 78281177295SEdward Tomasz Napierala */ 78381177295SEdward Tomasz Napierala be_lun->ctl_be_lun.maxlba = be_lun->size_blocks - 1; 78481177295SEdward Tomasz Napierala ctl_lun_capacity_changed(&be_lun->ctl_be_lun); 78581177295SEdward Tomasz Napierala 78681177295SEdward Tomasz Napierala /* Tell the user the exact size we ended up using */ 78781177295SEdward Tomasz Napierala params->lun_size_bytes = be_lun->size_bytes; 78881177295SEdward Tomasz Napierala 78981177295SEdward Tomasz Napierala req->status = CTL_LUN_OK; 79081177295SEdward Tomasz Napierala 79181177295SEdward Tomasz Napierala return (0); 79281177295SEdward Tomasz Napierala 79381177295SEdward Tomasz Napierala bailout_error: 79481177295SEdward Tomasz Napierala req->status = CTL_LUN_ERROR; 79581177295SEdward Tomasz Napierala 79681177295SEdward Tomasz Napierala return (0); 79781177295SEdward Tomasz Napierala } 79881177295SEdward Tomasz Napierala 799130f4520SKenneth D. Merry static void 800130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_shutdown(void *be_lun) 801130f4520SKenneth D. Merry { 802130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun; 803130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 804130f4520SKenneth D. Merry int do_free; 805130f4520SKenneth D. Merry 806130f4520SKenneth D. Merry lun = (struct ctl_be_ramdisk_lun *)be_lun; 807130f4520SKenneth D. Merry softc = lun->softc; 808130f4520SKenneth D. Merry do_free = 0; 809130f4520SKenneth D. Merry 810130f4520SKenneth D. Merry mtx_lock(&softc->lock); 811130f4520SKenneth D. Merry 812130f4520SKenneth D. Merry lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 813130f4520SKenneth D. Merry 814130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 815130f4520SKenneth D. Merry wakeup(lun); 816130f4520SKenneth D. Merry } else { 817130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 818130f4520SKenneth D. Merry links); 819130f4520SKenneth D. Merry softc->num_luns--; 820130f4520SKenneth D. Merry do_free = 1; 821130f4520SKenneth D. Merry } 822130f4520SKenneth D. Merry 823130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 824130f4520SKenneth D. Merry 825130f4520SKenneth D. Merry if (do_free != 0) 826130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 827130f4520SKenneth D. Merry } 828130f4520SKenneth D. Merry 829130f4520SKenneth D. Merry static void 830130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_config_status(void *be_lun, 831130f4520SKenneth D. Merry ctl_lun_config_status status) 832130f4520SKenneth D. Merry { 833130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun; 834130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 835130f4520SKenneth D. Merry 836130f4520SKenneth D. Merry lun = (struct ctl_be_ramdisk_lun *)be_lun; 837130f4520SKenneth D. Merry softc = lun->softc; 838130f4520SKenneth D. Merry 839130f4520SKenneth D. Merry if (status == CTL_LUN_CONFIG_OK) { 840130f4520SKenneth D. Merry mtx_lock(&softc->lock); 841130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 842130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 843130f4520SKenneth D. Merry wakeup(lun); 844130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 845130f4520SKenneth D. Merry 846130f4520SKenneth D. Merry /* 847130f4520SKenneth D. Merry * We successfully added the LUN, attempt to enable it. 848130f4520SKenneth D. Merry */ 849130f4520SKenneth D. Merry if (ctl_enable_lun(&lun->ctl_be_lun) != 0) { 850130f4520SKenneth D. Merry printf("%s: ctl_enable_lun() failed!\n", __func__); 851130f4520SKenneth D. Merry if (ctl_invalidate_lun(&lun->ctl_be_lun) != 0) { 852130f4520SKenneth D. Merry printf("%s: ctl_invalidate_lun() failed!\n", 853130f4520SKenneth D. Merry __func__); 854130f4520SKenneth D. Merry } 855130f4520SKenneth D. Merry } 856130f4520SKenneth D. Merry 857130f4520SKenneth D. Merry return; 858130f4520SKenneth D. Merry } 859130f4520SKenneth D. Merry 860130f4520SKenneth D. Merry 861130f4520SKenneth D. Merry mtx_lock(&softc->lock); 862130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 863130f4520SKenneth D. Merry 864130f4520SKenneth D. Merry /* 865130f4520SKenneth D. Merry * If we have a user waiting, let him handle the cleanup. If not, 866130f4520SKenneth D. Merry * clean things up here. 867130f4520SKenneth D. Merry */ 868130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 869130f4520SKenneth D. Merry lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR; 870130f4520SKenneth D. Merry wakeup(lun); 871130f4520SKenneth D. Merry } else { 872130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 873130f4520SKenneth D. Merry links); 874130f4520SKenneth D. Merry softc->num_luns--; 875130f4520SKenneth D. Merry free(lun, M_RAMDISK); 876130f4520SKenneth D. Merry } 877130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 878130f4520SKenneth D. Merry } 879130f4520SKenneth D. Merry 880130f4520SKenneth D. Merry static int 881130f4520SKenneth D. Merry ctl_backend_ramdisk_config_write(union ctl_io *io) 882130f4520SKenneth D. Merry { 883130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 884130f4520SKenneth D. Merry int retval; 885130f4520SKenneth D. Merry 886130f4520SKenneth D. Merry retval = 0; 887130f4520SKenneth D. Merry softc = &rd_softc; 888130f4520SKenneth D. Merry 889130f4520SKenneth D. Merry switch (io->scsiio.cdb[0]) { 890130f4520SKenneth D. Merry case SYNCHRONIZE_CACHE: 891130f4520SKenneth D. Merry case SYNCHRONIZE_CACHE_16: 892130f4520SKenneth D. Merry /* 893130f4520SKenneth D. Merry * The upper level CTL code will filter out any CDBs with 894130f4520SKenneth D. Merry * the immediate bit set and return the proper error. It 895130f4520SKenneth D. Merry * will also not allow a sync cache command to go to a LUN 896130f4520SKenneth D. Merry * that is powered down. 897130f4520SKenneth D. Merry * 898130f4520SKenneth D. Merry * We don't really need to worry about what LBA range the 899130f4520SKenneth D. Merry * user asked to be synced out. When they issue a sync 900130f4520SKenneth D. Merry * cache command, we'll sync out the whole thing. 901130f4520SKenneth D. Merry * 902130f4520SKenneth D. Merry * This is obviously just a stubbed out implementation. 903130f4520SKenneth D. Merry * The real implementation will be in the RAIDCore/CTL 904130f4520SKenneth D. Merry * interface, and can only really happen when RAIDCore 905130f4520SKenneth D. Merry * implements a per-array cache sync. 906130f4520SKenneth D. Merry */ 907130f4520SKenneth D. Merry ctl_set_success(&io->scsiio); 908130f4520SKenneth D. Merry ctl_config_write_done(io); 909130f4520SKenneth D. Merry break; 910130f4520SKenneth D. Merry case START_STOP_UNIT: { 911130f4520SKenneth D. Merry struct scsi_start_stop_unit *cdb; 912130f4520SKenneth D. Merry struct ctl_be_lun *ctl_be_lun; 913130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 914130f4520SKenneth D. Merry 915130f4520SKenneth D. Merry cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 916130f4520SKenneth D. Merry 917130f4520SKenneth D. Merry ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 918130f4520SKenneth D. Merry CTL_PRIV_BACKEND_LUN].ptr; 919130f4520SKenneth D. Merry be_lun = (struct ctl_be_ramdisk_lun *)ctl_be_lun->be_lun; 920130f4520SKenneth D. Merry 921130f4520SKenneth D. Merry if (cdb->how & SSS_START) 922130f4520SKenneth D. Merry retval = ctl_start_lun(ctl_be_lun); 923130f4520SKenneth D. Merry else { 924130f4520SKenneth D. Merry retval = ctl_stop_lun(ctl_be_lun); 925130f4520SKenneth D. Merry #ifdef NEEDTOPORT 926130f4520SKenneth D. Merry if ((retval == 0) 927130f4520SKenneth D. Merry && (cdb->byte2 & SSS_ONOFFLINE)) 928130f4520SKenneth D. Merry retval = ctl_lun_offline(ctl_be_lun); 929130f4520SKenneth D. Merry #endif 930130f4520SKenneth D. Merry } 931130f4520SKenneth D. Merry 932130f4520SKenneth D. Merry /* 933130f4520SKenneth D. Merry * In general, the above routines should not fail. They 934130f4520SKenneth D. Merry * just set state for the LUN. So we've got something 935130f4520SKenneth D. Merry * pretty wrong here if we can't start or stop the LUN. 936130f4520SKenneth D. Merry */ 937130f4520SKenneth D. Merry if (retval != 0) { 938130f4520SKenneth D. Merry ctl_set_internal_failure(&io->scsiio, 939130f4520SKenneth D. Merry /*sks_valid*/ 1, 940130f4520SKenneth D. Merry /*retry_count*/ 0xf051); 941130f4520SKenneth D. Merry retval = CTL_RETVAL_COMPLETE; 942130f4520SKenneth D. Merry } else { 943130f4520SKenneth D. Merry ctl_set_success(&io->scsiio); 944130f4520SKenneth D. Merry } 945130f4520SKenneth D. Merry ctl_config_write_done(io); 946130f4520SKenneth D. Merry break; 947130f4520SKenneth D. Merry } 948ee7f31c0SAlexander Motin case WRITE_SAME_10: 949ee7f31c0SAlexander Motin case WRITE_SAME_16: 950ee7f31c0SAlexander Motin case UNMAP: 951ee7f31c0SAlexander Motin ctl_set_success(&io->scsiio); 952ee7f31c0SAlexander Motin ctl_config_write_done(io); 953ee7f31c0SAlexander Motin break; 954130f4520SKenneth D. Merry default: 955130f4520SKenneth D. Merry ctl_set_invalid_opcode(&io->scsiio); 956130f4520SKenneth D. Merry ctl_config_write_done(io); 957130f4520SKenneth D. Merry retval = CTL_RETVAL_COMPLETE; 958130f4520SKenneth D. Merry break; 959130f4520SKenneth D. Merry } 960130f4520SKenneth D. Merry 961130f4520SKenneth D. Merry return (retval); 962130f4520SKenneth D. Merry } 963130f4520SKenneth D. Merry 964130f4520SKenneth D. Merry static int 965130f4520SKenneth D. Merry ctl_backend_ramdisk_config_read(union ctl_io *io) 966130f4520SKenneth D. Merry { 967130f4520SKenneth D. Merry /* 968130f4520SKenneth D. Merry * XXX KDM need to implement!! 969130f4520SKenneth D. Merry */ 970130f4520SKenneth D. Merry return (0); 971130f4520SKenneth D. Merry } 972