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_WAITING = 0x04 106130f4520SKenneth D. Merry } ctl_be_ramdisk_lun_flags; 107130f4520SKenneth D. Merry 108130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun { 109767300e8SAlexander Motin struct ctl_be_lun cbe_lun; /* Must be first element. */ 110a3977beaSAlexander Motin struct ctl_lun_create_params params; 111e7037673SAlexander Motin int indir; 112e7037673SAlexander Motin uint8_t **pages; 113e7037673SAlexander Motin uint8_t *zero_page; 114e7037673SAlexander Motin struct sx page_lock; 115e7037673SAlexander Motin u_int pblocksize; 116e7037673SAlexander Motin u_int pblockmul; 117130f4520SKenneth D. Merry uint64_t size_bytes; 118130f4520SKenneth D. Merry uint64_t size_blocks; 119e7037673SAlexander Motin uint64_t cap_bytes; 120e7037673SAlexander Motin uint64_t cap_used; 121130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc *softc; 122130f4520SKenneth D. Merry ctl_be_ramdisk_lun_flags flags; 12334144c2cSAlexander Motin SLIST_ENTRY(ctl_be_ramdisk_lun) links; 12408a7cce5SAlexander Motin struct taskqueue *io_taskqueue; 12508a7cce5SAlexander Motin struct task io_task; 12608a7cce5SAlexander Motin STAILQ_HEAD(, ctl_io_hdr) cont_queue; 12775c7a1d3SAlexander Motin struct mtx_padalign queue_lock; 128130f4520SKenneth D. Merry }; 129130f4520SKenneth D. Merry 130130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc { 13134144c2cSAlexander Motin struct sx modify_lock; 132130f4520SKenneth D. Merry struct mtx lock; 133130f4520SKenneth D. Merry int num_luns; 13434144c2cSAlexander Motin SLIST_HEAD(, ctl_be_ramdisk_lun) lun_list; 135130f4520SKenneth D. Merry }; 136130f4520SKenneth D. Merry 137130f4520SKenneth D. Merry static struct ctl_be_ramdisk_softc rd_softc; 1387ac58230SAlexander Motin extern struct ctl_softc *control_softc; 139130f4520SKenneth D. Merry 1400c629e28SAlexander Motin static int ctl_backend_ramdisk_init(void); 1410c629e28SAlexander Motin static int ctl_backend_ramdisk_shutdown(void); 1422c7dc6baSAlexander Motin static int ctl_backend_ramdisk_move_done(union ctl_io *io, bool samethr); 143e7037673SAlexander Motin static void ctl_backend_ramdisk_compare(union ctl_io *io); 144e7037673SAlexander Motin static void ctl_backend_ramdisk_rw(union ctl_io *io); 145130f4520SKenneth D. Merry static int ctl_backend_ramdisk_submit(union ctl_io *io); 146e7037673SAlexander Motin static void ctl_backend_ramdisk_worker(void *context, int pending); 147e7037673SAlexander Motin static int ctl_backend_ramdisk_config_read(union ctl_io *io); 148e7037673SAlexander Motin static int ctl_backend_ramdisk_config_write(union ctl_io *io); 149767300e8SAlexander Motin static uint64_t ctl_backend_ramdisk_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname); 150130f4520SKenneth D. Merry static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, 151130f4520SKenneth D. Merry caddr_t addr, int flag, struct thread *td); 152130f4520SKenneth D. Merry static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 153130f4520SKenneth D. Merry struct ctl_lun_req *req); 154130f4520SKenneth D. Merry static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 1550bcd4ab6SAlexander Motin struct ctl_lun_req *req); 15681177295SEdward Tomasz Napierala static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 15781177295SEdward Tomasz Napierala struct ctl_lun_req *req); 158767300e8SAlexander Motin static void ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun *cbe_lun); 159130f4520SKenneth D. Merry 160130f4520SKenneth D. Merry static struct ctl_backend_driver ctl_be_ramdisk_driver = 161130f4520SKenneth D. Merry { 1622a2443d8SKenneth D. Merry .name = "ramdisk", 1632a2443d8SKenneth D. Merry .flags = CTL_BE_FLAG_HAS_CONFIG, 1642a2443d8SKenneth D. Merry .init = ctl_backend_ramdisk_init, 1650c629e28SAlexander Motin .shutdown = ctl_backend_ramdisk_shutdown, 1662a2443d8SKenneth D. Merry .data_submit = ctl_backend_ramdisk_submit, 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 17334144c2cSAlexander Motin MALLOC_DEFINE(M_RAMDISK, "ctlramdisk", "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)); 18234144c2cSAlexander Motin sx_init(&softc->modify_lock, "ctlrammod"); 18334144c2cSAlexander Motin mtx_init(&softc->lock, "ctlram", NULL, MTX_DEF); 18434144c2cSAlexander Motin SLIST_INIT(&softc->lun_list); 185130f4520SKenneth D. Merry return (0); 186130f4520SKenneth D. Merry } 187130f4520SKenneth D. Merry 1880c629e28SAlexander Motin static int 189130f4520SKenneth D. Merry ctl_backend_ramdisk_shutdown(void) 190130f4520SKenneth D. Merry { 19167cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 19234144c2cSAlexander Motin struct ctl_be_ramdisk_lun *lun; 193130f4520SKenneth D. Merry 194130f4520SKenneth D. Merry mtx_lock(&softc->lock); 19534144c2cSAlexander Motin while ((lun = SLIST_FIRST(&softc->lun_list)) != NULL) { 19634144c2cSAlexander Motin SLIST_REMOVE_HEAD(&softc->lun_list, links); 19734144c2cSAlexander Motin softc->num_luns--; 198130f4520SKenneth D. Merry /* 19934144c2cSAlexander Motin * Drop our lock here. Since ctl_remove_lun() can call 200130f4520SKenneth D. Merry * back into us, this could potentially lead to a recursive 201130f4520SKenneth D. Merry * lock of the same mutex, which would cause a hang. 202130f4520SKenneth D. Merry */ 203130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 20434144c2cSAlexander Motin ctl_remove_lun(&lun->cbe_lun); 205130f4520SKenneth D. Merry mtx_lock(&softc->lock); 206130f4520SKenneth D. Merry } 207130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2080c629e28SAlexander Motin mtx_destroy(&softc->lock); 20934144c2cSAlexander Motin sx_destroy(&softc->modify_lock); 2100c629e28SAlexander Motin return (0); 211130f4520SKenneth D. Merry } 212130f4520SKenneth D. Merry 213e7037673SAlexander Motin static uint8_t * 214e7037673SAlexander Motin ctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn, 215e7037673SAlexander Motin getpage_op_t op) 216e7037673SAlexander Motin { 217e7037673SAlexander Motin uint8_t **p, ***pp; 218e7037673SAlexander Motin off_t i; 219e7037673SAlexander Motin int s; 220e7037673SAlexander Motin 221e7037673SAlexander Motin if (be_lun->cap_bytes == 0) { 222e7037673SAlexander Motin switch (op) { 223e7037673SAlexander Motin case GP_READ: 224e7037673SAlexander Motin return (be_lun->zero_page); 225e7037673SAlexander Motin case GP_WRITE: 226e7037673SAlexander Motin return ((uint8_t *)be_lun->pages); 227e7037673SAlexander Motin case GP_ANCHOR: 228e7037673SAlexander Motin return (P_ANCHORED); 229e7037673SAlexander Motin default: 230e7037673SAlexander Motin return (P_UNMAPPED); 231e7037673SAlexander Motin } 232e7037673SAlexander Motin } 233e7037673SAlexander Motin if (op == GP_WRITE || op == GP_ANCHOR) { 234e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 235e7037673SAlexander Motin pp = &be_lun->pages; 236e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 237e7037673SAlexander Motin if (*pp == NULL) { 238e7037673SAlexander Motin *pp = malloc(PAGE_SIZE, M_RAMDISK, 239e7037673SAlexander Motin M_WAITOK|M_ZERO); 240e7037673SAlexander Motin } 241e7037673SAlexander Motin i = pn >> s; 242e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 243e7037673SAlexander Motin pn -= i << s; 244e7037673SAlexander Motin } 245e7037673SAlexander Motin if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 246e7037673SAlexander Motin if (op == GP_WRITE) { 247e7037673SAlexander Motin *pp = malloc(be_lun->pblocksize, M_RAMDISK, 248e7037673SAlexander Motin M_WAITOK|M_ZERO); 249e7037673SAlexander Motin } else 250e7037673SAlexander Motin *pp = P_ANCHORED; 251e7037673SAlexander Motin be_lun->cap_used += be_lun->pblocksize; 252e7037673SAlexander Motin } else if (*pp == P_ANCHORED && op == GP_WRITE) { 253e7037673SAlexander Motin *pp = malloc(be_lun->pblocksize, M_RAMDISK, 254e7037673SAlexander Motin M_WAITOK|M_ZERO); 255e7037673SAlexander Motin } 256e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 257e7037673SAlexander Motin return ((uint8_t *)*pp); 258e7037673SAlexander Motin } else { 259e7037673SAlexander Motin sx_slock(&be_lun->page_lock); 260e7037673SAlexander Motin p = be_lun->pages; 261e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 262e7037673SAlexander Motin if (p == NULL) 263e7037673SAlexander Motin break; 264e7037673SAlexander Motin i = pn >> s; 265e7037673SAlexander Motin p = (uint8_t **)p[i]; 266e7037673SAlexander Motin pn -= i << s; 267e7037673SAlexander Motin } 268e7037673SAlexander Motin sx_sunlock(&be_lun->page_lock); 269e7037673SAlexander Motin if ((p == P_UNMAPPED || p == P_ANCHORED) && op == GP_READ) 270e7037673SAlexander Motin return (be_lun->zero_page); 271e7037673SAlexander Motin return ((uint8_t *)p); 272e7037673SAlexander Motin } 273e7037673SAlexander Motin }; 274e7037673SAlexander Motin 275e7037673SAlexander Motin static void 276e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 277e7037673SAlexander Motin { 278e7037673SAlexander Motin uint8_t ***pp; 279e7037673SAlexander Motin off_t i; 280e7037673SAlexander Motin int s; 281e7037673SAlexander Motin 282e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 283e7037673SAlexander Motin return; 284e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 285e7037673SAlexander Motin pp = &be_lun->pages; 286e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 287e7037673SAlexander Motin if (*pp == NULL) 288e7037673SAlexander Motin goto noindir; 289e7037673SAlexander Motin i = pn >> s; 290e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 291e7037673SAlexander Motin pn -= i << s; 292e7037673SAlexander Motin } 293e7037673SAlexander Motin if (*pp == P_ANCHORED) { 294e7037673SAlexander Motin be_lun->cap_used -= be_lun->pblocksize; 295e7037673SAlexander Motin *pp = P_UNMAPPED; 296e7037673SAlexander Motin } else if (*pp != P_UNMAPPED) { 297e7037673SAlexander Motin free(*pp, M_RAMDISK); 298e7037673SAlexander Motin be_lun->cap_used -= be_lun->pblocksize; 299e7037673SAlexander Motin *pp = P_UNMAPPED; 300e7037673SAlexander Motin } 301e7037673SAlexander Motin noindir: 302e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 303e7037673SAlexander Motin }; 304e7037673SAlexander Motin 305e7037673SAlexander Motin static void 306e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 307e7037673SAlexander Motin { 308e7037673SAlexander Motin uint8_t ***pp; 309e7037673SAlexander Motin off_t i; 310e7037673SAlexander Motin int s; 311e7037673SAlexander Motin 312e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 313e7037673SAlexander Motin return; 314e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 315e7037673SAlexander Motin pp = &be_lun->pages; 316e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 317e7037673SAlexander Motin if (*pp == NULL) 318e7037673SAlexander Motin goto noindir; 319e7037673SAlexander Motin i = pn >> s; 320e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 321e7037673SAlexander Motin pn -= i << s; 322e7037673SAlexander Motin } 323e7037673SAlexander Motin if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 324e7037673SAlexander Motin be_lun->cap_used += be_lun->pblocksize; 325e7037673SAlexander Motin *pp = P_ANCHORED; 326e7037673SAlexander Motin } else if (*pp != P_ANCHORED) { 327e7037673SAlexander Motin free(*pp, M_RAMDISK); 328e7037673SAlexander Motin *pp = P_ANCHORED; 329e7037673SAlexander Motin } 330e7037673SAlexander Motin noindir: 331e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 332e7037673SAlexander Motin }; 333e7037673SAlexander Motin 334e7037673SAlexander Motin static void 335e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(uint8_t **p, int indir) 336e7037673SAlexander Motin { 337e7037673SAlexander Motin int i; 338e7037673SAlexander Motin 339e7037673SAlexander Motin if (p == NULL) 340e7037673SAlexander Motin return; 341e7037673SAlexander Motin if (indir == 0) { 342e7037673SAlexander Motin free(p, M_RAMDISK); 343e7037673SAlexander Motin return; 344e7037673SAlexander Motin } 345e7037673SAlexander Motin for (i = 0; i < PPP; i++) { 346e7037673SAlexander Motin if (p[i] == NULL) 347e7037673SAlexander Motin continue; 348e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages((uint8_t **)p[i], indir - 1); 349e7037673SAlexander Motin } 350e7037673SAlexander Motin free(p, M_RAMDISK); 351e7037673SAlexander Motin }; 352e7037673SAlexander Motin 353e7037673SAlexander Motin static size_t 354e7037673SAlexander Motin cmp(uint8_t *a, uint8_t *b, size_t size) 355e7037673SAlexander Motin { 356e7037673SAlexander Motin size_t i; 357e7037673SAlexander Motin 358e7037673SAlexander Motin for (i = 0; i < size; i++) { 359e7037673SAlexander Motin if (a[i] != b[i]) 360e7037673SAlexander Motin break; 361e7037673SAlexander Motin } 362e7037673SAlexander Motin return (i); 363e7037673SAlexander Motin } 364e7037673SAlexander Motin 365e7037673SAlexander Motin static int 366e7037673SAlexander Motin ctl_backend_ramdisk_cmp(union ctl_io *io) 367e7037673SAlexander Motin { 368e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 369767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 370e7037673SAlexander Motin uint8_t *page; 371e7037673SAlexander Motin uint8_t info[8]; 372e7037673SAlexander Motin uint64_t lba; 373e7037673SAlexander Motin u_int lbaoff, lbas, res, off; 374e7037673SAlexander Motin 375e7037673SAlexander Motin lbas = io->scsiio.kern_data_len / cbe_lun->blocksize; 376e7037673SAlexander Motin lba = ARGS(io)->lba + PRIV(io)->len - lbas; 377e7037673SAlexander Motin off = 0; 378e7037673SAlexander Motin for (; lbas > 0; lbas--, lba++) { 379e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 380e7037673SAlexander Motin lba >> cbe_lun->pblockexp, GP_READ); 381e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 382e7037673SAlexander Motin page += lbaoff * cbe_lun->blocksize; 383e7037673SAlexander Motin res = cmp(io->scsiio.kern_data_ptr + off, page, 384e7037673SAlexander Motin cbe_lun->blocksize); 385e7037673SAlexander Motin off += res; 386e7037673SAlexander Motin if (res < cbe_lun->blocksize) 387e7037673SAlexander Motin break; 388e7037673SAlexander Motin } 389e7037673SAlexander Motin if (lbas > 0) { 390e7037673SAlexander Motin off += io->scsiio.kern_rel_offset - io->scsiio.kern_data_len; 391e7037673SAlexander Motin scsi_u64to8b(off, info); 392e7037673SAlexander Motin ctl_set_sense(&io->scsiio, /*current_error*/ 1, 393e7037673SAlexander Motin /*sense_key*/ SSD_KEY_MISCOMPARE, 394e7037673SAlexander Motin /*asc*/ 0x1D, /*ascq*/ 0x00, 395e7037673SAlexander Motin /*type*/ SSD_ELEM_INFO, 396e7037673SAlexander Motin /*size*/ sizeof(info), /*data*/ &info, 397e7037673SAlexander Motin /*type*/ SSD_ELEM_NONE); 398e7037673SAlexander Motin return (1); 399e7037673SAlexander Motin } 400e7037673SAlexander Motin return (0); 401e7037673SAlexander Motin } 402e7037673SAlexander Motin 403130f4520SKenneth D. Merry static int 4042c7dc6baSAlexander Motin ctl_backend_ramdisk_move_done(union ctl_io *io, bool samethr) 405130f4520SKenneth D. Merry { 406767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = 407767300e8SAlexander Motin (struct ctl_be_ramdisk_lun *)CTL_BACKEND_LUN(io); 408130f4520SKenneth D. Merry 409130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); 41008a7cce5SAlexander Motin if (io->scsiio.kern_sg_entries > 0) 41108a7cce5SAlexander Motin free(io->scsiio.kern_data_ptr, M_RAMDISK); 41208a7cce5SAlexander Motin io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 4132c7dc6baSAlexander Motin if ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0 && 4142c7dc6baSAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE) { 415e7037673SAlexander Motin if (ARGS(io)->flags & CTL_LLF_COMPARE) { 416e7037673SAlexander Motin /* We have data block ready for comparison. */ 417e7037673SAlexander Motin if (ctl_backend_ramdisk_cmp(io)) 418e7037673SAlexander Motin goto done; 419e7037673SAlexander Motin } 420e7037673SAlexander Motin if (ARGS(io)->len > PRIV(io)->len) { 42175c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 42208a7cce5SAlexander Motin STAILQ_INSERT_TAIL(&be_lun->cont_queue, 42308a7cce5SAlexander Motin &io->io_hdr, links); 42475c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 42508a7cce5SAlexander Motin taskqueue_enqueue(be_lun->io_taskqueue, 42608a7cce5SAlexander Motin &be_lun->io_task); 42708a7cce5SAlexander Motin return (0); 42808a7cce5SAlexander Motin } 4294a286345SAlexander Motin ctl_set_success(&io->scsiio); 430130f4520SKenneth D. Merry } 431e7037673SAlexander Motin done: 43211b569f7SAlexander Motin ctl_data_submit_done(io); 433130f4520SKenneth D. Merry return(0); 434130f4520SKenneth D. Merry } 435130f4520SKenneth D. Merry 436e7037673SAlexander Motin static void 437e7037673SAlexander Motin ctl_backend_ramdisk_compare(union ctl_io *io) 438e7037673SAlexander Motin { 439e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 440e7037673SAlexander Motin u_int lbas, len; 441e7037673SAlexander Motin 442e7037673SAlexander Motin lbas = ARGS(io)->len - PRIV(io)->len; 443e7037673SAlexander Motin lbas = MIN(lbas, 131072 / cbe_lun->blocksize); 444e7037673SAlexander Motin len = lbas * cbe_lun->blocksize; 445e7037673SAlexander Motin 446e7037673SAlexander Motin io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 447e7037673SAlexander Motin io->scsiio.kern_data_ptr = malloc(len, M_RAMDISK, M_WAITOK); 448e7037673SAlexander Motin io->scsiio.kern_data_len = len; 449e7037673SAlexander Motin io->scsiio.kern_sg_entries = 0; 450e7037673SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 451e7037673SAlexander Motin PRIV(io)->len += lbas; 452e7037673SAlexander Motin ctl_datamove(io); 453e7037673SAlexander Motin } 454e7037673SAlexander Motin 455e7037673SAlexander Motin static void 456e7037673SAlexander Motin ctl_backend_ramdisk_rw(union ctl_io *io) 457e7037673SAlexander Motin { 458e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 459767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 460e7037673SAlexander Motin struct ctl_sg_entry *sg_entries; 461e7037673SAlexander Motin uint8_t *page; 462e7037673SAlexander Motin uint64_t lba; 463e7037673SAlexander Motin u_int i, len, lbaoff, lbas, sgs, off; 464e7037673SAlexander Motin getpage_op_t op; 465e7037673SAlexander Motin 466e7037673SAlexander Motin lba = ARGS(io)->lba + PRIV(io)->len; 467e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 468e7037673SAlexander Motin lbas = ARGS(io)->len - PRIV(io)->len; 469e7037673SAlexander Motin lbas = MIN(lbas, (SGPP << cbe_lun->pblockexp) - lbaoff); 470e7037673SAlexander Motin sgs = (lbas + lbaoff + be_lun->pblockmul - 1) >> cbe_lun->pblockexp; 471e7037673SAlexander Motin off = lbaoff * cbe_lun->blocksize; 472e7037673SAlexander Motin op = (ARGS(io)->flags & CTL_LLF_WRITE) ? GP_WRITE : GP_READ; 473e7037673SAlexander Motin if (sgs > 1) { 474e7037673SAlexander Motin io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) * 475e7037673SAlexander Motin sgs, M_RAMDISK, M_WAITOK); 476e7037673SAlexander Motin sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 477e7037673SAlexander Motin len = lbas * cbe_lun->blocksize; 478e7037673SAlexander Motin for (i = 0; i < sgs; i++) { 479e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 480e7037673SAlexander Motin (lba >> cbe_lun->pblockexp) + i, op); 481e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) { 482e7037673SAlexander Motin free(io->scsiio.kern_data_ptr, M_RAMDISK); 483e7037673SAlexander Motin nospc: 484e7037673SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 485e7037673SAlexander Motin ctl_data_submit_done(io); 486e7037673SAlexander Motin return; 487e7037673SAlexander Motin } 488e7037673SAlexander Motin sg_entries[i].addr = page + off; 489e7037673SAlexander Motin sg_entries[i].len = MIN(len, be_lun->pblocksize - off); 490e7037673SAlexander Motin len -= sg_entries[i].len; 491e7037673SAlexander Motin off = 0; 492e7037673SAlexander Motin } 493e7037673SAlexander Motin } else { 494e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 495e7037673SAlexander Motin lba >> cbe_lun->pblockexp, op); 496e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) 497e7037673SAlexander Motin goto nospc; 498e7037673SAlexander Motin sgs = 0; 499e7037673SAlexander Motin io->scsiio.kern_data_ptr = page + off; 500e7037673SAlexander Motin } 501e7037673SAlexander Motin 502e7037673SAlexander Motin io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 503e7037673SAlexander Motin io->scsiio.kern_data_len = lbas * cbe_lun->blocksize; 504e7037673SAlexander Motin io->scsiio.kern_sg_entries = sgs; 505e7037673SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 506e7037673SAlexander Motin PRIV(io)->len += lbas; 507e8583acfSAlexander Motin if ((ARGS(io)->flags & CTL_LLF_READ) && 508e8583acfSAlexander Motin ARGS(io)->len <= PRIV(io)->len) { 509e8583acfSAlexander Motin ctl_set_success(&io->scsiio); 510ac503c19SAlexander Motin if (cbe_lun->serseq >= CTL_LUN_SERSEQ_SOFT) 511e8583acfSAlexander Motin ctl_serseq_done(io); 512e8583acfSAlexander Motin } 513e7037673SAlexander Motin ctl_datamove(io); 514e7037673SAlexander Motin } 515e7037673SAlexander Motin 516130f4520SKenneth D. Merry static int 517130f4520SKenneth D. Merry ctl_backend_ramdisk_submit(union ctl_io *io) 518130f4520SKenneth D. Merry { 519e7037673SAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 520130f4520SKenneth D. Merry 52111b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_VERIFY) { 52211b569f7SAlexander Motin ctl_set_success(&io->scsiio); 52311b569f7SAlexander Motin ctl_data_submit_done(io); 52411b569f7SAlexander Motin return (CTL_RETVAL_COMPLETE); 52511b569f7SAlexander Motin } 526e7037673SAlexander Motin PRIV(io)->len = 0; 527e7037673SAlexander Motin if (lbalen->flags & CTL_LLF_COMPARE) 528e7037673SAlexander Motin ctl_backend_ramdisk_compare(io); 529e7037673SAlexander Motin else 530e7037673SAlexander Motin ctl_backend_ramdisk_rw(io); 531130f4520SKenneth D. Merry return (CTL_RETVAL_COMPLETE); 532130f4520SKenneth D. Merry } 533130f4520SKenneth D. Merry 53408a7cce5SAlexander Motin static void 53508a7cce5SAlexander Motin ctl_backend_ramdisk_worker(void *context, int pending) 53608a7cce5SAlexander Motin { 53708a7cce5SAlexander Motin struct ctl_be_ramdisk_lun *be_lun; 53808a7cce5SAlexander Motin union ctl_io *io; 53908a7cce5SAlexander Motin 54008a7cce5SAlexander Motin be_lun = (struct ctl_be_ramdisk_lun *)context; 54175c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 54208a7cce5SAlexander Motin for (;;) { 54308a7cce5SAlexander Motin io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); 54408a7cce5SAlexander Motin if (io != NULL) { 54505d882b7SAlexander Motin STAILQ_REMOVE_HEAD(&be_lun->cont_queue, links); 54675c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 547e7037673SAlexander Motin if (ARGS(io)->flags & CTL_LLF_COMPARE) 548e7037673SAlexander Motin ctl_backend_ramdisk_compare(io); 549e7037673SAlexander Motin else 550e7037673SAlexander Motin ctl_backend_ramdisk_rw(io); 55175c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 55208a7cce5SAlexander Motin continue; 55308a7cce5SAlexander Motin } 55408a7cce5SAlexander Motin 55508a7cce5SAlexander Motin /* 55608a7cce5SAlexander Motin * If we get here, there is no work left in the queues, so 55708a7cce5SAlexander Motin * just break out and let the task queue go to sleep. 55808a7cce5SAlexander Motin */ 55908a7cce5SAlexander Motin break; 56008a7cce5SAlexander Motin } 56175c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 562130f4520SKenneth D. Merry } 563130f4520SKenneth D. Merry 564130f4520SKenneth D. Merry static int 565e7037673SAlexander Motin ctl_backend_ramdisk_gls(union ctl_io *io) 566e7037673SAlexander Motin { 567e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 568767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 569e7037673SAlexander Motin struct scsi_get_lba_status_data *data; 570e7037673SAlexander Motin uint8_t *page; 571e7037673SAlexander Motin u_int lbaoff; 572e7037673SAlexander Motin 573e7037673SAlexander Motin data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 574e7037673SAlexander Motin scsi_u64to8b(ARGS(io)->lba, data->descr[0].addr); 575e7037673SAlexander Motin lbaoff = ARGS(io)->lba & ~(UINT_MAX << cbe_lun->pblockexp); 576e7037673SAlexander Motin scsi_ulto4b(be_lun->pblockmul - lbaoff, data->descr[0].length); 577e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 578e7037673SAlexander Motin ARGS(io)->lba >> cbe_lun->pblockexp, GP_OTHER); 579e7037673SAlexander Motin if (page == P_UNMAPPED) 580e7037673SAlexander Motin data->descr[0].status = 1; 581e7037673SAlexander Motin else if (page == P_ANCHORED) 582e7037673SAlexander Motin data->descr[0].status = 2; 583e7037673SAlexander Motin else 584e7037673SAlexander Motin data->descr[0].status = 0; 585e7037673SAlexander Motin ctl_config_read_done(io); 586e7037673SAlexander Motin return (CTL_RETVAL_COMPLETE); 587e7037673SAlexander Motin } 588e7037673SAlexander Motin 589e7037673SAlexander Motin static int 590e7037673SAlexander Motin ctl_backend_ramdisk_config_read(union ctl_io *io) 591e7037673SAlexander Motin { 592e7037673SAlexander Motin int retval = 0; 593e7037673SAlexander Motin 594e7037673SAlexander Motin switch (io->scsiio.cdb[0]) { 595e7037673SAlexander Motin case SERVICE_ACTION_IN: 596e7037673SAlexander Motin if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 597e7037673SAlexander Motin retval = ctl_backend_ramdisk_gls(io); 598e7037673SAlexander Motin break; 599e7037673SAlexander Motin } 600e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 601e7037673SAlexander Motin /*sks_valid*/ 1, 602e7037673SAlexander Motin /*command*/ 1, 603e7037673SAlexander Motin /*field*/ 1, 604e7037673SAlexander Motin /*bit_valid*/ 1, 605e7037673SAlexander Motin /*bit*/ 4); 606e7037673SAlexander Motin ctl_config_read_done(io); 607e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 608e7037673SAlexander Motin break; 609e7037673SAlexander Motin default: 610e7037673SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 611e7037673SAlexander Motin ctl_config_read_done(io); 612e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 613e7037673SAlexander Motin break; 614e7037673SAlexander Motin } 615e7037673SAlexander Motin return (retval); 616e7037673SAlexander Motin } 617e7037673SAlexander Motin 618e7037673SAlexander Motin static void 619e7037673SAlexander Motin ctl_backend_ramdisk_delete(struct ctl_be_lun *cbe_lun, off_t lba, off_t len, 620e7037673SAlexander Motin int anchor) 621e7037673SAlexander Motin { 622767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 623e7037673SAlexander Motin uint8_t *page; 624e7037673SAlexander Motin uint64_t p, lp; 625e7037673SAlexander Motin u_int lbaoff; 626e7037673SAlexander Motin getpage_op_t op = anchor ? GP_ANCHOR : GP_OTHER; 627e7037673SAlexander Motin 628e7037673SAlexander Motin /* Partially zero first partial page. */ 629e7037673SAlexander Motin p = lba >> cbe_lun->pblockexp; 630e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 631e7037673SAlexander Motin if (lbaoff != 0) { 632e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, p, op); 633e7037673SAlexander Motin if (page != P_UNMAPPED && page != P_ANCHORED) { 634e7037673SAlexander Motin memset(page + lbaoff * cbe_lun->blocksize, 0, 635e7037673SAlexander Motin min(len, be_lun->pblockmul - lbaoff) * 636e7037673SAlexander Motin cbe_lun->blocksize); 637e7037673SAlexander Motin } 638e7037673SAlexander Motin p++; 639e7037673SAlexander Motin } 640e7037673SAlexander Motin 641e7037673SAlexander Motin /* Partially zero last partial page. */ 642e7037673SAlexander Motin lp = (lba + len) >> cbe_lun->pblockexp; 643e7037673SAlexander Motin lbaoff = (lba + len) & ~(UINT_MAX << cbe_lun->pblockexp); 644e7037673SAlexander Motin if (p <= lp && lbaoff != 0) { 645e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, lp, op); 646e7037673SAlexander Motin if (page != P_UNMAPPED && page != P_ANCHORED) 647e7037673SAlexander Motin memset(page, 0, lbaoff * cbe_lun->blocksize); 648e7037673SAlexander Motin } 649e7037673SAlexander Motin 650e7037673SAlexander Motin /* Delete remaining full pages. */ 651e7037673SAlexander Motin if (anchor) { 652e7037673SAlexander Motin for (; p < lp; p++) 653e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(be_lun, p); 654e7037673SAlexander Motin } else { 655e7037673SAlexander Motin for (; p < lp; p++) 656e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(be_lun, p); 657e7037673SAlexander Motin } 658e7037673SAlexander Motin } 659e7037673SAlexander Motin 660e7037673SAlexander Motin static void 661e7037673SAlexander Motin ctl_backend_ramdisk_ws(union ctl_io *io) 662e7037673SAlexander Motin { 663e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 664767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 665e7037673SAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 666e7037673SAlexander Motin uint8_t *page; 667e7037673SAlexander Motin uint64_t lba; 668e7037673SAlexander Motin u_int lbaoff, lbas; 669e7037673SAlexander Motin 670e7037673SAlexander Motin if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB)) { 671e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 672e7037673SAlexander Motin /*sks_valid*/ 1, 673e7037673SAlexander Motin /*command*/ 1, 674e7037673SAlexander Motin /*field*/ 1, 675e7037673SAlexander Motin /*bit_valid*/ 0, 676e7037673SAlexander Motin /*bit*/ 0); 677e7037673SAlexander Motin ctl_config_write_done(io); 678e7037673SAlexander Motin return; 679e7037673SAlexander Motin } 680e7037673SAlexander Motin if (lbalen->flags & SWS_UNMAP) { 681e7037673SAlexander Motin ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 682e7037673SAlexander Motin (lbalen->flags & SWS_ANCHOR) != 0); 683e7037673SAlexander Motin ctl_set_success(&io->scsiio); 684e7037673SAlexander Motin ctl_config_write_done(io); 685e7037673SAlexander Motin return; 686e7037673SAlexander Motin } 687e7037673SAlexander Motin 688e7037673SAlexander Motin for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) { 689e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 690e7037673SAlexander Motin lba >> cbe_lun->pblockexp, GP_WRITE); 691e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) { 692e7037673SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 693e7037673SAlexander Motin ctl_data_submit_done(io); 694e7037673SAlexander Motin return; 695e7037673SAlexander Motin } 696e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 697e7037673SAlexander Motin page += lbaoff * cbe_lun->blocksize; 698e7037673SAlexander Motin if (lbalen->flags & SWS_NDOB) { 699e7037673SAlexander Motin memset(page, 0, cbe_lun->blocksize); 700e7037673SAlexander Motin } else { 701e7037673SAlexander Motin memcpy(page, io->scsiio.kern_data_ptr, 702e7037673SAlexander Motin cbe_lun->blocksize); 703e7037673SAlexander Motin } 704e7037673SAlexander Motin if (lbalen->flags & SWS_LBDATA) 705e7037673SAlexander Motin scsi_ulto4b(lba, page); 706e7037673SAlexander Motin } 707e7037673SAlexander Motin ctl_set_success(&io->scsiio); 708e7037673SAlexander Motin ctl_config_write_done(io); 709e7037673SAlexander Motin } 710e7037673SAlexander Motin 711e7037673SAlexander Motin static void 712e7037673SAlexander Motin ctl_backend_ramdisk_unmap(union ctl_io *io) 713e7037673SAlexander Motin { 714e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 715e7037673SAlexander Motin struct ctl_ptr_len_flags *ptrlen = (struct ctl_ptr_len_flags *)ARGS(io); 716e7037673SAlexander Motin struct scsi_unmap_desc *buf, *end; 717e7037673SAlexander Motin 718e7037673SAlexander Motin if ((ptrlen->flags & ~SU_ANCHOR) != 0) { 719e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 720e7037673SAlexander Motin /*sks_valid*/ 0, 721e7037673SAlexander Motin /*command*/ 0, 722e7037673SAlexander Motin /*field*/ 0, 723e7037673SAlexander Motin /*bit_valid*/ 0, 724e7037673SAlexander Motin /*bit*/ 0); 725e7037673SAlexander Motin ctl_config_write_done(io); 726e7037673SAlexander Motin return; 727e7037673SAlexander Motin } 728e7037673SAlexander Motin 729e7037673SAlexander Motin buf = (struct scsi_unmap_desc *)ptrlen->ptr; 730e7037673SAlexander Motin end = buf + ptrlen->len / sizeof(*buf); 731e7037673SAlexander Motin for (; buf < end; buf++) { 732e7037673SAlexander Motin ctl_backend_ramdisk_delete(cbe_lun, 733e7037673SAlexander Motin scsi_8btou64(buf->lba), scsi_4btoul(buf->length), 734e7037673SAlexander Motin (ptrlen->flags & SU_ANCHOR) != 0); 735e7037673SAlexander Motin } 736e7037673SAlexander Motin 737e7037673SAlexander Motin ctl_set_success(&io->scsiio); 738e7037673SAlexander Motin ctl_config_write_done(io); 739e7037673SAlexander Motin } 740e7037673SAlexander Motin 741e7037673SAlexander Motin static int 742e7037673SAlexander Motin ctl_backend_ramdisk_config_write(union ctl_io *io) 743e7037673SAlexander Motin { 744e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 745e7037673SAlexander Motin int retval = 0; 746e7037673SAlexander Motin 747e7037673SAlexander Motin switch (io->scsiio.cdb[0]) { 748e7037673SAlexander Motin case SYNCHRONIZE_CACHE: 749e7037673SAlexander Motin case SYNCHRONIZE_CACHE_16: 750e7037673SAlexander Motin /* We have no cache to flush. */ 751e7037673SAlexander Motin ctl_set_success(&io->scsiio); 752e7037673SAlexander Motin ctl_config_write_done(io); 753e7037673SAlexander Motin break; 754e7037673SAlexander Motin case START_STOP_UNIT: { 755e7037673SAlexander Motin struct scsi_start_stop_unit *cdb; 756e7037673SAlexander Motin 757e7037673SAlexander Motin cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 758e7037673SAlexander Motin if ((cdb->how & SSS_PC_MASK) != 0) { 759e7037673SAlexander Motin ctl_set_success(&io->scsiio); 760e7037673SAlexander Motin ctl_config_write_done(io); 761e7037673SAlexander Motin break; 762e7037673SAlexander Motin } 763e7037673SAlexander Motin if (cdb->how & SSS_START) { 764e7037673SAlexander Motin if (cdb->how & SSS_LOEJ) 765e7037673SAlexander Motin ctl_lun_has_media(cbe_lun); 766e7037673SAlexander Motin ctl_start_lun(cbe_lun); 767e7037673SAlexander Motin } else { 768e7037673SAlexander Motin ctl_stop_lun(cbe_lun); 769e7037673SAlexander Motin if (cdb->how & SSS_LOEJ) 770e7037673SAlexander Motin ctl_lun_ejected(cbe_lun); 771e7037673SAlexander Motin } 772e7037673SAlexander Motin ctl_set_success(&io->scsiio); 773e7037673SAlexander Motin ctl_config_write_done(io); 774e7037673SAlexander Motin break; 775e7037673SAlexander Motin } 776e7037673SAlexander Motin case PREVENT_ALLOW: 777e7037673SAlexander Motin ctl_set_success(&io->scsiio); 778e7037673SAlexander Motin ctl_config_write_done(io); 779e7037673SAlexander Motin break; 780e7037673SAlexander Motin case WRITE_SAME_10: 781e7037673SAlexander Motin case WRITE_SAME_16: 782e7037673SAlexander Motin ctl_backend_ramdisk_ws(io); 783e7037673SAlexander Motin break; 784e7037673SAlexander Motin case UNMAP: 785e7037673SAlexander Motin ctl_backend_ramdisk_unmap(io); 786e7037673SAlexander Motin break; 787e7037673SAlexander Motin default: 788e7037673SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 789e7037673SAlexander Motin ctl_config_write_done(io); 790e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 791e7037673SAlexander Motin break; 792e7037673SAlexander Motin } 793e7037673SAlexander Motin 794e7037673SAlexander Motin return (retval); 795e7037673SAlexander Motin } 796e7037673SAlexander Motin 797e7037673SAlexander Motin static uint64_t 798767300e8SAlexander Motin ctl_backend_ramdisk_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname) 799e7037673SAlexander Motin { 800767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 801e7037673SAlexander Motin uint64_t val; 802e7037673SAlexander Motin 803e7037673SAlexander Motin val = UINT64_MAX; 804e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 805e7037673SAlexander Motin return (val); 806e7037673SAlexander Motin sx_slock(&be_lun->page_lock); 807e7037673SAlexander Motin if (strcmp(attrname, "blocksused") == 0) { 808e7037673SAlexander Motin val = be_lun->cap_used / be_lun->cbe_lun.blocksize; 809e7037673SAlexander Motin } else if (strcmp(attrname, "blocksavail") == 0) { 810e7037673SAlexander Motin val = (be_lun->cap_bytes - be_lun->cap_used) / 811e7037673SAlexander Motin be_lun->cbe_lun.blocksize; 812e7037673SAlexander Motin } 813e7037673SAlexander Motin sx_sunlock(&be_lun->page_lock); 814e7037673SAlexander Motin return (val); 815e7037673SAlexander Motin } 816e7037673SAlexander Motin 817e7037673SAlexander Motin static int 818130f4520SKenneth D. Merry ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 819130f4520SKenneth D. Merry int flag, struct thread *td) 820130f4520SKenneth D. Merry { 82167cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 82267cc546dSAlexander Motin struct ctl_lun_req *lun_req; 823130f4520SKenneth D. Merry int retval; 824130f4520SKenneth D. Merry 825130f4520SKenneth D. Merry retval = 0; 826130f4520SKenneth D. Merry switch (cmd) { 82767cc546dSAlexander Motin case CTL_LUN_REQ: 828130f4520SKenneth D. Merry lun_req = (struct ctl_lun_req *)addr; 829130f4520SKenneth D. Merry switch (lun_req->reqtype) { 830130f4520SKenneth D. Merry case CTL_LUNREQ_CREATE: 8310bcd4ab6SAlexander Motin retval = ctl_backend_ramdisk_create(softc, lun_req); 832130f4520SKenneth D. Merry break; 833130f4520SKenneth D. Merry case CTL_LUNREQ_RM: 834130f4520SKenneth D. Merry retval = ctl_backend_ramdisk_rm(softc, lun_req); 835130f4520SKenneth D. Merry break; 83681177295SEdward Tomasz Napierala case CTL_LUNREQ_MODIFY: 83781177295SEdward Tomasz Napierala retval = ctl_backend_ramdisk_modify(softc, lun_req); 83881177295SEdward Tomasz Napierala break; 839130f4520SKenneth D. Merry default: 840130f4520SKenneth D. Merry lun_req->status = CTL_LUN_ERROR; 841130f4520SKenneth D. Merry snprintf(lun_req->error_str, sizeof(lun_req->error_str), 842130f4520SKenneth D. Merry "%s: invalid LUN request type %d", __func__, 843130f4520SKenneth D. Merry lun_req->reqtype); 844130f4520SKenneth D. Merry break; 845130f4520SKenneth D. Merry } 846130f4520SKenneth D. Merry break; 847130f4520SKenneth D. Merry default: 848130f4520SKenneth D. Merry retval = ENOTTY; 849130f4520SKenneth D. Merry break; 850130f4520SKenneth D. Merry } 851130f4520SKenneth D. Merry 852130f4520SKenneth D. Merry return (retval); 853130f4520SKenneth D. Merry } 854130f4520SKenneth D. Merry 855130f4520SKenneth D. Merry static int 856130f4520SKenneth D. Merry ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 857130f4520SKenneth D. Merry struct ctl_lun_req *req) 858130f4520SKenneth D. Merry { 859130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 860130f4520SKenneth D. Merry struct ctl_lun_rm_params *params; 861130f4520SKenneth D. Merry int retval; 862130f4520SKenneth D. Merry 863130f4520SKenneth D. Merry params = &req->reqdata.rm; 86434144c2cSAlexander Motin sx_xlock(&softc->modify_lock); 865130f4520SKenneth D. Merry mtx_lock(&softc->lock); 86634144c2cSAlexander Motin SLIST_FOREACH(be_lun, &softc->lun_list, links) { 86734144c2cSAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) { 86834144c2cSAlexander Motin SLIST_REMOVE(&softc->lun_list, be_lun, 86934144c2cSAlexander Motin ctl_be_ramdisk_lun, links); 87034144c2cSAlexander Motin softc->num_luns--; 871130f4520SKenneth D. Merry break; 872130f4520SKenneth D. Merry } 87334144c2cSAlexander Motin } 874130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 87534144c2cSAlexander Motin sx_xunlock(&softc->modify_lock); 876130f4520SKenneth D. Merry if (be_lun == NULL) { 877130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 878130f4520SKenneth D. Merry "%s: LUN %u is not managed by the ramdisk backend", 879130f4520SKenneth D. Merry __func__, params->lun_id); 880130f4520SKenneth D. Merry goto bailout_error; 881130f4520SKenneth D. Merry } 882130f4520SKenneth D. Merry 883130f4520SKenneth D. Merry /* 884130f4520SKenneth D. Merry * Set the waiting flag before we invalidate the LUN. Our shutdown 885130f4520SKenneth D. Merry * routine can be called any time after we invalidate the LUN, 886130f4520SKenneth D. Merry * and can be called from our context. 887130f4520SKenneth D. Merry * 888130f4520SKenneth D. Merry * This tells the shutdown routine that we're waiting, or we're 889130f4520SKenneth D. Merry * going to wait for the shutdown to happen. 890130f4520SKenneth D. Merry */ 891130f4520SKenneth D. Merry mtx_lock(&softc->lock); 892130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 893130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 894130f4520SKenneth D. Merry 89534144c2cSAlexander Motin retval = ctl_remove_lun(&be_lun->cbe_lun); 896130f4520SKenneth D. Merry if (retval != 0) { 897130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 89834144c2cSAlexander Motin "%s: error %d returned from ctl_remove_lun() for " 899130f4520SKenneth D. Merry "LUN %d", __func__, retval, params->lun_id); 900ce300fbfSAlexander Motin mtx_lock(&softc->lock); 901ce300fbfSAlexander Motin be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 902ce300fbfSAlexander Motin mtx_unlock(&softc->lock); 903130f4520SKenneth D. Merry goto bailout_error; 904130f4520SKenneth D. Merry } 905130f4520SKenneth D. Merry 906130f4520SKenneth D. Merry mtx_lock(&softc->lock); 907130f4520SKenneth D. Merry while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) { 90834144c2cSAlexander Motin retval = msleep(be_lun, &softc->lock, PCATCH, "ctlramrm", 0); 909130f4520SKenneth D. Merry if (retval == EINTR) 910130f4520SKenneth D. Merry break; 911130f4520SKenneth D. Merry } 912130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 91334144c2cSAlexander Motin if (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 914130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 915130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 91634144c2cSAlexander Motin } else { 91734144c2cSAlexander Motin mtx_unlock(&softc->lock); 91834144c2cSAlexander Motin return (EINTR); 91908a7cce5SAlexander Motin } 920130f4520SKenneth D. Merry 921130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 922130f4520SKenneth D. Merry return (retval); 923130f4520SKenneth D. Merry 924130f4520SKenneth D. Merry bailout_error: 925130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 926130f4520SKenneth D. Merry return (0); 927130f4520SKenneth D. Merry } 928130f4520SKenneth D. Merry 929130f4520SKenneth D. Merry static int 930130f4520SKenneth D. Merry ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 9310bcd4ab6SAlexander Motin struct ctl_lun_req *req) 932130f4520SKenneth D. Merry { 933130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 9340bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 935130f4520SKenneth D. Merry struct ctl_lun_create_params *params; 9368951f055SMarcelo Araujo const char *value; 937130f4520SKenneth D. Merry char tmpstr[32]; 938e7037673SAlexander Motin uint64_t t; 9390bcd4ab6SAlexander Motin int retval; 940130f4520SKenneth D. Merry 941130f4520SKenneth D. Merry retval = 0; 942130f4520SKenneth D. Merry params = &req->reqdata.create; 943130f4520SKenneth D. Merry 9440bcd4ab6SAlexander Motin be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK); 9450bcd4ab6SAlexander Motin cbe_lun = &be_lun->cbe_lun; 9468951f055SMarcelo Araujo cbe_lun->options = nvlist_clone(req->args_nvl); 947a3977beaSAlexander Motin be_lun->params = req->reqdata.create; 9480bcd4ab6SAlexander Motin be_lun->softc = softc; 949130f4520SKenneth D. Merry 950130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 9510bcd4ab6SAlexander Motin cbe_lun->lun_type = params->device_type; 952130f4520SKenneth D. Merry else 9530bcd4ab6SAlexander Motin cbe_lun->lun_type = T_DIRECT; 95434144c2cSAlexander Motin be_lun->flags = 0; 9557ac58230SAlexander Motin cbe_lun->flags = 0; 9568951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 9577ac58230SAlexander Motin if (value != NULL) { 9587ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 9597ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 9607ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 9617ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 962130f4520SKenneth D. Merry 963e7037673SAlexander Motin be_lun->pblocksize = PAGE_SIZE; 9648951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); 965e7037673SAlexander Motin if (value != NULL) { 966e7037673SAlexander Motin ctl_expand_number(value, &t); 967e7037673SAlexander Motin be_lun->pblocksize = t; 968e7037673SAlexander Motin } 969e7037673SAlexander Motin if (be_lun->pblocksize < 512 || be_lun->pblocksize > 131072) { 970e7037673SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 971e7037673SAlexander Motin "%s: unsupported pblocksize %u", __func__, 972e7037673SAlexander Motin be_lun->pblocksize); 973e7037673SAlexander Motin goto bailout_error; 974e7037673SAlexander Motin } 975e7037673SAlexander Motin 97691be33dcSAlexander Motin if (cbe_lun->lun_type == T_DIRECT || 97791be33dcSAlexander Motin cbe_lun->lun_type == T_CDROM) { 9780bcd4ab6SAlexander Motin if (params->blocksize_bytes != 0) 9790bcd4ab6SAlexander Motin cbe_lun->blocksize = params->blocksize_bytes; 98091be33dcSAlexander Motin else if (cbe_lun->lun_type == T_CDROM) 98191be33dcSAlexander Motin cbe_lun->blocksize = 2048; 9820bcd4ab6SAlexander Motin else 9830bcd4ab6SAlexander Motin cbe_lun->blocksize = 512; 984e7037673SAlexander Motin be_lun->pblockmul = be_lun->pblocksize / cbe_lun->blocksize; 985e7037673SAlexander Motin if (be_lun->pblockmul < 1 || !powerof2(be_lun->pblockmul)) { 986e7037673SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 987e7037673SAlexander Motin "%s: pblocksize %u not exp2 of blocksize %u", 988e7037673SAlexander Motin __func__, 989e7037673SAlexander Motin be_lun->pblocksize, cbe_lun->blocksize); 990e7037673SAlexander Motin goto bailout_error; 991e7037673SAlexander Motin } 9920bcd4ab6SAlexander Motin if (params->lun_size_bytes < cbe_lun->blocksize) { 993130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 994130f4520SKenneth D. Merry "%s: LUN size %ju < blocksize %u", __func__, 9950bcd4ab6SAlexander Motin params->lun_size_bytes, cbe_lun->blocksize); 996130f4520SKenneth D. Merry goto bailout_error; 997130f4520SKenneth D. Merry } 9980bcd4ab6SAlexander Motin be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize; 9990bcd4ab6SAlexander Motin be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize; 1000e7037673SAlexander Motin be_lun->indir = 0; 1001e7037673SAlexander Motin t = be_lun->size_bytes / be_lun->pblocksize; 1002e7037673SAlexander Motin while (t > 1) { 1003e7037673SAlexander Motin t /= PPP; 1004e7037673SAlexander Motin be_lun->indir++; 1005e7037673SAlexander Motin } 10060bcd4ab6SAlexander Motin cbe_lun->maxlba = be_lun->size_blocks - 1; 1007e7037673SAlexander Motin cbe_lun->pblockexp = fls(be_lun->pblockmul) - 1; 1008e7037673SAlexander Motin cbe_lun->pblockoff = 0; 1009e7037673SAlexander Motin cbe_lun->ublockexp = cbe_lun->pblockexp; 1010e7037673SAlexander Motin cbe_lun->ublockoff = 0; 1011e7037673SAlexander Motin cbe_lun->atomicblock = be_lun->pblocksize; 1012e7037673SAlexander Motin cbe_lun->opttxferlen = SGPP * be_lun->pblocksize; 10138951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "capacity", NULL); 1014e7037673SAlexander Motin if (value != NULL) 1015e7037673SAlexander Motin ctl_expand_number(value, &be_lun->cap_bytes); 1016e7037673SAlexander Motin } else { 1017e7037673SAlexander Motin be_lun->pblockmul = 1; 1018e7037673SAlexander Motin cbe_lun->pblockexp = 0; 1019130f4520SKenneth D. Merry } 1020130f4520SKenneth D. Merry 1021130f4520SKenneth D. Merry /* Tell the user the blocksize we ended up using */ 10220bcd4ab6SAlexander Motin params->blocksize_bytes = cbe_lun->blocksize; 1023130f4520SKenneth D. Merry params->lun_size_bytes = be_lun->size_bytes; 1024130f4520SKenneth D. Merry 10258951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "unmap", NULL); 10261173e5a7SAlexander Motin if (value == NULL || strcmp(value, "off") != 0) 10270bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 10288951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "readonly", NULL); 102991be33dcSAlexander Motin if (value != NULL) { 103091be33dcSAlexander Motin if (strcmp(value, "on") == 0) 103191be33dcSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 103291be33dcSAlexander Motin } else if (cbe_lun->lun_type != T_DIRECT) 10330bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 10340bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 10358951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "serseq", NULL); 10360bcd4ab6SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 10370bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 10380bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "read") == 0) 10390bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 1040ac503c19SAlexander Motin else if (value != NULL && strcmp(value, "soft") == 0) 1041ac503c19SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_SOFT; 10420bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "off") == 0) 10430bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 1044130f4520SKenneth D. Merry 1045130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_ID_REQ) { 10460bcd4ab6SAlexander Motin cbe_lun->req_lun_id = params->req_lun_id; 10470bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 1048130f4520SKenneth D. Merry } else 10490bcd4ab6SAlexander Motin cbe_lun->req_lun_id = 0; 1050130f4520SKenneth D. Merry 10510bcd4ab6SAlexander Motin cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 10520bcd4ab6SAlexander Motin cbe_lun->be = &ctl_be_ramdisk_driver; 1053130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 105471cd87c6SAlan Somers snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%04d", 1055130f4520SKenneth D. Merry softc->num_luns); 10560bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, tmpstr, 10570bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 1058130f4520SKenneth D. Merry 1059130f4520SKenneth D. Merry /* Tell the user what we used for a serial number */ 1060130f4520SKenneth D. Merry strncpy((char *)params->serial_num, tmpstr, 1061e7038eb7SAlexander Motin MIN(sizeof(params->serial_num), sizeof(tmpstr))); 1062130f4520SKenneth D. Merry } else { 10630bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, params->serial_num, 10640bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), 1065130f4520SKenneth D. Merry sizeof(params->serial_num))); 1066130f4520SKenneth D. Merry } 1067130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 106871cd87c6SAlan Somers snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%04d", softc->num_luns); 10690bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, tmpstr, 10700bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 1071130f4520SKenneth D. Merry 1072130f4520SKenneth D. Merry /* Tell the user what we used for a device ID */ 1073130f4520SKenneth D. Merry strncpy((char *)params->device_id, tmpstr, 1074e7038eb7SAlexander Motin MIN(sizeof(params->device_id), sizeof(tmpstr))); 1075130f4520SKenneth D. Merry } else { 10760bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, params->device_id, 10770bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), 1078130f4520SKenneth D. Merry sizeof(params->device_id))); 1079130f4520SKenneth D. Merry } 1080130f4520SKenneth D. Merry 108108a7cce5SAlexander Motin STAILQ_INIT(&be_lun->cont_queue); 108234144c2cSAlexander Motin sx_init(&be_lun->page_lock, "ctlram page"); 10832fb36370SAlexander Motin if (be_lun->cap_bytes == 0) { 10842fb36370SAlexander Motin be_lun->indir = 0; 1085e7037673SAlexander Motin be_lun->pages = malloc(be_lun->pblocksize, M_RAMDISK, M_WAITOK); 10862fb36370SAlexander Motin } 1087e7037673SAlexander Motin be_lun->zero_page = malloc(be_lun->pblocksize, M_RAMDISK, 1088e7037673SAlexander Motin M_WAITOK|M_ZERO); 108934144c2cSAlexander Motin mtx_init(&be_lun->queue_lock, "ctlram queue", NULL, MTX_DEF); 109008a7cce5SAlexander Motin TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 109108a7cce5SAlexander Motin be_lun); 109208a7cce5SAlexander Motin 109334144c2cSAlexander Motin be_lun->io_taskqueue = taskqueue_create("ctlramtq", M_WAITOK, 109408a7cce5SAlexander Motin taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 109508a7cce5SAlexander Motin if (be_lun->io_taskqueue == NULL) { 109608a7cce5SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 109708a7cce5SAlexander Motin "%s: Unable to create taskqueue", __func__); 109808a7cce5SAlexander Motin goto bailout_error; 109908a7cce5SAlexander Motin } 110008a7cce5SAlexander Motin 110112373e95SAlexander Motin retval = taskqueue_start_threads_in_proc(&be_lun->io_taskqueue, 110208a7cce5SAlexander Motin /*num threads*/1, 1103053db1feSAlexander Motin /*priority*/PUSER, 110412373e95SAlexander Motin /*proc*/control_softc->ctl_proc, 110534144c2cSAlexander Motin /*thread name*/"ramdisk"); 110608a7cce5SAlexander Motin if (retval != 0) 110708a7cce5SAlexander Motin goto bailout_error; 110808a7cce5SAlexander Motin 11090bcd4ab6SAlexander Motin retval = ctl_add_lun(&be_lun->cbe_lun); 1110130f4520SKenneth D. Merry if (retval != 0) { 1111130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1112130f4520SKenneth D. Merry "%s: ctl_add_lun() returned error %d, see dmesg for " 1113130f4520SKenneth D. Merry "details", __func__, retval); 1114130f4520SKenneth D. Merry retval = 0; 1115130f4520SKenneth D. Merry goto bailout_error; 1116130f4520SKenneth D. Merry } 1117130f4520SKenneth D. Merry 1118130f4520SKenneth D. Merry mtx_lock(&softc->lock); 111934144c2cSAlexander Motin softc->num_luns++; 112034144c2cSAlexander Motin SLIST_INSERT_HEAD(&softc->lun_list, be_lun, links); 1121130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 112234144c2cSAlexander Motin 11230bcd4ab6SAlexander Motin params->req_lun_id = cbe_lun->lun_id; 1124130f4520SKenneth D. Merry 1125130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 1126130f4520SKenneth D. Merry return (retval); 1127130f4520SKenneth D. Merry 1128130f4520SKenneth D. Merry bailout_error: 1129130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 113008a7cce5SAlexander Motin if (be_lun != NULL) { 1131e7037673SAlexander Motin if (be_lun->io_taskqueue != NULL) 113208a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 11338951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 1134e7037673SAlexander Motin free(be_lun->zero_page, M_RAMDISK); 1135e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 1136e7037673SAlexander Motin sx_destroy(&be_lun->page_lock); 113775c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 1138130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 113908a7cce5SAlexander Motin } 1140130f4520SKenneth D. Merry return (retval); 1141130f4520SKenneth D. Merry } 1142130f4520SKenneth D. Merry 114381177295SEdward Tomasz Napierala static int 114481177295SEdward Tomasz Napierala ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 114581177295SEdward Tomasz Napierala struct ctl_lun_req *req) 114681177295SEdward Tomasz Napierala { 114781177295SEdward Tomasz Napierala struct ctl_be_ramdisk_lun *be_lun; 1148a3977beaSAlexander Motin struct ctl_be_lun *cbe_lun; 114981177295SEdward Tomasz Napierala struct ctl_lun_modify_params *params; 11508951f055SMarcelo Araujo const char *value; 115181177295SEdward Tomasz Napierala uint32_t blocksize; 11527ac58230SAlexander Motin int wasprim; 115381177295SEdward Tomasz Napierala 115481177295SEdward Tomasz Napierala params = &req->reqdata.modify; 115534144c2cSAlexander Motin sx_xlock(&softc->modify_lock); 115681177295SEdward Tomasz Napierala mtx_lock(&softc->lock); 115734144c2cSAlexander Motin SLIST_FOREACH(be_lun, &softc->lun_list, links) { 11580bcd4ab6SAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) 115981177295SEdward Tomasz Napierala break; 116081177295SEdward Tomasz Napierala } 116181177295SEdward Tomasz Napierala mtx_unlock(&softc->lock); 116281177295SEdward Tomasz Napierala if (be_lun == NULL) { 116381177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 116481177295SEdward Tomasz Napierala "%s: LUN %u is not managed by the ramdisk backend", 116581177295SEdward Tomasz Napierala __func__, params->lun_id); 116681177295SEdward Tomasz Napierala goto bailout_error; 116781177295SEdward Tomasz Napierala } 1168a3977beaSAlexander Motin cbe_lun = &be_lun->cbe_lun; 116981177295SEdward Tomasz Napierala 1170a3977beaSAlexander Motin if (params->lun_size_bytes != 0) 1171a3977beaSAlexander Motin be_lun->params.lun_size_bytes = params->lun_size_bytes; 11728951f055SMarcelo Araujo 1173efeedddcSAlexander Motin if (req->args_nvl != NULL) { 11748951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 11758951f055SMarcelo Araujo cbe_lun->options = nvlist_clone(req->args_nvl); 1176efeedddcSAlexander Motin } 117781177295SEdward Tomasz Napierala 11787ac58230SAlexander Motin wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 11798951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 11807ac58230SAlexander Motin if (value != NULL) { 11817ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 11827ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 11837ac58230SAlexander Motin else 11847ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 11857ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 11867ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 11877ac58230SAlexander Motin else 11887ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 11897ac58230SAlexander Motin if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 11907ac58230SAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 11917ac58230SAlexander Motin ctl_lun_primary(cbe_lun); 11927ac58230SAlexander Motin else 11937ac58230SAlexander Motin ctl_lun_secondary(cbe_lun); 11947ac58230SAlexander Motin } 11957ac58230SAlexander Motin 11967ac58230SAlexander Motin blocksize = be_lun->cbe_lun.blocksize; 1197a3977beaSAlexander Motin if (be_lun->params.lun_size_bytes < blocksize) { 119881177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 119981177295SEdward Tomasz Napierala "%s: LUN size %ju < blocksize %u", __func__, 1200a3977beaSAlexander Motin be_lun->params.lun_size_bytes, blocksize); 120181177295SEdward Tomasz Napierala goto bailout_error; 120281177295SEdward Tomasz Napierala } 1203a3977beaSAlexander Motin be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize; 120481177295SEdward Tomasz Napierala be_lun->size_bytes = be_lun->size_blocks * blocksize; 12050bcd4ab6SAlexander Motin be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1; 12060bcd4ab6SAlexander Motin ctl_lun_capacity_changed(&be_lun->cbe_lun); 120781177295SEdward Tomasz Napierala 120881177295SEdward Tomasz Napierala /* Tell the user the exact size we ended up using */ 120981177295SEdward Tomasz Napierala params->lun_size_bytes = be_lun->size_bytes; 121081177295SEdward Tomasz Napierala 121134144c2cSAlexander Motin sx_xunlock(&softc->modify_lock); 121281177295SEdward Tomasz Napierala req->status = CTL_LUN_OK; 121381177295SEdward Tomasz Napierala return (0); 121481177295SEdward Tomasz Napierala 121581177295SEdward Tomasz Napierala bailout_error: 121634144c2cSAlexander Motin sx_xunlock(&softc->modify_lock); 121781177295SEdward Tomasz Napierala req->status = CTL_LUN_ERROR; 121881177295SEdward Tomasz Napierala return (0); 121981177295SEdward Tomasz Napierala } 122081177295SEdward Tomasz Napierala 1221130f4520SKenneth D. Merry static void 1222767300e8SAlexander Motin ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun *cbe_lun) 1223130f4520SKenneth D. Merry { 1224767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 122534144c2cSAlexander Motin struct ctl_be_ramdisk_softc *softc = be_lun->softc; 122634144c2cSAlexander Motin 122734144c2cSAlexander Motin taskqueue_drain_all(be_lun->io_taskqueue); 122834144c2cSAlexander Motin taskqueue_free(be_lun->io_taskqueue); 122934144c2cSAlexander Motin nvlist_destroy(be_lun->cbe_lun.options); 123034144c2cSAlexander Motin free(be_lun->zero_page, M_RAMDISK); 123134144c2cSAlexander Motin ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 123234144c2cSAlexander Motin sx_destroy(&be_lun->page_lock); 123334144c2cSAlexander Motin mtx_destroy(&be_lun->queue_lock); 1234130f4520SKenneth D. Merry 1235130f4520SKenneth D. Merry mtx_lock(&softc->lock); 123634144c2cSAlexander Motin be_lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 123734144c2cSAlexander Motin if (be_lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 123834144c2cSAlexander Motin wakeup(be_lun); 123934144c2cSAlexander Motin else 124068bf823fSAlexander Motin free(be_lun, M_RAMDISK); 1241130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1242130f4520SKenneth D. Merry } 1243