1130f4520SKenneth D. Merry /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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/param.h> 46130f4520SKenneth D. Merry #include <sys/systm.h> 47130f4520SKenneth D. Merry #include <sys/kernel.h> 48130f4520SKenneth D. Merry #include <sys/condvar.h> 49130f4520SKenneth D. Merry #include <sys/types.h> 50e7037673SAlexander Motin #include <sys/limits.h> 51130f4520SKenneth D. Merry #include <sys/lock.h> 52130f4520SKenneth D. Merry #include <sys/mutex.h> 53130f4520SKenneth D. Merry #include <sys/malloc.h> 54e7037673SAlexander Motin #include <sys/sx.h> 5508a7cce5SAlexander Motin #include <sys/taskqueue.h> 56130f4520SKenneth D. Merry #include <sys/time.h> 57130f4520SKenneth D. Merry #include <sys/queue.h> 58130f4520SKenneth D. Merry #include <sys/conf.h> 59130f4520SKenneth D. Merry #include <sys/ioccom.h> 60130f4520SKenneth D. Merry #include <sys/module.h> 617ac58230SAlexander Motin #include <sys/sysctl.h> 628951f055SMarcelo Araujo #include <sys/nv.h> 638951f055SMarcelo Araujo #include <sys/dnv.h> 64130f4520SKenneth D. Merry 65130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 667ac58230SAlexander Motin #include <cam/scsi/scsi_da.h> 67130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 68130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 69130f4520SKenneth D. Merry #include <cam/ctl/ctl_util.h> 70130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h> 71130f4520SKenneth D. Merry #include <cam/ctl/ctl_debug.h> 72130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h> 737ac58230SAlexander Motin #include <cam/ctl/ctl_ha.h> 747ac58230SAlexander Motin #include <cam/ctl/ctl_private.h> 75130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h> 76130f4520SKenneth D. Merry 77e7037673SAlexander Motin #define PRIV(io) \ 78e7037673SAlexander Motin ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND]) 79e7037673SAlexander Motin #define ARGS(io) \ 80e7037673SAlexander Motin ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]) 81e7037673SAlexander Motin 82e7037673SAlexander Motin #define PPP (PAGE_SIZE / sizeof(uint8_t **)) 83e7037673SAlexander Motin #ifdef __LP64__ 84e7037673SAlexander Motin #define PPPS (PAGE_SHIFT - 3) 85e7037673SAlexander Motin #else 86e7037673SAlexander Motin #define PPPS (PAGE_SHIFT - 2) 87e7037673SAlexander Motin #endif 88e7037673SAlexander Motin #define SGPP (PAGE_SIZE / sizeof(struct ctl_sg_entry)) 89e7037673SAlexander Motin 90e7037673SAlexander Motin #define P_UNMAPPED NULL /* Page is unmapped. */ 91e7037673SAlexander Motin #define P_ANCHORED ((void *)(uintptr_t)1) /* Page is anchored. */ 92e7037673SAlexander Motin 93e7037673SAlexander Motin typedef enum { 94e7037673SAlexander Motin GP_READ, /* Return data page or zero page. */ 95e7037673SAlexander Motin GP_WRITE, /* Return data page, try allocate if none. */ 96e7037673SAlexander Motin GP_ANCHOR, /* Return data page, try anchor if none. */ 97e7037673SAlexander Motin GP_OTHER, /* Return what present, do not allocate/anchor. */ 98e7037673SAlexander Motin } getpage_op_t; 99e7037673SAlexander Motin 100130f4520SKenneth D. Merry typedef enum { 101130f4520SKenneth D. Merry CTL_BE_RAMDISK_LUN_UNCONFIGURED = 0x01, 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 { 106767300e8SAlexander Motin struct ctl_be_lun cbe_lun; /* Must be first element. */ 107a3977beaSAlexander Motin struct ctl_lun_create_params params; 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; 12034144c2cSAlexander Motin SLIST_ENTRY(ctl_be_ramdisk_lun) links; 12108a7cce5SAlexander Motin struct taskqueue *io_taskqueue; 12208a7cce5SAlexander Motin struct task io_task; 12308a7cce5SAlexander Motin STAILQ_HEAD(, ctl_io_hdr) cont_queue; 12475c7a1d3SAlexander Motin struct mtx_padalign queue_lock; 125130f4520SKenneth D. Merry }; 126130f4520SKenneth D. Merry 127130f4520SKenneth D. Merry struct ctl_be_ramdisk_softc { 12834144c2cSAlexander Motin struct sx modify_lock; 129130f4520SKenneth D. Merry struct mtx lock; 130130f4520SKenneth D. Merry int num_luns; 13134144c2cSAlexander Motin SLIST_HEAD(, ctl_be_ramdisk_lun) lun_list; 132130f4520SKenneth D. Merry }; 133130f4520SKenneth D. Merry 134130f4520SKenneth D. Merry static struct ctl_be_ramdisk_softc rd_softc; 135130f4520SKenneth D. Merry 1360c629e28SAlexander Motin static int ctl_backend_ramdisk_init(void); 1370c629e28SAlexander Motin static int ctl_backend_ramdisk_shutdown(void); 1382c7dc6baSAlexander Motin static int ctl_backend_ramdisk_move_done(union ctl_io *io, bool samethr); 139e7037673SAlexander Motin static void ctl_backend_ramdisk_compare(union ctl_io *io); 140e7037673SAlexander Motin static void ctl_backend_ramdisk_rw(union ctl_io *io); 141130f4520SKenneth D. Merry static int ctl_backend_ramdisk_submit(union ctl_io *io); 142e7037673SAlexander Motin static void ctl_backend_ramdisk_worker(void *context, int pending); 143e7037673SAlexander Motin static int ctl_backend_ramdisk_config_read(union ctl_io *io); 144e7037673SAlexander Motin static int ctl_backend_ramdisk_config_write(union ctl_io *io); 145767300e8SAlexander Motin static uint64_t ctl_backend_ramdisk_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname); 146130f4520SKenneth D. Merry static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, 147130f4520SKenneth D. Merry caddr_t addr, int flag, struct thread *td); 148130f4520SKenneth D. Merry static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 149130f4520SKenneth D. Merry struct ctl_lun_req *req); 150130f4520SKenneth D. Merry static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 1510bcd4ab6SAlexander Motin struct ctl_lun_req *req); 15281177295SEdward Tomasz Napierala static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 15381177295SEdward Tomasz Napierala struct ctl_lun_req *req); 154767300e8SAlexander Motin static void ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun *cbe_lun); 155130f4520SKenneth D. Merry 156130f4520SKenneth D. Merry static struct ctl_backend_driver ctl_be_ramdisk_driver = 157130f4520SKenneth D. Merry { 1582a2443d8SKenneth D. Merry .name = "ramdisk", 1592a2443d8SKenneth D. Merry .flags = CTL_BE_FLAG_HAS_CONFIG, 1602a2443d8SKenneth D. Merry .init = ctl_backend_ramdisk_init, 1610c629e28SAlexander Motin .shutdown = ctl_backend_ramdisk_shutdown, 1622a2443d8SKenneth D. Merry .data_submit = ctl_backend_ramdisk_submit, 1632a2443d8SKenneth D. Merry .config_read = ctl_backend_ramdisk_config_read, 1642a2443d8SKenneth D. Merry .config_write = ctl_backend_ramdisk_config_write, 165e7037673SAlexander Motin .ioctl = ctl_backend_ramdisk_ioctl, 166e7037673SAlexander Motin .lun_attr = ctl_backend_ramdisk_lun_attr, 167130f4520SKenneth D. Merry }; 168130f4520SKenneth D. Merry 16934144c2cSAlexander Motin MALLOC_DEFINE(M_RAMDISK, "ctlramdisk", "Memory used for CTL RAMdisk"); 170130f4520SKenneth D. Merry CTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver); 171130f4520SKenneth D. Merry 172e7037673SAlexander Motin static int 173130f4520SKenneth D. Merry ctl_backend_ramdisk_init(void) 174130f4520SKenneth D. Merry { 17567cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 176130f4520SKenneth D. Merry 177130f4520SKenneth D. Merry memset(softc, 0, sizeof(*softc)); 17834144c2cSAlexander Motin sx_init(&softc->modify_lock, "ctlrammod"); 17934144c2cSAlexander Motin mtx_init(&softc->lock, "ctlram", NULL, MTX_DEF); 18034144c2cSAlexander Motin SLIST_INIT(&softc->lun_list); 181130f4520SKenneth D. Merry return (0); 182130f4520SKenneth D. Merry } 183130f4520SKenneth D. Merry 1840c629e28SAlexander Motin static int 185130f4520SKenneth D. Merry ctl_backend_ramdisk_shutdown(void) 186130f4520SKenneth D. Merry { 18767cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 18834144c2cSAlexander Motin struct ctl_be_ramdisk_lun *lun; 189130f4520SKenneth D. Merry 190130f4520SKenneth D. Merry mtx_lock(&softc->lock); 19134144c2cSAlexander Motin while ((lun = SLIST_FIRST(&softc->lun_list)) != NULL) { 19234144c2cSAlexander Motin SLIST_REMOVE_HEAD(&softc->lun_list, links); 19334144c2cSAlexander Motin softc->num_luns--; 194130f4520SKenneth D. Merry /* 19534144c2cSAlexander Motin * Drop our lock here. Since ctl_remove_lun() can call 196130f4520SKenneth D. Merry * back into us, this could potentially lead to a recursive 197130f4520SKenneth D. Merry * lock of the same mutex, which would cause a hang. 198130f4520SKenneth D. Merry */ 199130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 20034144c2cSAlexander Motin ctl_remove_lun(&lun->cbe_lun); 201130f4520SKenneth D. Merry mtx_lock(&softc->lock); 202130f4520SKenneth D. Merry } 203130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2040c629e28SAlexander Motin mtx_destroy(&softc->lock); 20534144c2cSAlexander Motin sx_destroy(&softc->modify_lock); 2060c629e28SAlexander Motin return (0); 207130f4520SKenneth D. Merry } 208130f4520SKenneth D. Merry 209e7037673SAlexander Motin static uint8_t * 210e7037673SAlexander Motin ctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn, 211e7037673SAlexander Motin getpage_op_t op) 212e7037673SAlexander Motin { 213e7037673SAlexander Motin uint8_t **p, ***pp; 214e7037673SAlexander Motin off_t i; 215e7037673SAlexander Motin int s; 216e7037673SAlexander Motin 217e7037673SAlexander Motin if (be_lun->cap_bytes == 0) { 218e7037673SAlexander Motin switch (op) { 219e7037673SAlexander Motin case GP_READ: 220e7037673SAlexander Motin return (be_lun->zero_page); 221e7037673SAlexander Motin case GP_WRITE: 222e7037673SAlexander Motin return ((uint8_t *)be_lun->pages); 223e7037673SAlexander Motin case GP_ANCHOR: 224e7037673SAlexander Motin return (P_ANCHORED); 225e7037673SAlexander Motin default: 226e7037673SAlexander Motin return (P_UNMAPPED); 227e7037673SAlexander Motin } 228e7037673SAlexander Motin } 229e7037673SAlexander Motin if (op == GP_WRITE || op == GP_ANCHOR) { 230e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 231e7037673SAlexander Motin pp = &be_lun->pages; 232e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 233e7037673SAlexander Motin if (*pp == NULL) { 234e7037673SAlexander Motin *pp = malloc(PAGE_SIZE, M_RAMDISK, 235e7037673SAlexander Motin M_WAITOK|M_ZERO); 236e7037673SAlexander Motin } 237e7037673SAlexander Motin i = pn >> s; 238e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 239e7037673SAlexander Motin pn -= i << s; 240e7037673SAlexander Motin } 241e7037673SAlexander Motin if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 242e7037673SAlexander Motin if (op == GP_WRITE) { 243e7037673SAlexander Motin *pp = malloc(be_lun->pblocksize, M_RAMDISK, 244e7037673SAlexander Motin M_WAITOK|M_ZERO); 245e7037673SAlexander Motin } else 246e7037673SAlexander Motin *pp = P_ANCHORED; 247e7037673SAlexander Motin be_lun->cap_used += be_lun->pblocksize; 248e7037673SAlexander Motin } else if (*pp == P_ANCHORED && op == GP_WRITE) { 249e7037673SAlexander Motin *pp = malloc(be_lun->pblocksize, M_RAMDISK, 250e7037673SAlexander Motin M_WAITOK|M_ZERO); 251e7037673SAlexander Motin } 252e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 253e7037673SAlexander Motin return ((uint8_t *)*pp); 254e7037673SAlexander Motin } else { 255e7037673SAlexander Motin sx_slock(&be_lun->page_lock); 256e7037673SAlexander Motin p = be_lun->pages; 257e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 258e7037673SAlexander Motin if (p == NULL) 259e7037673SAlexander Motin break; 260e7037673SAlexander Motin i = pn >> s; 261e7037673SAlexander Motin p = (uint8_t **)p[i]; 262e7037673SAlexander Motin pn -= i << s; 263e7037673SAlexander Motin } 264e7037673SAlexander Motin sx_sunlock(&be_lun->page_lock); 265e7037673SAlexander Motin if ((p == P_UNMAPPED || p == P_ANCHORED) && op == GP_READ) 266e7037673SAlexander Motin return (be_lun->zero_page); 267e7037673SAlexander Motin return ((uint8_t *)p); 268e7037673SAlexander Motin } 269e7037673SAlexander Motin }; 270e7037673SAlexander Motin 271e7037673SAlexander Motin static void 272e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 273e7037673SAlexander Motin { 274e7037673SAlexander Motin uint8_t ***pp; 275e7037673SAlexander Motin off_t i; 276e7037673SAlexander Motin int s; 277e7037673SAlexander Motin 278e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 279e7037673SAlexander Motin return; 280e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 281e7037673SAlexander Motin pp = &be_lun->pages; 282e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 283e7037673SAlexander Motin if (*pp == NULL) 284e7037673SAlexander Motin goto noindir; 285e7037673SAlexander Motin i = pn >> s; 286e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 287e7037673SAlexander Motin pn -= i << s; 288e7037673SAlexander Motin } 289e7037673SAlexander Motin if (*pp == P_ANCHORED) { 290e7037673SAlexander Motin be_lun->cap_used -= be_lun->pblocksize; 291e7037673SAlexander Motin *pp = P_UNMAPPED; 292e7037673SAlexander Motin } else if (*pp != P_UNMAPPED) { 293e7037673SAlexander Motin free(*pp, M_RAMDISK); 294e7037673SAlexander Motin be_lun->cap_used -= be_lun->pblocksize; 295e7037673SAlexander Motin *pp = P_UNMAPPED; 296e7037673SAlexander Motin } 297e7037673SAlexander Motin noindir: 298e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 299e7037673SAlexander Motin }; 300e7037673SAlexander Motin 301e7037673SAlexander Motin static void 302e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 303e7037673SAlexander Motin { 304e7037673SAlexander Motin uint8_t ***pp; 305e7037673SAlexander Motin off_t i; 306e7037673SAlexander Motin int s; 307e7037673SAlexander Motin 308e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 309e7037673SAlexander Motin return; 310e7037673SAlexander Motin sx_xlock(&be_lun->page_lock); 311e7037673SAlexander Motin pp = &be_lun->pages; 312e7037673SAlexander Motin for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 313e7037673SAlexander Motin if (*pp == NULL) 314e7037673SAlexander Motin goto noindir; 315e7037673SAlexander Motin i = pn >> s; 316e7037673SAlexander Motin pp = (uint8_t ***)&(*pp)[i]; 317e7037673SAlexander Motin pn -= i << s; 318e7037673SAlexander Motin } 319e7037673SAlexander Motin if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 320e7037673SAlexander Motin be_lun->cap_used += be_lun->pblocksize; 321e7037673SAlexander Motin *pp = P_ANCHORED; 322e7037673SAlexander Motin } else if (*pp != P_ANCHORED) { 323e7037673SAlexander Motin free(*pp, M_RAMDISK); 324e7037673SAlexander Motin *pp = P_ANCHORED; 325e7037673SAlexander Motin } 326e7037673SAlexander Motin noindir: 327e7037673SAlexander Motin sx_xunlock(&be_lun->page_lock); 328e7037673SAlexander Motin }; 329e7037673SAlexander Motin 330e7037673SAlexander Motin static void 331e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(uint8_t **p, int indir) 332e7037673SAlexander Motin { 333e7037673SAlexander Motin int i; 334e7037673SAlexander Motin 335e7037673SAlexander Motin if (p == NULL) 336e7037673SAlexander Motin return; 337e7037673SAlexander Motin if (indir == 0) { 338e7037673SAlexander Motin free(p, M_RAMDISK); 339e7037673SAlexander Motin return; 340e7037673SAlexander Motin } 341e7037673SAlexander Motin for (i = 0; i < PPP; i++) { 342e7037673SAlexander Motin if (p[i] == NULL) 343e7037673SAlexander Motin continue; 344e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages((uint8_t **)p[i], indir - 1); 345e7037673SAlexander Motin } 346e7037673SAlexander Motin free(p, M_RAMDISK); 347e7037673SAlexander Motin }; 348e7037673SAlexander Motin 349e7037673SAlexander Motin static size_t 350e7037673SAlexander Motin cmp(uint8_t *a, uint8_t *b, size_t size) 351e7037673SAlexander Motin { 352e7037673SAlexander Motin size_t i; 353e7037673SAlexander Motin 354e7037673SAlexander Motin for (i = 0; i < size; i++) { 355e7037673SAlexander Motin if (a[i] != b[i]) 356e7037673SAlexander Motin break; 357e7037673SAlexander Motin } 358e7037673SAlexander Motin return (i); 359e7037673SAlexander Motin } 360e7037673SAlexander Motin 361e7037673SAlexander Motin static int 362e7037673SAlexander Motin ctl_backend_ramdisk_cmp(union ctl_io *io) 363e7037673SAlexander Motin { 364e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 365767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 366e7037673SAlexander Motin uint8_t *page; 367e7037673SAlexander Motin uint64_t lba; 368e7037673SAlexander Motin u_int lbaoff, lbas, res, off; 369e7037673SAlexander Motin 370ccaaee46SJohn Baldwin lbas = ctl_kern_data_len(io) / cbe_lun->blocksize; 371e7037673SAlexander Motin lba = ARGS(io)->lba + PRIV(io)->len - lbas; 372e7037673SAlexander Motin off = 0; 373e7037673SAlexander Motin for (; lbas > 0; lbas--, lba++) { 374e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 375e7037673SAlexander Motin lba >> cbe_lun->pblockexp, GP_READ); 376e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 377e7037673SAlexander Motin page += lbaoff * cbe_lun->blocksize; 378ccaaee46SJohn Baldwin res = cmp(ctl_kern_data_ptr(io) + off, page, 379e7037673SAlexander Motin cbe_lun->blocksize); 380e7037673SAlexander Motin off += res; 381e7037673SAlexander Motin if (res < cbe_lun->blocksize) 382e7037673SAlexander Motin break; 383e7037673SAlexander Motin } 384bd6e8729SJohn Baldwin free(io->scsiio.kern_data_ptr, M_RAMDISK); 385e7037673SAlexander Motin if (lbas > 0) { 386ccaaee46SJohn Baldwin off += ctl_kern_rel_offset(io) - ctl_kern_data_len(io); 387ccaaee46SJohn Baldwin ctl_io_set_compare_failure(io, off); 388e7037673SAlexander Motin return (1); 389e7037673SAlexander Motin } 390e7037673SAlexander Motin return (0); 391e7037673SAlexander Motin } 392e7037673SAlexander Motin 393130f4520SKenneth D. Merry static int 3942c7dc6baSAlexander Motin ctl_backend_ramdisk_move_done(union ctl_io *io, bool samethr) 395130f4520SKenneth D. Merry { 396767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = 397767300e8SAlexander Motin (struct ctl_be_ramdisk_lun *)CTL_BACKEND_LUN(io); 398130f4520SKenneth D. Merry 399130f4520SKenneth D. Merry CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); 400ccaaee46SJohn Baldwin if (ctl_kern_sg_entries(io) > 0) 401ccaaee46SJohn Baldwin free(ctl_kern_data_ptr(io), M_RAMDISK); 402ccaaee46SJohn Baldwin ctl_add_kern_rel_offset(io, ctl_kern_data_len(io)); 4032c7dc6baSAlexander Motin if ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0 && 4042c7dc6baSAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE) { 405e7037673SAlexander Motin if (ARGS(io)->flags & CTL_LLF_COMPARE) { 406e7037673SAlexander Motin /* We have data block ready for comparison. */ 407e7037673SAlexander Motin if (ctl_backend_ramdisk_cmp(io)) 408e7037673SAlexander Motin goto done; 409e7037673SAlexander Motin } 410e7037673SAlexander Motin if (ARGS(io)->len > PRIV(io)->len) { 41175c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 41208a7cce5SAlexander Motin STAILQ_INSERT_TAIL(&be_lun->cont_queue, 41308a7cce5SAlexander Motin &io->io_hdr, links); 41475c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 41508a7cce5SAlexander Motin taskqueue_enqueue(be_lun->io_taskqueue, 41608a7cce5SAlexander Motin &be_lun->io_task); 41708a7cce5SAlexander Motin return (0); 41808a7cce5SAlexander Motin } 419ccaaee46SJohn Baldwin ctl_io_set_success(io); 420130f4520SKenneth D. Merry } 421e7037673SAlexander Motin done: 42211b569f7SAlexander Motin ctl_data_submit_done(io); 423130f4520SKenneth D. Merry return(0); 424130f4520SKenneth D. Merry } 425130f4520SKenneth D. Merry 426e7037673SAlexander Motin static void 427e7037673SAlexander Motin ctl_backend_ramdisk_compare(union ctl_io *io) 428e7037673SAlexander Motin { 429e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 430e7037673SAlexander Motin u_int lbas, len; 431e7037673SAlexander Motin 432e7037673SAlexander Motin lbas = ARGS(io)->len - PRIV(io)->len; 433e7037673SAlexander Motin lbas = MIN(lbas, 131072 / cbe_lun->blocksize); 434e7037673SAlexander Motin len = lbas * cbe_lun->blocksize; 435e7037673SAlexander Motin 436ccaaee46SJohn Baldwin ctl_set_be_move_done(io, ctl_backend_ramdisk_move_done); 437ccaaee46SJohn Baldwin ctl_set_kern_data_ptr(io, malloc(len, M_RAMDISK, M_WAITOK)); 438ccaaee46SJohn Baldwin ctl_set_kern_data_len(io, len); 439ccaaee46SJohn Baldwin ctl_set_kern_sg_entries(io, 0); 440e7037673SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 441e7037673SAlexander Motin PRIV(io)->len += lbas; 442e7037673SAlexander Motin ctl_datamove(io); 443e7037673SAlexander Motin } 444e7037673SAlexander Motin 445e7037673SAlexander Motin static void 446e7037673SAlexander Motin ctl_backend_ramdisk_rw(union ctl_io *io) 447e7037673SAlexander Motin { 448e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 449767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 450e7037673SAlexander Motin struct ctl_sg_entry *sg_entries; 451e7037673SAlexander Motin uint8_t *page; 452e7037673SAlexander Motin uint64_t lba; 453e7037673SAlexander Motin u_int i, len, lbaoff, lbas, sgs, off; 454e7037673SAlexander Motin getpage_op_t op; 455e7037673SAlexander Motin 456e7037673SAlexander Motin lba = ARGS(io)->lba + PRIV(io)->len; 457e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 458e7037673SAlexander Motin lbas = ARGS(io)->len - PRIV(io)->len; 459e7037673SAlexander Motin lbas = MIN(lbas, (SGPP << cbe_lun->pblockexp) - lbaoff); 460e7037673SAlexander Motin sgs = (lbas + lbaoff + be_lun->pblockmul - 1) >> cbe_lun->pblockexp; 461e7037673SAlexander Motin off = lbaoff * cbe_lun->blocksize; 462e7037673SAlexander Motin op = (ARGS(io)->flags & CTL_LLF_WRITE) ? GP_WRITE : GP_READ; 463e7037673SAlexander Motin if (sgs > 1) { 464ccaaee46SJohn Baldwin sg_entries = malloc(sizeof(struct ctl_sg_entry) * sgs, 465ccaaee46SJohn Baldwin M_RAMDISK, M_WAITOK); 466ccaaee46SJohn Baldwin ctl_set_kern_data_ptr(io, sg_entries); 467e7037673SAlexander Motin len = lbas * cbe_lun->blocksize; 468e7037673SAlexander Motin for (i = 0; i < sgs; i++) { 469e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 470e7037673SAlexander Motin (lba >> cbe_lun->pblockexp) + i, op); 471e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) { 472ccaaee46SJohn Baldwin free(sg_entries, M_RAMDISK); 473e7037673SAlexander Motin nospc: 474ccaaee46SJohn Baldwin ctl_io_set_space_alloc_fail(io); 475e7037673SAlexander Motin ctl_data_submit_done(io); 476e7037673SAlexander Motin return; 477e7037673SAlexander Motin } 478e7037673SAlexander Motin sg_entries[i].addr = page + off; 479e7037673SAlexander Motin sg_entries[i].len = MIN(len, be_lun->pblocksize - off); 480e7037673SAlexander Motin len -= sg_entries[i].len; 481e7037673SAlexander Motin off = 0; 482e7037673SAlexander Motin } 483e7037673SAlexander Motin } else { 484e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 485e7037673SAlexander Motin lba >> cbe_lun->pblockexp, op); 486e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) 487e7037673SAlexander Motin goto nospc; 488e7037673SAlexander Motin sgs = 0; 489ccaaee46SJohn Baldwin ctl_set_kern_data_ptr(io, page + off); 490e7037673SAlexander Motin } 491e7037673SAlexander Motin 492ccaaee46SJohn Baldwin ctl_set_be_move_done(io, ctl_backend_ramdisk_move_done); 493ccaaee46SJohn Baldwin ctl_set_kern_data_len(io, lbas * cbe_lun->blocksize); 494ccaaee46SJohn Baldwin ctl_set_kern_sg_entries(io, sgs); 495e7037673SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 496e7037673SAlexander Motin PRIV(io)->len += lbas; 497e8583acfSAlexander Motin if ((ARGS(io)->flags & CTL_LLF_READ) && 498e8583acfSAlexander Motin ARGS(io)->len <= PRIV(io)->len) { 499ccaaee46SJohn Baldwin ctl_io_set_success(io); 500ac503c19SAlexander Motin if (cbe_lun->serseq >= CTL_LUN_SERSEQ_SOFT) 501e8583acfSAlexander Motin ctl_serseq_done(io); 502e8583acfSAlexander Motin } 503e7037673SAlexander Motin ctl_datamove(io); 504e7037673SAlexander Motin } 505e7037673SAlexander Motin 506130f4520SKenneth D. Merry static int 507130f4520SKenneth D. Merry ctl_backend_ramdisk_submit(union ctl_io *io) 508130f4520SKenneth D. Merry { 509e7037673SAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 510130f4520SKenneth D. Merry 51111b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_VERIFY) { 512ccaaee46SJohn Baldwin ctl_io_set_success(io); 51311b569f7SAlexander Motin ctl_data_submit_done(io); 51411b569f7SAlexander Motin return (CTL_RETVAL_COMPLETE); 51511b569f7SAlexander Motin } 516e7037673SAlexander Motin PRIV(io)->len = 0; 517e7037673SAlexander Motin if (lbalen->flags & CTL_LLF_COMPARE) 518e7037673SAlexander Motin ctl_backend_ramdisk_compare(io); 519e7037673SAlexander Motin else 520e7037673SAlexander Motin ctl_backend_ramdisk_rw(io); 521130f4520SKenneth D. Merry return (CTL_RETVAL_COMPLETE); 522130f4520SKenneth D. Merry } 523130f4520SKenneth D. Merry 52408a7cce5SAlexander Motin static void 52508a7cce5SAlexander Motin ctl_backend_ramdisk_worker(void *context, int pending) 52608a7cce5SAlexander Motin { 52708a7cce5SAlexander Motin struct ctl_be_ramdisk_lun *be_lun; 52808a7cce5SAlexander Motin union ctl_io *io; 52908a7cce5SAlexander Motin 53008a7cce5SAlexander Motin be_lun = (struct ctl_be_ramdisk_lun *)context; 53175c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 53208a7cce5SAlexander Motin for (;;) { 53308a7cce5SAlexander Motin io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); 53408a7cce5SAlexander Motin if (io != NULL) { 53505d882b7SAlexander Motin STAILQ_REMOVE_HEAD(&be_lun->cont_queue, links); 53675c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 537e7037673SAlexander Motin if (ARGS(io)->flags & CTL_LLF_COMPARE) 538e7037673SAlexander Motin ctl_backend_ramdisk_compare(io); 539e7037673SAlexander Motin else 540e7037673SAlexander Motin ctl_backend_ramdisk_rw(io); 54175c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 54208a7cce5SAlexander Motin continue; 54308a7cce5SAlexander Motin } 54408a7cce5SAlexander Motin 54508a7cce5SAlexander Motin /* 54608a7cce5SAlexander Motin * If we get here, there is no work left in the queues, so 54708a7cce5SAlexander Motin * just break out and let the task queue go to sleep. 54808a7cce5SAlexander Motin */ 54908a7cce5SAlexander Motin break; 55008a7cce5SAlexander Motin } 55175c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 552130f4520SKenneth D. Merry } 553130f4520SKenneth D. Merry 554130f4520SKenneth D. Merry static int 555e7037673SAlexander Motin ctl_backend_ramdisk_gls(union ctl_io *io) 556e7037673SAlexander Motin { 557e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 558767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 559e7037673SAlexander Motin struct scsi_get_lba_status_data *data; 560e7037673SAlexander Motin uint8_t *page; 561e7037673SAlexander Motin u_int lbaoff; 562e7037673SAlexander Motin 563e7037673SAlexander Motin data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 564e7037673SAlexander Motin scsi_u64to8b(ARGS(io)->lba, data->descr[0].addr); 565e7037673SAlexander Motin lbaoff = ARGS(io)->lba & ~(UINT_MAX << cbe_lun->pblockexp); 566e7037673SAlexander Motin scsi_ulto4b(be_lun->pblockmul - lbaoff, data->descr[0].length); 567e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 568e7037673SAlexander Motin ARGS(io)->lba >> cbe_lun->pblockexp, GP_OTHER); 569e7037673SAlexander Motin if (page == P_UNMAPPED) 570e7037673SAlexander Motin data->descr[0].status = 1; 571e7037673SAlexander Motin else if (page == P_ANCHORED) 572e7037673SAlexander Motin data->descr[0].status = 2; 573e7037673SAlexander Motin else 574e7037673SAlexander Motin data->descr[0].status = 0; 575e7037673SAlexander Motin ctl_config_read_done(io); 576e7037673SAlexander Motin return (CTL_RETVAL_COMPLETE); 577e7037673SAlexander Motin } 578e7037673SAlexander Motin 579e7037673SAlexander Motin static int 580*d5c21c68SJohn Baldwin ctl_backend_ramdisk_scsi_config_read(union ctl_io *io) 581e7037673SAlexander Motin { 582e7037673SAlexander Motin int retval = 0; 583e7037673SAlexander Motin 584e7037673SAlexander Motin switch (io->scsiio.cdb[0]) { 585e7037673SAlexander Motin case SERVICE_ACTION_IN: 586e7037673SAlexander Motin if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 587e7037673SAlexander Motin retval = ctl_backend_ramdisk_gls(io); 588e7037673SAlexander Motin break; 589e7037673SAlexander Motin } 590e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 591e7037673SAlexander Motin /*sks_valid*/ 1, 592e7037673SAlexander Motin /*command*/ 1, 593e7037673SAlexander Motin /*field*/ 1, 594e7037673SAlexander Motin /*bit_valid*/ 1, 595e7037673SAlexander Motin /*bit*/ 4); 596e7037673SAlexander Motin ctl_config_read_done(io); 597e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 598e7037673SAlexander Motin break; 599e7037673SAlexander Motin default: 600e7037673SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 601e7037673SAlexander Motin ctl_config_read_done(io); 602e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 603e7037673SAlexander Motin break; 604e7037673SAlexander Motin } 605e7037673SAlexander Motin return (retval); 606e7037673SAlexander Motin } 607e7037673SAlexander Motin 608*d5c21c68SJohn Baldwin static int 609*d5c21c68SJohn Baldwin ramdisk_namespace_data(union ctl_io *io) 610*d5c21c68SJohn Baldwin { 611*d5c21c68SJohn Baldwin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 612*d5c21c68SJohn Baldwin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 613*d5c21c68SJohn Baldwin struct nvme_namespace_data *nsdata; 614*d5c21c68SJohn Baldwin 615*d5c21c68SJohn Baldwin if (io->nvmeio.kern_data_len != sizeof(struct nvme_namespace_data) || 616*d5c21c68SJohn Baldwin io->nvmeio.kern_sg_entries != 0) 617*d5c21c68SJohn Baldwin return (CTL_RETVAL_ERROR); 618*d5c21c68SJohn Baldwin 619*d5c21c68SJohn Baldwin nsdata = (struct nvme_namespace_data *)io->nvmeio.kern_data_ptr; 620*d5c21c68SJohn Baldwin memset(nsdata, 0, sizeof(*nsdata)); 621*d5c21c68SJohn Baldwin nsdata->nsze = htole64(be_lun->size_blocks); 622*d5c21c68SJohn Baldwin nsdata->ncap = htole64(be_lun->cap_bytes / cbe_lun->blocksize); 623*d5c21c68SJohn Baldwin nsdata->nuse = htole64(be_lun->cap_used / cbe_lun->blocksize); 624*d5c21c68SJohn Baldwin nsdata->nsfeat = NVMEM(NVME_NS_DATA_NSFEAT_THIN_PROV) | 625*d5c21c68SJohn Baldwin NVMEM(NVME_NS_DATA_NSFEAT_DEALLOC); 626*d5c21c68SJohn Baldwin nsdata->nlbaf = 1 - 1; 627*d5c21c68SJohn Baldwin nsdata->dlfeat = NVMEM(NVME_NS_DATA_DLFEAT_DWZ) | 628*d5c21c68SJohn Baldwin NVMEF(NVME_NS_DATA_DLFEAT_READ, NVME_NS_DATA_DLFEAT_READ_00); 629*d5c21c68SJohn Baldwin nsdata->flbas = NVMEF(NVME_NS_DATA_FLBAS_FORMAT, 0); 630*d5c21c68SJohn Baldwin nsdata->lbaf[0] = NVMEF(NVME_NS_DATA_LBAF_LBADS, 631*d5c21c68SJohn Baldwin ffs(cbe_lun->blocksize) - 1); 632*d5c21c68SJohn Baldwin 633*d5c21c68SJohn Baldwin ctl_lun_nsdata_ids(cbe_lun, nsdata); 634*d5c21c68SJohn Baldwin ctl_config_read_done(io); 635*d5c21c68SJohn Baldwin return (CTL_RETVAL_COMPLETE); 636*d5c21c68SJohn Baldwin } 637*d5c21c68SJohn Baldwin 638*d5c21c68SJohn Baldwin static int 639*d5c21c68SJohn Baldwin ramdisk_nvme_ids(union ctl_io *io) 640*d5c21c68SJohn Baldwin { 641*d5c21c68SJohn Baldwin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 642*d5c21c68SJohn Baldwin 643*d5c21c68SJohn Baldwin if (io->nvmeio.kern_data_len != 4096 || io->nvmeio.kern_sg_entries != 0) 644*d5c21c68SJohn Baldwin return (CTL_RETVAL_ERROR); 645*d5c21c68SJohn Baldwin 646*d5c21c68SJohn Baldwin ctl_lun_nvme_ids(cbe_lun, io->nvmeio.kern_data_ptr); 647*d5c21c68SJohn Baldwin ctl_config_read_done(io); 648*d5c21c68SJohn Baldwin return (CTL_RETVAL_COMPLETE); 649*d5c21c68SJohn Baldwin } 650*d5c21c68SJohn Baldwin 651*d5c21c68SJohn Baldwin static int 652*d5c21c68SJohn Baldwin ctl_backend_ramdisk_nvme_config_read(union ctl_io *io) 653*d5c21c68SJohn Baldwin { 654*d5c21c68SJohn Baldwin switch (io->nvmeio.cmd.opc) { 655*d5c21c68SJohn Baldwin case NVME_OPC_IDENTIFY: 656*d5c21c68SJohn Baldwin { 657*d5c21c68SJohn Baldwin uint8_t cns; 658*d5c21c68SJohn Baldwin 659*d5c21c68SJohn Baldwin cns = le32toh(io->nvmeio.cmd.cdw10) & 0xff; 660*d5c21c68SJohn Baldwin switch (cns) { 661*d5c21c68SJohn Baldwin case 0: 662*d5c21c68SJohn Baldwin return (ramdisk_namespace_data(io)); 663*d5c21c68SJohn Baldwin case 3: 664*d5c21c68SJohn Baldwin return (ramdisk_nvme_ids(io)); 665*d5c21c68SJohn Baldwin default: 666*d5c21c68SJohn Baldwin ctl_nvme_set_invalid_field(&io->nvmeio); 667*d5c21c68SJohn Baldwin ctl_config_read_done(io); 668*d5c21c68SJohn Baldwin return (CTL_RETVAL_COMPLETE); 669*d5c21c68SJohn Baldwin } 670*d5c21c68SJohn Baldwin } 671*d5c21c68SJohn Baldwin default: 672*d5c21c68SJohn Baldwin ctl_nvme_set_invalid_opcode(&io->nvmeio); 673*d5c21c68SJohn Baldwin ctl_config_read_done(io); 674*d5c21c68SJohn Baldwin return (CTL_RETVAL_COMPLETE); 675*d5c21c68SJohn Baldwin } 676*d5c21c68SJohn Baldwin } 677*d5c21c68SJohn Baldwin 678*d5c21c68SJohn Baldwin static int 679*d5c21c68SJohn Baldwin ctl_backend_ramdisk_config_read(union ctl_io *io) 680*d5c21c68SJohn Baldwin { 681*d5c21c68SJohn Baldwin switch (io->io_hdr.io_type) { 682*d5c21c68SJohn Baldwin case CTL_IO_SCSI: 683*d5c21c68SJohn Baldwin return (ctl_backend_ramdisk_scsi_config_read(io)); 684*d5c21c68SJohn Baldwin case CTL_IO_NVME_ADMIN: 685*d5c21c68SJohn Baldwin return (ctl_backend_ramdisk_nvme_config_read(io)); 686*d5c21c68SJohn Baldwin default: 687*d5c21c68SJohn Baldwin __assert_unreachable(); 688*d5c21c68SJohn Baldwin } 689*d5c21c68SJohn Baldwin } 690*d5c21c68SJohn Baldwin 691e7037673SAlexander Motin static void 692e7037673SAlexander Motin ctl_backend_ramdisk_delete(struct ctl_be_lun *cbe_lun, off_t lba, off_t len, 693e7037673SAlexander Motin int anchor) 694e7037673SAlexander Motin { 695767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 696e7037673SAlexander Motin uint8_t *page; 697e7037673SAlexander Motin uint64_t p, lp; 698e7037673SAlexander Motin u_int lbaoff; 699e7037673SAlexander Motin getpage_op_t op = anchor ? GP_ANCHOR : GP_OTHER; 700e7037673SAlexander Motin 701e7037673SAlexander Motin /* Partially zero first partial page. */ 702e7037673SAlexander Motin p = lba >> cbe_lun->pblockexp; 703e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 704e7037673SAlexander Motin if (lbaoff != 0) { 705e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, p, op); 706e7037673SAlexander Motin if (page != P_UNMAPPED && page != P_ANCHORED) { 707e7037673SAlexander Motin memset(page + lbaoff * cbe_lun->blocksize, 0, 708e7037673SAlexander Motin min(len, be_lun->pblockmul - lbaoff) * 709e7037673SAlexander Motin cbe_lun->blocksize); 710e7037673SAlexander Motin } 711e7037673SAlexander Motin p++; 712e7037673SAlexander Motin } 713e7037673SAlexander Motin 714e7037673SAlexander Motin /* Partially zero last partial page. */ 715e7037673SAlexander Motin lp = (lba + len) >> cbe_lun->pblockexp; 716e7037673SAlexander Motin lbaoff = (lba + len) & ~(UINT_MAX << cbe_lun->pblockexp); 717e7037673SAlexander Motin if (p <= lp && lbaoff != 0) { 718e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, lp, op); 719e7037673SAlexander Motin if (page != P_UNMAPPED && page != P_ANCHORED) 720e7037673SAlexander Motin memset(page, 0, lbaoff * cbe_lun->blocksize); 721e7037673SAlexander Motin } 722e7037673SAlexander Motin 723e7037673SAlexander Motin /* Delete remaining full pages. */ 724e7037673SAlexander Motin if (anchor) { 725e7037673SAlexander Motin for (; p < lp; p++) 726e7037673SAlexander Motin ctl_backend_ramdisk_anchorpage(be_lun, p); 727e7037673SAlexander Motin } else { 728e7037673SAlexander Motin for (; p < lp; p++) 729e7037673SAlexander Motin ctl_backend_ramdisk_unmappage(be_lun, p); 730e7037673SAlexander Motin } 731e7037673SAlexander Motin } 732e7037673SAlexander Motin 733e7037673SAlexander Motin static void 734e7037673SAlexander Motin ctl_backend_ramdisk_ws(union ctl_io *io) 735e7037673SAlexander Motin { 736e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 737767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 738e7037673SAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 739e7037673SAlexander Motin uint8_t *page; 740e7037673SAlexander Motin uint64_t lba; 741e7037673SAlexander Motin u_int lbaoff, lbas; 742e7037673SAlexander Motin 743*d5c21c68SJohn Baldwin CTL_IO_ASSERT(io, SCSI); 744*d5c21c68SJohn Baldwin 745e7037673SAlexander Motin if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB)) { 746e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 747e7037673SAlexander Motin /*sks_valid*/ 1, 748e7037673SAlexander Motin /*command*/ 1, 749e7037673SAlexander Motin /*field*/ 1, 750e7037673SAlexander Motin /*bit_valid*/ 0, 751e7037673SAlexander Motin /*bit*/ 0); 752e7037673SAlexander Motin ctl_config_write_done(io); 753e7037673SAlexander Motin return; 754e7037673SAlexander Motin } 755e7037673SAlexander Motin if (lbalen->flags & SWS_UNMAP) { 756e7037673SAlexander Motin ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 757e7037673SAlexander Motin (lbalen->flags & SWS_ANCHOR) != 0); 758e7037673SAlexander Motin ctl_set_success(&io->scsiio); 759e7037673SAlexander Motin ctl_config_write_done(io); 760e7037673SAlexander Motin return; 761e7037673SAlexander Motin } 762e7037673SAlexander Motin 763e7037673SAlexander Motin for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) { 764e7037673SAlexander Motin page = ctl_backend_ramdisk_getpage(be_lun, 765e7037673SAlexander Motin lba >> cbe_lun->pblockexp, GP_WRITE); 766e7037673SAlexander Motin if (page == P_UNMAPPED || page == P_ANCHORED) { 767e7037673SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 768e7037673SAlexander Motin ctl_data_submit_done(io); 769e7037673SAlexander Motin return; 770e7037673SAlexander Motin } 771e7037673SAlexander Motin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 772e7037673SAlexander Motin page += lbaoff * cbe_lun->blocksize; 773e7037673SAlexander Motin if (lbalen->flags & SWS_NDOB) { 774e7037673SAlexander Motin memset(page, 0, cbe_lun->blocksize); 775e7037673SAlexander Motin } else { 776e7037673SAlexander Motin memcpy(page, io->scsiio.kern_data_ptr, 777e7037673SAlexander Motin cbe_lun->blocksize); 778e7037673SAlexander Motin } 779e7037673SAlexander Motin if (lbalen->flags & SWS_LBDATA) 780e7037673SAlexander Motin scsi_ulto4b(lba, page); 781e7037673SAlexander Motin } 782e7037673SAlexander Motin ctl_set_success(&io->scsiio); 783e7037673SAlexander Motin ctl_config_write_done(io); 784e7037673SAlexander Motin } 785e7037673SAlexander Motin 786e7037673SAlexander Motin static void 787e7037673SAlexander Motin ctl_backend_ramdisk_unmap(union ctl_io *io) 788e7037673SAlexander Motin { 789e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 790e7037673SAlexander Motin struct ctl_ptr_len_flags *ptrlen = (struct ctl_ptr_len_flags *)ARGS(io); 791e7037673SAlexander Motin struct scsi_unmap_desc *buf, *end; 792e7037673SAlexander Motin 793*d5c21c68SJohn Baldwin CTL_IO_ASSERT(io, SCSI); 794*d5c21c68SJohn Baldwin 795e7037673SAlexander Motin if ((ptrlen->flags & ~SU_ANCHOR) != 0) { 796e7037673SAlexander Motin ctl_set_invalid_field(&io->scsiio, 797e7037673SAlexander Motin /*sks_valid*/ 0, 798e7037673SAlexander Motin /*command*/ 0, 799e7037673SAlexander Motin /*field*/ 0, 800e7037673SAlexander Motin /*bit_valid*/ 0, 801e7037673SAlexander Motin /*bit*/ 0); 802e7037673SAlexander Motin ctl_config_write_done(io); 803e7037673SAlexander Motin return; 804e7037673SAlexander Motin } 805e7037673SAlexander Motin 806e7037673SAlexander Motin buf = (struct scsi_unmap_desc *)ptrlen->ptr; 807e7037673SAlexander Motin end = buf + ptrlen->len / sizeof(*buf); 808e7037673SAlexander Motin for (; buf < end; buf++) { 809e7037673SAlexander Motin ctl_backend_ramdisk_delete(cbe_lun, 810e7037673SAlexander Motin scsi_8btou64(buf->lba), scsi_4btoul(buf->length), 811e7037673SAlexander Motin (ptrlen->flags & SU_ANCHOR) != 0); 812e7037673SAlexander Motin } 813e7037673SAlexander Motin 814e7037673SAlexander Motin ctl_set_success(&io->scsiio); 815e7037673SAlexander Motin ctl_config_write_done(io); 816e7037673SAlexander Motin } 817e7037673SAlexander Motin 818e7037673SAlexander Motin static int 819*d5c21c68SJohn Baldwin ctl_backend_ramdisk_scsi_config_write(union ctl_io *io) 820e7037673SAlexander Motin { 821e7037673SAlexander Motin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 822e7037673SAlexander Motin int retval = 0; 823e7037673SAlexander Motin 824e7037673SAlexander Motin switch (io->scsiio.cdb[0]) { 825e7037673SAlexander Motin case SYNCHRONIZE_CACHE: 826e7037673SAlexander Motin case SYNCHRONIZE_CACHE_16: 827e7037673SAlexander Motin /* We have no cache to flush. */ 828e7037673SAlexander Motin ctl_set_success(&io->scsiio); 829e7037673SAlexander Motin ctl_config_write_done(io); 830e7037673SAlexander Motin break; 831e7037673SAlexander Motin case START_STOP_UNIT: { 832e7037673SAlexander Motin struct scsi_start_stop_unit *cdb; 833e7037673SAlexander Motin 834e7037673SAlexander Motin cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 835e7037673SAlexander Motin if ((cdb->how & SSS_PC_MASK) != 0) { 836e7037673SAlexander Motin ctl_set_success(&io->scsiio); 837e7037673SAlexander Motin ctl_config_write_done(io); 838e7037673SAlexander Motin break; 839e7037673SAlexander Motin } 840e7037673SAlexander Motin if (cdb->how & SSS_START) { 841e7037673SAlexander Motin if (cdb->how & SSS_LOEJ) 842e7037673SAlexander Motin ctl_lun_has_media(cbe_lun); 843e7037673SAlexander Motin ctl_start_lun(cbe_lun); 844e7037673SAlexander Motin } else { 845e7037673SAlexander Motin ctl_stop_lun(cbe_lun); 846e7037673SAlexander Motin if (cdb->how & SSS_LOEJ) 847e7037673SAlexander Motin ctl_lun_ejected(cbe_lun); 848e7037673SAlexander Motin } 849e7037673SAlexander Motin ctl_set_success(&io->scsiio); 850e7037673SAlexander Motin ctl_config_write_done(io); 851e7037673SAlexander Motin break; 852e7037673SAlexander Motin } 853e7037673SAlexander Motin case PREVENT_ALLOW: 854e7037673SAlexander Motin ctl_set_success(&io->scsiio); 855e7037673SAlexander Motin ctl_config_write_done(io); 856e7037673SAlexander Motin break; 857e7037673SAlexander Motin case WRITE_SAME_10: 858e7037673SAlexander Motin case WRITE_SAME_16: 859e7037673SAlexander Motin ctl_backend_ramdisk_ws(io); 860e7037673SAlexander Motin break; 861e7037673SAlexander Motin case UNMAP: 862e7037673SAlexander Motin ctl_backend_ramdisk_unmap(io); 863e7037673SAlexander Motin break; 864e7037673SAlexander Motin default: 865e7037673SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 866e7037673SAlexander Motin ctl_config_write_done(io); 867e7037673SAlexander Motin retval = CTL_RETVAL_COMPLETE; 868e7037673SAlexander Motin break; 869e7037673SAlexander Motin } 870e7037673SAlexander Motin 871e7037673SAlexander Motin return (retval); 872e7037673SAlexander Motin } 873e7037673SAlexander Motin 874*d5c21c68SJohn Baldwin static void 875*d5c21c68SJohn Baldwin ctl_backend_ramdisk_wu(union ctl_io *io) 876*d5c21c68SJohn Baldwin { 877*d5c21c68SJohn Baldwin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 878*d5c21c68SJohn Baldwin struct ctl_lba_len_flags *lbalen = ARGS(io); 879*d5c21c68SJohn Baldwin 880*d5c21c68SJohn Baldwin CTL_IO_ASSERT(io, NVME); 881*d5c21c68SJohn Baldwin 882*d5c21c68SJohn Baldwin /* 883*d5c21c68SJohn Baldwin * XXX: Not quite right as reads will return zeroes rather 884*d5c21c68SJohn Baldwin * than failing. 885*d5c21c68SJohn Baldwin */ 886*d5c21c68SJohn Baldwin ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 1); 887*d5c21c68SJohn Baldwin ctl_nvme_set_success(&io->nvmeio); 888*d5c21c68SJohn Baldwin ctl_config_write_done(io); 889*d5c21c68SJohn Baldwin } 890*d5c21c68SJohn Baldwin 891*d5c21c68SJohn Baldwin static void 892*d5c21c68SJohn Baldwin ctl_backend_ramdisk_wz(union ctl_io *io) 893*d5c21c68SJohn Baldwin { 894*d5c21c68SJohn Baldwin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 895*d5c21c68SJohn Baldwin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 896*d5c21c68SJohn Baldwin struct ctl_lba_len_flags *lbalen = ARGS(io); 897*d5c21c68SJohn Baldwin uint8_t *page; 898*d5c21c68SJohn Baldwin uint64_t lba; 899*d5c21c68SJohn Baldwin u_int lbaoff, lbas; 900*d5c21c68SJohn Baldwin 901*d5c21c68SJohn Baldwin CTL_IO_ASSERT(io, NVME); 902*d5c21c68SJohn Baldwin 903*d5c21c68SJohn Baldwin if ((le32toh(io->nvmeio.cmd.cdw12) & (1U << 25)) != 0) { 904*d5c21c68SJohn Baldwin ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 905*d5c21c68SJohn Baldwin 0); 906*d5c21c68SJohn Baldwin ctl_nvme_set_success(&io->nvmeio); 907*d5c21c68SJohn Baldwin ctl_config_write_done(io); 908*d5c21c68SJohn Baldwin return; 909*d5c21c68SJohn Baldwin } 910*d5c21c68SJohn Baldwin 911*d5c21c68SJohn Baldwin for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) { 912*d5c21c68SJohn Baldwin page = ctl_backend_ramdisk_getpage(be_lun, 913*d5c21c68SJohn Baldwin lba >> cbe_lun->pblockexp, GP_WRITE); 914*d5c21c68SJohn Baldwin if (page == P_UNMAPPED || page == P_ANCHORED) { 915*d5c21c68SJohn Baldwin ctl_nvme_set_space_alloc_fail(&io->nvmeio); 916*d5c21c68SJohn Baldwin ctl_data_submit_done(io); 917*d5c21c68SJohn Baldwin return; 918*d5c21c68SJohn Baldwin } 919*d5c21c68SJohn Baldwin lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 920*d5c21c68SJohn Baldwin page += lbaoff * cbe_lun->blocksize; 921*d5c21c68SJohn Baldwin memset(page, 0, cbe_lun->blocksize); 922*d5c21c68SJohn Baldwin } 923*d5c21c68SJohn Baldwin ctl_nvme_set_success(&io->nvmeio); 924*d5c21c68SJohn Baldwin ctl_config_write_done(io); 925*d5c21c68SJohn Baldwin } 926*d5c21c68SJohn Baldwin 927*d5c21c68SJohn Baldwin static void 928*d5c21c68SJohn Baldwin ctl_backend_ramdisk_dsm(union ctl_io *io) 929*d5c21c68SJohn Baldwin { 930*d5c21c68SJohn Baldwin struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 931*d5c21c68SJohn Baldwin struct nvme_dsm_range *r; 932*d5c21c68SJohn Baldwin uint64_t lba; 933*d5c21c68SJohn Baldwin uint32_t num_blocks; 934*d5c21c68SJohn Baldwin u_int i, ranges; 935*d5c21c68SJohn Baldwin 936*d5c21c68SJohn Baldwin CTL_IO_ASSERT(io, NVME); 937*d5c21c68SJohn Baldwin 938*d5c21c68SJohn Baldwin ranges = le32toh(io->nvmeio.cmd.cdw10) & 0xff; 939*d5c21c68SJohn Baldwin r = (struct nvme_dsm_range *)io->nvmeio.kern_data_ptr; 940*d5c21c68SJohn Baldwin for (i = 0; i < ranges; i++) { 941*d5c21c68SJohn Baldwin lba = le64toh(r[i].starting_lba); 942*d5c21c68SJohn Baldwin num_blocks = le32toh(r[i].length); 943*d5c21c68SJohn Baldwin if ((le32toh(r[i].attributes) & (1U << 2)) != 0) 944*d5c21c68SJohn Baldwin ctl_backend_ramdisk_delete(cbe_lun, lba, num_blocks, 0); 945*d5c21c68SJohn Baldwin } 946*d5c21c68SJohn Baldwin 947*d5c21c68SJohn Baldwin ctl_nvme_set_success(&io->nvmeio); 948*d5c21c68SJohn Baldwin ctl_config_write_done(io); 949*d5c21c68SJohn Baldwin } 950*d5c21c68SJohn Baldwin 951*d5c21c68SJohn Baldwin static int 952*d5c21c68SJohn Baldwin ctl_backend_ramdisk_nvme_config_write(union ctl_io *io) 953*d5c21c68SJohn Baldwin { 954*d5c21c68SJohn Baldwin switch (io->nvmeio.cmd.opc) { 955*d5c21c68SJohn Baldwin case NVME_OPC_FLUSH: 956*d5c21c68SJohn Baldwin /* We have no cache to flush. */ 957*d5c21c68SJohn Baldwin ctl_nvme_set_success(&io->nvmeio); 958*d5c21c68SJohn Baldwin ctl_config_write_done(io); 959*d5c21c68SJohn Baldwin break; 960*d5c21c68SJohn Baldwin case NVME_OPC_WRITE_UNCORRECTABLE: 961*d5c21c68SJohn Baldwin ctl_backend_ramdisk_wu(io); 962*d5c21c68SJohn Baldwin break; 963*d5c21c68SJohn Baldwin case NVME_OPC_WRITE_ZEROES: 964*d5c21c68SJohn Baldwin ctl_backend_ramdisk_wz(io); 965*d5c21c68SJohn Baldwin break; 966*d5c21c68SJohn Baldwin case NVME_OPC_DATASET_MANAGEMENT: 967*d5c21c68SJohn Baldwin ctl_backend_ramdisk_dsm(io); 968*d5c21c68SJohn Baldwin break; 969*d5c21c68SJohn Baldwin default: 970*d5c21c68SJohn Baldwin ctl_nvme_set_invalid_opcode(&io->nvmeio); 971*d5c21c68SJohn Baldwin ctl_config_write_done(io); 972*d5c21c68SJohn Baldwin break; 973*d5c21c68SJohn Baldwin } 974*d5c21c68SJohn Baldwin return (CTL_RETVAL_COMPLETE); 975*d5c21c68SJohn Baldwin } 976*d5c21c68SJohn Baldwin 977*d5c21c68SJohn Baldwin static int 978*d5c21c68SJohn Baldwin ctl_backend_ramdisk_config_write(union ctl_io *io) 979*d5c21c68SJohn Baldwin { 980*d5c21c68SJohn Baldwin switch (io->io_hdr.io_type) { 981*d5c21c68SJohn Baldwin case CTL_IO_SCSI: 982*d5c21c68SJohn Baldwin return (ctl_backend_ramdisk_scsi_config_write(io)); 983*d5c21c68SJohn Baldwin case CTL_IO_NVME: 984*d5c21c68SJohn Baldwin return (ctl_backend_ramdisk_nvme_config_write(io)); 985*d5c21c68SJohn Baldwin default: 986*d5c21c68SJohn Baldwin __assert_unreachable(); 987*d5c21c68SJohn Baldwin } 988*d5c21c68SJohn Baldwin } 989*d5c21c68SJohn Baldwin 990e7037673SAlexander Motin static uint64_t 991767300e8SAlexander Motin ctl_backend_ramdisk_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname) 992e7037673SAlexander Motin { 993767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 994e7037673SAlexander Motin uint64_t val; 995e7037673SAlexander Motin 996e7037673SAlexander Motin val = UINT64_MAX; 997e7037673SAlexander Motin if (be_lun->cap_bytes == 0) 998e7037673SAlexander Motin return (val); 999e7037673SAlexander Motin sx_slock(&be_lun->page_lock); 1000e7037673SAlexander Motin if (strcmp(attrname, "blocksused") == 0) { 1001e7037673SAlexander Motin val = be_lun->cap_used / be_lun->cbe_lun.blocksize; 1002e7037673SAlexander Motin } else if (strcmp(attrname, "blocksavail") == 0) { 1003e7037673SAlexander Motin val = (be_lun->cap_bytes - be_lun->cap_used) / 1004e7037673SAlexander Motin be_lun->cbe_lun.blocksize; 1005e7037673SAlexander Motin } 1006e7037673SAlexander Motin sx_sunlock(&be_lun->page_lock); 1007e7037673SAlexander Motin return (val); 1008e7037673SAlexander Motin } 1009e7037673SAlexander Motin 1010e7037673SAlexander Motin static int 1011130f4520SKenneth D. Merry ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 1012130f4520SKenneth D. Merry int flag, struct thread *td) 1013130f4520SKenneth D. Merry { 101467cc546dSAlexander Motin struct ctl_be_ramdisk_softc *softc = &rd_softc; 101567cc546dSAlexander Motin struct ctl_lun_req *lun_req; 1016130f4520SKenneth D. Merry int retval; 1017130f4520SKenneth D. Merry 1018130f4520SKenneth D. Merry retval = 0; 1019130f4520SKenneth D. Merry switch (cmd) { 102067cc546dSAlexander Motin case CTL_LUN_REQ: 1021130f4520SKenneth D. Merry lun_req = (struct ctl_lun_req *)addr; 1022130f4520SKenneth D. Merry switch (lun_req->reqtype) { 1023130f4520SKenneth D. Merry case CTL_LUNREQ_CREATE: 10240bcd4ab6SAlexander Motin retval = ctl_backend_ramdisk_create(softc, lun_req); 1025130f4520SKenneth D. Merry break; 1026130f4520SKenneth D. Merry case CTL_LUNREQ_RM: 1027130f4520SKenneth D. Merry retval = ctl_backend_ramdisk_rm(softc, lun_req); 1028130f4520SKenneth D. Merry break; 102981177295SEdward Tomasz Napierala case CTL_LUNREQ_MODIFY: 103081177295SEdward Tomasz Napierala retval = ctl_backend_ramdisk_modify(softc, lun_req); 103181177295SEdward Tomasz Napierala break; 1032130f4520SKenneth D. Merry default: 1033130f4520SKenneth D. Merry lun_req->status = CTL_LUN_ERROR; 1034130f4520SKenneth D. Merry snprintf(lun_req->error_str, sizeof(lun_req->error_str), 1035130f4520SKenneth D. Merry "%s: invalid LUN request type %d", __func__, 1036130f4520SKenneth D. Merry lun_req->reqtype); 1037130f4520SKenneth D. Merry break; 1038130f4520SKenneth D. Merry } 1039130f4520SKenneth D. Merry break; 1040130f4520SKenneth D. Merry default: 1041130f4520SKenneth D. Merry retval = ENOTTY; 1042130f4520SKenneth D. Merry break; 1043130f4520SKenneth D. Merry } 1044130f4520SKenneth D. Merry 1045130f4520SKenneth D. Merry return (retval); 1046130f4520SKenneth D. Merry } 1047130f4520SKenneth D. Merry 1048130f4520SKenneth D. Merry static int 1049130f4520SKenneth D. Merry ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 1050130f4520SKenneth D. Merry struct ctl_lun_req *req) 1051130f4520SKenneth D. Merry { 1052130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 1053130f4520SKenneth D. Merry struct ctl_lun_rm_params *params; 1054130f4520SKenneth D. Merry int retval; 1055130f4520SKenneth D. Merry 1056130f4520SKenneth D. Merry params = &req->reqdata.rm; 105734144c2cSAlexander Motin sx_xlock(&softc->modify_lock); 1058130f4520SKenneth D. Merry mtx_lock(&softc->lock); 105934144c2cSAlexander Motin SLIST_FOREACH(be_lun, &softc->lun_list, links) { 106034144c2cSAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) { 106134144c2cSAlexander Motin SLIST_REMOVE(&softc->lun_list, be_lun, 106234144c2cSAlexander Motin ctl_be_ramdisk_lun, links); 106334144c2cSAlexander Motin softc->num_luns--; 1064130f4520SKenneth D. Merry break; 1065130f4520SKenneth D. Merry } 106634144c2cSAlexander Motin } 1067130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 106834144c2cSAlexander Motin sx_xunlock(&softc->modify_lock); 1069130f4520SKenneth D. Merry if (be_lun == NULL) { 1070130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1071130f4520SKenneth D. Merry "%s: LUN %u is not managed by the ramdisk backend", 1072130f4520SKenneth D. Merry __func__, params->lun_id); 1073130f4520SKenneth D. Merry goto bailout_error; 1074130f4520SKenneth D. Merry } 1075130f4520SKenneth D. Merry 1076130f4520SKenneth D. Merry /* 1077130f4520SKenneth D. Merry * Set the waiting flag before we invalidate the LUN. Our shutdown 1078130f4520SKenneth D. Merry * routine can be called any time after we invalidate the LUN, 1079130f4520SKenneth D. Merry * and can be called from our context. 1080130f4520SKenneth D. Merry * 1081130f4520SKenneth D. Merry * This tells the shutdown routine that we're waiting, or we're 1082130f4520SKenneth D. Merry * going to wait for the shutdown to happen. 1083130f4520SKenneth D. Merry */ 1084130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1085130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 1086130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1087130f4520SKenneth D. Merry 108834144c2cSAlexander Motin retval = ctl_remove_lun(&be_lun->cbe_lun); 1089130f4520SKenneth D. Merry if (retval != 0) { 1090130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 109134144c2cSAlexander Motin "%s: error %d returned from ctl_remove_lun() for " 1092130f4520SKenneth D. Merry "LUN %d", __func__, retval, params->lun_id); 1093ce300fbfSAlexander Motin mtx_lock(&softc->lock); 1094ce300fbfSAlexander Motin be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 1095ce300fbfSAlexander Motin mtx_unlock(&softc->lock); 1096130f4520SKenneth D. Merry goto bailout_error; 1097130f4520SKenneth D. Merry } 1098130f4520SKenneth D. Merry 1099130f4520SKenneth D. Merry mtx_lock(&softc->lock); 1100130f4520SKenneth D. Merry while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) { 110134144c2cSAlexander Motin retval = msleep(be_lun, &softc->lock, PCATCH, "ctlramrm", 0); 1102130f4520SKenneth D. Merry if (retval == EINTR) 1103130f4520SKenneth D. Merry break; 1104130f4520SKenneth D. Merry } 1105130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 110634144c2cSAlexander Motin if (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 1107130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1108130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 110934144c2cSAlexander Motin } else { 111034144c2cSAlexander Motin mtx_unlock(&softc->lock); 111134144c2cSAlexander Motin return (EINTR); 111208a7cce5SAlexander Motin } 1113130f4520SKenneth D. Merry 1114130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 1115130f4520SKenneth D. Merry return (retval); 1116130f4520SKenneth D. Merry 1117130f4520SKenneth D. Merry bailout_error: 1118130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 1119130f4520SKenneth D. Merry return (0); 1120130f4520SKenneth D. Merry } 1121130f4520SKenneth D. Merry 1122130f4520SKenneth D. Merry static int 1123130f4520SKenneth D. Merry ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 11240bcd4ab6SAlexander Motin struct ctl_lun_req *req) 1125130f4520SKenneth D. Merry { 1126130f4520SKenneth D. Merry struct ctl_be_ramdisk_lun *be_lun; 11270bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 1128130f4520SKenneth D. Merry struct ctl_lun_create_params *params; 11298951f055SMarcelo Araujo const char *value; 1130130f4520SKenneth D. Merry char tmpstr[32]; 1131e7037673SAlexander Motin uint64_t t; 11320bcd4ab6SAlexander Motin int retval; 1133130f4520SKenneth D. Merry 1134130f4520SKenneth D. Merry retval = 0; 1135130f4520SKenneth D. Merry params = &req->reqdata.create; 1136130f4520SKenneth D. Merry 11370bcd4ab6SAlexander Motin be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK); 11380bcd4ab6SAlexander Motin cbe_lun = &be_lun->cbe_lun; 11398951f055SMarcelo Araujo cbe_lun->options = nvlist_clone(req->args_nvl); 1140a3977beaSAlexander Motin be_lun->params = req->reqdata.create; 11410bcd4ab6SAlexander Motin be_lun->softc = softc; 1142130f4520SKenneth D. Merry 1143130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 11440bcd4ab6SAlexander Motin cbe_lun->lun_type = params->device_type; 1145130f4520SKenneth D. Merry else 11460bcd4ab6SAlexander Motin cbe_lun->lun_type = T_DIRECT; 114734144c2cSAlexander Motin be_lun->flags = 0; 11487ac58230SAlexander Motin cbe_lun->flags = 0; 11498951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 11507ac58230SAlexander Motin if (value != NULL) { 11517ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 11527ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 11537ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 11547ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 1155130f4520SKenneth D. Merry 1156e7037673SAlexander Motin be_lun->pblocksize = PAGE_SIZE; 11578951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); 1158e7037673SAlexander Motin if (value != NULL) { 1159e7037673SAlexander Motin ctl_expand_number(value, &t); 1160e7037673SAlexander Motin be_lun->pblocksize = t; 1161e7037673SAlexander Motin } 1162e7037673SAlexander Motin if (be_lun->pblocksize < 512 || be_lun->pblocksize > 131072) { 1163e7037673SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 1164e7037673SAlexander Motin "%s: unsupported pblocksize %u", __func__, 1165e7037673SAlexander Motin be_lun->pblocksize); 1166e7037673SAlexander Motin goto bailout_error; 1167e7037673SAlexander Motin } 1168e7037673SAlexander Motin 116991be33dcSAlexander Motin if (cbe_lun->lun_type == T_DIRECT || 117091be33dcSAlexander Motin cbe_lun->lun_type == T_CDROM) { 11710bcd4ab6SAlexander Motin if (params->blocksize_bytes != 0) 11720bcd4ab6SAlexander Motin cbe_lun->blocksize = params->blocksize_bytes; 117391be33dcSAlexander Motin else if (cbe_lun->lun_type == T_CDROM) 117491be33dcSAlexander Motin cbe_lun->blocksize = 2048; 11750bcd4ab6SAlexander Motin else 11760bcd4ab6SAlexander Motin cbe_lun->blocksize = 512; 1177e7037673SAlexander Motin be_lun->pblockmul = be_lun->pblocksize / cbe_lun->blocksize; 1178e7037673SAlexander Motin if (be_lun->pblockmul < 1 || !powerof2(be_lun->pblockmul)) { 1179e7037673SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 1180e7037673SAlexander Motin "%s: pblocksize %u not exp2 of blocksize %u", 1181e7037673SAlexander Motin __func__, 1182e7037673SAlexander Motin be_lun->pblocksize, cbe_lun->blocksize); 1183e7037673SAlexander Motin goto bailout_error; 1184e7037673SAlexander Motin } 11850bcd4ab6SAlexander Motin if (params->lun_size_bytes < cbe_lun->blocksize) { 1186130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1187130f4520SKenneth D. Merry "%s: LUN size %ju < blocksize %u", __func__, 11880bcd4ab6SAlexander Motin params->lun_size_bytes, cbe_lun->blocksize); 1189130f4520SKenneth D. Merry goto bailout_error; 1190130f4520SKenneth D. Merry } 11910bcd4ab6SAlexander Motin be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize; 11920bcd4ab6SAlexander Motin be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize; 1193e7037673SAlexander Motin be_lun->indir = 0; 1194e7037673SAlexander Motin t = be_lun->size_bytes / be_lun->pblocksize; 1195e7037673SAlexander Motin while (t > 1) { 1196e7037673SAlexander Motin t /= PPP; 1197e7037673SAlexander Motin be_lun->indir++; 1198e7037673SAlexander Motin } 11990bcd4ab6SAlexander Motin cbe_lun->maxlba = be_lun->size_blocks - 1; 1200e7037673SAlexander Motin cbe_lun->pblockexp = fls(be_lun->pblockmul) - 1; 1201e7037673SAlexander Motin cbe_lun->pblockoff = 0; 1202e7037673SAlexander Motin cbe_lun->ublockexp = cbe_lun->pblockexp; 1203e7037673SAlexander Motin cbe_lun->ublockoff = 0; 1204e7037673SAlexander Motin cbe_lun->atomicblock = be_lun->pblocksize; 1205e7037673SAlexander Motin cbe_lun->opttxferlen = SGPP * be_lun->pblocksize; 12068951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "capacity", NULL); 1207e7037673SAlexander Motin if (value != NULL) 1208e7037673SAlexander Motin ctl_expand_number(value, &be_lun->cap_bytes); 1209e7037673SAlexander Motin } else { 1210e7037673SAlexander Motin be_lun->pblockmul = 1; 1211e7037673SAlexander Motin cbe_lun->pblockexp = 0; 1212130f4520SKenneth D. Merry } 1213130f4520SKenneth D. Merry 1214130f4520SKenneth D. Merry /* Tell the user the blocksize we ended up using */ 12150bcd4ab6SAlexander Motin params->blocksize_bytes = cbe_lun->blocksize; 1216130f4520SKenneth D. Merry params->lun_size_bytes = be_lun->size_bytes; 1217130f4520SKenneth D. Merry 12188951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "unmap", NULL); 12191173e5a7SAlexander Motin if (value == NULL || strcmp(value, "off") != 0) 12200bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 12218951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "readonly", NULL); 122291be33dcSAlexander Motin if (value != NULL) { 122391be33dcSAlexander Motin if (strcmp(value, "on") == 0) 122491be33dcSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 122591be33dcSAlexander Motin } else if (cbe_lun->lun_type != T_DIRECT) 12260bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 12270bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 12288951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "serseq", NULL); 12290bcd4ab6SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 12300bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 12310bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "read") == 0) 12320bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 1233ac503c19SAlexander Motin else if (value != NULL && strcmp(value, "soft") == 0) 1234ac503c19SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_SOFT; 12350bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "off") == 0) 12360bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 1237130f4520SKenneth D. Merry 1238130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_ID_REQ) { 12390bcd4ab6SAlexander Motin cbe_lun->req_lun_id = params->req_lun_id; 12400bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 1241130f4520SKenneth D. Merry } else 12420bcd4ab6SAlexander Motin cbe_lun->req_lun_id = 0; 1243130f4520SKenneth D. Merry 12440bcd4ab6SAlexander Motin cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 12450bcd4ab6SAlexander Motin cbe_lun->be = &ctl_be_ramdisk_driver; 1246130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 124771cd87c6SAlan Somers snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%04d", 1248130f4520SKenneth D. Merry softc->num_luns); 12490bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, tmpstr, 12500bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 1251130f4520SKenneth D. Merry 1252130f4520SKenneth D. Merry /* Tell the user what we used for a serial number */ 1253130f4520SKenneth D. Merry strncpy((char *)params->serial_num, tmpstr, 1254e7038eb7SAlexander Motin MIN(sizeof(params->serial_num), sizeof(tmpstr))); 1255130f4520SKenneth D. Merry } else { 12560bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, params->serial_num, 12570bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), 1258130f4520SKenneth D. Merry sizeof(params->serial_num))); 1259130f4520SKenneth D. Merry } 1260130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 126171cd87c6SAlan Somers snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%04d", softc->num_luns); 12620bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, tmpstr, 12630bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 1264130f4520SKenneth D. Merry 1265130f4520SKenneth D. Merry /* Tell the user what we used for a device ID */ 1266130f4520SKenneth D. Merry strncpy((char *)params->device_id, tmpstr, 1267e7038eb7SAlexander Motin MIN(sizeof(params->device_id), sizeof(tmpstr))); 1268130f4520SKenneth D. Merry } else { 12690bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, params->device_id, 12700bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), 1271130f4520SKenneth D. Merry sizeof(params->device_id))); 1272130f4520SKenneth D. Merry } 1273130f4520SKenneth D. Merry 127408a7cce5SAlexander Motin STAILQ_INIT(&be_lun->cont_queue); 127534144c2cSAlexander Motin sx_init(&be_lun->page_lock, "ctlram page"); 12762fb36370SAlexander Motin if (be_lun->cap_bytes == 0) { 12772fb36370SAlexander Motin be_lun->indir = 0; 1278e7037673SAlexander Motin be_lun->pages = malloc(be_lun->pblocksize, M_RAMDISK, M_WAITOK); 12792fb36370SAlexander Motin } 1280e7037673SAlexander Motin be_lun->zero_page = malloc(be_lun->pblocksize, M_RAMDISK, 1281e7037673SAlexander Motin M_WAITOK|M_ZERO); 128234144c2cSAlexander Motin mtx_init(&be_lun->queue_lock, "ctlram queue", NULL, MTX_DEF); 128308a7cce5SAlexander Motin TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 128408a7cce5SAlexander Motin be_lun); 128508a7cce5SAlexander Motin 128634144c2cSAlexander Motin be_lun->io_taskqueue = taskqueue_create("ctlramtq", M_WAITOK, 128708a7cce5SAlexander Motin taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 128808a7cce5SAlexander Motin if (be_lun->io_taskqueue == NULL) { 128908a7cce5SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 129008a7cce5SAlexander Motin "%s: Unable to create taskqueue", __func__); 129108a7cce5SAlexander Motin goto bailout_error; 129208a7cce5SAlexander Motin } 129308a7cce5SAlexander Motin 129412373e95SAlexander Motin retval = taskqueue_start_threads_in_proc(&be_lun->io_taskqueue, 129508a7cce5SAlexander Motin /*num threads*/1, 1296053db1feSAlexander Motin /*priority*/PUSER, 129712373e95SAlexander Motin /*proc*/control_softc->ctl_proc, 129834144c2cSAlexander Motin /*thread name*/"ramdisk"); 129908a7cce5SAlexander Motin if (retval != 0) 130008a7cce5SAlexander Motin goto bailout_error; 130108a7cce5SAlexander Motin 13020bcd4ab6SAlexander Motin retval = ctl_add_lun(&be_lun->cbe_lun); 1303130f4520SKenneth D. Merry if (retval != 0) { 1304130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1305130f4520SKenneth D. Merry "%s: ctl_add_lun() returned error %d, see dmesg for " 1306130f4520SKenneth D. Merry "details", __func__, retval); 1307130f4520SKenneth D. Merry retval = 0; 1308130f4520SKenneth D. Merry goto bailout_error; 1309130f4520SKenneth D. Merry } 1310130f4520SKenneth D. Merry 1311130f4520SKenneth D. Merry mtx_lock(&softc->lock); 131234144c2cSAlexander Motin softc->num_luns++; 131334144c2cSAlexander Motin SLIST_INSERT_HEAD(&softc->lun_list, be_lun, links); 1314130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 131534144c2cSAlexander Motin 13160bcd4ab6SAlexander Motin params->req_lun_id = cbe_lun->lun_id; 1317130f4520SKenneth D. Merry 1318130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 1319130f4520SKenneth D. Merry return (retval); 1320130f4520SKenneth D. Merry 1321130f4520SKenneth D. Merry bailout_error: 1322130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 132308a7cce5SAlexander Motin if (be_lun != NULL) { 1324e7037673SAlexander Motin if (be_lun->io_taskqueue != NULL) 132508a7cce5SAlexander Motin taskqueue_free(be_lun->io_taskqueue); 13268951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 1327e7037673SAlexander Motin free(be_lun->zero_page, M_RAMDISK); 1328e7037673SAlexander Motin ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 1329e7037673SAlexander Motin sx_destroy(&be_lun->page_lock); 133075c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 1331130f4520SKenneth D. Merry free(be_lun, M_RAMDISK); 133208a7cce5SAlexander Motin } 1333130f4520SKenneth D. Merry return (retval); 1334130f4520SKenneth D. Merry } 1335130f4520SKenneth D. Merry 133681177295SEdward Tomasz Napierala static int 133781177295SEdward Tomasz Napierala ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 133881177295SEdward Tomasz Napierala struct ctl_lun_req *req) 133981177295SEdward Tomasz Napierala { 134081177295SEdward Tomasz Napierala struct ctl_be_ramdisk_lun *be_lun; 1341a3977beaSAlexander Motin struct ctl_be_lun *cbe_lun; 134281177295SEdward Tomasz Napierala struct ctl_lun_modify_params *params; 13438951f055SMarcelo Araujo const char *value; 134481177295SEdward Tomasz Napierala uint32_t blocksize; 13457ac58230SAlexander Motin int wasprim; 134681177295SEdward Tomasz Napierala 134781177295SEdward Tomasz Napierala params = &req->reqdata.modify; 134834144c2cSAlexander Motin sx_xlock(&softc->modify_lock); 134981177295SEdward Tomasz Napierala mtx_lock(&softc->lock); 135034144c2cSAlexander Motin SLIST_FOREACH(be_lun, &softc->lun_list, links) { 13510bcd4ab6SAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) 135281177295SEdward Tomasz Napierala break; 135381177295SEdward Tomasz Napierala } 135481177295SEdward Tomasz Napierala mtx_unlock(&softc->lock); 135581177295SEdward Tomasz Napierala if (be_lun == NULL) { 135681177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 135781177295SEdward Tomasz Napierala "%s: LUN %u is not managed by the ramdisk backend", 135881177295SEdward Tomasz Napierala __func__, params->lun_id); 135981177295SEdward Tomasz Napierala goto bailout_error; 136081177295SEdward Tomasz Napierala } 1361a3977beaSAlexander Motin cbe_lun = &be_lun->cbe_lun; 136281177295SEdward Tomasz Napierala 1363a3977beaSAlexander Motin if (params->lun_size_bytes != 0) 1364a3977beaSAlexander Motin be_lun->params.lun_size_bytes = params->lun_size_bytes; 13658951f055SMarcelo Araujo 1366efeedddcSAlexander Motin if (req->args_nvl != NULL) { 13678951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 13688951f055SMarcelo Araujo cbe_lun->options = nvlist_clone(req->args_nvl); 1369efeedddcSAlexander Motin } 137081177295SEdward Tomasz Napierala 13717ac58230SAlexander Motin wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 13728951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 13737ac58230SAlexander Motin if (value != NULL) { 13747ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 13757ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 13767ac58230SAlexander Motin else 13777ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 13787ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 13797ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 13807ac58230SAlexander Motin else 13817ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 13827ac58230SAlexander Motin if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 13837ac58230SAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 13847ac58230SAlexander Motin ctl_lun_primary(cbe_lun); 13857ac58230SAlexander Motin else 13867ac58230SAlexander Motin ctl_lun_secondary(cbe_lun); 13877ac58230SAlexander Motin } 13887ac58230SAlexander Motin 13897ac58230SAlexander Motin blocksize = be_lun->cbe_lun.blocksize; 1390a3977beaSAlexander Motin if (be_lun->params.lun_size_bytes < blocksize) { 139181177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 139281177295SEdward Tomasz Napierala "%s: LUN size %ju < blocksize %u", __func__, 1393a3977beaSAlexander Motin be_lun->params.lun_size_bytes, blocksize); 139481177295SEdward Tomasz Napierala goto bailout_error; 139581177295SEdward Tomasz Napierala } 1396a3977beaSAlexander Motin be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize; 139781177295SEdward Tomasz Napierala be_lun->size_bytes = be_lun->size_blocks * blocksize; 13980bcd4ab6SAlexander Motin be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1; 13990bcd4ab6SAlexander Motin ctl_lun_capacity_changed(&be_lun->cbe_lun); 140081177295SEdward Tomasz Napierala 140181177295SEdward Tomasz Napierala /* Tell the user the exact size we ended up using */ 140281177295SEdward Tomasz Napierala params->lun_size_bytes = be_lun->size_bytes; 140381177295SEdward Tomasz Napierala 140434144c2cSAlexander Motin sx_xunlock(&softc->modify_lock); 140581177295SEdward Tomasz Napierala req->status = CTL_LUN_OK; 140681177295SEdward Tomasz Napierala return (0); 140781177295SEdward Tomasz Napierala 140881177295SEdward Tomasz Napierala bailout_error: 140934144c2cSAlexander Motin sx_xunlock(&softc->modify_lock); 141081177295SEdward Tomasz Napierala req->status = CTL_LUN_ERROR; 141181177295SEdward Tomasz Napierala return (0); 141281177295SEdward Tomasz Napierala } 141381177295SEdward Tomasz Napierala 1414130f4520SKenneth D. Merry static void 1415767300e8SAlexander Motin ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun *cbe_lun) 1416130f4520SKenneth D. Merry { 1417767300e8SAlexander Motin struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 141834144c2cSAlexander Motin struct ctl_be_ramdisk_softc *softc = be_lun->softc; 141934144c2cSAlexander Motin 142034144c2cSAlexander Motin taskqueue_drain_all(be_lun->io_taskqueue); 142134144c2cSAlexander Motin taskqueue_free(be_lun->io_taskqueue); 142234144c2cSAlexander Motin nvlist_destroy(be_lun->cbe_lun.options); 142334144c2cSAlexander Motin free(be_lun->zero_page, M_RAMDISK); 142434144c2cSAlexander Motin ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 142534144c2cSAlexander Motin sx_destroy(&be_lun->page_lock); 142634144c2cSAlexander Motin mtx_destroy(&be_lun->queue_lock); 1427130f4520SKenneth D. Merry 1428130f4520SKenneth D. Merry mtx_lock(&softc->lock); 142934144c2cSAlexander Motin be_lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 143034144c2cSAlexander Motin if (be_lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 143134144c2cSAlexander Motin wakeup(be_lun); 143234144c2cSAlexander Motin else 143368bf823fSAlexander Motin free(be_lun, M_RAMDISK); 1434130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 1435130f4520SKenneth D. Merry } 1436