1130f4520SKenneth D. Merry /*- 2bec9534dSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3bec9534dSPedro F. Giffuni * 4130f4520SKenneth D. Merry * Copyright (c) 2003, 2008 Silicon Graphics International Corp. 581177295SEdward Tomasz Napierala * Copyright (c) 2012 The FreeBSD Foundation 6e7037673SAlexander Motin * Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org> 7130f4520SKenneth D. Merry * All rights reserved. 8130f4520SKenneth D. Merry * 981177295SEdward Tomasz Napierala * Portions of this software were developed by Edward Tomasz Napierala 1081177295SEdward Tomasz Napierala * under sponsorship from the FreeBSD Foundation. 1181177295SEdward Tomasz Napierala * 12130f4520SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 13130f4520SKenneth D. Merry * modification, are permitted provided that the following conditions 14130f4520SKenneth D. Merry * are met: 15130f4520SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 16130f4520SKenneth D. Merry * notice, this list of conditions, and the following disclaimer, 17130f4520SKenneth D. Merry * without modification. 18130f4520SKenneth D. Merry * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19130f4520SKenneth D. Merry * substantially similar to the "NO WARRANTY" disclaimer below 20130f4520SKenneth D. Merry * ("Disclaimer") and any redistribution must be conditioned upon 21130f4520SKenneth D. Merry * including a substantially similar Disclaimer requirement for further 22130f4520SKenneth D. Merry * binary redistribution. 23130f4520SKenneth D. Merry * 24130f4520SKenneth D. Merry * NO WARRANTY 25130f4520SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26130f4520SKenneth D. Merry * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27130f4520SKenneth D. Merry * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 28130f4520SKenneth D. Merry * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29130f4520SKenneth D. Merry * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30130f4520SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31130f4520SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32130f4520SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33130f4520SKenneth D. Merry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 34130f4520SKenneth D. Merry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35130f4520SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGES. 36130f4520SKenneth D. Merry * 37130f4520SKenneth D. Merry * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $ 38130f4520SKenneth D. Merry */ 39130f4520SKenneth D. Merry /* 40e7037673SAlexander Motin * CAM Target Layer black hole and RAM disk backend. 41130f4520SKenneth D. Merry * 42130f4520SKenneth D. Merry * Author: Ken Merry <ken@FreeBSD.org> 43130f4520SKenneth D. Merry */ 44130f4520SKenneth D. Merry 45130f4520SKenneth D. Merry #include <sys/cdefs.h> 46130f4520SKenneth D. Merry __FBSDID("$FreeBSD$"); 47130f4520SKenneth D. Merry 48130f4520SKenneth D. Merry #include <sys/param.h> 49130f4520SKenneth D. Merry #include <sys/systm.h> 50130f4520SKenneth D. Merry #include <sys/kernel.h> 51130f4520SKenneth D. Merry #include <sys/condvar.h> 52130f4520SKenneth D. Merry #include <sys/types.h> 53e7037673SAlexander Motin #include <sys/limits.h> 54130f4520SKenneth D. Merry #include <sys/lock.h> 55130f4520SKenneth D. Merry #include <sys/mutex.h> 56130f4520SKenneth D. Merry #include <sys/malloc.h> 57e7037673SAlexander Motin #include <sys/sx.h> 5808a7cce5SAlexander Motin #include <sys/taskqueue.h> 59130f4520SKenneth D. Merry #include <sys/time.h> 60130f4520SKenneth D. Merry #include <sys/queue.h> 61130f4520SKenneth D. Merry #include <sys/conf.h> 62130f4520SKenneth D. Merry #include <sys/ioccom.h> 63130f4520SKenneth D. Merry #include <sys/module.h> 647ac58230SAlexander Motin #include <sys/sysctl.h> 658951f055SMarcelo Araujo #include <sys/nv.h> 668951f055SMarcelo Araujo #include <sys/dnv.h> 67130f4520SKenneth D. Merry 68130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 697ac58230SAlexander Motin #include <cam/scsi/scsi_da.h> 70130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 71130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 72130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h> 73130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h> 74130f4520SKenneth D. Merry #include <cam/ctl/ctl_debug.h> 75130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h> 767ac58230SAlexander Motin #include <cam/ctl/ctl_ha.h> 777ac58230SAlexander Motin #include <cam/ctl/ctl_private.h> 78130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h> 79130f4520SKenneth D. Merry 80e7037673SAlexander Motin #define PRIV(io) \ 81e7037673SAlexander Motin ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND]) 82e7037673SAlexander Motin #define ARGS(io) \ 83e7037673SAlexander Motin ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]) 84e7037673SAlexander Motin 85e7037673SAlexander Motin #define PPP (PAGE_SIZE / sizeof(uint8_t **)) 86e7037673SAlexander Motin #ifdef __LP64__ 87e7037673SAlexander Motin #define PPPS (PAGE_SHIFT - 3) 88e7037673SAlexander Motin #else 89e7037673SAlexander Motin #define PPPS (PAGE_SHIFT - 2) 90e7037673SAlexander Motin #endif 91e7037673SAlexander Motin #define SGPP (PAGE_SIZE / sizeof(struct ctl_sg_entry)) 92e7037673SAlexander Motin 93e7037673SAlexander Motin #define P_UNMAPPED NULL /* Page is unmapped. */ 94e7037673SAlexander Motin #define P_ANCHORED ((void *)(uintptr_t)1) /* Page is anchored. */ 95e7037673SAlexander Motin 96e7037673SAlexander Motin typedef enum { 97e7037673SAlexander Motin GP_READ, /* Return data page or zero page. */ 98e7037673SAlexander Motin GP_WRITE, /* Return data page, try allocate if none. */ 99e7037673SAlexander Motin GP_ANCHOR, /* Return data page, try anchor if none. */ 100e7037673SAlexander Motin GP_OTHER, /* Return what present, do not allocate/anchor. */ 101e7037673SAlexander Motin } getpage_op_t; 102e7037673SAlexander Motin 103130f4520SKenneth D. Merry typedef enum { 104130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_UNCONFIGURED = 0x01, 105130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_CONFIG_ERR = 0x02, 106130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_WAITING = 0x04 107130f4520SKenneth D. Merry } ctl_be_ramdisk_lun_flags; 108130f4520SKenneth D. Merry 109130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun { 110a3977beaSAlexander Motin struct ctl_lun_create_params params; 11108a7cce5SAlexander Motin char lunname[32]; 112e7037673SAlexander Motin int indir; 113e7037673SAlexander Motin uint8_t **pages; 114e7037673SAlexander Motin uint8_t *zero_page; 115e7037673SAlexander Motin struct sx page_lock; 116e7037673SAlexander Motin u_int pblocksize; 117e7037673SAlexander Motin u_int pblockmul; 118130f4520SKenneth D. Merry uint64_t size_bytes; 119130f4520SKenneth D. Merry uint64_t size_blocks; 120e7037673SAlexander Motin uint64_t cap_bytes; 121e7037673SAlexander Motin uint64_t cap_used; 122130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 123130f4520SKenneth D. Merry ctl_be_ramdisk_lun_flags flags; 124130f4520SKenneth D. Merry STAILQ_ENTRY(ctl_be_ramdisk_lun) links; 1250bcd4ab6SAlexander Motin struct ctl_be_lun cbe_lun; 12608a7cce5SAlexander Motin struct taskqueue *io_taskqueue; 12708a7cce5SAlexander Motin struct task io_task; 12808a7cce5SAlexander Motin STAILQ_HEAD(, ctl_io_hdr) cont_queue; 12975c7a1d3SAlexander Motin struct mtx_padalign queue_lock; 130130f4520SKenneth D. Merry }; 131130f4520SKenneth D. Merry 132130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc { 133130f4520SKenneth D. Merry struct mtx lock; 134130f4520SKenneth D. Merry int num_luns; 135130f4520SKenneth D. Merry STAILQ_HEAD(, ctl_be_ramdisk_lun) lun_list; 136130f4520SKenneth D. Merry }; 137130f4520SKenneth D. Merry 138130f4520SKenneth D. Merry static struct ctl_be_ramdisk_softc rd_softc; 1397ac58230SAlexander Motin extern struct ctl_softc *control_softc; 140130f4520SKenneth D. Merry 1410c629e28SAlexander Motin static int ctl_backend_ramdisk_init(void); 1420c629e28SAlexander Motin static int ctl_backend_ramdisk_shutdown(void); 143130f4520SKenneth D. Merry static int ctl_backend_ramdisk_move_done(union ctl_io *io); 144e7037673SAlexander Motin static void ctl_backend_ramdisk_compare(union ctl_io *io); 145e7037673SAlexander Motin static void ctl_backend_ramdisk_rw(union ctl_io *io); 146130f4520SKenneth D. Merry static int ctl_backend_ramdisk_submit(union ctl_io *io); 147e7037673SAlexander Motin static void ctl_backend_ramdisk_worker(void *context, int pending); 148e7037673SAlexander Motin static int ctl_backend_ramdisk_config_read(union ctl_io *io); 149e7037673SAlexander Motin static int ctl_backend_ramdisk_config_write(union ctl_io *io); 150e7037673SAlexander Motin static uint64_t ctl_backend_ramdisk_lun_attr(void *be_lun, const char *attrname); 151130f4520SKenneth D. Merry static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, 152130f4520SKenneth D. Merry caddr_t addr, int flag, struct thread *td); 153130f4520SKenneth D. Merry static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 154130f4520SKenneth D. Merry struct ctl_lun_req *req); 155130f4520SKenneth D. Merry static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 1560bcd4ab6SAlexander Motin struct ctl_lun_req *req); 15781177295SEdward Tomasz Napierala static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 15881177295SEdward Tomasz Napierala struct ctl_lun_req *req); 159130f4520SKenneth D. Merry static void ctl_backend_ramdisk_lun_shutdown(void *be_lun); 160130f4520SKenneth D. Merry static void ctl_backend_ramdisk_lun_config_status(void *be_lun, 161130f4520SKenneth D. Merry ctl_lun_config_status status); 162130f4520SKenneth D. Merry 163130f4520SKenneth D. Merry static struct ctl_backend_driver ctl_be_ramdisk_driver = 164130f4520SKenneth D. Merry { 1652a2443d8SKenneth D. Merry .name = "ramdisk", 1662a2443d8SKenneth D. Merry .flags = CTL_BE_FLAG_HAS_CONFIG, 1672a2443d8SKenneth D. Merry .init = ctl_backend_ramdisk_init, 1680c629e28SAlexander Motin .shutdown = ctl_backend_ramdisk_shutdown, 1692a2443d8SKenneth D. Merry .data_submit = ctl_backend_ramdisk_submit, 1702a2443d8SKenneth D. Merry .data_move_done = ctl_backend_ramdisk_move_done, 1712a2443d8SKenneth D. Merry .config_read = ctl_backend_ramdisk_config_read, 1722a2443d8SKenneth D. Merry .config_write = ctl_backend_ramdisk_config_write, 173e7037673SAlexander Motin .ioctl = ctl_backend_ramdisk_ioctl, 174e7037673SAlexander Motin .lun_attr = ctl_backend_ramdisk_lun_attr, 175130f4520SKenneth D. Merry }; 176130f4520SKenneth D. Merry 177130f4520SKenneth D. Merry MALLOC_DEFINE(M_RAMDISK, "ramdisk", "Memory used for CTL RAMdisk"); 178130f4520SKenneth D. Merry CTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver); 179130f4520SKenneth D. Merry 180e7037673SAlexander Motin static int 181130f4520SKenneth D. Merry ctl_backend_ramdisk_init(void) 182130f4520SKenneth D. Merry { 18367cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 184130f4520SKenneth D. Merry 185130f4520SKenneth D. Merry memset(softc, 0, sizeof(*softc)); 18675c7a1d3SAlexander Motin mtx_init(&softc->lock, "ctlramdisk", NULL, MTX_DEF); 187130f4520SKenneth D. Merry STAILQ_INIT(&softc->lun_list); 188130f4520SKenneth D. Merry return (0); 189130f4520SKenneth D. Merry } 190130f4520SKenneth D. Merry 1910c629e28SAlexander Motin static int 192130f4520SKenneth D. Merry ctl_backend_ramdisk_shutdown(void) 193130f4520SKenneth D. Merry { 19467cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 195130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun, *next_lun; 196130f4520SKenneth D. Merry 197130f4520SKenneth D. Merry mtx_lock(&softc->lock); 198f5a2bbe6SAlexander Motin STAILQ_FOREACH_SAFE(lun, &softc->lun_list, links, next_lun) { 199130f4520SKenneth D. Merry /* 200130f4520SKenneth D. Merry * Drop our lock here. Since ctl_invalidate_lun() can call 201130f4520SKenneth D. Merry * back into us, this could potentially lead to a recursive 202130f4520SKenneth D. Merry * lock of the same mutex, which would cause a hang. 203130f4520SKenneth D. Merry */ 204130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2050bcd4ab6SAlexander Motin ctl_disable_lun(&lun->cbe_lun); 2060bcd4ab6SAlexander Motin ctl_invalidate_lun(&lun->cbe_lun); 207130f4520SKenneth D. Merry mtx_lock(&softc->lock); 208130f4520SKenneth D. Merry } 209130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2100c629e28SAlexander Motin mtx_destroy(&softc->lock); 2110c629e28SAlexander Motin return (0); 212130f4520SKenneth D. Merry } 213130f4520SKenneth D. Merry 214e7037673SAlexander Motin static uint8_t * 215e7037673SAlexander Motin ctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn, 216e7037673SAlexander Motin getpage_op_t op) 217e7037673SAlexander Motin { 218e7037673SAlexander Motin uint8_t **p, ***pp; 219e7037673SAlexander Motin off_t i; 220e7037673SAlexander Motin int s; 221e7037673SAlexander Motin 222e7037673SAlexander Motin if (be_lun->cap_bytes == 0) { 223e7037673SAlexander Motin switch (op) { 224e7037673SAlexander Motin case GP_READ: 225e7037673SAlexander Motin return (be_lun->zero_page); 226e7037673SAlexander Motin case GP_WRITE: 227e7037673SAlexander Motin return ((uint8_t *)be_lun->pages); 228e7037673SAlexander Motin case GP_ANCHOR: 229e7037673SAlexander Motin return (P_ANCHORED); 230e7037673SAlexander Motin default: 231e7037673SAlexander Motin return (P_UNMAPPED); 232e7037673SAlexander Motin } 233e7037673SAlexander Motin } 234e7037673SAlexander Motin if (op == GP_WRITE || op == GP_ANCHOR) { 235e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 236e7037673SAlexander Motin pp = &be_lun->pages; 237e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 238e7037673SAlexander Motin if (*pp == NULL) { 239e7037673SAlexander Motin *pp = malloc(PAGE_SIZE, M_RAMDISK, 240e7037673SAlexander Motin M_WAITOK|M_ZERO); 241e7037673SAlexander Motin } 242e7037673SAlexander Motin i = pn >> s; 243e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 244e7037673SAlexander Motin pn -= i << s; 245e7037673SAlexander Motin } 246e7037673SAlexander Motin if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 247e7037673SAlexander Motin if (op == GP_WRITE) { 248e7037673SAlexander Motin *pp = malloc(be_lun->pblocksize, M_RAMDISK, 249e7037673SAlexander Motin M_WAITOK|M_ZERO); 250e7037673SAlexander Motin } else 251e7037673SAlexander Motin *pp = P_ANCHORED; 252e7037673SAlexander Motin be_lun->cap_used += be_lun->pblocksize; 253e7037673SAlexander Motin } else if (*pp == P_ANCHORED && op == GP_WRITE) { 254e7037673SAlexander Motin *pp = malloc(be_lun->pblocksize, M_RAMDISK, 255e7037673SAlexander Motin M_WAITOK|M_ZERO); 256e7037673SAlexander Motin } 257e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 258e7037673SAlexander Motin return ((uint8_t *)*pp); 259e7037673SAlexander Motin } else { 260e7037673SAlexander Motin sx_slock(&be_lun->page_lock); 261e7037673SAlexander Motin p = be_lun->pages; 262e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 263e7037673SAlexander Motin if (p == NULL) 264e7037673SAlexander Motin break; 265e7037673SAlexander Motin i = pn >> s; 266e7037673SAlexander Motin p = (uint8_t **)p[i]; 267e7037673SAlexander Motin pn -= i << s; 268e7037673SAlexander Motin } 269e7037673SAlexander Motin sx_sunlock(&be_lun->page_lock); 270e7037673SAlexander Motin if ((p == P_UNMAPPED || p == P_ANCHORED) && op == GP_READ) 271e7037673SAlexander Motin return (be_lun->zero_page); 272e7037673SAlexander Motin return ((uint8_t *)p); 273e7037673SAlexander Motin } 274e7037673SAlexander Motin }; 275e7037673SAlexander Motin 276e7037673SAlexander Motin static void 277e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 278e7037673SAlexander Motin { 279e7037673SAlexander Motin uint8_t ***pp; 280e7037673SAlexander Motin off_t i; 281e7037673SAlexander Motin int s; 282e7037673SAlexander Motin 283e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 284e7037673SAlexander Motin return; 285e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 286e7037673SAlexander Motin pp = &be_lun->pages; 287e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 288e7037673SAlexander Motin if (*pp == NULL) 289e7037673SAlexander Motin goto noindir; 290e7037673SAlexander Motin i = pn >> s; 291e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 292e7037673SAlexander Motin pn -= i << s; 293e7037673SAlexander Motin } 294e7037673SAlexander Motin if (*pp == P_ANCHORED) { 295e7037673SAlexander Motin be_lun->cap_used -= be_lun->pblocksize; 296e7037673SAlexander Motin *pp = P_UNMAPPED; 297e7037673SAlexander Motin } else if (*pp != P_UNMAPPED) { 298e7037673SAlexander Motin free(*pp, M_RAMDISK); 299e7037673SAlexander Motin be_lun->cap_used -= be_lun->pblocksize; 300e7037673SAlexander Motin *pp = P_UNMAPPED; 301e7037673SAlexander Motin } 302e7037673SAlexander Motin noindir: 303e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 304e7037673SAlexander Motin }; 305e7037673SAlexander Motin 306e7037673SAlexander Motin static void 307e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 308e7037673SAlexander Motin { 309e7037673SAlexander Motin uint8_t ***pp; 310e7037673SAlexander Motin off_t i; 311e7037673SAlexander Motin int s; 312e7037673SAlexander Motin 313e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 314e7037673SAlexander Motin return; 315e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 316e7037673SAlexander Motin pp = &be_lun->pages; 317e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 318e7037673SAlexander Motin if (*pp == NULL) 319e7037673SAlexander Motin goto noindir; 320e7037673SAlexander Motin i = pn >> s; 321e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 322e7037673SAlexander Motin pn -= i << s; 323e7037673SAlexander Motin } 324e7037673SAlexander Motin if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 325e7037673SAlexander Motin be_lun->cap_used += be_lun->pblocksize; 326e7037673SAlexander Motin *pp = P_ANCHORED; 327e7037673SAlexander Motin } else if (*pp != P_ANCHORED) { 328e7037673SAlexander Motin free(*pp, M_RAMDISK); 329e7037673SAlexander Motin *pp = P_ANCHORED; 330e7037673SAlexander Motin } 331e7037673SAlexander Motin noindir: 332e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 333e7037673SAlexander Motin }; 334e7037673SAlexander Motin 335e7037673SAlexander Motin static void 336e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(uint8_t **p, int indir) 337e7037673SAlexander Motin { 338e7037673SAlexander Motin int i; 339e7037673SAlexander Motin 340e7037673SAlexander Motin if (p == NULL) 341e7037673SAlexander Motin return; 342e7037673SAlexander Motin if (indir == 0) { 343e7037673SAlexander Motin free(p, M_RAMDISK); 344e7037673SAlexander Motin return; 345e7037673SAlexander Motin } 346e7037673SAlexander Motin for (i = 0; i < PPP; i++) { 347e7037673SAlexander Motin if (p[i] == NULL) 348e7037673SAlexander Motin continue; 349e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages((uint8_t **)p[i], indir - 1); 350e7037673SAlexander Motin } 351e7037673SAlexander Motin free(p, M_RAMDISK); 352e7037673SAlexander Motin }; 353e7037673SAlexander Motin 354e7037673SAlexander Motin static size_t 355e7037673SAlexander Motin cmp(uint8_t *a, uint8_t *b, size_t size) 356e7037673SAlexander Motin { 357e7037673SAlexander Motin size_t i; 358e7037673SAlexander Motin 359e7037673SAlexander Motin for (i = 0; i < size; i++) { 360e7037673SAlexander Motin if (a[i] != b[i]) 361e7037673SAlexander Motin break; 362e7037673SAlexander Motin } 363e7037673SAlexander Motin return (i); 364e7037673SAlexander Motin } 365e7037673SAlexander Motin 366e7037673SAlexander Motin static int 367e7037673SAlexander Motin ctl_backend_ramdisk_cmp(union ctl_io *io) 368e7037673SAlexander Motin { 369e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 370e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 371e7037673SAlexander Motin uint8_t *page; 372e7037673SAlexander Motin uint8_t info[8]; 373e7037673SAlexander Motin uint64_t lba; 374e7037673SAlexander Motin u_int lbaoff, lbas, res, off; 375e7037673SAlexander Motin 376e7037673SAlexander Motin lbas = io->scsiio.kern_data_len / cbe_lun->blocksize; 377e7037673SAlexander Motin lba = ARGS(io)->lba + PRIV(io)->len - lbas; 378e7037673SAlexander Motin off = 0; 379e7037673SAlexander Motin for (; lbas > 0; lbas--, lba++) { 380e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 381e7037673SAlexander Motin lba >> cbe_lun->pblockexp, GP_READ); 382e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 383e7037673SAlexander Motin page += lbaoff * cbe_lun->blocksize; 384e7037673SAlexander Motin res = cmp(io->scsiio.kern_data_ptr + off, page, 385e7037673SAlexander Motin cbe_lun->blocksize); 386e7037673SAlexander Motin off += res; 387e7037673SAlexander Motin if (res < cbe_lun->blocksize) 388e7037673SAlexander Motin break; 389e7037673SAlexander Motin } 390e7037673SAlexander Motin if (lbas > 0) { 391e7037673SAlexander Motin off += io->scsiio.kern_rel_offset - io->scsiio.kern_data_len; 392e7037673SAlexander Motin scsi_u64to8b(off, info); 393e7037673SAlexander Motin ctl_set_sense(&io->scsiio, /*current_error*/ 1, 394e7037673SAlexander Motin /*sense_key*/ SSD_KEY_MISCOMPARE, 395e7037673SAlexander Motin /*asc*/ 0x1D, /*ascq*/ 0x00, 396e7037673SAlexander Motin /*type*/ SSD_ELEM_INFO, 397e7037673SAlexander Motin /*size*/ sizeof(info), /*data*/ &info, 398e7037673SAlexander Motin /*type*/ SSD_ELEM_NONE); 399e7037673SAlexander Motin return (1); 400e7037673SAlexander Motin } 401e7037673SAlexander Motin return (0); 402e7037673SAlexander Motin } 403e7037673SAlexander Motin 404130f4520SKenneth D. Merry static int 405130f4520SKenneth D. Merry ctl_backend_ramdisk_move_done(union ctl_io *io) 406130f4520SKenneth D. Merry { 407e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 408e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 409130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 410130f4520SKenneth D. Merry struct bintime cur_bt; 411130f4520SKenneth D. Merry #endif 412130f4520SKenneth D. Merry 413130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); 41408a7cce5SAlexander Motin #ifdef CTL_TIME_IO 415e675024aSAlexander Motin getbinuptime(&cur_bt); 41608a7cce5SAlexander Motin bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 41708a7cce5SAlexander Motin bintime_add(&io->io_hdr.dma_bt, &cur_bt); 41808a7cce5SAlexander Motin #endif 419e675024aSAlexander Motin io->io_hdr.num_dmas++; 42008a7cce5SAlexander Motin if (io->scsiio.kern_sg_entries > 0) 42108a7cce5SAlexander Motin free(io->scsiio.kern_data_ptr, M_RAMDISK); 42208a7cce5SAlexander Motin io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 423f7241cceSAlexander Motin if (io->io_hdr.flags & CTL_FLAG_ABORT) { 424f7241cceSAlexander Motin ; 425eb6ac6f9SAlexander Motin } else if (io->io_hdr.port_status != 0 && 426eb6ac6f9SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 427eb6ac6f9SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 428eb6ac6f9SAlexander Motin ctl_set_internal_failure(&io->scsiio, /*sks_valid*/ 1, 429eb6ac6f9SAlexander Motin /*retry_count*/ io->io_hdr.port_status); 430eb6ac6f9SAlexander Motin } else if (io->scsiio.kern_data_resid != 0 && 431eb6ac6f9SAlexander Motin (io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_OUT && 432eb6ac6f9SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 433eb6ac6f9SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 434eb6ac6f9SAlexander Motin ctl_set_invalid_field_ciu(&io->scsiio); 435f7241cceSAlexander Motin } else if ((io->io_hdr.port_status == 0) && 436f7241cceSAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 437e7037673SAlexander Motin if (ARGS(io)->flags & CTL_LLF_COMPARE) { 438e7037673SAlexander Motin /* We have data block ready for comparison. */ 439e7037673SAlexander Motin if (ctl_backend_ramdisk_cmp(io)) 440e7037673SAlexander Motin goto done; 441e7037673SAlexander Motin } 442e7037673SAlexander Motin if (ARGS(io)->len > PRIV(io)->len) { 44375c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 44408a7cce5SAlexander Motin STAILQ_INSERT_TAIL(&be_lun->cont_queue, 44508a7cce5SAlexander Motin &io->io_hdr, links); 44675c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 44708a7cce5SAlexander Motin taskqueue_enqueue(be_lun->io_taskqueue, 44808a7cce5SAlexander Motin &be_lun->io_task); 44908a7cce5SAlexander Motin return (0); 45008a7cce5SAlexander Motin } 4514a286345SAlexander Motin ctl_set_success(&io->scsiio); 452130f4520SKenneth D. Merry } 453e7037673SAlexander Motin done: 45411b569f7SAlexander Motin ctl_data_submit_done(io); 455130f4520SKenneth D. Merry return(0); 456130f4520SKenneth D. Merry } 457130f4520SKenneth D. Merry 458e7037673SAlexander Motin static void 459e7037673SAlexander Motin ctl_backend_ramdisk_compare(union ctl_io *io) 460e7037673SAlexander Motin { 461e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 462e7037673SAlexander Motin u_int lbas, len; 463e7037673SAlexander Motin 464e7037673SAlexander Motin lbas = ARGS(io)->len - PRIV(io)->len; 465e7037673SAlexander Motin lbas = MIN(lbas, 131072 / cbe_lun->blocksize); 466e7037673SAlexander Motin len = lbas * cbe_lun->blocksize; 467e7037673SAlexander Motin 468e7037673SAlexander Motin io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 469e7037673SAlexander Motin io->scsiio.kern_data_ptr = malloc(len, M_RAMDISK, M_WAITOK); 470e7037673SAlexander Motin io->scsiio.kern_data_len = len; 471e7037673SAlexander Motin io->scsiio.kern_sg_entries = 0; 472e7037673SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 473e7037673SAlexander Motin PRIV(io)->len += lbas; 474e7037673SAlexander Motin #ifdef CTL_TIME_IO 475e7037673SAlexander Motin getbinuptime(&io->io_hdr.dma_start_bt); 476e7037673SAlexander Motin #endif 477e7037673SAlexander Motin ctl_datamove(io); 478e7037673SAlexander Motin } 479e7037673SAlexander Motin 480e7037673SAlexander Motin static void 481e7037673SAlexander Motin ctl_backend_ramdisk_rw(union ctl_io *io) 482e7037673SAlexander Motin { 483e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 484e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 485e7037673SAlexander Motin struct ctl_sg_entry *sg_entries; 486e7037673SAlexander Motin uint8_t *page; 487e7037673SAlexander Motin uint64_t lba; 488e7037673SAlexander Motin u_int i, len, lbaoff, lbas, sgs, off; 489e7037673SAlexander Motin getpage_op_t op; 490e7037673SAlexander Motin 491e7037673SAlexander Motin lba = ARGS(io)->lba + PRIV(io)->len; 492e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 493e7037673SAlexander Motin lbas = ARGS(io)->len - PRIV(io)->len; 494e7037673SAlexander Motin lbas = MIN(lbas, (SGPP << cbe_lun->pblockexp) - lbaoff); 495e7037673SAlexander Motin sgs = (lbas + lbaoff + be_lun->pblockmul - 1) >> cbe_lun->pblockexp; 496e7037673SAlexander Motin off = lbaoff * cbe_lun->blocksize; 497e7037673SAlexander Motin op = (ARGS(io)->flags & CTL_LLF_WRITE) ? GP_WRITE : GP_READ; 498e7037673SAlexander Motin if (sgs > 1) { 499e7037673SAlexander Motin io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) * 500e7037673SAlexander Motin sgs, M_RAMDISK, M_WAITOK); 501e7037673SAlexander Motin sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 502e7037673SAlexander Motin len = lbas * cbe_lun->blocksize; 503e7037673SAlexander Motin for (i = 0; i < sgs; i++) { 504e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 505e7037673SAlexander Motin (lba >> cbe_lun->pblockexp) + i, op); 506e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) { 507e7037673SAlexander Motin free(io->scsiio.kern_data_ptr, M_RAMDISK); 508e7037673SAlexander Motin nospc: 509e7037673SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 510e7037673SAlexander Motin ctl_data_submit_done(io); 511e7037673SAlexander Motin return; 512e7037673SAlexander Motin } 513e7037673SAlexander Motin sg_entries[i].addr = page + off; 514e7037673SAlexander Motin sg_entries[i].len = MIN(len, be_lun->pblocksize - off); 515e7037673SAlexander Motin len -= sg_entries[i].len; 516e7037673SAlexander Motin off = 0; 517e7037673SAlexander Motin } 518e7037673SAlexander Motin } else { 519e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 520e7037673SAlexander Motin lba >> cbe_lun->pblockexp, op); 521e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) 522e7037673SAlexander Motin goto nospc; 523e7037673SAlexander Motin sgs = 0; 524e7037673SAlexander Motin io->scsiio.kern_data_ptr = page + off; 525e7037673SAlexander Motin } 526e7037673SAlexander Motin 527e7037673SAlexander Motin io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 528e7037673SAlexander Motin io->scsiio.kern_data_len = lbas * cbe_lun->blocksize; 529e7037673SAlexander Motin io->scsiio.kern_sg_entries = sgs; 530e7037673SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 531e7037673SAlexander Motin PRIV(io)->len += lbas; 532e8583acfSAlexander Motin if ((ARGS(io)->flags & CTL_LLF_READ) && 533e8583acfSAlexander Motin ARGS(io)->len <= PRIV(io)->len) { 534e8583acfSAlexander Motin ctl_set_success(&io->scsiio); 535e8583acfSAlexander Motin ctl_serseq_done(io); 536e8583acfSAlexander Motin } 537e7037673SAlexander Motin #ifdef CTL_TIME_IO 538e7037673SAlexander Motin getbinuptime(&io->io_hdr.dma_start_bt); 539e7037673SAlexander Motin #endif 540e7037673SAlexander Motin ctl_datamove(io); 541e7037673SAlexander Motin } 542e7037673SAlexander Motin 543130f4520SKenneth D. Merry static int 544130f4520SKenneth D. Merry ctl_backend_ramdisk_submit(union ctl_io *io) 545130f4520SKenneth D. Merry { 546e7037673SAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 547130f4520SKenneth D. Merry 54811b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_VERIFY) { 54911b569f7SAlexander Motin ctl_set_success(&io->scsiio); 55011b569f7SAlexander Motin ctl_data_submit_done(io); 55111b569f7SAlexander Motin return (CTL_RETVAL_COMPLETE); 55211b569f7SAlexander Motin } 553e7037673SAlexander Motin PRIV(io)->len = 0; 554e7037673SAlexander Motin if (lbalen->flags & CTL_LLF_COMPARE) 555e7037673SAlexander Motin ctl_backend_ramdisk_compare(io); 556e7037673SAlexander Motin else 557e7037673SAlexander Motin ctl_backend_ramdisk_rw(io); 558130f4520SKenneth D. Merry return (CTL_RETVAL_COMPLETE); 559130f4520SKenneth D. Merry } 560130f4520SKenneth D. Merry 56108a7cce5SAlexander Motin static void 56208a7cce5SAlexander Motin ctl_backend_ramdisk_worker(void *context, int pending) 56308a7cce5SAlexander Motin { 56408a7cce5SAlexander Motin struct ctl_be_ramdisk_lun *be_lun; 56508a7cce5SAlexander Motin union ctl_io *io; 56608a7cce5SAlexander Motin 56708a7cce5SAlexander Motin be_lun = (struct ctl_be_ramdisk_lun *)context; 56875c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 56908a7cce5SAlexander Motin for (;;) { 57008a7cce5SAlexander Motin io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); 57108a7cce5SAlexander Motin if (io != NULL) { 57208a7cce5SAlexander Motin STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr, 57308a7cce5SAlexander Motin ctl_io_hdr, links); 57475c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 575e7037673SAlexander Motin if (ARGS(io)->flags & CTL_LLF_COMPARE) 576e7037673SAlexander Motin ctl_backend_ramdisk_compare(io); 577e7037673SAlexander Motin else 578e7037673SAlexander Motin ctl_backend_ramdisk_rw(io); 57975c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 58008a7cce5SAlexander Motin continue; 58108a7cce5SAlexander Motin } 58208a7cce5SAlexander Motin 58308a7cce5SAlexander Motin /* 58408a7cce5SAlexander Motin * If we get here, there is no work left in the queues, so 58508a7cce5SAlexander Motin * just break out and let the task queue go to sleep. 58608a7cce5SAlexander Motin */ 58708a7cce5SAlexander Motin break; 58808a7cce5SAlexander Motin } 58975c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 590130f4520SKenneth D. Merry } 591130f4520SKenneth D. Merry 592130f4520SKenneth D. Merry static int 593e7037673SAlexander Motin ctl_backend_ramdisk_gls(union ctl_io *io) 594e7037673SAlexander Motin { 595e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 596e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 597e7037673SAlexander Motin struct scsi_get_lba_status_data *data; 598e7037673SAlexander Motin uint8_t *page; 599e7037673SAlexander Motin u_int lbaoff; 600e7037673SAlexander Motin 601e7037673SAlexander Motin data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 602e7037673SAlexander Motin scsi_u64to8b(ARGS(io)->lba, data->descr[0].addr); 603e7037673SAlexander Motin lbaoff = ARGS(io)->lba & ~(UINT_MAX << cbe_lun->pblockexp); 604e7037673SAlexander Motin scsi_ulto4b(be_lun->pblockmul - lbaoff, data->descr[0].length); 605e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 606e7037673SAlexander Motin ARGS(io)->lba >> cbe_lun->pblockexp, GP_OTHER); 607e7037673SAlexander Motin if (page == P_UNMAPPED) 608e7037673SAlexander Motin data->descr[0].status = 1; 609e7037673SAlexander Motin else if (page == P_ANCHORED) 610e7037673SAlexander Motin data->descr[0].status = 2; 611e7037673SAlexander Motin else 612e7037673SAlexander Motin data->descr[0].status = 0; 613e7037673SAlexander Motin ctl_config_read_done(io); 614e7037673SAlexander Motin return (CTL_RETVAL_COMPLETE); 615e7037673SAlexander Motin } 616e7037673SAlexander Motin 617e7037673SAlexander Motin static int 618e7037673SAlexander Motin ctl_backend_ramdisk_config_read(union ctl_io *io) 619e7037673SAlexander Motin { 620e7037673SAlexander Motin int retval = 0; 621e7037673SAlexander Motin 622e7037673SAlexander Motin switch (io->scsiio.cdb[0]) { 623e7037673SAlexander Motin case SERVICE_ACTION_IN: 624e7037673SAlexander Motin if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 625e7037673SAlexander Motin retval = ctl_backend_ramdisk_gls(io); 626e7037673SAlexander Motin break; 627e7037673SAlexander Motin } 628e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 629e7037673SAlexander Motin /*sks_valid*/ 1, 630e7037673SAlexander Motin /*command*/ 1, 631e7037673SAlexander Motin /*field*/ 1, 632e7037673SAlexander Motin /*bit_valid*/ 1, 633e7037673SAlexander Motin /*bit*/ 4); 634e7037673SAlexander Motin ctl_config_read_done(io); 635e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 636e7037673SAlexander Motin break; 637e7037673SAlexander Motin default: 638e7037673SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 639e7037673SAlexander Motin ctl_config_read_done(io); 640e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 641e7037673SAlexander Motin break; 642e7037673SAlexander Motin } 643e7037673SAlexander Motin return (retval); 644e7037673SAlexander Motin } 645e7037673SAlexander Motin 646e7037673SAlexander Motin static void 647e7037673SAlexander Motin ctl_backend_ramdisk_delete(struct ctl_be_lun *cbe_lun, off_t lba, off_t len, 648e7037673SAlexander Motin int anchor) 649e7037673SAlexander Motin { 650e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 651e7037673SAlexander Motin uint8_t *page; 652e7037673SAlexander Motin uint64_t p, lp; 653e7037673SAlexander Motin u_int lbaoff; 654e7037673SAlexander Motin getpage_op_t op = anchor ? GP_ANCHOR : GP_OTHER; 655e7037673SAlexander Motin 656e7037673SAlexander Motin /* Partially zero first partial page. */ 657e7037673SAlexander Motin p = lba >> cbe_lun->pblockexp; 658e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 659e7037673SAlexander Motin if (lbaoff != 0) { 660e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, p, op); 661e7037673SAlexander Motin if (page != P_UNMAPPED && page != P_ANCHORED) { 662e7037673SAlexander Motin memset(page + lbaoff * cbe_lun->blocksize, 0, 663e7037673SAlexander Motin min(len, be_lun->pblockmul - lbaoff) * 664e7037673SAlexander Motin cbe_lun->blocksize); 665e7037673SAlexander Motin } 666e7037673SAlexander Motin p++; 667e7037673SAlexander Motin } 668e7037673SAlexander Motin 669e7037673SAlexander Motin /* Partially zero last partial page. */ 670e7037673SAlexander Motin lp = (lba + len) >> cbe_lun->pblockexp; 671e7037673SAlexander Motin lbaoff = (lba + len) & ~(UINT_MAX << cbe_lun->pblockexp); 672e7037673SAlexander Motin if (p <= lp && lbaoff != 0) { 673e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, lp, op); 674e7037673SAlexander Motin if (page != P_UNMAPPED && page != P_ANCHORED) 675e7037673SAlexander Motin memset(page, 0, lbaoff * cbe_lun->blocksize); 676e7037673SAlexander Motin } 677e7037673SAlexander Motin 678e7037673SAlexander Motin /* Delete remaining full pages. */ 679e7037673SAlexander Motin if (anchor) { 680e7037673SAlexander Motin for (; p < lp; p++) 681e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(be_lun, p); 682e7037673SAlexander Motin } else { 683e7037673SAlexander Motin for (; p < lp; p++) 684e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(be_lun, p); 685e7037673SAlexander Motin } 686e7037673SAlexander Motin } 687e7037673SAlexander Motin 688e7037673SAlexander Motin static void 689e7037673SAlexander Motin ctl_backend_ramdisk_ws(union ctl_io *io) 690e7037673SAlexander Motin { 691e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 692e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 693e7037673SAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 694e7037673SAlexander Motin uint8_t *page; 695e7037673SAlexander Motin uint64_t lba; 696e7037673SAlexander Motin u_int lbaoff, lbas; 697e7037673SAlexander Motin 698e7037673SAlexander Motin if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB)) { 699e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 700e7037673SAlexander Motin /*sks_valid*/ 1, 701e7037673SAlexander Motin /*command*/ 1, 702e7037673SAlexander Motin /*field*/ 1, 703e7037673SAlexander Motin /*bit_valid*/ 0, 704e7037673SAlexander Motin /*bit*/ 0); 705e7037673SAlexander Motin ctl_config_write_done(io); 706e7037673SAlexander Motin return; 707e7037673SAlexander Motin } 708e7037673SAlexander Motin if (lbalen->flags & SWS_UNMAP) { 709e7037673SAlexander Motin ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 710e7037673SAlexander Motin (lbalen->flags & SWS_ANCHOR) != 0); 711e7037673SAlexander Motin ctl_set_success(&io->scsiio); 712e7037673SAlexander Motin ctl_config_write_done(io); 713e7037673SAlexander Motin return; 714e7037673SAlexander Motin } 715e7037673SAlexander Motin 716e7037673SAlexander Motin for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) { 717e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 718e7037673SAlexander Motin lba >> cbe_lun->pblockexp, GP_WRITE); 719e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) { 720e7037673SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 721e7037673SAlexander Motin ctl_data_submit_done(io); 722e7037673SAlexander Motin return; 723e7037673SAlexander Motin } 724e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 725e7037673SAlexander Motin page += lbaoff * cbe_lun->blocksize; 726e7037673SAlexander Motin if (lbalen->flags & SWS_NDOB) { 727e7037673SAlexander Motin memset(page, 0, cbe_lun->blocksize); 728e7037673SAlexander Motin } else { 729e7037673SAlexander Motin memcpy(page, io->scsiio.kern_data_ptr, 730e7037673SAlexander Motin cbe_lun->blocksize); 731e7037673SAlexander Motin } 732e7037673SAlexander Motin if (lbalen->flags & SWS_LBDATA) 733e7037673SAlexander Motin scsi_ulto4b(lba, page); 734e7037673SAlexander Motin } 735e7037673SAlexander Motin ctl_set_success(&io->scsiio); 736e7037673SAlexander Motin ctl_config_write_done(io); 737e7037673SAlexander Motin } 738e7037673SAlexander Motin 739e7037673SAlexander Motin static void 740e7037673SAlexander Motin ctl_backend_ramdisk_unmap(union ctl_io *io) 741e7037673SAlexander Motin { 742e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 743e7037673SAlexander Motin struct ctl_ptr_len_flags *ptrlen = (struct ctl_ptr_len_flags *)ARGS(io); 744e7037673SAlexander Motin struct scsi_unmap_desc *buf, *end; 745e7037673SAlexander Motin 746e7037673SAlexander Motin if ((ptrlen->flags & ~SU_ANCHOR) != 0) { 747e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 748e7037673SAlexander Motin /*sks_valid*/ 0, 749e7037673SAlexander Motin /*command*/ 0, 750e7037673SAlexander Motin /*field*/ 0, 751e7037673SAlexander Motin /*bit_valid*/ 0, 752e7037673SAlexander Motin /*bit*/ 0); 753e7037673SAlexander Motin ctl_config_write_done(io); 754e7037673SAlexander Motin return; 755e7037673SAlexander Motin } 756e7037673SAlexander Motin 757e7037673SAlexander Motin buf = (struct scsi_unmap_desc *)ptrlen->ptr; 758e7037673SAlexander Motin end = buf + ptrlen->len / sizeof(*buf); 759e7037673SAlexander Motin for (; buf < end; buf++) { 760e7037673SAlexander Motin ctl_backend_ramdisk_delete(cbe_lun, 761e7037673SAlexander Motin scsi_8btou64(buf->lba), scsi_4btoul(buf->length), 762e7037673SAlexander Motin (ptrlen->flags & SU_ANCHOR) != 0); 763e7037673SAlexander Motin } 764e7037673SAlexander Motin 765e7037673SAlexander Motin ctl_set_success(&io->scsiio); 766e7037673SAlexander Motin ctl_config_write_done(io); 767e7037673SAlexander Motin } 768e7037673SAlexander Motin 769e7037673SAlexander Motin static int 770e7037673SAlexander Motin ctl_backend_ramdisk_config_write(union ctl_io *io) 771e7037673SAlexander Motin { 772e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 773e7037673SAlexander Motin int retval = 0; 774e7037673SAlexander Motin 775e7037673SAlexander Motin switch (io->scsiio.cdb[0]) { 776e7037673SAlexander Motin case SYNCHRONIZE_CACHE: 777e7037673SAlexander Motin case SYNCHRONIZE_CACHE_16: 778e7037673SAlexander Motin /* We have no cache to flush. */ 779e7037673SAlexander Motin ctl_set_success(&io->scsiio); 780e7037673SAlexander Motin ctl_config_write_done(io); 781e7037673SAlexander Motin break; 782e7037673SAlexander Motin case START_STOP_UNIT: { 783e7037673SAlexander Motin struct scsi_start_stop_unit *cdb; 784e7037673SAlexander Motin 785e7037673SAlexander Motin cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 786e7037673SAlexander Motin if ((cdb->how & SSS_PC_MASK) != 0) { 787e7037673SAlexander Motin ctl_set_success(&io->scsiio); 788e7037673SAlexander Motin ctl_config_write_done(io); 789e7037673SAlexander Motin break; 790e7037673SAlexander Motin } 791e7037673SAlexander Motin if (cdb->how & SSS_START) { 792e7037673SAlexander Motin if (cdb->how & SSS_LOEJ) 793e7037673SAlexander Motin ctl_lun_has_media(cbe_lun); 794e7037673SAlexander Motin ctl_start_lun(cbe_lun); 795e7037673SAlexander Motin } else { 796e7037673SAlexander Motin ctl_stop_lun(cbe_lun); 797e7037673SAlexander Motin if (cdb->how & SSS_LOEJ) 798e7037673SAlexander Motin ctl_lun_ejected(cbe_lun); 799e7037673SAlexander Motin } 800e7037673SAlexander Motin ctl_set_success(&io->scsiio); 801e7037673SAlexander Motin ctl_config_write_done(io); 802e7037673SAlexander Motin break; 803e7037673SAlexander Motin } 804e7037673SAlexander Motin case PREVENT_ALLOW: 805e7037673SAlexander Motin ctl_set_success(&io->scsiio); 806e7037673SAlexander Motin ctl_config_write_done(io); 807e7037673SAlexander Motin break; 808e7037673SAlexander Motin case WRITE_SAME_10: 809e7037673SAlexander Motin case WRITE_SAME_16: 810e7037673SAlexander Motin ctl_backend_ramdisk_ws(io); 811e7037673SAlexander Motin break; 812e7037673SAlexander Motin case UNMAP: 813e7037673SAlexander Motin ctl_backend_ramdisk_unmap(io); 814e7037673SAlexander Motin break; 815e7037673SAlexander Motin default: 816e7037673SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 817e7037673SAlexander Motin ctl_config_write_done(io); 818e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 819e7037673SAlexander Motin break; 820e7037673SAlexander Motin } 821e7037673SAlexander Motin 822e7037673SAlexander Motin return (retval); 823e7037673SAlexander Motin } 824e7037673SAlexander Motin 825e7037673SAlexander Motin static uint64_t 826e7037673SAlexander Motin ctl_backend_ramdisk_lun_attr(void *arg, const char *attrname) 827e7037673SAlexander Motin { 828e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = arg; 829e7037673SAlexander Motin uint64_t val; 830e7037673SAlexander Motin 831e7037673SAlexander Motin val = UINT64_MAX; 832e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 833e7037673SAlexander Motin return (val); 834e7037673SAlexander Motin sx_slock(&be_lun->page_lock); 835e7037673SAlexander Motin if (strcmp(attrname, "blocksused") == 0) { 836e7037673SAlexander Motin val = be_lun->cap_used / be_lun->cbe_lun.blocksize; 837e7037673SAlexander Motin } else if (strcmp(attrname, "blocksavail") == 0) { 838e7037673SAlexander Motin val = (be_lun->cap_bytes - be_lun->cap_used) / 839e7037673SAlexander Motin be_lun->cbe_lun.blocksize; 840e7037673SAlexander Motin } 841e7037673SAlexander Motin sx_sunlock(&be_lun->page_lock); 842e7037673SAlexander Motin return (val); 843e7037673SAlexander Motin } 844e7037673SAlexander Motin 845e7037673SAlexander Motin static int 846130f4520SKenneth D. Merry ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 847130f4520SKenneth D. Merry int flag, struct thread *td) 848130f4520SKenneth D. Merry { 84967cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 85067cc546dSAlexander Motin struct ctl_lun_req *lun_req; 851130f4520SKenneth D. Merry int retval; 852130f4520SKenneth D. Merry 853130f4520SKenneth D. Merry retval = 0; 854130f4520SKenneth D. Merry switch (cmd) { 85567cc546dSAlexander Motin case CTL_LUN_REQ: 856130f4520SKenneth D. Merry lun_req = (struct ctl_lun_req *)addr; 857130f4520SKenneth D. Merry switch (lun_req->reqtype) { 858130f4520SKenneth D. Merry case CTL_LUNREQ_CREATE: 8590bcd4ab6SAlexander Motin retval = ctl_backend_ramdisk_create(softc, lun_req); 860130f4520SKenneth D. Merry break; 861130f4520SKenneth D. Merry case CTL_LUNREQ_RM: 862130f4520SKenneth D. Merry retval = ctl_backend_ramdisk_rm(softc, lun_req); 863130f4520SKenneth D. Merry break; 86481177295SEdward Tomasz Napierala case CTL_LUNREQ_MODIFY: 86581177295SEdward Tomasz Napierala retval = ctl_backend_ramdisk_modify(softc, lun_req); 86681177295SEdward Tomasz Napierala break; 867130f4520SKenneth D. Merry default: 868130f4520SKenneth D. Merry lun_req->status = CTL_LUN_ERROR; 869130f4520SKenneth D. Merry snprintf(lun_req->error_str, sizeof(lun_req->error_str), 870130f4520SKenneth D. Merry "%s: invalid LUN request type %d", __func__, 871130f4520SKenneth D. Merry lun_req->reqtype); 872130f4520SKenneth D. Merry break; 873130f4520SKenneth D. Merry } 874130f4520SKenneth D. Merry break; 875130f4520SKenneth D. Merry default: 876130f4520SKenneth D. Merry retval = ENOTTY; 877130f4520SKenneth D. Merry break; 878130f4520SKenneth D. Merry } 879130f4520SKenneth D. Merry 880130f4520SKenneth D. Merry return (retval); 881130f4520SKenneth D. Merry } 882130f4520SKenneth D. Merry 883130f4520SKenneth D. Merry static int 884130f4520SKenneth D. Merry ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 885130f4520SKenneth D. Merry struct ctl_lun_req *req) 886130f4520SKenneth D. Merry { 887130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 888130f4520SKenneth D. Merry struct ctl_lun_rm_params *params; 889130f4520SKenneth D. Merry int retval; 890130f4520SKenneth D. Merry 891130f4520SKenneth D. Merry params = &req->reqdata.rm; 892130f4520SKenneth D. Merry mtx_lock(&softc->lock); 893130f4520SKenneth D. Merry STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 8940bcd4ab6SAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) 895130f4520SKenneth D. Merry break; 896130f4520SKenneth D. Merry } 897130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 898130f4520SKenneth D. Merry if (be_lun == NULL) { 899130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 900130f4520SKenneth D. Merry "%s: LUN %u is not managed by the ramdisk backend", 901130f4520SKenneth D. Merry __func__, params->lun_id); 902130f4520SKenneth D. Merry goto bailout_error; 903130f4520SKenneth D. Merry } 904130f4520SKenneth D. Merry 9050bcd4ab6SAlexander Motin retval = ctl_disable_lun(&be_lun->cbe_lun); 906130f4520SKenneth D. Merry if (retval != 0) { 907130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 908130f4520SKenneth D. Merry "%s: error %d returned from ctl_disable_lun() for " 909130f4520SKenneth D. Merry "LUN %d", __func__, retval, params->lun_id); 910130f4520SKenneth D. Merry goto bailout_error; 911130f4520SKenneth D. Merry } 912130f4520SKenneth D. Merry 913130f4520SKenneth D. Merry /* 914130f4520SKenneth D. Merry * Set the waiting flag before we invalidate the LUN. Our shutdown 915130f4520SKenneth D. Merry * routine can be called any time after we invalidate the LUN, 916130f4520SKenneth D. Merry * and can be called from our context. 917130f4520SKenneth D. Merry * 918130f4520SKenneth D. Merry * This tells the shutdown routine that we're waiting, or we're 919130f4520SKenneth D. Merry * going to wait for the shutdown to happen. 920130f4520SKenneth D. Merry */ 921130f4520SKenneth D. Merry mtx_lock(&softc->lock); 922130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 923130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 924130f4520SKenneth D. Merry 9250bcd4ab6SAlexander Motin retval = ctl_invalidate_lun(&be_lun->cbe_lun); 926130f4520SKenneth D. Merry if (retval != 0) { 927130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 928130f4520SKenneth D. Merry "%s: error %d returned from ctl_invalidate_lun() for " 929130f4520SKenneth D. Merry "LUN %d", __func__, retval, params->lun_id); 930ce300fbfSAlexander Motin mtx_lock(&softc->lock); 931ce300fbfSAlexander Motin be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 932ce300fbfSAlexander Motin mtx_unlock(&softc->lock); 933130f4520SKenneth D. Merry goto bailout_error; 934130f4520SKenneth D. Merry } 935130f4520SKenneth D. Merry 936130f4520SKenneth D. Merry mtx_lock(&softc->lock); 937130f4520SKenneth D. Merry while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) { 938130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 939130f4520SKenneth D. Merry if (retval == EINTR) 940130f4520SKenneth D. Merry break; 941130f4520SKenneth D. Merry } 942130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 943130f4520SKenneth D. Merry 944130f4520SKenneth D. Merry /* 945130f4520SKenneth D. Merry * We only remove this LUN from the list and free it (below) if 946130f4520SKenneth D. Merry * retval == 0. If the user interrupted the wait, we just bail out 947130f4520SKenneth D. Merry * without actually freeing the LUN. We let the shutdown routine 948130f4520SKenneth D. Merry * free the LUN if that happens. 949130f4520SKenneth D. Merry */ 950130f4520SKenneth D. Merry if (retval == 0) { 951130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 952130f4520SKenneth D. Merry links); 953130f4520SKenneth D. Merry softc->num_luns--; 954130f4520SKenneth D. Merry } 955130f4520SKenneth D. Merry 956130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 957130f4520SKenneth D. Merry 95808a7cce5SAlexander Motin if (retval == 0) { 959ee4ad294SAlexander Motin taskqueue_drain_all(be_lun->io_taskqueue); 96008a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 9618951f055SMarcelo Araujo nvlist_destroy(be_lun->cbe_lun.options); 962e7037673SAlexander Motin free(be_lun->zero_page, M_RAMDISK); 963e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 964e7037673SAlexander Motin sx_destroy(&be_lun->page_lock); 96575c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 966130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 96708a7cce5SAlexander Motin } 968130f4520SKenneth D. Merry 969130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 970130f4520SKenneth D. Merry return (retval); 971130f4520SKenneth D. Merry 972130f4520SKenneth D. Merry bailout_error: 973130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 974130f4520SKenneth D. Merry return (0); 975130f4520SKenneth D. Merry } 976130f4520SKenneth D. Merry 977130f4520SKenneth D. Merry static int 978130f4520SKenneth D. Merry ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 9790bcd4ab6SAlexander Motin struct ctl_lun_req *req) 980130f4520SKenneth D. Merry { 981130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 9820bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 983130f4520SKenneth D. Merry struct ctl_lun_create_params *params; 9848951f055SMarcelo Araujo const char *value; 985130f4520SKenneth D. Merry char tmpstr[32]; 986e7037673SAlexander Motin uint64_t t; 9870bcd4ab6SAlexander Motin int retval; 988130f4520SKenneth D. Merry 989130f4520SKenneth D. Merry retval = 0; 990130f4520SKenneth D. Merry params = &req->reqdata.create; 991130f4520SKenneth D. Merry 9920bcd4ab6SAlexander Motin be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK); 9930bcd4ab6SAlexander Motin cbe_lun = &be_lun->cbe_lun; 9940bcd4ab6SAlexander Motin cbe_lun->be_lun = be_lun; 9958951f055SMarcelo Araujo cbe_lun->options = nvlist_clone(req->args_nvl); 996a3977beaSAlexander Motin be_lun->params = req->reqdata.create; 9970bcd4ab6SAlexander Motin be_lun->softc = softc; 99808a7cce5SAlexander Motin sprintf(be_lun->lunname, "cram%d", softc->num_luns); 999130f4520SKenneth D. Merry 1000130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 10010bcd4ab6SAlexander Motin cbe_lun->lun_type = params->device_type; 1002130f4520SKenneth D. Merry else 10030bcd4ab6SAlexander Motin cbe_lun->lun_type = T_DIRECT; 10040bcd4ab6SAlexander Motin be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED; 10057ac58230SAlexander Motin cbe_lun->flags = 0; 10068951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 10077ac58230SAlexander Motin if (value != NULL) { 10087ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 10097ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 10107ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 10117ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 1012130f4520SKenneth D. Merry 1013e7037673SAlexander Motin be_lun->pblocksize = PAGE_SIZE; 10148951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); 1015e7037673SAlexander Motin if (value != NULL) { 1016e7037673SAlexander Motin ctl_expand_number(value, &t); 1017e7037673SAlexander Motin be_lun->pblocksize = t; 1018e7037673SAlexander Motin } 1019e7037673SAlexander Motin if (be_lun->pblocksize < 512 || be_lun->pblocksize > 131072) { 1020e7037673SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 1021e7037673SAlexander Motin "%s: unsupported pblocksize %u", __func__, 1022e7037673SAlexander Motin be_lun->pblocksize); 1023e7037673SAlexander Motin goto bailout_error; 1024e7037673SAlexander Motin } 1025e7037673SAlexander Motin 102691be33dcSAlexander Motin if (cbe_lun->lun_type == T_DIRECT || 102791be33dcSAlexander Motin cbe_lun->lun_type == T_CDROM) { 10280bcd4ab6SAlexander Motin if (params->blocksize_bytes != 0) 10290bcd4ab6SAlexander Motin cbe_lun->blocksize = params->blocksize_bytes; 103091be33dcSAlexander Motin else if (cbe_lun->lun_type == T_CDROM) 103191be33dcSAlexander Motin cbe_lun->blocksize = 2048; 10320bcd4ab6SAlexander Motin else 10330bcd4ab6SAlexander Motin cbe_lun->blocksize = 512; 1034e7037673SAlexander Motin be_lun->pblockmul = be_lun->pblocksize / cbe_lun->blocksize; 1035e7037673SAlexander Motin if (be_lun->pblockmul < 1 || !powerof2(be_lun->pblockmul)) { 1036e7037673SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 1037e7037673SAlexander Motin "%s: pblocksize %u not exp2 of blocksize %u", 1038e7037673SAlexander Motin __func__, 1039e7037673SAlexander Motin be_lun->pblocksize, cbe_lun->blocksize); 1040e7037673SAlexander Motin goto bailout_error; 1041e7037673SAlexander Motin } 10420bcd4ab6SAlexander Motin if (params->lun_size_bytes < cbe_lun->blocksize) { 1043130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1044130f4520SKenneth D. Merry "%s: LUN size %ju < blocksize %u", __func__, 10450bcd4ab6SAlexander Motin params->lun_size_bytes, cbe_lun->blocksize); 1046130f4520SKenneth D. Merry goto bailout_error; 1047130f4520SKenneth D. Merry } 10480bcd4ab6SAlexander Motin be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize; 10490bcd4ab6SAlexander Motin be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize; 1050e7037673SAlexander Motin be_lun->indir = 0; 1051e7037673SAlexander Motin t = be_lun->size_bytes / be_lun->pblocksize; 1052e7037673SAlexander Motin while (t > 1) { 1053e7037673SAlexander Motin t /= PPP; 1054e7037673SAlexander Motin be_lun->indir++; 1055e7037673SAlexander Motin } 10560bcd4ab6SAlexander Motin cbe_lun->maxlba = be_lun->size_blocks - 1; 1057e7037673SAlexander Motin cbe_lun->pblockexp = fls(be_lun->pblockmul) - 1; 1058e7037673SAlexander Motin cbe_lun->pblockoff = 0; 1059e7037673SAlexander Motin cbe_lun->ublockexp = cbe_lun->pblockexp; 1060e7037673SAlexander Motin cbe_lun->ublockoff = 0; 1061e7037673SAlexander Motin cbe_lun->atomicblock = be_lun->pblocksize; 1062e7037673SAlexander Motin cbe_lun->opttxferlen = SGPP * be_lun->pblocksize; 10638951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "capacity", NULL); 1064e7037673SAlexander Motin if (value != NULL) 1065e7037673SAlexander Motin ctl_expand_number(value, &be_lun->cap_bytes); 1066e7037673SAlexander Motin } else { 1067e7037673SAlexander Motin be_lun->pblockmul = 1; 1068e7037673SAlexander Motin cbe_lun->pblockexp = 0; 1069130f4520SKenneth D. Merry } 1070130f4520SKenneth D. Merry 1071130f4520SKenneth D. Merry /* Tell the user the blocksize we ended up using */ 10720bcd4ab6SAlexander Motin params->blocksize_bytes = cbe_lun->blocksize; 1073130f4520SKenneth D. Merry params->lun_size_bytes = be_lun->size_bytes; 1074130f4520SKenneth D. Merry 10758951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "unmap", NULL); 10761173e5a7SAlexander Motin if (value == NULL || strcmp(value, "off") != 0) 10770bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 10788951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "readonly", NULL); 107991be33dcSAlexander Motin if (value != NULL) { 108091be33dcSAlexander Motin if (strcmp(value, "on") == 0) 108191be33dcSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 108291be33dcSAlexander Motin } else if (cbe_lun->lun_type != T_DIRECT) 10830bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 10840bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 10858951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "serseq", NULL); 10860bcd4ab6SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 10870bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 10880bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "read") == 0) 10890bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 10900bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "off") == 0) 10910bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 1092130f4520SKenneth D. Merry 1093130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_ID_REQ) { 10940bcd4ab6SAlexander Motin cbe_lun->req_lun_id = params->req_lun_id; 10950bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 1096130f4520SKenneth D. Merry } else 10970bcd4ab6SAlexander Motin cbe_lun->req_lun_id = 0; 1098130f4520SKenneth D. Merry 10990bcd4ab6SAlexander Motin cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 11000bcd4ab6SAlexander Motin cbe_lun->lun_config_status = ctl_backend_ramdisk_lun_config_status; 11010bcd4ab6SAlexander Motin cbe_lun->be = &ctl_be_ramdisk_driver; 1102130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 110371cd87c6SAlan Somers snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%04d", 1104130f4520SKenneth D. Merry softc->num_luns); 11050bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, tmpstr, 11060bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 1107130f4520SKenneth D. Merry 1108130f4520SKenneth D. Merry /* Tell the user what we used for a serial number */ 1109130f4520SKenneth D. Merry strncpy((char *)params->serial_num, tmpstr, 1110e7038eb7SAlexander Motin MIN(sizeof(params->serial_num), sizeof(tmpstr))); 1111130f4520SKenneth D. Merry } else { 11120bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, params->serial_num, 11130bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), 1114130f4520SKenneth D. Merry sizeof(params->serial_num))); 1115130f4520SKenneth D. Merry } 1116130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 111771cd87c6SAlan Somers snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%04d", softc->num_luns); 11180bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, tmpstr, 11190bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 1120130f4520SKenneth D. Merry 1121130f4520SKenneth D. Merry /* Tell the user what we used for a device ID */ 1122130f4520SKenneth D. Merry strncpy((char *)params->device_id, tmpstr, 1123e7038eb7SAlexander Motin MIN(sizeof(params->device_id), sizeof(tmpstr))); 1124130f4520SKenneth D. Merry } else { 11250bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, params->device_id, 11260bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), 1127130f4520SKenneth D. Merry sizeof(params->device_id))); 1128130f4520SKenneth D. Merry } 1129130f4520SKenneth D. Merry 113008a7cce5SAlexander Motin STAILQ_INIT(&be_lun->cont_queue); 1131e7037673SAlexander Motin sx_init(&be_lun->page_lock, "cram page lock"); 11322fb36370SAlexander Motin if (be_lun->cap_bytes == 0) { 11332fb36370SAlexander Motin be_lun->indir = 0; 1134e7037673SAlexander Motin be_lun->pages = malloc(be_lun->pblocksize, M_RAMDISK, M_WAITOK); 11352fb36370SAlexander Motin } 1136e7037673SAlexander Motin be_lun->zero_page = malloc(be_lun->pblocksize, M_RAMDISK, 1137e7037673SAlexander Motin M_WAITOK|M_ZERO); 113875c7a1d3SAlexander Motin mtx_init(&be_lun->queue_lock, "cram queue lock", NULL, MTX_DEF); 113908a7cce5SAlexander Motin TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 114008a7cce5SAlexander Motin be_lun); 114108a7cce5SAlexander Motin 114208a7cce5SAlexander Motin be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 114308a7cce5SAlexander Motin taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 114408a7cce5SAlexander Motin if (be_lun->io_taskqueue == NULL) { 114508a7cce5SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 114608a7cce5SAlexander Motin "%s: Unable to create taskqueue", __func__); 114708a7cce5SAlexander Motin goto bailout_error; 114808a7cce5SAlexander Motin } 114908a7cce5SAlexander Motin 115008a7cce5SAlexander Motin retval = taskqueue_start_threads(&be_lun->io_taskqueue, 115108a7cce5SAlexander Motin /*num threads*/1, 1152053db1feSAlexander Motin /*priority*/PUSER, 115308a7cce5SAlexander Motin /*thread name*/ 115408a7cce5SAlexander Motin "%s taskq", be_lun->lunname); 115508a7cce5SAlexander Motin if (retval != 0) 115608a7cce5SAlexander Motin goto bailout_error; 115708a7cce5SAlexander Motin 1158130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1159130f4520SKenneth D. Merry softc->num_luns++; 1160130f4520SKenneth D. Merry STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 1161130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1162130f4520SKenneth D. Merry 11630bcd4ab6SAlexander Motin retval = ctl_add_lun(&be_lun->cbe_lun); 1164130f4520SKenneth D. Merry if (retval != 0) { 1165130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1166130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 1167130f4520SKenneth D. Merry links); 1168130f4520SKenneth D. Merry softc->num_luns--; 1169130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1170130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1171130f4520SKenneth D. Merry "%s: ctl_add_lun() returned error %d, see dmesg for " 1172130f4520SKenneth D. Merry "details", __func__, retval); 1173130f4520SKenneth D. Merry retval = 0; 1174130f4520SKenneth D. Merry goto bailout_error; 1175130f4520SKenneth D. Merry } 1176130f4520SKenneth D. Merry 1177130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1178130f4520SKenneth D. Merry 1179130f4520SKenneth D. Merry /* 1180130f4520SKenneth D. Merry * Tell the config_status routine that we're waiting so it won't 1181130f4520SKenneth D. Merry * clean up the LUN in the event of an error. 1182130f4520SKenneth D. Merry */ 1183130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 1184130f4520SKenneth D. Merry 1185130f4520SKenneth D. Merry while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 1186130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 1187130f4520SKenneth D. Merry if (retval == EINTR) 1188130f4520SKenneth D. Merry break; 1189130f4520SKenneth D. Merry } 1190130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 1191130f4520SKenneth D. Merry 1192130f4520SKenneth D. Merry if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) { 1193130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1194130f4520SKenneth D. Merry "%s: LUN configuration error, see dmesg for details", 1195130f4520SKenneth D. Merry __func__); 1196130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 1197130f4520SKenneth D. Merry links); 1198130f4520SKenneth D. Merry softc->num_luns--; 1199130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1200130f4520SKenneth D. Merry goto bailout_error; 1201130f4520SKenneth D. Merry } else { 12020bcd4ab6SAlexander Motin params->req_lun_id = cbe_lun->lun_id; 1203130f4520SKenneth D. Merry } 1204130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1205130f4520SKenneth D. Merry 1206130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 1207130f4520SKenneth D. Merry return (retval); 1208130f4520SKenneth D. Merry 1209130f4520SKenneth D. Merry bailout_error: 1210130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 121108a7cce5SAlexander Motin if (be_lun != NULL) { 1212e7037673SAlexander Motin if (be_lun->io_taskqueue != NULL) 121308a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 12148951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 1215e7037673SAlexander Motin free(be_lun->zero_page, M_RAMDISK); 1216e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 1217e7037673SAlexander Motin sx_destroy(&be_lun->page_lock); 121875c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 1219130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 122008a7cce5SAlexander Motin } 1221130f4520SKenneth D. Merry return (retval); 1222130f4520SKenneth D. Merry } 1223130f4520SKenneth D. Merry 122481177295SEdward Tomasz Napierala static int 122581177295SEdward Tomasz Napierala ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 122681177295SEdward Tomasz Napierala struct ctl_lun_req *req) 122781177295SEdward Tomasz Napierala { 122881177295SEdward Tomasz Napierala struct ctl_be_ramdisk_lun *be_lun; 1229a3977beaSAlexander Motin struct ctl_be_lun *cbe_lun; 123081177295SEdward Tomasz Napierala struct ctl_lun_modify_params *params; 12318951f055SMarcelo Araujo const char *value; 123281177295SEdward Tomasz Napierala uint32_t blocksize; 12337ac58230SAlexander Motin int wasprim; 123481177295SEdward Tomasz Napierala 123581177295SEdward Tomasz Napierala params = &req->reqdata.modify; 123681177295SEdward Tomasz Napierala 123781177295SEdward Tomasz Napierala mtx_lock(&softc->lock); 123881177295SEdward Tomasz Napierala STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 12390bcd4ab6SAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) 124081177295SEdward Tomasz Napierala break; 124181177295SEdward Tomasz Napierala } 124281177295SEdward Tomasz Napierala mtx_unlock(&softc->lock); 124381177295SEdward Tomasz Napierala if (be_lun == NULL) { 124481177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 124581177295SEdward Tomasz Napierala "%s: LUN %u is not managed by the ramdisk backend", 124681177295SEdward Tomasz Napierala __func__, params->lun_id); 124781177295SEdward Tomasz Napierala goto bailout_error; 124881177295SEdward Tomasz Napierala } 1249a3977beaSAlexander Motin cbe_lun = &be_lun->cbe_lun; 125081177295SEdward Tomasz Napierala 1251a3977beaSAlexander Motin if (params->lun_size_bytes != 0) 1252a3977beaSAlexander Motin be_lun->params.lun_size_bytes = params->lun_size_bytes; 12538951f055SMarcelo Araujo 12548951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 12558951f055SMarcelo Araujo cbe_lun->options = nvlist_clone(req->args_nvl); 125681177295SEdward Tomasz Napierala 12577ac58230SAlexander Motin wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 12588951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 12597ac58230SAlexander Motin if (value != NULL) { 12607ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 12617ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 12627ac58230SAlexander Motin else 12637ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 12647ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 12657ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 12667ac58230SAlexander Motin else 12677ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 12687ac58230SAlexander Motin if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 12697ac58230SAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 12707ac58230SAlexander Motin ctl_lun_primary(cbe_lun); 12717ac58230SAlexander Motin else 12727ac58230SAlexander Motin ctl_lun_secondary(cbe_lun); 12737ac58230SAlexander Motin } 12747ac58230SAlexander Motin 12757ac58230SAlexander Motin blocksize = be_lun->cbe_lun.blocksize; 1276a3977beaSAlexander Motin if (be_lun->params.lun_size_bytes < blocksize) { 127781177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 127881177295SEdward Tomasz Napierala "%s: LUN size %ju < blocksize %u", __func__, 1279a3977beaSAlexander Motin be_lun->params.lun_size_bytes, blocksize); 128081177295SEdward Tomasz Napierala goto bailout_error; 128181177295SEdward Tomasz Napierala } 1282a3977beaSAlexander Motin be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize; 128381177295SEdward Tomasz Napierala be_lun->size_bytes = be_lun->size_blocks * blocksize; 12840bcd4ab6SAlexander Motin be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1; 12850bcd4ab6SAlexander Motin ctl_lun_capacity_changed(&be_lun->cbe_lun); 128681177295SEdward Tomasz Napierala 128781177295SEdward Tomasz Napierala /* Tell the user the exact size we ended up using */ 128881177295SEdward Tomasz Napierala params->lun_size_bytes = be_lun->size_bytes; 128981177295SEdward Tomasz Napierala 129081177295SEdward Tomasz Napierala req->status = CTL_LUN_OK; 129181177295SEdward Tomasz Napierala return (0); 129281177295SEdward Tomasz Napierala 129381177295SEdward Tomasz Napierala bailout_error: 129481177295SEdward Tomasz Napierala req->status = CTL_LUN_ERROR; 129581177295SEdward Tomasz Napierala return (0); 129681177295SEdward Tomasz Napierala } 129781177295SEdward Tomasz Napierala 1298130f4520SKenneth D. Merry static void 1299130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_shutdown(void *be_lun) 1300130f4520SKenneth D. Merry { 130168bf823fSAlexander Motin struct ctl_be_ramdisk_lun *lun = be_lun; 130268bf823fSAlexander Motin struct ctl_be_ramdisk_softc *softc = lun->softc; 1303130f4520SKenneth D. Merry 1304130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1305130f4520SKenneth D. Merry lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 1306130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 1307130f4520SKenneth D. Merry wakeup(lun); 1308130f4520SKenneth D. Merry } else { 1309e2507751SAlexander Motin STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 1310130f4520SKenneth D. Merry links); 1311130f4520SKenneth D. Merry softc->num_luns--; 131268bf823fSAlexander Motin free(be_lun, M_RAMDISK); 1313130f4520SKenneth D. Merry } 1314130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1315130f4520SKenneth D. Merry } 1316130f4520SKenneth D. Merry 1317130f4520SKenneth D. Merry static void 1318130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_config_status(void *be_lun, 1319130f4520SKenneth D. Merry ctl_lun_config_status status) 1320130f4520SKenneth D. Merry { 1321130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun; 1322130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 1323130f4520SKenneth D. Merry 1324130f4520SKenneth D. Merry lun = (struct ctl_be_ramdisk_lun *)be_lun; 1325130f4520SKenneth D. Merry softc = lun->softc; 1326130f4520SKenneth D. Merry 1327130f4520SKenneth D. Merry if (status == CTL_LUN_CONFIG_OK) { 1328130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1329130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 1330130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 1331130f4520SKenneth D. Merry wakeup(lun); 1332130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1333130f4520SKenneth D. Merry 1334130f4520SKenneth D. Merry /* 1335130f4520SKenneth D. Merry * We successfully added the LUN, attempt to enable it. 1336130f4520SKenneth D. Merry */ 13370bcd4ab6SAlexander Motin if (ctl_enable_lun(&lun->cbe_lun) != 0) { 1338130f4520SKenneth D. Merry printf("%s: ctl_enable_lun() failed!\n", __func__); 13390bcd4ab6SAlexander Motin if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 1340130f4520SKenneth D. Merry printf("%s: ctl_invalidate_lun() failed!\n", 1341130f4520SKenneth D. Merry __func__); 1342130f4520SKenneth D. Merry } 1343130f4520SKenneth D. Merry } 1344130f4520SKenneth D. Merry 1345130f4520SKenneth D. Merry return; 1346130f4520SKenneth D. Merry } 1347130f4520SKenneth D. Merry 1348130f4520SKenneth D. Merry 1349130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1350130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 1351130f4520SKenneth D. Merry 1352130f4520SKenneth D. Merry /* 1353130f4520SKenneth D. Merry * If we have a user waiting, let him handle the cleanup. If not, 1354130f4520SKenneth D. Merry * clean things up here. 1355130f4520SKenneth D. Merry */ 1356130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 1357130f4520SKenneth D. Merry lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR; 1358130f4520SKenneth D. Merry wakeup(lun); 1359130f4520SKenneth D. Merry } else { 1360130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 1361130f4520SKenneth D. Merry links); 1362130f4520SKenneth D. Merry softc->num_luns--; 1363130f4520SKenneth D. Merry free(lun, M_RAMDISK); 1364130f4520SKenneth D. Merry } 1365130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1366130f4520SKenneth D. Merry } 1367