1130f4520SKenneth D. Merry /*- 2130f4520SKenneth D. Merry * Copyright (c) 2003, 2008 Silicon Graphics International Corp. 381177295SEdward Tomasz Napierala * Copyright (c) 2012 The FreeBSD Foundation 4e7037673SAlexander Motin * Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org> 5130f4520SKenneth D. Merry * All rights reserved. 6130f4520SKenneth D. Merry * 781177295SEdward Tomasz Napierala * Portions of this software were developed by Edward Tomasz Napierala 881177295SEdward Tomasz Napierala * under sponsorship from the FreeBSD Foundation. 981177295SEdward Tomasz Napierala * 10130f4520SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 11130f4520SKenneth D. Merry * modification, are permitted provided that the following conditions 12130f4520SKenneth D. Merry * are met: 13130f4520SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 14130f4520SKenneth D. Merry * notice, this list of conditions, and the following disclaimer, 15130f4520SKenneth D. Merry * without modification. 16130f4520SKenneth D. Merry * 2. Redistributions in binary form must reproduce at minimum a disclaimer 17130f4520SKenneth D. Merry * substantially similar to the "NO WARRANTY" disclaimer below 18130f4520SKenneth D. Merry * ("Disclaimer") and any redistribution must be conditioned upon 19130f4520SKenneth D. Merry * including a substantially similar Disclaimer requirement for further 20130f4520SKenneth D. Merry * binary redistribution. 21130f4520SKenneth D. Merry * 22130f4520SKenneth D. Merry * NO WARRANTY 23130f4520SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24130f4520SKenneth D. Merry * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25130f4520SKenneth D. Merry * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 26130f4520SKenneth D. Merry * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27130f4520SKenneth D. Merry * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28130f4520SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29130f4520SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30130f4520SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31130f4520SKenneth D. Merry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 32130f4520SKenneth D. Merry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33130f4520SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGES. 34130f4520SKenneth D. Merry * 35130f4520SKenneth D. Merry * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $ 36130f4520SKenneth D. Merry */ 37130f4520SKenneth D. Merry /* 38e7037673SAlexander Motin * CAM Target Layer black hole and RAM disk backend. 39130f4520SKenneth D. Merry * 40130f4520SKenneth D. Merry * Author: Ken Merry <ken@FreeBSD.org> 41130f4520SKenneth D. Merry */ 42130f4520SKenneth D. Merry 43130f4520SKenneth D. Merry #include <sys/cdefs.h> 44130f4520SKenneth D. Merry __FBSDID("$FreeBSD$"); 45130f4520SKenneth D. Merry 46130f4520SKenneth D. Merry #include <sys/param.h> 47130f4520SKenneth D. Merry #include <sys/systm.h> 48130f4520SKenneth D. Merry #include <sys/kernel.h> 49130f4520SKenneth D. Merry #include <sys/condvar.h> 50130f4520SKenneth D. Merry #include <sys/types.h> 51e7037673SAlexander Motin #include <sys/limits.h> 52130f4520SKenneth D. Merry #include <sys/lock.h> 53130f4520SKenneth D. Merry #include <sys/mutex.h> 54130f4520SKenneth D. Merry #include <sys/malloc.h> 55e7037673SAlexander Motin #include <sys/sx.h> 5608a7cce5SAlexander Motin #include <sys/taskqueue.h> 57130f4520SKenneth D. Merry #include <sys/time.h> 58130f4520SKenneth D. Merry #include <sys/queue.h> 59130f4520SKenneth D. Merry #include <sys/conf.h> 60130f4520SKenneth D. Merry #include <sys/ioccom.h> 61130f4520SKenneth D. Merry #include <sys/module.h> 627ac58230SAlexander Motin #include <sys/sysctl.h> 63130f4520SKenneth D. Merry 64130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 657ac58230SAlexander Motin #include <cam/scsi/scsi_da.h> 66130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 67130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 68130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h> 69130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h> 70130f4520SKenneth D. Merry #include <cam/ctl/ctl_debug.h> 71130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h> 727ac58230SAlexander Motin #include <cam/ctl/ctl_ha.h> 737ac58230SAlexander Motin #include <cam/ctl/ctl_private.h> 74130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h> 75130f4520SKenneth D. Merry 76e7037673SAlexander Motin #define PRIV(io) \ 77e7037673SAlexander Motin ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND]) 78e7037673SAlexander Motin #define ARGS(io) \ 79e7037673SAlexander Motin ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]) 80e7037673SAlexander Motin 81e7037673SAlexander Motin #define PPP (PAGE_SIZE / sizeof(uint8_t **)) 82e7037673SAlexander Motin #ifdef __LP64__ 83e7037673SAlexander Motin #define PPPS (PAGE_SHIFT - 3) 84e7037673SAlexander Motin #else 85e7037673SAlexander Motin #define PPPS (PAGE_SHIFT - 2) 86e7037673SAlexander Motin #endif 87e7037673SAlexander Motin #define SGPP (PAGE_SIZE / sizeof(struct ctl_sg_entry)) 88e7037673SAlexander Motin 89e7037673SAlexander Motin #define P_UNMAPPED NULL /* Page is unmapped. */ 90e7037673SAlexander Motin #define P_ANCHORED ((void *)(uintptr_t)1) /* Page is anchored. */ 91e7037673SAlexander Motin 92e7037673SAlexander Motin typedef enum { 93e7037673SAlexander Motin GP_READ, /* Return data page or zero page. */ 94e7037673SAlexander Motin GP_WRITE, /* Return data page, try allocate if none. */ 95e7037673SAlexander Motin GP_ANCHOR, /* Return data page, try anchor if none. */ 96e7037673SAlexander Motin GP_OTHER, /* Return what present, do not allocate/anchor. */ 97e7037673SAlexander Motin } getpage_op_t; 98e7037673SAlexander Motin 99130f4520SKenneth D. Merry typedef enum { 100130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_UNCONFIGURED = 0x01, 101130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_CONFIG_ERR = 0x02, 102130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_WAITING = 0x04 103130f4520SKenneth D. Merry } ctl_be_ramdisk_lun_flags; 104130f4520SKenneth D. Merry 105130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun { 106a3977beaSAlexander Motin struct ctl_lun_create_params params; 10708a7cce5SAlexander Motin char lunname[32]; 108e7037673SAlexander Motin int indir; 109e7037673SAlexander Motin uint8_t **pages; 110e7037673SAlexander Motin uint8_t *zero_page; 111e7037673SAlexander Motin struct sx page_lock; 112e7037673SAlexander Motin u_int pblocksize; 113e7037673SAlexander Motin u_int pblockmul; 114130f4520SKenneth D. Merry uint64_t size_bytes; 115130f4520SKenneth D. Merry uint64_t size_blocks; 116e7037673SAlexander Motin uint64_t cap_bytes; 117e7037673SAlexander Motin uint64_t cap_used; 118130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 119130f4520SKenneth D. Merry ctl_be_ramdisk_lun_flags flags; 120130f4520SKenneth D. Merry STAILQ_ENTRY(ctl_be_ramdisk_lun) links; 1210bcd4ab6SAlexander Motin struct ctl_be_lun cbe_lun; 12208a7cce5SAlexander Motin struct taskqueue *io_taskqueue; 12308a7cce5SAlexander Motin struct task io_task; 12408a7cce5SAlexander Motin STAILQ_HEAD(, ctl_io_hdr) cont_queue; 12575c7a1d3SAlexander Motin struct mtx_padalign queue_lock; 126130f4520SKenneth D. Merry }; 127130f4520SKenneth D. Merry 128130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc { 129130f4520SKenneth D. Merry struct mtx lock; 130130f4520SKenneth D. Merry int num_luns; 131130f4520SKenneth D. Merry STAILQ_HEAD(, ctl_be_ramdisk_lun) lun_list; 132130f4520SKenneth D. Merry }; 133130f4520SKenneth D. Merry 134130f4520SKenneth D. Merry static struct ctl_be_ramdisk_softc rd_softc; 1357ac58230SAlexander Motin extern struct ctl_softc *control_softc; 136130f4520SKenneth D. Merry 1370c629e28SAlexander Motin static int ctl_backend_ramdisk_init(void); 1380c629e28SAlexander Motin static int ctl_backend_ramdisk_shutdown(void); 139130f4520SKenneth D. Merry static int ctl_backend_ramdisk_move_done(union ctl_io *io); 140e7037673SAlexander Motin static void ctl_backend_ramdisk_compare(union ctl_io *io); 141e7037673SAlexander Motin static void ctl_backend_ramdisk_rw(union ctl_io *io); 142130f4520SKenneth D. Merry static int ctl_backend_ramdisk_submit(union ctl_io *io); 143e7037673SAlexander Motin static void ctl_backend_ramdisk_worker(void *context, int pending); 144e7037673SAlexander Motin static int ctl_backend_ramdisk_config_read(union ctl_io *io); 145e7037673SAlexander Motin static int ctl_backend_ramdisk_config_write(union ctl_io *io); 146e7037673SAlexander Motin static uint64_t ctl_backend_ramdisk_lun_attr(void *be_lun, const char *attrname); 147130f4520SKenneth D. Merry static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, 148130f4520SKenneth D. Merry caddr_t addr, int flag, struct thread *td); 149130f4520SKenneth D. Merry static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 150130f4520SKenneth D. Merry struct ctl_lun_req *req); 151130f4520SKenneth D. Merry static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 1520bcd4ab6SAlexander Motin struct ctl_lun_req *req); 15381177295SEdward Tomasz Napierala static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 15481177295SEdward Tomasz Napierala struct ctl_lun_req *req); 155130f4520SKenneth D. Merry static void ctl_backend_ramdisk_lun_shutdown(void *be_lun); 156130f4520SKenneth D. Merry static void ctl_backend_ramdisk_lun_config_status(void *be_lun, 157130f4520SKenneth D. Merry ctl_lun_config_status status); 158130f4520SKenneth D. Merry 159130f4520SKenneth D. Merry static struct ctl_backend_driver ctl_be_ramdisk_driver = 160130f4520SKenneth D. Merry { 1612a2443d8SKenneth D. Merry .name = "ramdisk", 1622a2443d8SKenneth D. Merry .flags = CTL_BE_FLAG_HAS_CONFIG, 1632a2443d8SKenneth D. Merry .init = ctl_backend_ramdisk_init, 1640c629e28SAlexander Motin .shutdown = ctl_backend_ramdisk_shutdown, 1652a2443d8SKenneth D. Merry .data_submit = ctl_backend_ramdisk_submit, 1662a2443d8SKenneth D. Merry .data_move_done = ctl_backend_ramdisk_move_done, 1672a2443d8SKenneth D. Merry .config_read = ctl_backend_ramdisk_config_read, 1682a2443d8SKenneth D. Merry .config_write = ctl_backend_ramdisk_config_write, 169e7037673SAlexander Motin .ioctl = ctl_backend_ramdisk_ioctl, 170e7037673SAlexander Motin .lun_attr = ctl_backend_ramdisk_lun_attr, 171130f4520SKenneth D. Merry }; 172130f4520SKenneth D. Merry 173130f4520SKenneth D. Merry MALLOC_DEFINE(M_RAMDISK, "ramdisk", "Memory used for CTL RAMdisk"); 174130f4520SKenneth D. Merry CTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver); 175130f4520SKenneth D. Merry 176e7037673SAlexander Motin static int 177130f4520SKenneth D. Merry ctl_backend_ramdisk_init(void) 178130f4520SKenneth D. Merry { 17967cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 180130f4520SKenneth D. Merry 181130f4520SKenneth D. Merry memset(softc, 0, sizeof(*softc)); 18275c7a1d3SAlexander Motin mtx_init(&softc->lock, "ctlramdisk", NULL, MTX_DEF); 183130f4520SKenneth D. Merry STAILQ_INIT(&softc->lun_list); 184130f4520SKenneth D. Merry return (0); 185130f4520SKenneth D. Merry } 186130f4520SKenneth D. Merry 1870c629e28SAlexander Motin static int 188130f4520SKenneth D. Merry ctl_backend_ramdisk_shutdown(void) 189130f4520SKenneth D. Merry { 19067cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 191130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun, *next_lun; 192130f4520SKenneth D. Merry 193130f4520SKenneth D. Merry mtx_lock(&softc->lock); 194f5a2bbe6SAlexander Motin STAILQ_FOREACH_SAFE(lun, &softc->lun_list, links, next_lun) { 195130f4520SKenneth D. Merry /* 196130f4520SKenneth D. Merry * Drop our lock here. Since ctl_invalidate_lun() can call 197130f4520SKenneth D. Merry * back into us, this could potentially lead to a recursive 198130f4520SKenneth D. Merry * lock of the same mutex, which would cause a hang. 199130f4520SKenneth D. Merry */ 200130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2010bcd4ab6SAlexander Motin ctl_disable_lun(&lun->cbe_lun); 2020bcd4ab6SAlexander Motin ctl_invalidate_lun(&lun->cbe_lun); 203130f4520SKenneth D. Merry mtx_lock(&softc->lock); 204130f4520SKenneth D. Merry } 205130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2060c629e28SAlexander Motin mtx_destroy(&softc->lock); 2070c629e28SAlexander Motin return (0); 208130f4520SKenneth D. Merry } 209130f4520SKenneth D. Merry 210e7037673SAlexander Motin static uint8_t * 211e7037673SAlexander Motin ctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn, 212e7037673SAlexander Motin getpage_op_t op) 213e7037673SAlexander Motin { 214e7037673SAlexander Motin uint8_t **p, ***pp; 215e7037673SAlexander Motin off_t i; 216e7037673SAlexander Motin int s; 217e7037673SAlexander Motin 218e7037673SAlexander Motin if (be_lun->cap_bytes == 0) { 219e7037673SAlexander Motin switch (op) { 220e7037673SAlexander Motin case GP_READ: 221e7037673SAlexander Motin return (be_lun->zero_page); 222e7037673SAlexander Motin case GP_WRITE: 223e7037673SAlexander Motin return ((uint8_t *)be_lun->pages); 224e7037673SAlexander Motin case GP_ANCHOR: 225e7037673SAlexander Motin return (P_ANCHORED); 226e7037673SAlexander Motin default: 227e7037673SAlexander Motin return (P_UNMAPPED); 228e7037673SAlexander Motin } 229e7037673SAlexander Motin } 230e7037673SAlexander Motin if (op == GP_WRITE || op == GP_ANCHOR) { 231e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 232e7037673SAlexander Motin pp = &be_lun->pages; 233e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 234e7037673SAlexander Motin if (*pp == NULL) { 235e7037673SAlexander Motin *pp = malloc(PAGE_SIZE, M_RAMDISK, 236e7037673SAlexander Motin M_WAITOK|M_ZERO); 237e7037673SAlexander Motin } 238e7037673SAlexander Motin i = pn >> s; 239e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 240e7037673SAlexander Motin pn -= i << s; 241e7037673SAlexander Motin } 242e7037673SAlexander Motin if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 243e7037673SAlexander Motin if (op == GP_WRITE) { 244e7037673SAlexander Motin *pp = malloc(be_lun->pblocksize, M_RAMDISK, 245e7037673SAlexander Motin M_WAITOK|M_ZERO); 246e7037673SAlexander Motin } else 247e7037673SAlexander Motin *pp = P_ANCHORED; 248e7037673SAlexander Motin be_lun->cap_used += be_lun->pblocksize; 249e7037673SAlexander Motin } else if (*pp == P_ANCHORED && op == GP_WRITE) { 250e7037673SAlexander Motin *pp = malloc(be_lun->pblocksize, M_RAMDISK, 251e7037673SAlexander Motin M_WAITOK|M_ZERO); 252e7037673SAlexander Motin } 253e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 254e7037673SAlexander Motin return ((uint8_t *)*pp); 255e7037673SAlexander Motin } else { 256e7037673SAlexander Motin sx_slock(&be_lun->page_lock); 257e7037673SAlexander Motin p = be_lun->pages; 258e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 259e7037673SAlexander Motin if (p == NULL) 260e7037673SAlexander Motin break; 261e7037673SAlexander Motin i = pn >> s; 262e7037673SAlexander Motin p = (uint8_t **)p[i]; 263e7037673SAlexander Motin pn -= i << s; 264e7037673SAlexander Motin } 265e7037673SAlexander Motin sx_sunlock(&be_lun->page_lock); 266e7037673SAlexander Motin if ((p == P_UNMAPPED || p == P_ANCHORED) && op == GP_READ) 267e7037673SAlexander Motin return (be_lun->zero_page); 268e7037673SAlexander Motin return ((uint8_t *)p); 269e7037673SAlexander Motin } 270e7037673SAlexander Motin }; 271e7037673SAlexander Motin 272e7037673SAlexander Motin static void 273e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 274e7037673SAlexander Motin { 275e7037673SAlexander Motin uint8_t ***pp; 276e7037673SAlexander Motin off_t i; 277e7037673SAlexander Motin int s; 278e7037673SAlexander Motin 279e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 280e7037673SAlexander Motin return; 281e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 282e7037673SAlexander Motin pp = &be_lun->pages; 283e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 284e7037673SAlexander Motin if (*pp == NULL) 285e7037673SAlexander Motin goto noindir; 286e7037673SAlexander Motin i = pn >> s; 287e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 288e7037673SAlexander Motin pn -= i << s; 289e7037673SAlexander Motin } 290e7037673SAlexander Motin if (*pp == P_ANCHORED) { 291e7037673SAlexander Motin be_lun->cap_used -= be_lun->pblocksize; 292e7037673SAlexander Motin *pp = P_UNMAPPED; 293e7037673SAlexander Motin } else if (*pp != P_UNMAPPED) { 294e7037673SAlexander Motin free(*pp, M_RAMDISK); 295e7037673SAlexander Motin be_lun->cap_used -= be_lun->pblocksize; 296e7037673SAlexander Motin *pp = P_UNMAPPED; 297e7037673SAlexander Motin } 298e7037673SAlexander Motin noindir: 299e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 300e7037673SAlexander Motin }; 301e7037673SAlexander Motin 302e7037673SAlexander Motin static void 303e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 304e7037673SAlexander Motin { 305e7037673SAlexander Motin uint8_t ***pp; 306e7037673SAlexander Motin off_t i; 307e7037673SAlexander Motin int s; 308e7037673SAlexander Motin 309e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 310e7037673SAlexander Motin return; 311e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 312e7037673SAlexander Motin pp = &be_lun->pages; 313e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 314e7037673SAlexander Motin if (*pp == NULL) 315e7037673SAlexander Motin goto noindir; 316e7037673SAlexander Motin i = pn >> s; 317e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 318e7037673SAlexander Motin pn -= i << s; 319e7037673SAlexander Motin } 320e7037673SAlexander Motin if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 321e7037673SAlexander Motin be_lun->cap_used += be_lun->pblocksize; 322e7037673SAlexander Motin *pp = P_ANCHORED; 323e7037673SAlexander Motin } else if (*pp != P_ANCHORED) { 324e7037673SAlexander Motin free(*pp, M_RAMDISK); 325e7037673SAlexander Motin *pp = P_ANCHORED; 326e7037673SAlexander Motin } 327e7037673SAlexander Motin noindir: 328e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 329e7037673SAlexander Motin }; 330e7037673SAlexander Motin 331e7037673SAlexander Motin static void 332e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(uint8_t **p, int indir) 333e7037673SAlexander Motin { 334e7037673SAlexander Motin int i; 335e7037673SAlexander Motin 336e7037673SAlexander Motin if (p == NULL) 337e7037673SAlexander Motin return; 338e7037673SAlexander Motin if (indir == 0) { 339e7037673SAlexander Motin free(p, M_RAMDISK); 340e7037673SAlexander Motin return; 341e7037673SAlexander Motin } 342e7037673SAlexander Motin for (i = 0; i < PPP; i++) { 343e7037673SAlexander Motin if (p[i] == NULL) 344e7037673SAlexander Motin continue; 345e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages((uint8_t **)p[i], indir - 1); 346e7037673SAlexander Motin } 347e7037673SAlexander Motin free(p, M_RAMDISK); 348e7037673SAlexander Motin }; 349e7037673SAlexander Motin 350e7037673SAlexander Motin static size_t 351e7037673SAlexander Motin cmp(uint8_t *a, uint8_t *b, size_t size) 352e7037673SAlexander Motin { 353e7037673SAlexander Motin size_t i; 354e7037673SAlexander Motin 355e7037673SAlexander Motin for (i = 0; i < size; i++) { 356e7037673SAlexander Motin if (a[i] != b[i]) 357e7037673SAlexander Motin break; 358e7037673SAlexander Motin } 359e7037673SAlexander Motin return (i); 360e7037673SAlexander Motin } 361e7037673SAlexander Motin 362e7037673SAlexander Motin static int 363e7037673SAlexander Motin ctl_backend_ramdisk_cmp(union ctl_io *io) 364e7037673SAlexander Motin { 365e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 366e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 367e7037673SAlexander Motin uint8_t *page; 368e7037673SAlexander Motin uint8_t info[8]; 369e7037673SAlexander Motin uint64_t lba; 370e7037673SAlexander Motin u_int lbaoff, lbas, res, off; 371e7037673SAlexander Motin 372e7037673SAlexander Motin lbas = io->scsiio.kern_data_len / cbe_lun->blocksize; 373e7037673SAlexander Motin lba = ARGS(io)->lba + PRIV(io)->len - lbas; 374e7037673SAlexander Motin off = 0; 375e7037673SAlexander Motin for (; lbas > 0; lbas--, lba++) { 376e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 377e7037673SAlexander Motin lba >> cbe_lun->pblockexp, GP_READ); 378e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 379e7037673SAlexander Motin page += lbaoff * cbe_lun->blocksize; 380e7037673SAlexander Motin res = cmp(io->scsiio.kern_data_ptr + off, page, 381e7037673SAlexander Motin cbe_lun->blocksize); 382e7037673SAlexander Motin off += res; 383e7037673SAlexander Motin if (res < cbe_lun->blocksize) 384e7037673SAlexander Motin break; 385e7037673SAlexander Motin } 386e7037673SAlexander Motin if (lbas > 0) { 387e7037673SAlexander Motin off += io->scsiio.kern_rel_offset - io->scsiio.kern_data_len; 388e7037673SAlexander Motin scsi_u64to8b(off, info); 389e7037673SAlexander Motin ctl_set_sense(&io->scsiio, /*current_error*/ 1, 390e7037673SAlexander Motin /*sense_key*/ SSD_KEY_MISCOMPARE, 391e7037673SAlexander Motin /*asc*/ 0x1D, /*ascq*/ 0x00, 392e7037673SAlexander Motin /*type*/ SSD_ELEM_INFO, 393e7037673SAlexander Motin /*size*/ sizeof(info), /*data*/ &info, 394e7037673SAlexander Motin /*type*/ SSD_ELEM_NONE); 395e7037673SAlexander Motin return (1); 396e7037673SAlexander Motin } 397e7037673SAlexander Motin return (0); 398e7037673SAlexander Motin } 399e7037673SAlexander Motin 400130f4520SKenneth D. Merry static int 401130f4520SKenneth D. Merry ctl_backend_ramdisk_move_done(union ctl_io *io) 402130f4520SKenneth D. Merry { 403e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 404e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 405130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 406130f4520SKenneth D. Merry struct bintime cur_bt; 407130f4520SKenneth D. Merry #endif 408130f4520SKenneth D. Merry 409130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); 41008a7cce5SAlexander Motin #ifdef CTL_TIME_IO 411e675024aSAlexander Motin getbinuptime(&cur_bt); 41208a7cce5SAlexander Motin bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 41308a7cce5SAlexander Motin bintime_add(&io->io_hdr.dma_bt, &cur_bt); 41408a7cce5SAlexander Motin #endif 415e675024aSAlexander Motin io->io_hdr.num_dmas++; 41608a7cce5SAlexander Motin if (io->scsiio.kern_sg_entries > 0) 41708a7cce5SAlexander Motin free(io->scsiio.kern_data_ptr, M_RAMDISK); 41808a7cce5SAlexander Motin io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 419f7241cceSAlexander Motin if (io->io_hdr.flags & CTL_FLAG_ABORT) { 420f7241cceSAlexander Motin ; 421eb6ac6f9SAlexander Motin } else if (io->io_hdr.port_status != 0 && 422eb6ac6f9SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 423eb6ac6f9SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 424eb6ac6f9SAlexander Motin ctl_set_internal_failure(&io->scsiio, /*sks_valid*/ 1, 425eb6ac6f9SAlexander Motin /*retry_count*/ io->io_hdr.port_status); 426eb6ac6f9SAlexander Motin } else if (io->scsiio.kern_data_resid != 0 && 427eb6ac6f9SAlexander Motin (io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_OUT && 428eb6ac6f9SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 429eb6ac6f9SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 430eb6ac6f9SAlexander Motin ctl_set_invalid_field_ciu(&io->scsiio); 431f7241cceSAlexander Motin } else if ((io->io_hdr.port_status == 0) && 432f7241cceSAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 433e7037673SAlexander Motin if (ARGS(io)->flags & CTL_LLF_COMPARE) { 434e7037673SAlexander Motin /* We have data block ready for comparison. */ 435e7037673SAlexander Motin if (ctl_backend_ramdisk_cmp(io)) 436e7037673SAlexander Motin goto done; 437e7037673SAlexander Motin } 438e7037673SAlexander Motin if (ARGS(io)->len > PRIV(io)->len) { 43975c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 44008a7cce5SAlexander Motin STAILQ_INSERT_TAIL(&be_lun->cont_queue, 44108a7cce5SAlexander Motin &io->io_hdr, links); 44275c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 44308a7cce5SAlexander Motin taskqueue_enqueue(be_lun->io_taskqueue, 44408a7cce5SAlexander Motin &be_lun->io_task); 44508a7cce5SAlexander Motin return (0); 44608a7cce5SAlexander Motin } 4474a286345SAlexander Motin ctl_set_success(&io->scsiio); 448130f4520SKenneth D. Merry } 449e7037673SAlexander Motin done: 45011b569f7SAlexander Motin ctl_data_submit_done(io); 451130f4520SKenneth D. Merry return(0); 452130f4520SKenneth D. Merry } 453130f4520SKenneth D. Merry 454e7037673SAlexander Motin static void 455e7037673SAlexander Motin ctl_backend_ramdisk_compare(union ctl_io *io) 456e7037673SAlexander Motin { 457e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 458e7037673SAlexander Motin u_int lbas, len; 459e7037673SAlexander Motin 460e7037673SAlexander Motin lbas = ARGS(io)->len - PRIV(io)->len; 461e7037673SAlexander Motin lbas = MIN(lbas, 131072 / cbe_lun->blocksize); 462e7037673SAlexander Motin len = lbas * cbe_lun->blocksize; 463e7037673SAlexander Motin 464e7037673SAlexander Motin io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 465e7037673SAlexander Motin io->scsiio.kern_data_ptr = malloc(len, M_RAMDISK, M_WAITOK); 466e7037673SAlexander Motin io->scsiio.kern_data_len = len; 467e7037673SAlexander Motin io->scsiio.kern_sg_entries = 0; 468e7037673SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 469e7037673SAlexander Motin PRIV(io)->len += lbas; 470e7037673SAlexander Motin #ifdef CTL_TIME_IO 471e7037673SAlexander Motin getbinuptime(&io->io_hdr.dma_start_bt); 472e7037673SAlexander Motin #endif 473e7037673SAlexander Motin ctl_datamove(io); 474e7037673SAlexander Motin } 475e7037673SAlexander Motin 476e7037673SAlexander Motin static void 477e7037673SAlexander Motin ctl_backend_ramdisk_rw(union ctl_io *io) 478e7037673SAlexander Motin { 479e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 480e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 481e7037673SAlexander Motin struct ctl_sg_entry *sg_entries; 482e7037673SAlexander Motin uint8_t *page; 483e7037673SAlexander Motin uint64_t lba; 484e7037673SAlexander Motin u_int i, len, lbaoff, lbas, sgs, off; 485e7037673SAlexander Motin getpage_op_t op; 486e7037673SAlexander Motin 487e7037673SAlexander Motin lba = ARGS(io)->lba + PRIV(io)->len; 488e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 489e7037673SAlexander Motin lbas = ARGS(io)->len - PRIV(io)->len; 490e7037673SAlexander Motin lbas = MIN(lbas, (SGPP << cbe_lun->pblockexp) - lbaoff); 491e7037673SAlexander Motin sgs = (lbas + lbaoff + be_lun->pblockmul - 1) >> cbe_lun->pblockexp; 492e7037673SAlexander Motin off = lbaoff * cbe_lun->blocksize; 493e7037673SAlexander Motin op = (ARGS(io)->flags & CTL_LLF_WRITE) ? GP_WRITE : GP_READ; 494e7037673SAlexander Motin if (sgs > 1) { 495e7037673SAlexander Motin io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) * 496e7037673SAlexander Motin sgs, M_RAMDISK, M_WAITOK); 497e7037673SAlexander Motin sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 498e7037673SAlexander Motin len = lbas * cbe_lun->blocksize; 499e7037673SAlexander Motin for (i = 0; i < sgs; i++) { 500e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 501e7037673SAlexander Motin (lba >> cbe_lun->pblockexp) + i, op); 502e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) { 503e7037673SAlexander Motin free(io->scsiio.kern_data_ptr, M_RAMDISK); 504e7037673SAlexander Motin nospc: 505e7037673SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 506e7037673SAlexander Motin ctl_data_submit_done(io); 507e7037673SAlexander Motin return; 508e7037673SAlexander Motin } 509e7037673SAlexander Motin sg_entries[i].addr = page + off; 510e7037673SAlexander Motin sg_entries[i].len = MIN(len, be_lun->pblocksize - off); 511e7037673SAlexander Motin len -= sg_entries[i].len; 512e7037673SAlexander Motin off = 0; 513e7037673SAlexander Motin } 514e7037673SAlexander Motin } else { 515e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 516e7037673SAlexander Motin lba >> cbe_lun->pblockexp, op); 517e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) 518e7037673SAlexander Motin goto nospc; 519e7037673SAlexander Motin sgs = 0; 520e7037673SAlexander Motin io->scsiio.kern_data_ptr = page + off; 521e7037673SAlexander Motin } 522e7037673SAlexander Motin 523e7037673SAlexander Motin io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 524e7037673SAlexander Motin io->scsiio.kern_data_len = lbas * cbe_lun->blocksize; 525e7037673SAlexander Motin io->scsiio.kern_sg_entries = sgs; 526e7037673SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 527e7037673SAlexander Motin PRIV(io)->len += lbas; 528e7037673SAlexander Motin #ifdef CTL_TIME_IO 529e7037673SAlexander Motin getbinuptime(&io->io_hdr.dma_start_bt); 530e7037673SAlexander Motin #endif 531e7037673SAlexander Motin ctl_datamove(io); 532e7037673SAlexander Motin } 533e7037673SAlexander Motin 534130f4520SKenneth D. Merry static int 535130f4520SKenneth D. Merry ctl_backend_ramdisk_submit(union ctl_io *io) 536130f4520SKenneth D. Merry { 537e7037673SAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 538130f4520SKenneth D. Merry 53911b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_VERIFY) { 54011b569f7SAlexander Motin ctl_set_success(&io->scsiio); 54111b569f7SAlexander Motin ctl_data_submit_done(io); 54211b569f7SAlexander Motin return (CTL_RETVAL_COMPLETE); 54311b569f7SAlexander Motin } 544e7037673SAlexander Motin PRIV(io)->len = 0; 545e7037673SAlexander Motin if (lbalen->flags & CTL_LLF_COMPARE) 546e7037673SAlexander Motin ctl_backend_ramdisk_compare(io); 547e7037673SAlexander Motin else 548e7037673SAlexander Motin ctl_backend_ramdisk_rw(io); 549130f4520SKenneth D. Merry return (CTL_RETVAL_COMPLETE); 550130f4520SKenneth D. Merry } 551130f4520SKenneth D. Merry 55208a7cce5SAlexander Motin static void 55308a7cce5SAlexander Motin ctl_backend_ramdisk_worker(void *context, int pending) 55408a7cce5SAlexander Motin { 55508a7cce5SAlexander Motin struct ctl_be_ramdisk_lun *be_lun; 55608a7cce5SAlexander Motin union ctl_io *io; 55708a7cce5SAlexander Motin 55808a7cce5SAlexander Motin be_lun = (struct ctl_be_ramdisk_lun *)context; 55975c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 56008a7cce5SAlexander Motin for (;;) { 56108a7cce5SAlexander Motin io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); 56208a7cce5SAlexander Motin if (io != NULL) { 56308a7cce5SAlexander Motin STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr, 56408a7cce5SAlexander Motin ctl_io_hdr, links); 56575c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 566e7037673SAlexander Motin if (ARGS(io)->flags & CTL_LLF_COMPARE) 567e7037673SAlexander Motin ctl_backend_ramdisk_compare(io); 568e7037673SAlexander Motin else 569e7037673SAlexander Motin ctl_backend_ramdisk_rw(io); 57075c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 57108a7cce5SAlexander Motin continue; 57208a7cce5SAlexander Motin } 57308a7cce5SAlexander Motin 57408a7cce5SAlexander Motin /* 57508a7cce5SAlexander Motin * If we get here, there is no work left in the queues, so 57608a7cce5SAlexander Motin * just break out and let the task queue go to sleep. 57708a7cce5SAlexander Motin */ 57808a7cce5SAlexander Motin break; 57908a7cce5SAlexander Motin } 58075c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 581130f4520SKenneth D. Merry } 582130f4520SKenneth D. Merry 583130f4520SKenneth D. Merry static int 584e7037673SAlexander Motin ctl_backend_ramdisk_gls(union ctl_io *io) 585e7037673SAlexander Motin { 586e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 587e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 588e7037673SAlexander Motin struct scsi_get_lba_status_data *data; 589e7037673SAlexander Motin uint8_t *page; 590e7037673SAlexander Motin u_int lbaoff; 591e7037673SAlexander Motin 592e7037673SAlexander Motin data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 593e7037673SAlexander Motin scsi_u64to8b(ARGS(io)->lba, data->descr[0].addr); 594e7037673SAlexander Motin lbaoff = ARGS(io)->lba & ~(UINT_MAX << cbe_lun->pblockexp); 595e7037673SAlexander Motin scsi_ulto4b(be_lun->pblockmul - lbaoff, data->descr[0].length); 596e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 597e7037673SAlexander Motin ARGS(io)->lba >> cbe_lun->pblockexp, GP_OTHER); 598e7037673SAlexander Motin if (page == P_UNMAPPED) 599e7037673SAlexander Motin data->descr[0].status = 1; 600e7037673SAlexander Motin else if (page == P_ANCHORED) 601e7037673SAlexander Motin data->descr[0].status = 2; 602e7037673SAlexander Motin else 603e7037673SAlexander Motin data->descr[0].status = 0; 604e7037673SAlexander Motin ctl_config_read_done(io); 605e7037673SAlexander Motin return (CTL_RETVAL_COMPLETE); 606e7037673SAlexander Motin } 607e7037673SAlexander Motin 608e7037673SAlexander Motin static int 609e7037673SAlexander Motin ctl_backend_ramdisk_config_read(union ctl_io *io) 610e7037673SAlexander Motin { 611e7037673SAlexander Motin int retval = 0; 612e7037673SAlexander Motin 613e7037673SAlexander Motin switch (io->scsiio.cdb[0]) { 614e7037673SAlexander Motin case SERVICE_ACTION_IN: 615e7037673SAlexander Motin if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 616e7037673SAlexander Motin retval = ctl_backend_ramdisk_gls(io); 617e7037673SAlexander Motin break; 618e7037673SAlexander Motin } 619e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 620e7037673SAlexander Motin /*sks_valid*/ 1, 621e7037673SAlexander Motin /*command*/ 1, 622e7037673SAlexander Motin /*field*/ 1, 623e7037673SAlexander Motin /*bit_valid*/ 1, 624e7037673SAlexander Motin /*bit*/ 4); 625e7037673SAlexander Motin ctl_config_read_done(io); 626e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 627e7037673SAlexander Motin break; 628e7037673SAlexander Motin default: 629e7037673SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 630e7037673SAlexander Motin ctl_config_read_done(io); 631e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 632e7037673SAlexander Motin break; 633e7037673SAlexander Motin } 634e7037673SAlexander Motin return (retval); 635e7037673SAlexander Motin } 636e7037673SAlexander Motin 637e7037673SAlexander Motin static void 638e7037673SAlexander Motin ctl_backend_ramdisk_delete(struct ctl_be_lun *cbe_lun, off_t lba, off_t len, 639e7037673SAlexander Motin int anchor) 640e7037673SAlexander Motin { 641e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 642e7037673SAlexander Motin uint8_t *page; 643e7037673SAlexander Motin uint64_t p, lp; 644e7037673SAlexander Motin u_int lbaoff; 645e7037673SAlexander Motin getpage_op_t op = anchor ? GP_ANCHOR : GP_OTHER; 646e7037673SAlexander Motin 647e7037673SAlexander Motin /* Partially zero first partial page. */ 648e7037673SAlexander Motin p = lba >> cbe_lun->pblockexp; 649e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 650e7037673SAlexander Motin if (lbaoff != 0) { 651e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, p, op); 652e7037673SAlexander Motin if (page != P_UNMAPPED && page != P_ANCHORED) { 653e7037673SAlexander Motin memset(page + lbaoff * cbe_lun->blocksize, 0, 654e7037673SAlexander Motin min(len, be_lun->pblockmul - lbaoff) * 655e7037673SAlexander Motin cbe_lun->blocksize); 656e7037673SAlexander Motin } 657e7037673SAlexander Motin p++; 658e7037673SAlexander Motin } 659e7037673SAlexander Motin 660e7037673SAlexander Motin /* Partially zero last partial page. */ 661e7037673SAlexander Motin lp = (lba + len) >> cbe_lun->pblockexp; 662e7037673SAlexander Motin lbaoff = (lba + len) & ~(UINT_MAX << cbe_lun->pblockexp); 663e7037673SAlexander Motin if (p <= lp && lbaoff != 0) { 664e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, lp, op); 665e7037673SAlexander Motin if (page != P_UNMAPPED && page != P_ANCHORED) 666e7037673SAlexander Motin memset(page, 0, lbaoff * cbe_lun->blocksize); 667e7037673SAlexander Motin } 668e7037673SAlexander Motin 669e7037673SAlexander Motin /* Delete remaining full pages. */ 670e7037673SAlexander Motin if (anchor) { 671e7037673SAlexander Motin for (; p < lp; p++) 672e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(be_lun, p); 673e7037673SAlexander Motin } else { 674e7037673SAlexander Motin for (; p < lp; p++) 675e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(be_lun, p); 676e7037673SAlexander Motin } 677e7037673SAlexander Motin } 678e7037673SAlexander Motin 679e7037673SAlexander Motin static void 680e7037673SAlexander Motin ctl_backend_ramdisk_ws(union ctl_io *io) 681e7037673SAlexander Motin { 682e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 683e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = cbe_lun->be_lun; 684e7037673SAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 685e7037673SAlexander Motin uint8_t *page; 686e7037673SAlexander Motin uint64_t lba; 687e7037673SAlexander Motin u_int lbaoff, lbas; 688e7037673SAlexander Motin 689e7037673SAlexander Motin if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB)) { 690e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 691e7037673SAlexander Motin /*sks_valid*/ 1, 692e7037673SAlexander Motin /*command*/ 1, 693e7037673SAlexander Motin /*field*/ 1, 694e7037673SAlexander Motin /*bit_valid*/ 0, 695e7037673SAlexander Motin /*bit*/ 0); 696e7037673SAlexander Motin ctl_config_write_done(io); 697e7037673SAlexander Motin return; 698e7037673SAlexander Motin } 699e7037673SAlexander Motin if (lbalen->flags & SWS_UNMAP) { 700e7037673SAlexander Motin ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 701e7037673SAlexander Motin (lbalen->flags & SWS_ANCHOR) != 0); 702e7037673SAlexander Motin ctl_set_success(&io->scsiio); 703e7037673SAlexander Motin ctl_config_write_done(io); 704e7037673SAlexander Motin return; 705e7037673SAlexander Motin } 706e7037673SAlexander Motin 707e7037673SAlexander Motin for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) { 708e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 709e7037673SAlexander Motin lba >> cbe_lun->pblockexp, GP_WRITE); 710e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) { 711e7037673SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 712e7037673SAlexander Motin ctl_data_submit_done(io); 713e7037673SAlexander Motin return; 714e7037673SAlexander Motin } 715e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 716e7037673SAlexander Motin page += lbaoff * cbe_lun->blocksize; 717e7037673SAlexander Motin if (lbalen->flags & SWS_NDOB) { 718e7037673SAlexander Motin memset(page, 0, cbe_lun->blocksize); 719e7037673SAlexander Motin } else { 720e7037673SAlexander Motin memcpy(page, io->scsiio.kern_data_ptr, 721e7037673SAlexander Motin cbe_lun->blocksize); 722e7037673SAlexander Motin } 723e7037673SAlexander Motin if (lbalen->flags & SWS_LBDATA) 724e7037673SAlexander Motin scsi_ulto4b(lba, page); 725e7037673SAlexander Motin } 726e7037673SAlexander Motin ctl_set_success(&io->scsiio); 727e7037673SAlexander Motin ctl_config_write_done(io); 728e7037673SAlexander Motin } 729e7037673SAlexander Motin 730e7037673SAlexander Motin static void 731e7037673SAlexander Motin ctl_backend_ramdisk_unmap(union ctl_io *io) 732e7037673SAlexander Motin { 733e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 734e7037673SAlexander Motin struct ctl_ptr_len_flags *ptrlen = (struct ctl_ptr_len_flags *)ARGS(io); 735e7037673SAlexander Motin struct scsi_unmap_desc *buf, *end; 736e7037673SAlexander Motin 737e7037673SAlexander Motin if ((ptrlen->flags & ~SU_ANCHOR) != 0) { 738e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 739e7037673SAlexander Motin /*sks_valid*/ 0, 740e7037673SAlexander Motin /*command*/ 0, 741e7037673SAlexander Motin /*field*/ 0, 742e7037673SAlexander Motin /*bit_valid*/ 0, 743e7037673SAlexander Motin /*bit*/ 0); 744e7037673SAlexander Motin ctl_config_write_done(io); 745e7037673SAlexander Motin return; 746e7037673SAlexander Motin } 747e7037673SAlexander Motin 748e7037673SAlexander Motin buf = (struct scsi_unmap_desc *)ptrlen->ptr; 749e7037673SAlexander Motin end = buf + ptrlen->len / sizeof(*buf); 750e7037673SAlexander Motin for (; buf < end; buf++) { 751e7037673SAlexander Motin ctl_backend_ramdisk_delete(cbe_lun, 752e7037673SAlexander Motin scsi_8btou64(buf->lba), scsi_4btoul(buf->length), 753e7037673SAlexander Motin (ptrlen->flags & SU_ANCHOR) != 0); 754e7037673SAlexander Motin } 755e7037673SAlexander Motin 756e7037673SAlexander Motin ctl_set_success(&io->scsiio); 757e7037673SAlexander Motin ctl_config_write_done(io); 758e7037673SAlexander Motin } 759e7037673SAlexander Motin 760e7037673SAlexander Motin static int 761e7037673SAlexander Motin ctl_backend_ramdisk_config_write(union ctl_io *io) 762e7037673SAlexander Motin { 763e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 764e7037673SAlexander Motin int retval = 0; 765e7037673SAlexander Motin 766e7037673SAlexander Motin switch (io->scsiio.cdb[0]) { 767e7037673SAlexander Motin case SYNCHRONIZE_CACHE: 768e7037673SAlexander Motin case SYNCHRONIZE_CACHE_16: 769e7037673SAlexander Motin /* We have no cache to flush. */ 770e7037673SAlexander Motin ctl_set_success(&io->scsiio); 771e7037673SAlexander Motin ctl_config_write_done(io); 772e7037673SAlexander Motin break; 773e7037673SAlexander Motin case START_STOP_UNIT: { 774e7037673SAlexander Motin struct scsi_start_stop_unit *cdb; 775e7037673SAlexander Motin 776e7037673SAlexander Motin cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 777e7037673SAlexander Motin if ((cdb->how & SSS_PC_MASK) != 0) { 778e7037673SAlexander Motin ctl_set_success(&io->scsiio); 779e7037673SAlexander Motin ctl_config_write_done(io); 780e7037673SAlexander Motin break; 781e7037673SAlexander Motin } 782e7037673SAlexander Motin if (cdb->how & SSS_START) { 783e7037673SAlexander Motin if (cdb->how & SSS_LOEJ) 784e7037673SAlexander Motin ctl_lun_has_media(cbe_lun); 785e7037673SAlexander Motin ctl_start_lun(cbe_lun); 786e7037673SAlexander Motin } else { 787e7037673SAlexander Motin ctl_stop_lun(cbe_lun); 788e7037673SAlexander Motin if (cdb->how & SSS_LOEJ) 789e7037673SAlexander Motin ctl_lun_ejected(cbe_lun); 790e7037673SAlexander Motin } 791e7037673SAlexander Motin ctl_set_success(&io->scsiio); 792e7037673SAlexander Motin ctl_config_write_done(io); 793e7037673SAlexander Motin break; 794e7037673SAlexander Motin } 795e7037673SAlexander Motin case PREVENT_ALLOW: 796e7037673SAlexander Motin ctl_set_success(&io->scsiio); 797e7037673SAlexander Motin ctl_config_write_done(io); 798e7037673SAlexander Motin break; 799e7037673SAlexander Motin case WRITE_SAME_10: 800e7037673SAlexander Motin case WRITE_SAME_16: 801e7037673SAlexander Motin ctl_backend_ramdisk_ws(io); 802e7037673SAlexander Motin break; 803e7037673SAlexander Motin case UNMAP: 804e7037673SAlexander Motin ctl_backend_ramdisk_unmap(io); 805e7037673SAlexander Motin break; 806e7037673SAlexander Motin default: 807e7037673SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 808e7037673SAlexander Motin ctl_config_write_done(io); 809e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 810e7037673SAlexander Motin break; 811e7037673SAlexander Motin } 812e7037673SAlexander Motin 813e7037673SAlexander Motin return (retval); 814e7037673SAlexander Motin } 815e7037673SAlexander Motin 816e7037673SAlexander Motin static uint64_t 817e7037673SAlexander Motin ctl_backend_ramdisk_lun_attr(void *arg, const char *attrname) 818e7037673SAlexander Motin { 819e7037673SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = arg; 820e7037673SAlexander Motin uint64_t val; 821e7037673SAlexander Motin 822e7037673SAlexander Motin val = UINT64_MAX; 823e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 824e7037673SAlexander Motin return (val); 825e7037673SAlexander Motin sx_slock(&be_lun->page_lock); 826e7037673SAlexander Motin if (strcmp(attrname, "blocksused") == 0) { 827e7037673SAlexander Motin val = be_lun->cap_used / be_lun->cbe_lun.blocksize; 828e7037673SAlexander Motin } else if (strcmp(attrname, "blocksavail") == 0) { 829e7037673SAlexander Motin val = (be_lun->cap_bytes - be_lun->cap_used) / 830e7037673SAlexander Motin be_lun->cbe_lun.blocksize; 831e7037673SAlexander Motin } 832e7037673SAlexander Motin sx_sunlock(&be_lun->page_lock); 833e7037673SAlexander Motin return (val); 834e7037673SAlexander Motin } 835e7037673SAlexander Motin 836e7037673SAlexander Motin static int 837130f4520SKenneth D. Merry ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 838130f4520SKenneth D. Merry int flag, struct thread *td) 839130f4520SKenneth D. Merry { 84067cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 84167cc546dSAlexander Motin struct ctl_lun_req *lun_req; 842130f4520SKenneth D. Merry int retval; 843130f4520SKenneth D. Merry 844130f4520SKenneth D. Merry retval = 0; 845130f4520SKenneth D. Merry switch (cmd) { 84667cc546dSAlexander Motin case CTL_LUN_REQ: 847130f4520SKenneth D. Merry lun_req = (struct ctl_lun_req *)addr; 848130f4520SKenneth D. Merry switch (lun_req->reqtype) { 849130f4520SKenneth D. Merry case CTL_LUNREQ_CREATE: 8500bcd4ab6SAlexander Motin retval = ctl_backend_ramdisk_create(softc, lun_req); 851130f4520SKenneth D. Merry break; 852130f4520SKenneth D. Merry case CTL_LUNREQ_RM: 853130f4520SKenneth D. Merry retval = ctl_backend_ramdisk_rm(softc, lun_req); 854130f4520SKenneth D. Merry break; 85581177295SEdward Tomasz Napierala case CTL_LUNREQ_MODIFY: 85681177295SEdward Tomasz Napierala retval = ctl_backend_ramdisk_modify(softc, lun_req); 85781177295SEdward Tomasz Napierala break; 858130f4520SKenneth D. Merry default: 859130f4520SKenneth D. Merry lun_req->status = CTL_LUN_ERROR; 860130f4520SKenneth D. Merry snprintf(lun_req->error_str, sizeof(lun_req->error_str), 861130f4520SKenneth D. Merry "%s: invalid LUN request type %d", __func__, 862130f4520SKenneth D. Merry lun_req->reqtype); 863130f4520SKenneth D. Merry break; 864130f4520SKenneth D. Merry } 865130f4520SKenneth D. Merry break; 866130f4520SKenneth D. Merry default: 867130f4520SKenneth D. Merry retval = ENOTTY; 868130f4520SKenneth D. Merry break; 869130f4520SKenneth D. Merry } 870130f4520SKenneth D. Merry 871130f4520SKenneth D. Merry return (retval); 872130f4520SKenneth D. Merry } 873130f4520SKenneth D. Merry 874130f4520SKenneth D. Merry static int 875130f4520SKenneth D. Merry ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 876130f4520SKenneth D. Merry struct ctl_lun_req *req) 877130f4520SKenneth D. Merry { 878130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 879130f4520SKenneth D. Merry struct ctl_lun_rm_params *params; 880130f4520SKenneth D. Merry int retval; 881130f4520SKenneth D. Merry 882130f4520SKenneth D. Merry params = &req->reqdata.rm; 883130f4520SKenneth D. Merry mtx_lock(&softc->lock); 884130f4520SKenneth D. Merry STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 8850bcd4ab6SAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) 886130f4520SKenneth D. Merry break; 887130f4520SKenneth D. Merry } 888130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 889130f4520SKenneth D. Merry if (be_lun == NULL) { 890130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 891130f4520SKenneth D. Merry "%s: LUN %u is not managed by the ramdisk backend", 892130f4520SKenneth D. Merry __func__, params->lun_id); 893130f4520SKenneth D. Merry goto bailout_error; 894130f4520SKenneth D. Merry } 895130f4520SKenneth D. Merry 8960bcd4ab6SAlexander Motin retval = ctl_disable_lun(&be_lun->cbe_lun); 897130f4520SKenneth D. Merry if (retval != 0) { 898130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 899130f4520SKenneth D. Merry "%s: error %d returned from ctl_disable_lun() for " 900130f4520SKenneth D. Merry "LUN %d", __func__, retval, params->lun_id); 901130f4520SKenneth D. Merry goto bailout_error; 902130f4520SKenneth D. Merry } 903130f4520SKenneth D. Merry 904130f4520SKenneth D. Merry /* 905130f4520SKenneth D. Merry * Set the waiting flag before we invalidate the LUN. Our shutdown 906130f4520SKenneth D. Merry * routine can be called any time after we invalidate the LUN, 907130f4520SKenneth D. Merry * and can be called from our context. 908130f4520SKenneth D. Merry * 909130f4520SKenneth D. Merry * This tells the shutdown routine that we're waiting, or we're 910130f4520SKenneth D. Merry * going to wait for the shutdown to happen. 911130f4520SKenneth D. Merry */ 912130f4520SKenneth D. Merry mtx_lock(&softc->lock); 913130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 914130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 915130f4520SKenneth D. Merry 9160bcd4ab6SAlexander Motin retval = ctl_invalidate_lun(&be_lun->cbe_lun); 917130f4520SKenneth D. Merry if (retval != 0) { 918130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 919130f4520SKenneth D. Merry "%s: error %d returned from ctl_invalidate_lun() for " 920130f4520SKenneth D. Merry "LUN %d", __func__, retval, params->lun_id); 921ce300fbfSAlexander Motin mtx_lock(&softc->lock); 922ce300fbfSAlexander Motin be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 923ce300fbfSAlexander Motin mtx_unlock(&softc->lock); 924130f4520SKenneth D. Merry goto bailout_error; 925130f4520SKenneth D. Merry } 926130f4520SKenneth D. Merry 927130f4520SKenneth D. Merry mtx_lock(&softc->lock); 928130f4520SKenneth D. Merry while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) { 929130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 930130f4520SKenneth D. Merry if (retval == EINTR) 931130f4520SKenneth D. Merry break; 932130f4520SKenneth D. Merry } 933130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 934130f4520SKenneth D. Merry 935130f4520SKenneth D. Merry /* 936130f4520SKenneth D. Merry * We only remove this LUN from the list and free it (below) if 937130f4520SKenneth D. Merry * retval == 0. If the user interrupted the wait, we just bail out 938130f4520SKenneth D. Merry * without actually freeing the LUN. We let the shutdown routine 939130f4520SKenneth D. Merry * free the LUN if that happens. 940130f4520SKenneth D. Merry */ 941130f4520SKenneth D. Merry if (retval == 0) { 942130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 943130f4520SKenneth D. Merry links); 944130f4520SKenneth D. Merry softc->num_luns--; 945130f4520SKenneth D. Merry } 946130f4520SKenneth D. Merry 947130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 948130f4520SKenneth D. Merry 94908a7cce5SAlexander Motin if (retval == 0) { 950ee4ad294SAlexander Motin taskqueue_drain_all(be_lun->io_taskqueue); 95108a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 9520bcd4ab6SAlexander Motin ctl_free_opts(&be_lun->cbe_lun.options); 953e7037673SAlexander Motin free(be_lun->zero_page, M_RAMDISK); 954e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 955e7037673SAlexander Motin sx_destroy(&be_lun->page_lock); 95675c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 957130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 95808a7cce5SAlexander Motin } 959130f4520SKenneth D. Merry 960130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 961130f4520SKenneth D. Merry return (retval); 962130f4520SKenneth D. Merry 963130f4520SKenneth D. Merry bailout_error: 964130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 965130f4520SKenneth D. Merry return (0); 966130f4520SKenneth D. Merry } 967130f4520SKenneth D. Merry 968130f4520SKenneth D. Merry static int 969130f4520SKenneth D. Merry ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 9700bcd4ab6SAlexander Motin struct ctl_lun_req *req) 971130f4520SKenneth D. Merry { 972130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 9730bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 974130f4520SKenneth D. Merry struct ctl_lun_create_params *params; 97557a5db13SAlexander Motin char *value; 976130f4520SKenneth D. Merry char tmpstr[32]; 977e7037673SAlexander Motin uint64_t t; 9780bcd4ab6SAlexander Motin int retval; 979130f4520SKenneth D. Merry 980130f4520SKenneth D. Merry retval = 0; 981130f4520SKenneth D. Merry params = &req->reqdata.create; 982130f4520SKenneth D. Merry 9830bcd4ab6SAlexander Motin be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK); 9840bcd4ab6SAlexander Motin cbe_lun = &be_lun->cbe_lun; 9850bcd4ab6SAlexander Motin cbe_lun->be_lun = be_lun; 986a3977beaSAlexander Motin be_lun->params = req->reqdata.create; 9870bcd4ab6SAlexander Motin be_lun->softc = softc; 98808a7cce5SAlexander Motin sprintf(be_lun->lunname, "cram%d", softc->num_luns); 9890bcd4ab6SAlexander Motin ctl_init_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 990130f4520SKenneth D. Merry 991130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 9920bcd4ab6SAlexander Motin cbe_lun->lun_type = params->device_type; 993130f4520SKenneth D. Merry else 9940bcd4ab6SAlexander Motin cbe_lun->lun_type = T_DIRECT; 9950bcd4ab6SAlexander Motin be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED; 9967ac58230SAlexander Motin cbe_lun->flags = 0; 9977ac58230SAlexander Motin value = ctl_get_opt(&cbe_lun->options, "ha_role"); 9987ac58230SAlexander Motin if (value != NULL) { 9997ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 10007ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 10017ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 10027ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 1003130f4520SKenneth D. Merry 1004e7037673SAlexander Motin be_lun->pblocksize = PAGE_SIZE; 1005e7037673SAlexander Motin value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 1006e7037673SAlexander Motin if (value != NULL) { 1007e7037673SAlexander Motin ctl_expand_number(value, &t); 1008e7037673SAlexander Motin be_lun->pblocksize = t; 1009e7037673SAlexander Motin } 1010e7037673SAlexander Motin if (be_lun->pblocksize < 512 || be_lun->pblocksize > 131072) { 1011e7037673SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 1012e7037673SAlexander Motin "%s: unsupported pblocksize %u", __func__, 1013e7037673SAlexander Motin be_lun->pblocksize); 1014e7037673SAlexander Motin goto bailout_error; 1015e7037673SAlexander Motin } 1016e7037673SAlexander Motin 101791be33dcSAlexander Motin if (cbe_lun->lun_type == T_DIRECT || 101891be33dcSAlexander Motin cbe_lun->lun_type == T_CDROM) { 10190bcd4ab6SAlexander Motin if (params->blocksize_bytes != 0) 10200bcd4ab6SAlexander Motin cbe_lun->blocksize = params->blocksize_bytes; 102191be33dcSAlexander Motin else if (cbe_lun->lun_type == T_CDROM) 102291be33dcSAlexander Motin cbe_lun->blocksize = 2048; 10230bcd4ab6SAlexander Motin else 10240bcd4ab6SAlexander Motin cbe_lun->blocksize = 512; 1025e7037673SAlexander Motin be_lun->pblockmul = be_lun->pblocksize / cbe_lun->blocksize; 1026e7037673SAlexander Motin if (be_lun->pblockmul < 1 || !powerof2(be_lun->pblockmul)) { 1027e7037673SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 1028e7037673SAlexander Motin "%s: pblocksize %u not exp2 of blocksize %u", 1029e7037673SAlexander Motin __func__, 1030e7037673SAlexander Motin be_lun->pblocksize, cbe_lun->blocksize); 1031e7037673SAlexander Motin goto bailout_error; 1032e7037673SAlexander Motin } 10330bcd4ab6SAlexander Motin if (params->lun_size_bytes < cbe_lun->blocksize) { 1034130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1035130f4520SKenneth D. Merry "%s: LUN size %ju < blocksize %u", __func__, 10360bcd4ab6SAlexander Motin params->lun_size_bytes, cbe_lun->blocksize); 1037130f4520SKenneth D. Merry goto bailout_error; 1038130f4520SKenneth D. Merry } 10390bcd4ab6SAlexander Motin be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize; 10400bcd4ab6SAlexander Motin be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize; 1041e7037673SAlexander Motin be_lun->indir = 0; 1042e7037673SAlexander Motin t = be_lun->size_bytes / be_lun->pblocksize; 1043e7037673SAlexander Motin while (t > 1) { 1044e7037673SAlexander Motin t /= PPP; 1045e7037673SAlexander Motin be_lun->indir++; 1046e7037673SAlexander Motin } 10470bcd4ab6SAlexander Motin cbe_lun->maxlba = be_lun->size_blocks - 1; 1048e7037673SAlexander Motin cbe_lun->pblockexp = fls(be_lun->pblockmul) - 1; 1049e7037673SAlexander Motin cbe_lun->pblockoff = 0; 1050e7037673SAlexander Motin cbe_lun->ublockexp = cbe_lun->pblockexp; 1051e7037673SAlexander Motin cbe_lun->ublockoff = 0; 1052e7037673SAlexander Motin cbe_lun->atomicblock = be_lun->pblocksize; 1053e7037673SAlexander Motin cbe_lun->opttxferlen = SGPP * be_lun->pblocksize; 1054e7037673SAlexander Motin value = ctl_get_opt(&cbe_lun->options, "capacity"); 1055e7037673SAlexander Motin if (value != NULL) 1056e7037673SAlexander Motin ctl_expand_number(value, &be_lun->cap_bytes); 1057e7037673SAlexander Motin } else { 1058e7037673SAlexander Motin be_lun->pblockmul = 1; 1059e7037673SAlexander Motin cbe_lun->pblockexp = 0; 1060130f4520SKenneth D. Merry } 1061130f4520SKenneth D. Merry 1062130f4520SKenneth D. Merry /* Tell the user the blocksize we ended up using */ 10630bcd4ab6SAlexander Motin params->blocksize_bytes = cbe_lun->blocksize; 1064130f4520SKenneth D. Merry params->lun_size_bytes = be_lun->size_bytes; 1065130f4520SKenneth D. Merry 10660bcd4ab6SAlexander Motin value = ctl_get_opt(&cbe_lun->options, "unmap"); 1067e7037673SAlexander Motin if (value == NULL || strcmp(value, "off") != 0) 10680bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 10690bcd4ab6SAlexander Motin value = ctl_get_opt(&cbe_lun->options, "readonly"); 107091be33dcSAlexander Motin if (value != NULL) { 107191be33dcSAlexander Motin if (strcmp(value, "on") == 0) 107291be33dcSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 107391be33dcSAlexander Motin } else if (cbe_lun->lun_type != T_DIRECT) 10740bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 10750bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 10760bcd4ab6SAlexander Motin value = ctl_get_opt(&cbe_lun->options, "serseq"); 10770bcd4ab6SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 10780bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 10790bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "read") == 0) 10800bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 10810bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "off") == 0) 10820bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 1083130f4520SKenneth D. Merry 1084130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_ID_REQ) { 10850bcd4ab6SAlexander Motin cbe_lun->req_lun_id = params->req_lun_id; 10860bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 1087130f4520SKenneth D. Merry } else 10880bcd4ab6SAlexander Motin cbe_lun->req_lun_id = 0; 1089130f4520SKenneth D. Merry 10900bcd4ab6SAlexander Motin cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 10910bcd4ab6SAlexander Motin cbe_lun->lun_config_status = ctl_backend_ramdisk_lun_config_status; 10920bcd4ab6SAlexander Motin cbe_lun->be = &ctl_be_ramdisk_driver; 1093130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 1094130f4520SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 1095130f4520SKenneth D. Merry softc->num_luns); 10960bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, tmpstr, 10970bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 1098130f4520SKenneth D. Merry 1099130f4520SKenneth D. Merry /* Tell the user what we used for a serial number */ 1100130f4520SKenneth D. Merry strncpy((char *)params->serial_num, tmpstr, 1101e7038eb7SAlexander Motin MIN(sizeof(params->serial_num), sizeof(tmpstr))); 1102130f4520SKenneth D. Merry } else { 11030bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, params->serial_num, 11040bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), 1105130f4520SKenneth D. Merry sizeof(params->serial_num))); 1106130f4520SKenneth D. Merry } 1107130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 1108130f4520SKenneth D. Merry snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 11090bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, tmpstr, 11100bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 1111130f4520SKenneth D. Merry 1112130f4520SKenneth D. Merry /* Tell the user what we used for a device ID */ 1113130f4520SKenneth D. Merry strncpy((char *)params->device_id, tmpstr, 1114e7038eb7SAlexander Motin MIN(sizeof(params->device_id), sizeof(tmpstr))); 1115130f4520SKenneth D. Merry } else { 11160bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, params->device_id, 11170bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), 1118130f4520SKenneth D. Merry sizeof(params->device_id))); 1119130f4520SKenneth D. Merry } 1120130f4520SKenneth D. Merry 112108a7cce5SAlexander Motin STAILQ_INIT(&be_lun->cont_queue); 1122e7037673SAlexander Motin sx_init(&be_lun->page_lock, "cram page lock"); 11232fb36370SAlexander Motin if (be_lun->cap_bytes == 0) { 11242fb36370SAlexander Motin be_lun->indir = 0; 1125e7037673SAlexander Motin be_lun->pages = malloc(be_lun->pblocksize, M_RAMDISK, M_WAITOK); 11262fb36370SAlexander Motin } 1127e7037673SAlexander Motin be_lun->zero_page = malloc(be_lun->pblocksize, M_RAMDISK, 1128e7037673SAlexander Motin M_WAITOK|M_ZERO); 112975c7a1d3SAlexander Motin mtx_init(&be_lun->queue_lock, "cram queue lock", NULL, MTX_DEF); 113008a7cce5SAlexander Motin TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 113108a7cce5SAlexander Motin be_lun); 113208a7cce5SAlexander Motin 113308a7cce5SAlexander Motin be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 113408a7cce5SAlexander Motin taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 113508a7cce5SAlexander Motin if (be_lun->io_taskqueue == NULL) { 113608a7cce5SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 113708a7cce5SAlexander Motin "%s: Unable to create taskqueue", __func__); 113808a7cce5SAlexander Motin goto bailout_error; 113908a7cce5SAlexander Motin } 114008a7cce5SAlexander Motin 114108a7cce5SAlexander Motin retval = taskqueue_start_threads(&be_lun->io_taskqueue, 114208a7cce5SAlexander Motin /*num threads*/1, 114308a7cce5SAlexander Motin /*priority*/PWAIT, 114408a7cce5SAlexander Motin /*thread name*/ 114508a7cce5SAlexander Motin "%s taskq", be_lun->lunname); 114608a7cce5SAlexander Motin if (retval != 0) 114708a7cce5SAlexander Motin goto bailout_error; 114808a7cce5SAlexander Motin 1149130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1150130f4520SKenneth D. Merry softc->num_luns++; 1151130f4520SKenneth D. Merry STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 1152130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1153130f4520SKenneth D. Merry 11540bcd4ab6SAlexander Motin retval = ctl_add_lun(&be_lun->cbe_lun); 1155130f4520SKenneth D. Merry if (retval != 0) { 1156130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1157130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 1158130f4520SKenneth D. Merry links); 1159130f4520SKenneth D. Merry softc->num_luns--; 1160130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1161130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1162130f4520SKenneth D. Merry "%s: ctl_add_lun() returned error %d, see dmesg for " 1163130f4520SKenneth D. Merry "details", __func__, retval); 1164130f4520SKenneth D. Merry retval = 0; 1165130f4520SKenneth D. Merry goto bailout_error; 1166130f4520SKenneth D. Merry } 1167130f4520SKenneth D. Merry 1168130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1169130f4520SKenneth D. Merry 1170130f4520SKenneth D. Merry /* 1171130f4520SKenneth D. Merry * Tell the config_status routine that we're waiting so it won't 1172130f4520SKenneth D. Merry * clean up the LUN in the event of an error. 1173130f4520SKenneth D. Merry */ 1174130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 1175130f4520SKenneth D. Merry 1176130f4520SKenneth D. Merry while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 1177130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 1178130f4520SKenneth D. Merry if (retval == EINTR) 1179130f4520SKenneth D. Merry break; 1180130f4520SKenneth D. Merry } 1181130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 1182130f4520SKenneth D. Merry 1183130f4520SKenneth D. Merry if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) { 1184130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1185130f4520SKenneth D. Merry "%s: LUN configuration error, see dmesg for details", 1186130f4520SKenneth D. Merry __func__); 1187130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 1188130f4520SKenneth D. Merry links); 1189130f4520SKenneth D. Merry softc->num_luns--; 1190130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1191130f4520SKenneth D. Merry goto bailout_error; 1192130f4520SKenneth D. Merry } else { 11930bcd4ab6SAlexander Motin params->req_lun_id = cbe_lun->lun_id; 1194130f4520SKenneth D. Merry } 1195130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1196130f4520SKenneth D. Merry 1197130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 1198130f4520SKenneth D. Merry return (retval); 1199130f4520SKenneth D. Merry 1200130f4520SKenneth D. Merry bailout_error: 1201130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 120208a7cce5SAlexander Motin if (be_lun != NULL) { 1203e7037673SAlexander Motin if (be_lun->io_taskqueue != NULL) 120408a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 12050bcd4ab6SAlexander Motin ctl_free_opts(&cbe_lun->options); 1206e7037673SAlexander Motin free(be_lun->zero_page, M_RAMDISK); 1207e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 1208e7037673SAlexander Motin sx_destroy(&be_lun->page_lock); 120975c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 1210130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 121108a7cce5SAlexander Motin } 1212130f4520SKenneth D. Merry return (retval); 1213130f4520SKenneth D. Merry } 1214130f4520SKenneth D. Merry 121581177295SEdward Tomasz Napierala static int 121681177295SEdward Tomasz Napierala ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 121781177295SEdward Tomasz Napierala struct ctl_lun_req *req) 121881177295SEdward Tomasz Napierala { 121981177295SEdward Tomasz Napierala struct ctl_be_ramdisk_lun *be_lun; 1220a3977beaSAlexander Motin struct ctl_be_lun *cbe_lun; 122181177295SEdward Tomasz Napierala struct ctl_lun_modify_params *params; 12227ac58230SAlexander Motin char *value; 122381177295SEdward Tomasz Napierala uint32_t blocksize; 12247ac58230SAlexander Motin int wasprim; 122581177295SEdward Tomasz Napierala 122681177295SEdward Tomasz Napierala params = &req->reqdata.modify; 122781177295SEdward Tomasz Napierala 122881177295SEdward Tomasz Napierala mtx_lock(&softc->lock); 122981177295SEdward Tomasz Napierala STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 12300bcd4ab6SAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) 123181177295SEdward Tomasz Napierala break; 123281177295SEdward Tomasz Napierala } 123381177295SEdward Tomasz Napierala mtx_unlock(&softc->lock); 123481177295SEdward Tomasz Napierala if (be_lun == NULL) { 123581177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 123681177295SEdward Tomasz Napierala "%s: LUN %u is not managed by the ramdisk backend", 123781177295SEdward Tomasz Napierala __func__, params->lun_id); 123881177295SEdward Tomasz Napierala goto bailout_error; 123981177295SEdward Tomasz Napierala } 1240a3977beaSAlexander Motin cbe_lun = &be_lun->cbe_lun; 124181177295SEdward Tomasz Napierala 1242a3977beaSAlexander Motin if (params->lun_size_bytes != 0) 1243a3977beaSAlexander Motin be_lun->params.lun_size_bytes = params->lun_size_bytes; 1244a3977beaSAlexander Motin ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 124581177295SEdward Tomasz Napierala 12467ac58230SAlexander Motin wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 12477ac58230SAlexander Motin value = ctl_get_opt(&cbe_lun->options, "ha_role"); 12487ac58230SAlexander Motin if (value != NULL) { 12497ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 12507ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 12517ac58230SAlexander Motin else 12527ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 12537ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 12547ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 12557ac58230SAlexander Motin else 12567ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 12577ac58230SAlexander Motin if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 12587ac58230SAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 12597ac58230SAlexander Motin ctl_lun_primary(cbe_lun); 12607ac58230SAlexander Motin else 12617ac58230SAlexander Motin ctl_lun_secondary(cbe_lun); 12627ac58230SAlexander Motin } 12637ac58230SAlexander Motin 12647ac58230SAlexander Motin blocksize = be_lun->cbe_lun.blocksize; 1265a3977beaSAlexander Motin if (be_lun->params.lun_size_bytes < blocksize) { 126681177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 126781177295SEdward Tomasz Napierala "%s: LUN size %ju < blocksize %u", __func__, 1268a3977beaSAlexander Motin be_lun->params.lun_size_bytes, blocksize); 126981177295SEdward Tomasz Napierala goto bailout_error; 127081177295SEdward Tomasz Napierala } 1271a3977beaSAlexander Motin be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize; 127281177295SEdward Tomasz Napierala be_lun->size_bytes = be_lun->size_blocks * blocksize; 12730bcd4ab6SAlexander Motin be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1; 12740bcd4ab6SAlexander Motin ctl_lun_capacity_changed(&be_lun->cbe_lun); 127581177295SEdward Tomasz Napierala 127681177295SEdward Tomasz Napierala /* Tell the user the exact size we ended up using */ 127781177295SEdward Tomasz Napierala params->lun_size_bytes = be_lun->size_bytes; 127881177295SEdward Tomasz Napierala 127981177295SEdward Tomasz Napierala req->status = CTL_LUN_OK; 128081177295SEdward Tomasz Napierala return (0); 128181177295SEdward Tomasz Napierala 128281177295SEdward Tomasz Napierala bailout_error: 128381177295SEdward Tomasz Napierala req->status = CTL_LUN_ERROR; 128481177295SEdward Tomasz Napierala return (0); 128581177295SEdward Tomasz Napierala } 128681177295SEdward Tomasz Napierala 1287130f4520SKenneth D. Merry static void 1288130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_shutdown(void *be_lun) 1289130f4520SKenneth D. Merry { 1290130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun; 1291130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 1292130f4520SKenneth D. Merry int do_free; 1293130f4520SKenneth D. Merry 1294130f4520SKenneth D. Merry lun = (struct ctl_be_ramdisk_lun *)be_lun; 1295130f4520SKenneth D. Merry softc = lun->softc; 1296130f4520SKenneth D. Merry do_free = 0; 1297130f4520SKenneth D. Merry 1298130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1299130f4520SKenneth D. Merry lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 1300130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 1301130f4520SKenneth D. Merry wakeup(lun); 1302130f4520SKenneth D. Merry } else { 1303e2507751SAlexander Motin STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 1304130f4520SKenneth D. Merry links); 1305130f4520SKenneth D. Merry softc->num_luns--; 1306130f4520SKenneth D. Merry do_free = 1; 1307130f4520SKenneth D. Merry } 1308130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1309130f4520SKenneth D. Merry 1310130f4520SKenneth D. Merry if (do_free != 0) 1311130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 1312130f4520SKenneth D. Merry } 1313130f4520SKenneth D. Merry 1314130f4520SKenneth D. Merry static void 1315130f4520SKenneth D. Merry ctl_backend_ramdisk_lun_config_status(void *be_lun, 1316130f4520SKenneth D. Merry ctl_lun_config_status status) 1317130f4520SKenneth D. Merry { 1318130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *lun; 1319130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 1320130f4520SKenneth D. Merry 1321130f4520SKenneth D. Merry lun = (struct ctl_be_ramdisk_lun *)be_lun; 1322130f4520SKenneth D. Merry softc = lun->softc; 1323130f4520SKenneth D. Merry 1324130f4520SKenneth D. Merry if (status == CTL_LUN_CONFIG_OK) { 1325130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1326130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 1327130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 1328130f4520SKenneth D. Merry wakeup(lun); 1329130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1330130f4520SKenneth D. Merry 1331130f4520SKenneth D. Merry /* 1332130f4520SKenneth D. Merry * We successfully added the LUN, attempt to enable it. 1333130f4520SKenneth D. Merry */ 13340bcd4ab6SAlexander Motin if (ctl_enable_lun(&lun->cbe_lun) != 0) { 1335130f4520SKenneth D. Merry printf("%s: ctl_enable_lun() failed!\n", __func__); 13360bcd4ab6SAlexander Motin if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 1337130f4520SKenneth D. Merry printf("%s: ctl_invalidate_lun() failed!\n", 1338130f4520SKenneth D. Merry __func__); 1339130f4520SKenneth D. Merry } 1340130f4520SKenneth D. Merry } 1341130f4520SKenneth D. Merry 1342130f4520SKenneth D. Merry return; 1343130f4520SKenneth D. Merry } 1344130f4520SKenneth D. Merry 1345130f4520SKenneth D. Merry 1346130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1347130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 1348130f4520SKenneth D. Merry 1349130f4520SKenneth D. Merry /* 1350130f4520SKenneth D. Merry * If we have a user waiting, let him handle the cleanup. If not, 1351130f4520SKenneth D. Merry * clean things up here. 1352130f4520SKenneth D. Merry */ 1353130f4520SKenneth D. Merry if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 1354130f4520SKenneth D. Merry lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR; 1355130f4520SKenneth D. Merry wakeup(lun); 1356130f4520SKenneth D. Merry } else { 1357130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 1358130f4520SKenneth D. Merry links); 1359130f4520SKenneth D. Merry softc->num_luns--; 1360130f4520SKenneth D. Merry free(lun, M_RAMDISK); 1361130f4520SKenneth D. Merry } 1362130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1363130f4520SKenneth D. Merry } 1364