1130f4520SKenneth D. Merry /*- 2bec9534dSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3bec9534dSPedro F. Giffuni * 4130f4520SKenneth D. Merry * Copyright (c) 2003 Silicon Graphics International Corp. 5130f4520SKenneth D. Merry * Copyright (c) 2009-2011 Spectra Logic Corporation 681177295SEdward Tomasz Napierala * Copyright (c) 2012 The FreeBSD Foundation 7648dfc1aSAlexander Motin * Copyright (c) 2014-2015 Alexander Motin <mav@FreeBSD.org> 8130f4520SKenneth D. Merry * All rights reserved. 9130f4520SKenneth D. Merry * 1081177295SEdward Tomasz Napierala * Portions of this software were developed by Edward Tomasz Napierala 1181177295SEdward Tomasz Napierala * under sponsorship from the FreeBSD Foundation. 1281177295SEdward Tomasz Napierala * 13130f4520SKenneth D. Merry * Redistribution and use in source and binary forms, with or without 14130f4520SKenneth D. Merry * modification, are permitted provided that the following conditions 15130f4520SKenneth D. Merry * are met: 16130f4520SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright 17130f4520SKenneth D. Merry * notice, this list of conditions, and the following disclaimer, 18130f4520SKenneth D. Merry * without modification. 19130f4520SKenneth D. Merry * 2. Redistributions in binary form must reproduce at minimum a disclaimer 20130f4520SKenneth D. Merry * substantially similar to the "NO WARRANTY" disclaimer below 21130f4520SKenneth D. Merry * ("Disclaimer") and any redistribution must be conditioned upon 22130f4520SKenneth D. Merry * including a substantially similar Disclaimer requirement for further 23130f4520SKenneth D. Merry * binary redistribution. 24130f4520SKenneth D. Merry * 25130f4520SKenneth D. Merry * NO WARRANTY 26130f4520SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27130f4520SKenneth D. Merry * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28130f4520SKenneth D. Merry * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 29130f4520SKenneth D. Merry * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 30130f4520SKenneth D. Merry * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31130f4520SKenneth D. Merry * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32130f4520SKenneth D. Merry * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33130f4520SKenneth D. Merry * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 34130f4520SKenneth D. Merry * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 35130f4520SKenneth D. Merry * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36130f4520SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGES. 37130f4520SKenneth D. Merry * 38130f4520SKenneth D. Merry * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_block.c#5 $ 39130f4520SKenneth D. Merry */ 40130f4520SKenneth D. Merry /* 41130f4520SKenneth D. Merry * CAM Target Layer driver backend for block devices. 42130f4520SKenneth D. Merry * 43130f4520SKenneth D. Merry * Author: Ken Merry <ken@FreeBSD.org> 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/types.h> 52130f4520SKenneth D. Merry #include <sys/kthread.h> 53130f4520SKenneth D. Merry #include <sys/bio.h> 54130f4520SKenneth D. Merry #include <sys/fcntl.h> 55ee7f31c0SAlexander Motin #include <sys/limits.h> 56130f4520SKenneth D. Merry #include <sys/lock.h> 57130f4520SKenneth D. Merry #include <sys/mutex.h> 58130f4520SKenneth D. Merry #include <sys/condvar.h> 59130f4520SKenneth D. Merry #include <sys/malloc.h> 60130f4520SKenneth D. Merry #include <sys/conf.h> 61130f4520SKenneth D. Merry #include <sys/ioccom.h> 62130f4520SKenneth D. Merry #include <sys/queue.h> 63130f4520SKenneth D. Merry #include <sys/sbuf.h> 64130f4520SKenneth D. Merry #include <sys/endian.h> 65130f4520SKenneth D. Merry #include <sys/uio.h> 66130f4520SKenneth D. Merry #include <sys/buf.h> 67130f4520SKenneth D. Merry #include <sys/taskqueue.h> 68130f4520SKenneth D. Merry #include <sys/vnode.h> 69130f4520SKenneth D. Merry #include <sys/namei.h> 70130f4520SKenneth D. Merry #include <sys/mount.h> 71130f4520SKenneth D. Merry #include <sys/disk.h> 72130f4520SKenneth D. Merry #include <sys/fcntl.h> 73130f4520SKenneth D. Merry #include <sys/filedesc.h> 74ef8daf3fSAlexander Motin #include <sys/filio.h> 75130f4520SKenneth D. Merry #include <sys/proc.h> 76130f4520SKenneth D. Merry #include <sys/pcpu.h> 77130f4520SKenneth D. Merry #include <sys/module.h> 78130f4520SKenneth D. Merry #include <sys/sdt.h> 79130f4520SKenneth D. Merry #include <sys/devicestat.h> 80130f4520SKenneth D. Merry #include <sys/sysctl.h> 818951f055SMarcelo Araujo #include <sys/nv.h> 828951f055SMarcelo Araujo #include <sys/dnv.h> 83130f4520SKenneth D. Merry 84130f4520SKenneth D. Merry #include <geom/geom.h> 85130f4520SKenneth D. Merry 86130f4520SKenneth D. Merry #include <cam/cam.h> 87130f4520SKenneth D. Merry #include <cam/scsi/scsi_all.h> 88130f4520SKenneth D. Merry #include <cam/scsi/scsi_da.h> 89130f4520SKenneth D. Merry #include <cam/ctl/ctl_io.h> 90130f4520SKenneth D. Merry #include <cam/ctl/ctl.h> 91130f4520SKenneth D. Merry #include <cam/ctl/ctl_backend.h> 92130f4520SKenneth D. Merry #include <cam/ctl/ctl_ioctl.h> 937ac58230SAlexander Motin #include <cam/ctl/ctl_ha.h> 94130f4520SKenneth D. Merry #include <cam/ctl/ctl_scsi_all.h> 957ac58230SAlexander Motin #include <cam/ctl/ctl_private.h> 96130f4520SKenneth D. Merry #include <cam/ctl/ctl_error.h> 97130f4520SKenneth D. Merry 98130f4520SKenneth D. Merry /* 9908a7cce5SAlexander Motin * The idea here is that we'll allocate enough S/G space to hold a 1MB 10008a7cce5SAlexander Motin * I/O. If we get an I/O larger than that, we'll split it. 101130f4520SKenneth D. Merry */ 10211b569f7SAlexander Motin #define CTLBLK_HALF_IO_SIZE (512 * 1024) 10311b569f7SAlexander Motin #define CTLBLK_MAX_IO_SIZE (CTLBLK_HALF_IO_SIZE * 2) 10408a7cce5SAlexander Motin #define CTLBLK_MAX_SEG MAXPHYS 10511b569f7SAlexander Motin #define CTLBLK_HALF_SEGS MAX(CTLBLK_HALF_IO_SIZE / CTLBLK_MAX_SEG, 1) 10611b569f7SAlexander Motin #define CTLBLK_MAX_SEGS (CTLBLK_HALF_SEGS * 2) 107130f4520SKenneth D. Merry 108130f4520SKenneth D. Merry #ifdef CTLBLK_DEBUG 109130f4520SKenneth D. Merry #define DPRINTF(fmt, args...) \ 110130f4520SKenneth D. Merry printf("cbb(%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) 111130f4520SKenneth D. Merry #else 112130f4520SKenneth D. Merry #define DPRINTF(fmt, args...) do {} while(0) 113130f4520SKenneth D. Merry #endif 114130f4520SKenneth D. Merry 115e86a4142SAlexander Motin #define PRIV(io) \ 116e86a4142SAlexander Motin ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND]) 11711b569f7SAlexander Motin #define ARGS(io) \ 11811b569f7SAlexander Motin ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]) 119e86a4142SAlexander Motin 120130f4520SKenneth D. Merry SDT_PROVIDER_DEFINE(cbb); 121130f4520SKenneth D. Merry 122130f4520SKenneth D. Merry typedef enum { 123130f4520SKenneth D. Merry CTL_BE_BLOCK_LUN_UNCONFIGURED = 0x01, 124130f4520SKenneth D. Merry CTL_BE_BLOCK_LUN_CONFIG_ERR = 0x02, 125130f4520SKenneth D. Merry CTL_BE_BLOCK_LUN_WAITING = 0x04, 126130f4520SKenneth D. Merry } ctl_be_block_lun_flags; 127130f4520SKenneth D. Merry 128130f4520SKenneth D. Merry typedef enum { 129130f4520SKenneth D. Merry CTL_BE_BLOCK_NONE, 130130f4520SKenneth D. Merry CTL_BE_BLOCK_DEV, 131130f4520SKenneth D. Merry CTL_BE_BLOCK_FILE 132130f4520SKenneth D. Merry } ctl_be_block_type; 133130f4520SKenneth D. Merry 134130f4520SKenneth D. Merry struct ctl_be_block_filedata { 135130f4520SKenneth D. Merry struct ucred *cred; 136130f4520SKenneth D. Merry }; 137130f4520SKenneth D. Merry 138130f4520SKenneth D. Merry union ctl_be_block_bedata { 139130f4520SKenneth D. Merry struct ctl_be_block_filedata file; 140130f4520SKenneth D. Merry }; 141130f4520SKenneth D. Merry 142130f4520SKenneth D. Merry struct ctl_be_block_io; 143130f4520SKenneth D. Merry struct ctl_be_block_lun; 144130f4520SKenneth D. Merry 145130f4520SKenneth D. Merry typedef void (*cbb_dispatch_t)(struct ctl_be_block_lun *be_lun, 146130f4520SKenneth D. Merry struct ctl_be_block_io *beio); 147c3e7ba3eSAlexander Motin typedef uint64_t (*cbb_getattr_t)(struct ctl_be_block_lun *be_lun, 148c3e7ba3eSAlexander Motin const char *attrname); 149130f4520SKenneth D. Merry 150130f4520SKenneth D. Merry /* 151130f4520SKenneth D. Merry * Backend LUN structure. There is a 1:1 mapping between a block device 152130f4520SKenneth D. Merry * and a backend block LUN, and between a backend block LUN and a CTL LUN. 153130f4520SKenneth D. Merry */ 154130f4520SKenneth D. Merry struct ctl_be_block_lun { 15519720f41SAlexander Motin struct ctl_lun_create_params params; 156130f4520SKenneth D. Merry char lunname[32]; 157130f4520SKenneth D. Merry char *dev_path; 158130f4520SKenneth D. Merry ctl_be_block_type dev_type; 159130f4520SKenneth D. Merry struct vnode *vn; 160130f4520SKenneth D. Merry union ctl_be_block_bedata backend; 161130f4520SKenneth D. Merry cbb_dispatch_t dispatch; 162130f4520SKenneth D. Merry cbb_dispatch_t lun_flush; 163ee7f31c0SAlexander Motin cbb_dispatch_t unmap; 164ef8daf3fSAlexander Motin cbb_dispatch_t get_lba_status; 165c3e7ba3eSAlexander Motin cbb_getattr_t getattr; 166130f4520SKenneth D. Merry uma_zone_t lun_zone; 167130f4520SKenneth D. Merry uint64_t size_blocks; 168130f4520SKenneth D. Merry uint64_t size_bytes; 169130f4520SKenneth D. Merry struct ctl_be_block_softc *softc; 170130f4520SKenneth D. Merry struct devstat *disk_stats; 171130f4520SKenneth D. Merry ctl_be_block_lun_flags flags; 172130f4520SKenneth D. Merry STAILQ_ENTRY(ctl_be_block_lun) links; 1730bcd4ab6SAlexander Motin struct ctl_be_lun cbe_lun; 174130f4520SKenneth D. Merry struct taskqueue *io_taskqueue; 175130f4520SKenneth D. Merry struct task io_task; 176130f4520SKenneth D. Merry int num_threads; 177130f4520SKenneth D. Merry STAILQ_HEAD(, ctl_io_hdr) input_queue; 178ef8daf3fSAlexander Motin STAILQ_HEAD(, ctl_io_hdr) config_read_queue; 179130f4520SKenneth D. Merry STAILQ_HEAD(, ctl_io_hdr) config_write_queue; 180130f4520SKenneth D. Merry STAILQ_HEAD(, ctl_io_hdr) datamove_queue; 18175c7a1d3SAlexander Motin struct mtx_padalign io_lock; 18275c7a1d3SAlexander Motin struct mtx_padalign queue_lock; 183130f4520SKenneth D. Merry }; 184130f4520SKenneth D. Merry 185130f4520SKenneth D. Merry /* 186130f4520SKenneth D. Merry * Overall softc structure for the block backend module. 187130f4520SKenneth D. Merry */ 188130f4520SKenneth D. Merry struct ctl_be_block_softc { 189130f4520SKenneth D. Merry struct mtx lock; 1900c629e28SAlexander Motin uma_zone_t beio_zone; 191130f4520SKenneth D. Merry int num_luns; 192130f4520SKenneth D. Merry STAILQ_HEAD(, ctl_be_block_lun) lun_list; 193130f4520SKenneth D. Merry }; 194130f4520SKenneth D. Merry 195130f4520SKenneth D. Merry static struct ctl_be_block_softc backend_block_softc; 196130f4520SKenneth D. Merry 197130f4520SKenneth D. Merry /* 198130f4520SKenneth D. Merry * Per-I/O information. 199130f4520SKenneth D. Merry */ 200130f4520SKenneth D. Merry struct ctl_be_block_io { 201130f4520SKenneth D. Merry union ctl_io *io; 202130f4520SKenneth D. Merry struct ctl_sg_entry sg_segs[CTLBLK_MAX_SEGS]; 203130f4520SKenneth D. Merry struct iovec xiovecs[CTLBLK_MAX_SEGS]; 204130f4520SKenneth D. Merry int bio_cmd; 205130f4520SKenneth D. Merry int num_segs; 206130f4520SKenneth D. Merry int num_bios_sent; 207130f4520SKenneth D. Merry int num_bios_done; 208130f4520SKenneth D. Merry int send_complete; 2091f0694a6SAlexander Motin int first_error; 2101f0694a6SAlexander Motin uint64_t first_error_offset; 211130f4520SKenneth D. Merry struct bintime ds_t0; 212130f4520SKenneth D. Merry devstat_tag_type ds_tag_type; 213130f4520SKenneth D. Merry devstat_trans_flags ds_trans_type; 214130f4520SKenneth D. Merry uint64_t io_len; 215130f4520SKenneth D. Merry uint64_t io_offset; 2167d0d4342SAlexander Motin int io_arg; 217130f4520SKenneth D. Merry struct ctl_be_block_softc *softc; 218130f4520SKenneth D. Merry struct ctl_be_block_lun *lun; 219ee7f31c0SAlexander Motin void (*beio_cont)(struct ctl_be_block_io *beio); /* to continue processing */ 220130f4520SKenneth D. Merry }; 221130f4520SKenneth D. Merry 2227ac58230SAlexander Motin extern struct ctl_softc *control_softc; 2237ac58230SAlexander Motin 224130f4520SKenneth D. Merry static int cbb_num_threads = 14; 225130f4520SKenneth D. Merry SYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD, 0, 226130f4520SKenneth D. Merry "CAM Target Layer Block Backend"); 227af3b2549SHans Petter Selasky SYSCTL_INT(_kern_cam_ctl_block, OID_AUTO, num_threads, CTLFLAG_RWTUN, 228130f4520SKenneth D. Merry &cbb_num_threads, 0, "Number of threads per backing file"); 229130f4520SKenneth D. Merry 230130f4520SKenneth D. Merry static struct ctl_be_block_io *ctl_alloc_beio(struct ctl_be_block_softc *softc); 231130f4520SKenneth D. Merry static void ctl_free_beio(struct ctl_be_block_io *beio); 232130f4520SKenneth D. Merry static void ctl_complete_beio(struct ctl_be_block_io *beio); 233130f4520SKenneth D. Merry static int ctl_be_block_move_done(union ctl_io *io); 234130f4520SKenneth D. Merry static void ctl_be_block_biodone(struct bio *bio); 235130f4520SKenneth D. Merry static void ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 236130f4520SKenneth D. Merry struct ctl_be_block_io *beio); 237130f4520SKenneth D. Merry static void ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 238130f4520SKenneth D. Merry struct ctl_be_block_io *beio); 239ef8daf3fSAlexander Motin static void ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 240ef8daf3fSAlexander Motin struct ctl_be_block_io *beio); 24153c146deSAlexander Motin static uint64_t ctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, 24253c146deSAlexander Motin const char *attrname); 243130f4520SKenneth D. Merry static void ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 244130f4520SKenneth D. Merry struct ctl_be_block_io *beio); 245ee7f31c0SAlexander Motin static void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 246ee7f31c0SAlexander Motin struct ctl_be_block_io *beio); 247130f4520SKenneth D. Merry static void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 248130f4520SKenneth D. Merry struct ctl_be_block_io *beio); 249c3e7ba3eSAlexander Motin static uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, 250c3e7ba3eSAlexander Motin const char *attrname); 251ef8daf3fSAlexander Motin static void ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 252ef8daf3fSAlexander Motin union ctl_io *io); 253130f4520SKenneth D. Merry static void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 254130f4520SKenneth D. Merry union ctl_io *io); 255130f4520SKenneth D. Merry static void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 256130f4520SKenneth D. Merry union ctl_io *io); 257130f4520SKenneth D. Merry static void ctl_be_block_worker(void *context, int pending); 258130f4520SKenneth D. Merry static int ctl_be_block_submit(union ctl_io *io); 259130f4520SKenneth D. Merry static int ctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 260130f4520SKenneth D. Merry int flag, struct thread *td); 261130f4520SKenneth D. Merry static int ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, 262130f4520SKenneth D. Merry struct ctl_lun_req *req); 263130f4520SKenneth D. Merry static int ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, 264130f4520SKenneth D. Merry struct ctl_lun_req *req); 265130f4520SKenneth D. Merry static int ctl_be_block_close(struct ctl_be_block_lun *be_lun); 266648dfc1aSAlexander Motin static int ctl_be_block_open(struct ctl_be_block_lun *be_lun, 267130f4520SKenneth D. Merry struct ctl_lun_req *req); 268130f4520SKenneth D. Merry static int ctl_be_block_create(struct ctl_be_block_softc *softc, 269130f4520SKenneth D. Merry struct ctl_lun_req *req); 270130f4520SKenneth D. Merry static int ctl_be_block_rm(struct ctl_be_block_softc *softc, 271130f4520SKenneth D. Merry struct ctl_lun_req *req); 27281177295SEdward Tomasz Napierala static int ctl_be_block_modify(struct ctl_be_block_softc *softc, 27381177295SEdward Tomasz Napierala struct ctl_lun_req *req); 274130f4520SKenneth D. Merry static void ctl_be_block_lun_shutdown(void *be_lun); 275130f4520SKenneth D. Merry static void ctl_be_block_lun_config_status(void *be_lun, 276130f4520SKenneth D. Merry ctl_lun_config_status status); 277130f4520SKenneth D. Merry static int ctl_be_block_config_write(union ctl_io *io); 278130f4520SKenneth D. Merry static int ctl_be_block_config_read(union ctl_io *io); 279130f4520SKenneth D. Merry static int ctl_be_block_lun_info(void *be_lun, struct sbuf *sb); 280c3e7ba3eSAlexander Motin static uint64_t ctl_be_block_lun_attr(void *be_lun, const char *attrname); 2810c629e28SAlexander Motin static int ctl_be_block_init(void); 2820c629e28SAlexander Motin static int ctl_be_block_shutdown(void); 283130f4520SKenneth D. Merry 284130f4520SKenneth D. Merry static struct ctl_backend_driver ctl_be_block_driver = 285130f4520SKenneth D. Merry { 2862a2443d8SKenneth D. Merry .name = "block", 2872a2443d8SKenneth D. Merry .flags = CTL_BE_FLAG_HAS_CONFIG, 2882a2443d8SKenneth D. Merry .init = ctl_be_block_init, 2890c629e28SAlexander Motin .shutdown = ctl_be_block_shutdown, 2902a2443d8SKenneth D. Merry .data_submit = ctl_be_block_submit, 2912a2443d8SKenneth D. Merry .data_move_done = ctl_be_block_move_done, 2922a2443d8SKenneth D. Merry .config_read = ctl_be_block_config_read, 2932a2443d8SKenneth D. Merry .config_write = ctl_be_block_config_write, 2942a2443d8SKenneth D. Merry .ioctl = ctl_be_block_ioctl, 295c3e7ba3eSAlexander Motin .lun_info = ctl_be_block_lun_info, 296c3e7ba3eSAlexander Motin .lun_attr = ctl_be_block_lun_attr 297130f4520SKenneth D. Merry }; 298130f4520SKenneth D. Merry 299130f4520SKenneth D. Merry MALLOC_DEFINE(M_CTLBLK, "ctlblk", "Memory used for CTL block backend"); 300130f4520SKenneth D. Merry CTL_BACKEND_DECLARE(cbb, ctl_be_block_driver); 301130f4520SKenneth D. Merry 302130f4520SKenneth D. Merry static struct ctl_be_block_io * 303130f4520SKenneth D. Merry ctl_alloc_beio(struct ctl_be_block_softc *softc) 304130f4520SKenneth D. Merry { 305130f4520SKenneth D. Merry struct ctl_be_block_io *beio; 306130f4520SKenneth D. Merry 3070c629e28SAlexander Motin beio = uma_zalloc(softc->beio_zone, M_WAITOK | M_ZERO); 308130f4520SKenneth D. Merry beio->softc = softc; 309130f4520SKenneth D. Merry return (beio); 310130f4520SKenneth D. Merry } 311130f4520SKenneth D. Merry 312130f4520SKenneth D. Merry static void 313130f4520SKenneth D. Merry ctl_free_beio(struct ctl_be_block_io *beio) 314130f4520SKenneth D. Merry { 315130f4520SKenneth D. Merry int duplicate_free; 316130f4520SKenneth D. Merry int i; 317130f4520SKenneth D. Merry 318130f4520SKenneth D. Merry duplicate_free = 0; 319130f4520SKenneth D. Merry 320130f4520SKenneth D. Merry for (i = 0; i < beio->num_segs; i++) { 321130f4520SKenneth D. Merry if (beio->sg_segs[i].addr == NULL) 322130f4520SKenneth D. Merry duplicate_free++; 323130f4520SKenneth D. Merry 324130f4520SKenneth D. Merry uma_zfree(beio->lun->lun_zone, beio->sg_segs[i].addr); 325130f4520SKenneth D. Merry beio->sg_segs[i].addr = NULL; 32611b569f7SAlexander Motin 32711b569f7SAlexander Motin /* For compare we had two equal S/G lists. */ 32811b569f7SAlexander Motin if (ARGS(beio->io)->flags & CTL_LLF_COMPARE) { 32911b569f7SAlexander Motin uma_zfree(beio->lun->lun_zone, 33011b569f7SAlexander Motin beio->sg_segs[i + CTLBLK_HALF_SEGS].addr); 33111b569f7SAlexander Motin beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = NULL; 33211b569f7SAlexander Motin } 333130f4520SKenneth D. Merry } 334130f4520SKenneth D. Merry 335130f4520SKenneth D. Merry if (duplicate_free > 0) { 336130f4520SKenneth D. Merry printf("%s: %d duplicate frees out of %d segments\n", __func__, 337130f4520SKenneth D. Merry duplicate_free, beio->num_segs); 338130f4520SKenneth D. Merry } 339a0e36aeeSEdward Tomasz Napierala 3400c629e28SAlexander Motin uma_zfree(beio->softc->beio_zone, beio); 341130f4520SKenneth D. Merry } 342130f4520SKenneth D. Merry 343130f4520SKenneth D. Merry static void 344130f4520SKenneth D. Merry ctl_complete_beio(struct ctl_be_block_io *beio) 345130f4520SKenneth D. Merry { 34675c7a1d3SAlexander Motin union ctl_io *io = beio->io; 347130f4520SKenneth D. Merry 348ee7f31c0SAlexander Motin if (beio->beio_cont != NULL) { 349ee7f31c0SAlexander Motin beio->beio_cont(beio); 350ee7f31c0SAlexander Motin } else { 351130f4520SKenneth D. Merry ctl_free_beio(beio); 35211b569f7SAlexander Motin ctl_data_submit_done(io); 353130f4520SKenneth D. Merry } 354ee7f31c0SAlexander Motin } 355130f4520SKenneth D. Merry 356d6043e46SAlexander Motin static size_t 357d6043e46SAlexander Motin cmp(uint8_t *a, uint8_t *b, size_t size) 358d6043e46SAlexander Motin { 359d6043e46SAlexander Motin size_t i; 360d6043e46SAlexander Motin 361d6043e46SAlexander Motin for (i = 0; i < size; i++) { 362d6043e46SAlexander Motin if (a[i] != b[i]) 363d6043e46SAlexander Motin break; 364d6043e46SAlexander Motin } 365d6043e46SAlexander Motin return (i); 366d6043e46SAlexander Motin } 367d6043e46SAlexander Motin 368d6043e46SAlexander Motin static void 369d6043e46SAlexander Motin ctl_be_block_compare(union ctl_io *io) 370d6043e46SAlexander Motin { 371d6043e46SAlexander Motin struct ctl_be_block_io *beio; 372d6043e46SAlexander Motin uint64_t off, res; 373d6043e46SAlexander Motin int i; 374d6043e46SAlexander Motin uint8_t info[8]; 375d6043e46SAlexander Motin 376d6043e46SAlexander Motin beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 377d6043e46SAlexander Motin off = 0; 378d6043e46SAlexander Motin for (i = 0; i < beio->num_segs; i++) { 379d6043e46SAlexander Motin res = cmp(beio->sg_segs[i].addr, 380d6043e46SAlexander Motin beio->sg_segs[i + CTLBLK_HALF_SEGS].addr, 381d6043e46SAlexander Motin beio->sg_segs[i].len); 382d6043e46SAlexander Motin off += res; 383d6043e46SAlexander Motin if (res < beio->sg_segs[i].len) 384d6043e46SAlexander Motin break; 385d6043e46SAlexander Motin } 386d6043e46SAlexander Motin if (i < beio->num_segs) { 387d6043e46SAlexander Motin scsi_u64to8b(off, info); 388d6043e46SAlexander Motin ctl_set_sense(&io->scsiio, /*current_error*/ 1, 389d6043e46SAlexander Motin /*sense_key*/ SSD_KEY_MISCOMPARE, 390d6043e46SAlexander Motin /*asc*/ 0x1D, /*ascq*/ 0x00, 391d6043e46SAlexander Motin /*type*/ SSD_ELEM_INFO, 392d6043e46SAlexander Motin /*size*/ sizeof(info), /*data*/ &info, 393d6043e46SAlexander Motin /*type*/ SSD_ELEM_NONE); 394d6043e46SAlexander Motin } else 395d6043e46SAlexander Motin ctl_set_success(&io->scsiio); 396d6043e46SAlexander Motin } 397d6043e46SAlexander Motin 398130f4520SKenneth D. Merry static int 399130f4520SKenneth D. Merry ctl_be_block_move_done(union ctl_io *io) 400130f4520SKenneth D. Merry { 401130f4520SKenneth D. Merry struct ctl_be_block_io *beio; 402130f4520SKenneth D. Merry struct ctl_be_block_lun *be_lun; 40311b569f7SAlexander Motin struct ctl_lba_len_flags *lbalen; 404130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 405130f4520SKenneth D. Merry struct bintime cur_bt; 406130f4520SKenneth D. Merry #endif 407130f4520SKenneth D. Merry 408e86a4142SAlexander Motin beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 409130f4520SKenneth D. Merry be_lun = beio->lun; 410130f4520SKenneth D. Merry 411130f4520SKenneth D. Merry DPRINTF("entered\n"); 412130f4520SKenneth D. Merry 413130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 414e675024aSAlexander Motin getbinuptime(&cur_bt); 415130f4520SKenneth D. Merry bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 416130f4520SKenneth D. Merry bintime_add(&io->io_hdr.dma_bt, &cur_bt); 417130f4520SKenneth D. Merry #endif 418e675024aSAlexander Motin io->io_hdr.num_dmas++; 41911b569f7SAlexander Motin io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 420130f4520SKenneth D. Merry 421130f4520SKenneth D. Merry /* 422130f4520SKenneth D. Merry * We set status at this point for read commands, and write 423130f4520SKenneth D. Merry * commands with errors. 424130f4520SKenneth D. Merry */ 425f7241cceSAlexander Motin if (io->io_hdr.flags & CTL_FLAG_ABORT) { 426f7241cceSAlexander Motin ; 427eb6ac6f9SAlexander Motin } else if ((io->io_hdr.port_status != 0) && 428eb6ac6f9SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 429eb6ac6f9SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 430eb6ac6f9SAlexander Motin ctl_set_internal_failure(&io->scsiio, /*sks_valid*/ 1, 431eb6ac6f9SAlexander Motin /*retry_count*/ io->io_hdr.port_status); 432eb6ac6f9SAlexander Motin } else if (io->scsiio.kern_data_resid != 0 && 433eb6ac6f9SAlexander Motin (io->io_hdr.flags & CTL_FLAG_DATA_MASK) == CTL_FLAG_DATA_OUT && 434eb6ac6f9SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 435eb6ac6f9SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 436eb6ac6f9SAlexander Motin ctl_set_invalid_field_ciu(&io->scsiio); 437f7241cceSAlexander Motin } else if ((io->io_hdr.port_status == 0) && 43811b569f7SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 43911b569f7SAlexander Motin lbalen = ARGS(beio->io); 44011b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_READ) { 441130f4520SKenneth D. Merry ctl_set_success(&io->scsiio); 44211b569f7SAlexander Motin } else if (lbalen->flags & CTL_LLF_COMPARE) { 44311b569f7SAlexander Motin /* We have two data blocks ready for comparison. */ 444d6043e46SAlexander Motin ctl_be_block_compare(io); 44511b569f7SAlexander Motin } 446130f4520SKenneth D. Merry } 447130f4520SKenneth D. Merry 448130f4520SKenneth D. Merry /* 449130f4520SKenneth D. Merry * If this is a read, or a write with errors, it is done. 450130f4520SKenneth D. Merry */ 451130f4520SKenneth D. Merry if ((beio->bio_cmd == BIO_READ) 452130f4520SKenneth D. Merry || ((io->io_hdr.flags & CTL_FLAG_ABORT) != 0) 453130f4520SKenneth D. Merry || ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE)) { 454130f4520SKenneth D. Merry ctl_complete_beio(beio); 455130f4520SKenneth D. Merry return (0); 456130f4520SKenneth D. Merry } 457130f4520SKenneth D. Merry 458130f4520SKenneth D. Merry /* 459130f4520SKenneth D. Merry * At this point, we have a write and the DMA completed 460130f4520SKenneth D. Merry * successfully. We now have to queue it to the task queue to 461130f4520SKenneth D. Merry * execute the backend I/O. That is because we do blocking 462130f4520SKenneth D. Merry * memory allocations, and in the file backing case, blocking I/O. 463130f4520SKenneth D. Merry * This move done routine is generally called in the SIM's 464130f4520SKenneth D. Merry * interrupt context, and therefore we cannot block. 465130f4520SKenneth D. Merry */ 46675c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 467130f4520SKenneth D. Merry STAILQ_INSERT_TAIL(&be_lun->datamove_queue, &io->io_hdr, links); 46875c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 469130f4520SKenneth D. Merry taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 470130f4520SKenneth D. Merry 471130f4520SKenneth D. Merry return (0); 472130f4520SKenneth D. Merry } 473130f4520SKenneth D. Merry 474130f4520SKenneth D. Merry static void 475130f4520SKenneth D. Merry ctl_be_block_biodone(struct bio *bio) 476130f4520SKenneth D. Merry { 477130f4520SKenneth D. Merry struct ctl_be_block_io *beio; 478130f4520SKenneth D. Merry struct ctl_be_block_lun *be_lun; 479130f4520SKenneth D. Merry union ctl_io *io; 480e0c2f975SAlexander Motin int error; 481130f4520SKenneth D. Merry 482130f4520SKenneth D. Merry beio = bio->bio_caller1; 483130f4520SKenneth D. Merry be_lun = beio->lun; 484130f4520SKenneth D. Merry io = beio->io; 485130f4520SKenneth D. Merry 486130f4520SKenneth D. Merry DPRINTF("entered\n"); 487130f4520SKenneth D. Merry 488e0c2f975SAlexander Motin error = bio->bio_error; 48975c7a1d3SAlexander Motin mtx_lock(&be_lun->io_lock); 4901f0694a6SAlexander Motin if (error != 0 && 4911f0694a6SAlexander Motin (beio->first_error == 0 || 4921f0694a6SAlexander Motin bio->bio_offset < beio->first_error_offset)) { 4931f0694a6SAlexander Motin beio->first_error = error; 4941f0694a6SAlexander Motin beio->first_error_offset = bio->bio_offset; 4951f0694a6SAlexander Motin } 496130f4520SKenneth D. Merry 497130f4520SKenneth D. Merry beio->num_bios_done++; 498130f4520SKenneth D. Merry 499130f4520SKenneth D. Merry /* 500130f4520SKenneth D. Merry * XXX KDM will this cause WITNESS to complain? Holding a lock 501130f4520SKenneth D. Merry * during the free might cause it to complain. 502130f4520SKenneth D. Merry */ 503130f4520SKenneth D. Merry g_destroy_bio(bio); 504130f4520SKenneth D. Merry 505130f4520SKenneth D. Merry /* 506130f4520SKenneth D. Merry * If the send complete bit isn't set, or we aren't the last I/O to 507130f4520SKenneth D. Merry * complete, then we're done. 508130f4520SKenneth D. Merry */ 509130f4520SKenneth D. Merry if ((beio->send_complete == 0) 510130f4520SKenneth D. Merry || (beio->num_bios_done < beio->num_bios_sent)) { 51175c7a1d3SAlexander Motin mtx_unlock(&be_lun->io_lock); 512130f4520SKenneth D. Merry return; 513130f4520SKenneth D. Merry } 514130f4520SKenneth D. Merry 515130f4520SKenneth D. Merry /* 516130f4520SKenneth D. Merry * At this point, we've verified that we are the last I/O to 517130f4520SKenneth D. Merry * complete, so it's safe to drop the lock. 518130f4520SKenneth D. Merry */ 51975c7a1d3SAlexander Motin devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 52075c7a1d3SAlexander Motin beio->ds_tag_type, beio->ds_trans_type, 52175c7a1d3SAlexander Motin /*now*/ NULL, /*then*/&beio->ds_t0); 52275c7a1d3SAlexander Motin mtx_unlock(&be_lun->io_lock); 523130f4520SKenneth D. Merry 524130f4520SKenneth D. Merry /* 525130f4520SKenneth D. Merry * If there are any errors from the backing device, we fail the 526130f4520SKenneth D. Merry * entire I/O with a medium error. 527130f4520SKenneth D. Merry */ 5281f0694a6SAlexander Motin error = beio->first_error; 5291f0694a6SAlexander Motin if (error != 0) { 530e0c2f975SAlexander Motin if (error == EOPNOTSUPP) { 531e0c2f975SAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 5320631de4aSAlexander Motin } else if (error == ENOSPC || error == EDQUOT) { 5334fc18ff9SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 5346187d472SAlexander Motin } else if (error == EROFS || error == EACCES) { 5356187d472SAlexander Motin ctl_set_hw_write_protected(&io->scsiio); 536e0c2f975SAlexander Motin } else if (beio->bio_cmd == BIO_FLUSH) { 537130f4520SKenneth D. Merry /* XXX KDM is there is a better error here? */ 538130f4520SKenneth D. Merry ctl_set_internal_failure(&io->scsiio, 539130f4520SKenneth D. Merry /*sks_valid*/ 1, 540130f4520SKenneth D. Merry /*retry_count*/ 0xbad2); 5417f7bb97aSAlexander Motin } else { 5427f7bb97aSAlexander Motin ctl_set_medium_error(&io->scsiio, 5437f7bb97aSAlexander Motin beio->bio_cmd == BIO_READ); 5447f7bb97aSAlexander Motin } 545130f4520SKenneth D. Merry ctl_complete_beio(beio); 546130f4520SKenneth D. Merry return; 547130f4520SKenneth D. Merry } 548130f4520SKenneth D. Merry 549130f4520SKenneth D. Merry /* 55011b569f7SAlexander Motin * If this is a write, a flush, a delete or verify, we're all done. 551130f4520SKenneth D. Merry * If this is a read, we can now send the data to the user. 552130f4520SKenneth D. Merry */ 553130f4520SKenneth D. Merry if ((beio->bio_cmd == BIO_WRITE) 554ee7f31c0SAlexander Motin || (beio->bio_cmd == BIO_FLUSH) 55511b569f7SAlexander Motin || (beio->bio_cmd == BIO_DELETE) 55611b569f7SAlexander Motin || (ARGS(io)->flags & CTL_LLF_VERIFY)) { 557130f4520SKenneth D. Merry ctl_set_success(&io->scsiio); 558130f4520SKenneth D. Merry ctl_complete_beio(beio); 559130f4520SKenneth D. Merry } else { 560f7241cceSAlexander Motin if ((ARGS(io)->flags & CTL_LLF_READ) && 56175a3108eSAlexander Motin beio->beio_cont == NULL) { 562f7241cceSAlexander Motin ctl_set_success(&io->scsiio); 56375a3108eSAlexander Motin ctl_serseq_done(io); 56475a3108eSAlexander Motin } 565130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 566e675024aSAlexander Motin getbinuptime(&io->io_hdr.dma_start_bt); 567130f4520SKenneth D. Merry #endif 568130f4520SKenneth D. Merry ctl_datamove(io); 569130f4520SKenneth D. Merry } 570130f4520SKenneth D. Merry } 571130f4520SKenneth D. Merry 572130f4520SKenneth D. Merry static void 573130f4520SKenneth D. Merry ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 574130f4520SKenneth D. Merry struct ctl_be_block_io *beio) 575130f4520SKenneth D. Merry { 57675c7a1d3SAlexander Motin union ctl_io *io = beio->io; 577130f4520SKenneth D. Merry struct mount *mountpoint; 5785050aa86SKonstantin Belousov int error, lock_flags; 579130f4520SKenneth D. Merry 580130f4520SKenneth D. Merry DPRINTF("entered\n"); 581130f4520SKenneth D. Merry 58275c7a1d3SAlexander Motin binuptime(&beio->ds_t0); 58375c7a1d3SAlexander Motin devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 584130f4520SKenneth D. Merry 585130f4520SKenneth D. Merry (void) vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 586130f4520SKenneth D. Merry 58767cc546dSAlexander Motin if (MNT_SHARED_WRITES(mountpoint) || 58867cc546dSAlexander Motin ((mountpoint == NULL) && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 589130f4520SKenneth D. Merry lock_flags = LK_SHARED; 590130f4520SKenneth D. Merry else 591130f4520SKenneth D. Merry lock_flags = LK_EXCLUSIVE; 592130f4520SKenneth D. Merry vn_lock(be_lun->vn, lock_flags | LK_RETRY); 5937d0d4342SAlexander Motin error = VOP_FSYNC(be_lun->vn, beio->io_arg ? MNT_NOWAIT : MNT_WAIT, 5947d0d4342SAlexander Motin curthread); 595b249ce48SMateusz Guzik VOP_UNLOCK(be_lun->vn); 596130f4520SKenneth D. Merry 597130f4520SKenneth D. Merry vn_finished_write(mountpoint); 598130f4520SKenneth D. Merry 59975c7a1d3SAlexander Motin mtx_lock(&be_lun->io_lock); 60075c7a1d3SAlexander Motin devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 60175c7a1d3SAlexander Motin beio->ds_tag_type, beio->ds_trans_type, 60275c7a1d3SAlexander Motin /*now*/ NULL, /*then*/&beio->ds_t0); 60375c7a1d3SAlexander Motin mtx_unlock(&be_lun->io_lock); 60475c7a1d3SAlexander Motin 605130f4520SKenneth D. Merry if (error == 0) 606130f4520SKenneth D. Merry ctl_set_success(&io->scsiio); 607130f4520SKenneth D. Merry else { 608130f4520SKenneth D. Merry /* XXX KDM is there is a better error here? */ 609130f4520SKenneth D. Merry ctl_set_internal_failure(&io->scsiio, 610130f4520SKenneth D. Merry /*sks_valid*/ 1, 611130f4520SKenneth D. Merry /*retry_count*/ 0xbad1); 612130f4520SKenneth D. Merry } 613130f4520SKenneth D. Merry 614130f4520SKenneth D. Merry ctl_complete_beio(beio); 615130f4520SKenneth D. Merry } 616130f4520SKenneth D. Merry 61736160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , read, file_start, "uint64_t"); 61836160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , write, file_start, "uint64_t"); 61936160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , read, file_done,"uint64_t"); 62036160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , write, file_done, "uint64_t"); 621130f4520SKenneth D. Merry 622130f4520SKenneth D. Merry static void 623130f4520SKenneth D. Merry ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 624130f4520SKenneth D. Merry struct ctl_be_block_io *beio) 625130f4520SKenneth D. Merry { 626130f4520SKenneth D. Merry struct ctl_be_block_filedata *file_data; 627130f4520SKenneth D. Merry union ctl_io *io; 628130f4520SKenneth D. Merry struct uio xuio; 629130f4520SKenneth D. Merry struct iovec *xiovec; 63083981e31SAlexander Motin size_t s; 63183981e31SAlexander Motin int error, flags, i; 632130f4520SKenneth D. Merry 633130f4520SKenneth D. Merry DPRINTF("entered\n"); 634130f4520SKenneth D. Merry 635130f4520SKenneth D. Merry file_data = &be_lun->backend.file; 636130f4520SKenneth D. Merry io = beio->io; 63755551d05SAlexander Motin flags = 0; 63855551d05SAlexander Motin if (ARGS(io)->flags & CTL_LLF_DPO) 63955551d05SAlexander Motin flags |= IO_DIRECT; 64055551d05SAlexander Motin if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 64155551d05SAlexander Motin flags |= IO_SYNC; 642130f4520SKenneth D. Merry 64311b569f7SAlexander Motin bzero(&xuio, sizeof(xuio)); 644130f4520SKenneth D. Merry if (beio->bio_cmd == BIO_READ) { 64536160958SMark Johnston SDT_PROBE0(cbb, , read, file_start); 64611b569f7SAlexander Motin xuio.uio_rw = UIO_READ; 647130f4520SKenneth D. Merry } else { 64836160958SMark Johnston SDT_PROBE0(cbb, , write, file_start); 649130f4520SKenneth D. Merry xuio.uio_rw = UIO_WRITE; 65011b569f7SAlexander Motin } 651130f4520SKenneth D. Merry xuio.uio_offset = beio->io_offset; 652130f4520SKenneth D. Merry xuio.uio_resid = beio->io_len; 653130f4520SKenneth D. Merry xuio.uio_segflg = UIO_SYSSPACE; 654130f4520SKenneth D. Merry xuio.uio_iov = beio->xiovecs; 655130f4520SKenneth D. Merry xuio.uio_iovcnt = beio->num_segs; 656130f4520SKenneth D. Merry xuio.uio_td = curthread; 657130f4520SKenneth D. Merry 658130f4520SKenneth D. Merry for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 659130f4520SKenneth D. Merry xiovec->iov_base = beio->sg_segs[i].addr; 660130f4520SKenneth D. Merry xiovec->iov_len = beio->sg_segs[i].len; 661130f4520SKenneth D. Merry } 662130f4520SKenneth D. Merry 66375c7a1d3SAlexander Motin binuptime(&beio->ds_t0); 66475c7a1d3SAlexander Motin devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 66575c7a1d3SAlexander Motin 666130f4520SKenneth D. Merry if (beio->bio_cmd == BIO_READ) { 667130f4520SKenneth D. Merry vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 668130f4520SKenneth D. Merry 669130f4520SKenneth D. Merry /* 670130f4520SKenneth D. Merry * UFS pays attention to IO_DIRECT for reads. If the 671130f4520SKenneth D. Merry * DIRECTIO option is configured into the kernel, it calls 672130f4520SKenneth D. Merry * ffs_rawread(). But that only works for single-segment 673130f4520SKenneth D. Merry * uios with user space addresses. In our case, with a 674130f4520SKenneth D. Merry * kernel uio, it still reads into the buffer cache, but it 675130f4520SKenneth D. Merry * will just try to release the buffer from the cache later 676130f4520SKenneth D. Merry * on in ffs_read(). 677130f4520SKenneth D. Merry * 678130f4520SKenneth D. Merry * ZFS does not pay attention to IO_DIRECT for reads. 679130f4520SKenneth D. Merry * 680130f4520SKenneth D. Merry * UFS does not pay attention to IO_SYNC for reads. 681130f4520SKenneth D. Merry * 682130f4520SKenneth D. Merry * ZFS pays attention to IO_SYNC (which translates into the 683130f4520SKenneth D. Merry * Solaris define FRSYNC for zfs_read()) for reads. It 684130f4520SKenneth D. Merry * attempts to sync the file before reading. 685130f4520SKenneth D. Merry */ 68655551d05SAlexander Motin error = VOP_READ(be_lun->vn, &xuio, flags, file_data->cred); 687130f4520SKenneth D. Merry 688b249ce48SMateusz Guzik VOP_UNLOCK(be_lun->vn); 68936160958SMark Johnston SDT_PROBE0(cbb, , read, file_done); 69083981e31SAlexander Motin if (error == 0 && xuio.uio_resid > 0) { 69183981e31SAlexander Motin /* 69283981e31SAlexander Motin * If we red less then requested (EOF), then 69383981e31SAlexander Motin * we should clean the rest of the buffer. 69483981e31SAlexander Motin */ 69583981e31SAlexander Motin s = beio->io_len - xuio.uio_resid; 69683981e31SAlexander Motin for (i = 0; i < beio->num_segs; i++) { 69783981e31SAlexander Motin if (s >= beio->sg_segs[i].len) { 69883981e31SAlexander Motin s -= beio->sg_segs[i].len; 69983981e31SAlexander Motin continue; 70083981e31SAlexander Motin } 70183981e31SAlexander Motin bzero((uint8_t *)beio->sg_segs[i].addr + s, 70283981e31SAlexander Motin beio->sg_segs[i].len - s); 70383981e31SAlexander Motin s = 0; 70483981e31SAlexander Motin } 70583981e31SAlexander Motin } 706130f4520SKenneth D. Merry } else { 707130f4520SKenneth D. Merry struct mount *mountpoint; 708130f4520SKenneth D. Merry int lock_flags; 709130f4520SKenneth D. Merry 710130f4520SKenneth D. Merry (void)vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 711130f4520SKenneth D. Merry 71267cc546dSAlexander Motin if (MNT_SHARED_WRITES(mountpoint) || ((mountpoint == NULL) 713130f4520SKenneth D. Merry && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 714130f4520SKenneth D. Merry lock_flags = LK_SHARED; 715130f4520SKenneth D. Merry else 716130f4520SKenneth D. Merry lock_flags = LK_EXCLUSIVE; 717130f4520SKenneth D. Merry vn_lock(be_lun->vn, lock_flags | LK_RETRY); 718130f4520SKenneth D. Merry 719130f4520SKenneth D. Merry /* 720130f4520SKenneth D. Merry * UFS pays attention to IO_DIRECT for writes. The write 721130f4520SKenneth D. Merry * is done asynchronously. (Normally the write would just 722130f4520SKenneth D. Merry * get put into cache. 723130f4520SKenneth D. Merry * 724130f4520SKenneth D. Merry * UFS pays attention to IO_SYNC for writes. It will 725130f4520SKenneth D. Merry * attempt to write the buffer out synchronously if that 726130f4520SKenneth D. Merry * flag is set. 727130f4520SKenneth D. Merry * 728130f4520SKenneth D. Merry * ZFS does not pay attention to IO_DIRECT for writes. 729130f4520SKenneth D. Merry * 730130f4520SKenneth D. Merry * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC) 731130f4520SKenneth D. Merry * for writes. It will flush the transaction from the 732130f4520SKenneth D. Merry * cache before returning. 733130f4520SKenneth D. Merry */ 73455551d05SAlexander Motin error = VOP_WRITE(be_lun->vn, &xuio, flags, file_data->cred); 735b249ce48SMateusz Guzik VOP_UNLOCK(be_lun->vn); 736130f4520SKenneth D. Merry 737130f4520SKenneth D. Merry vn_finished_write(mountpoint); 73836160958SMark Johnston SDT_PROBE0(cbb, , write, file_done); 739130f4520SKenneth D. Merry } 740130f4520SKenneth D. Merry 74175c7a1d3SAlexander Motin mtx_lock(&be_lun->io_lock); 74275c7a1d3SAlexander Motin devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 74375c7a1d3SAlexander Motin beio->ds_tag_type, beio->ds_trans_type, 74475c7a1d3SAlexander Motin /*now*/ NULL, /*then*/&beio->ds_t0); 74575c7a1d3SAlexander Motin mtx_unlock(&be_lun->io_lock); 74675c7a1d3SAlexander Motin 747130f4520SKenneth D. Merry /* 748130f4520SKenneth D. Merry * If we got an error, set the sense data to "MEDIUM ERROR" and 749130f4520SKenneth D. Merry * return the I/O to the user. 750130f4520SKenneth D. Merry */ 751130f4520SKenneth D. Merry if (error != 0) { 7520631de4aSAlexander Motin if (error == ENOSPC || error == EDQUOT) { 7534fc18ff9SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 7546187d472SAlexander Motin } else if (error == EROFS || error == EACCES) { 7556187d472SAlexander Motin ctl_set_hw_write_protected(&io->scsiio); 7567f7bb97aSAlexander Motin } else { 7577f7bb97aSAlexander Motin ctl_set_medium_error(&io->scsiio, 7587f7bb97aSAlexander Motin beio->bio_cmd == BIO_READ); 7597f7bb97aSAlexander Motin } 760130f4520SKenneth D. Merry ctl_complete_beio(beio); 761130f4520SKenneth D. Merry return; 762130f4520SKenneth D. Merry } 763130f4520SKenneth D. Merry 764130f4520SKenneth D. Merry /* 765696297adSAlexander Motin * If this is a write or a verify, we're all done. 766130f4520SKenneth D. Merry * If this is a read, we can now send the data to the user. 767130f4520SKenneth D. Merry */ 768696297adSAlexander Motin if ((beio->bio_cmd == BIO_WRITE) || 769696297adSAlexander Motin (ARGS(io)->flags & CTL_LLF_VERIFY)) { 770130f4520SKenneth D. Merry ctl_set_success(&io->scsiio); 771130f4520SKenneth D. Merry ctl_complete_beio(beio); 772130f4520SKenneth D. Merry } else { 773f7241cceSAlexander Motin if ((ARGS(io)->flags & CTL_LLF_READ) && 77475a3108eSAlexander Motin beio->beio_cont == NULL) { 775f7241cceSAlexander Motin ctl_set_success(&io->scsiio); 77675a3108eSAlexander Motin ctl_serseq_done(io); 77775a3108eSAlexander Motin } 778130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 779e675024aSAlexander Motin getbinuptime(&io->io_hdr.dma_start_bt); 780130f4520SKenneth D. Merry #endif 781130f4520SKenneth D. Merry ctl_datamove(io); 782130f4520SKenneth D. Merry } 783130f4520SKenneth D. Merry } 784130f4520SKenneth D. Merry 785130f4520SKenneth D. Merry static void 786ef8daf3fSAlexander Motin ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 787ef8daf3fSAlexander Motin struct ctl_be_block_io *beio) 788ef8daf3fSAlexander Motin { 789ef8daf3fSAlexander Motin union ctl_io *io = beio->io; 790ef8daf3fSAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 791ef8daf3fSAlexander Motin struct scsi_get_lba_status_data *data; 792ef8daf3fSAlexander Motin off_t roff, off; 793ef8daf3fSAlexander Motin int error, status; 794ef8daf3fSAlexander Motin 795ef8daf3fSAlexander Motin DPRINTF("entered\n"); 796ef8daf3fSAlexander Motin 7970bcd4ab6SAlexander Motin off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 798ef8daf3fSAlexander Motin vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 799ef8daf3fSAlexander Motin error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off, 800ef8daf3fSAlexander Motin 0, curthread->td_ucred, curthread); 801ef8daf3fSAlexander Motin if (error == 0 && off > roff) 802ef8daf3fSAlexander Motin status = 0; /* mapped up to off */ 803ef8daf3fSAlexander Motin else { 804ef8daf3fSAlexander Motin error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off, 805ef8daf3fSAlexander Motin 0, curthread->td_ucred, curthread); 806ef8daf3fSAlexander Motin if (error == 0 && off > roff) 807ef8daf3fSAlexander Motin status = 1; /* deallocated up to off */ 808ef8daf3fSAlexander Motin else { 809ef8daf3fSAlexander Motin status = 0; /* unknown up to the end */ 810ef8daf3fSAlexander Motin off = be_lun->size_bytes; 811ef8daf3fSAlexander Motin } 812ef8daf3fSAlexander Motin } 813b249ce48SMateusz Guzik VOP_UNLOCK(be_lun->vn); 814ef8daf3fSAlexander Motin 815ef8daf3fSAlexander Motin data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 816ef8daf3fSAlexander Motin scsi_u64to8b(lbalen->lba, data->descr[0].addr); 8170bcd4ab6SAlexander Motin scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 8180bcd4ab6SAlexander Motin lbalen->lba), data->descr[0].length); 819ef8daf3fSAlexander Motin data->descr[0].status = status; 820ef8daf3fSAlexander Motin 821ef8daf3fSAlexander Motin ctl_complete_beio(beio); 822ef8daf3fSAlexander Motin } 823ef8daf3fSAlexander Motin 82453c146deSAlexander Motin static uint64_t 82553c146deSAlexander Motin ctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, const char *attrname) 82653c146deSAlexander Motin { 82753c146deSAlexander Motin struct vattr vattr; 82853c146deSAlexander Motin struct statfs statfs; 829b9b4269cSAlexander Motin uint64_t val; 83053c146deSAlexander Motin int error; 83153c146deSAlexander Motin 832b9b4269cSAlexander Motin val = UINT64_MAX; 83353c146deSAlexander Motin if (be_lun->vn == NULL) 834b9b4269cSAlexander Motin return (val); 835b9b4269cSAlexander Motin vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 83653c146deSAlexander Motin if (strcmp(attrname, "blocksused") == 0) { 83753c146deSAlexander Motin error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 838b9b4269cSAlexander Motin if (error == 0) 8390bcd4ab6SAlexander Motin val = vattr.va_bytes / be_lun->cbe_lun.blocksize; 84053c146deSAlexander Motin } 841b9b4269cSAlexander Motin if (strcmp(attrname, "blocksavail") == 0 && 842abd80ddbSMateusz Guzik !VN_IS_DOOMED(be_lun->vn)) { 84353c146deSAlexander Motin error = VFS_STATFS(be_lun->vn->v_mount, &statfs); 844b9b4269cSAlexander Motin if (error == 0) 845a15bbf15SAlexander Motin val = statfs.f_bavail * statfs.f_bsize / 8460bcd4ab6SAlexander Motin be_lun->cbe_lun.blocksize; 84753c146deSAlexander Motin } 848b249ce48SMateusz Guzik VOP_UNLOCK(be_lun->vn); 849b9b4269cSAlexander Motin return (val); 85053c146deSAlexander Motin } 85153c146deSAlexander Motin 852ef8daf3fSAlexander Motin static void 85367f586a8SAlexander Motin ctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, 85467f586a8SAlexander Motin struct ctl_be_block_io *beio) 85567f586a8SAlexander Motin { 85667f586a8SAlexander Motin union ctl_io *io; 8573236151eSAlexander Motin struct cdevsw *csw; 8583236151eSAlexander Motin struct cdev *dev; 85967f586a8SAlexander Motin struct uio xuio; 86067f586a8SAlexander Motin struct iovec *xiovec; 8613236151eSAlexander Motin int error, flags, i, ref; 86267f586a8SAlexander Motin 86367f586a8SAlexander Motin DPRINTF("entered\n"); 86467f586a8SAlexander Motin 86567f586a8SAlexander Motin io = beio->io; 86655551d05SAlexander Motin flags = 0; 86755551d05SAlexander Motin if (ARGS(io)->flags & CTL_LLF_DPO) 86855551d05SAlexander Motin flags |= IO_DIRECT; 86955551d05SAlexander Motin if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 87055551d05SAlexander Motin flags |= IO_SYNC; 87167f586a8SAlexander Motin 87267f586a8SAlexander Motin bzero(&xuio, sizeof(xuio)); 87367f586a8SAlexander Motin if (beio->bio_cmd == BIO_READ) { 87436160958SMark Johnston SDT_PROBE0(cbb, , read, file_start); 87567f586a8SAlexander Motin xuio.uio_rw = UIO_READ; 87667f586a8SAlexander Motin } else { 87736160958SMark Johnston SDT_PROBE0(cbb, , write, file_start); 87867f586a8SAlexander Motin xuio.uio_rw = UIO_WRITE; 87967f586a8SAlexander Motin } 88067f586a8SAlexander Motin xuio.uio_offset = beio->io_offset; 88167f586a8SAlexander Motin xuio.uio_resid = beio->io_len; 88267f586a8SAlexander Motin xuio.uio_segflg = UIO_SYSSPACE; 88367f586a8SAlexander Motin xuio.uio_iov = beio->xiovecs; 88467f586a8SAlexander Motin xuio.uio_iovcnt = beio->num_segs; 88567f586a8SAlexander Motin xuio.uio_td = curthread; 88667f586a8SAlexander Motin 88767f586a8SAlexander Motin for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 88867f586a8SAlexander Motin xiovec->iov_base = beio->sg_segs[i].addr; 88967f586a8SAlexander Motin xiovec->iov_len = beio->sg_segs[i].len; 89067f586a8SAlexander Motin } 89167f586a8SAlexander Motin 89267f586a8SAlexander Motin binuptime(&beio->ds_t0); 89367f586a8SAlexander Motin devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 89467f586a8SAlexander Motin 8953236151eSAlexander Motin csw = devvn_refthread(be_lun->vn, &dev, &ref); 8963236151eSAlexander Motin if (csw) { 8973236151eSAlexander Motin if (beio->bio_cmd == BIO_READ) 8983236151eSAlexander Motin error = csw->d_read(dev, &xuio, flags); 8993236151eSAlexander Motin else 9003236151eSAlexander Motin error = csw->d_write(dev, &xuio, flags); 9013236151eSAlexander Motin dev_relthread(dev, ref); 9023236151eSAlexander Motin } else 9033236151eSAlexander Motin error = ENXIO; 9043236151eSAlexander Motin 9053236151eSAlexander Motin if (beio->bio_cmd == BIO_READ) 90636160958SMark Johnston SDT_PROBE0(cbb, , read, file_done); 9073236151eSAlexander Motin else 90836160958SMark Johnston SDT_PROBE0(cbb, , write, file_done); 90967f586a8SAlexander Motin 91067f586a8SAlexander Motin mtx_lock(&be_lun->io_lock); 91167f586a8SAlexander Motin devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 91267f586a8SAlexander Motin beio->ds_tag_type, beio->ds_trans_type, 91367f586a8SAlexander Motin /*now*/ NULL, /*then*/&beio->ds_t0); 91467f586a8SAlexander Motin mtx_unlock(&be_lun->io_lock); 91567f586a8SAlexander Motin 91667f586a8SAlexander Motin /* 91767f586a8SAlexander Motin * If we got an error, set the sense data to "MEDIUM ERROR" and 91867f586a8SAlexander Motin * return the I/O to the user. 91967f586a8SAlexander Motin */ 92067f586a8SAlexander Motin if (error != 0) { 9210631de4aSAlexander Motin if (error == ENOSPC || error == EDQUOT) { 9224fc18ff9SAlexander Motin ctl_set_space_alloc_fail(&io->scsiio); 9236187d472SAlexander Motin } else if (error == EROFS || error == EACCES) { 9246187d472SAlexander Motin ctl_set_hw_write_protected(&io->scsiio); 9257f7bb97aSAlexander Motin } else { 9267f7bb97aSAlexander Motin ctl_set_medium_error(&io->scsiio, 9277f7bb97aSAlexander Motin beio->bio_cmd == BIO_READ); 9287f7bb97aSAlexander Motin } 92967f586a8SAlexander Motin ctl_complete_beio(beio); 93067f586a8SAlexander Motin return; 93167f586a8SAlexander Motin } 93267f586a8SAlexander Motin 93367f586a8SAlexander Motin /* 93467f586a8SAlexander Motin * If this is a write or a verify, we're all done. 93567f586a8SAlexander Motin * If this is a read, we can now send the data to the user. 93667f586a8SAlexander Motin */ 93767f586a8SAlexander Motin if ((beio->bio_cmd == BIO_WRITE) || 93867f586a8SAlexander Motin (ARGS(io)->flags & CTL_LLF_VERIFY)) { 93967f586a8SAlexander Motin ctl_set_success(&io->scsiio); 94067f586a8SAlexander Motin ctl_complete_beio(beio); 94167f586a8SAlexander Motin } else { 942f7241cceSAlexander Motin if ((ARGS(io)->flags & CTL_LLF_READ) && 94375a3108eSAlexander Motin beio->beio_cont == NULL) { 944f7241cceSAlexander Motin ctl_set_success(&io->scsiio); 94575a3108eSAlexander Motin ctl_serseq_done(io); 94675a3108eSAlexander Motin } 94767f586a8SAlexander Motin #ifdef CTL_TIME_IO 948e675024aSAlexander Motin getbinuptime(&io->io_hdr.dma_start_bt); 94967f586a8SAlexander Motin #endif 95067f586a8SAlexander Motin ctl_datamove(io); 95167f586a8SAlexander Motin } 95267f586a8SAlexander Motin } 95367f586a8SAlexander Motin 95467f586a8SAlexander Motin static void 955ef8daf3fSAlexander Motin ctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, 956ef8daf3fSAlexander Motin struct ctl_be_block_io *beio) 957ef8daf3fSAlexander Motin { 958ef8daf3fSAlexander Motin union ctl_io *io = beio->io; 9593236151eSAlexander Motin struct cdevsw *csw; 9603236151eSAlexander Motin struct cdev *dev; 961ef8daf3fSAlexander Motin struct ctl_lba_len_flags *lbalen = ARGS(io); 962ef8daf3fSAlexander Motin struct scsi_get_lba_status_data *data; 963ef8daf3fSAlexander Motin off_t roff, off; 9643236151eSAlexander Motin int error, ref, status; 965ef8daf3fSAlexander Motin 966ef8daf3fSAlexander Motin DPRINTF("entered\n"); 967ef8daf3fSAlexander Motin 9683236151eSAlexander Motin csw = devvn_refthread(be_lun->vn, &dev, &ref); 9693236151eSAlexander Motin if (csw == NULL) { 9703236151eSAlexander Motin status = 0; /* unknown up to the end */ 9713236151eSAlexander Motin off = be_lun->size_bytes; 9723236151eSAlexander Motin goto done; 9733236151eSAlexander Motin } 9740bcd4ab6SAlexander Motin off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 9753236151eSAlexander Motin error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD, 9763236151eSAlexander Motin curthread); 977ef8daf3fSAlexander Motin if (error == 0 && off > roff) 978ef8daf3fSAlexander Motin status = 0; /* mapped up to off */ 979ef8daf3fSAlexander Motin else { 9803236151eSAlexander Motin error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD, 9813236151eSAlexander Motin curthread); 982ef8daf3fSAlexander Motin if (error == 0 && off > roff) 983ef8daf3fSAlexander Motin status = 1; /* deallocated up to off */ 984ef8daf3fSAlexander Motin else { 985ef8daf3fSAlexander Motin status = 0; /* unknown up to the end */ 986ef8daf3fSAlexander Motin off = be_lun->size_bytes; 987ef8daf3fSAlexander Motin } 988ef8daf3fSAlexander Motin } 9893236151eSAlexander Motin dev_relthread(dev, ref); 990ef8daf3fSAlexander Motin 9913236151eSAlexander Motin done: 992ef8daf3fSAlexander Motin data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 993ef8daf3fSAlexander Motin scsi_u64to8b(lbalen->lba, data->descr[0].addr); 9940bcd4ab6SAlexander Motin scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 9950bcd4ab6SAlexander Motin lbalen->lba), data->descr[0].length); 996ef8daf3fSAlexander Motin data->descr[0].status = status; 997ef8daf3fSAlexander Motin 998ef8daf3fSAlexander Motin ctl_complete_beio(beio); 999ef8daf3fSAlexander Motin } 1000ef8daf3fSAlexander Motin 1001ef8daf3fSAlexander Motin static void 1002130f4520SKenneth D. Merry ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 1003130f4520SKenneth D. Merry struct ctl_be_block_io *beio) 1004130f4520SKenneth D. Merry { 1005130f4520SKenneth D. Merry struct bio *bio; 10063236151eSAlexander Motin struct cdevsw *csw; 10073236151eSAlexander Motin struct cdev *dev; 10083236151eSAlexander Motin int ref; 1009130f4520SKenneth D. Merry 1010130f4520SKenneth D. Merry DPRINTF("entered\n"); 1011130f4520SKenneth D. Merry 1012130f4520SKenneth D. Merry /* This can't fail, it's a blocking allocation. */ 1013130f4520SKenneth D. Merry bio = g_alloc_bio(); 1014130f4520SKenneth D. Merry 1015130f4520SKenneth D. Merry bio->bio_cmd = BIO_FLUSH; 1016130f4520SKenneth D. Merry bio->bio_offset = 0; 1017130f4520SKenneth D. Merry bio->bio_data = 0; 1018130f4520SKenneth D. Merry bio->bio_done = ctl_be_block_biodone; 1019130f4520SKenneth D. Merry bio->bio_caller1 = beio; 1020130f4520SKenneth D. Merry bio->bio_pblkno = 0; 1021130f4520SKenneth D. Merry 1022130f4520SKenneth D. Merry /* 1023130f4520SKenneth D. Merry * We don't need to acquire the LUN lock here, because we are only 1024130f4520SKenneth D. Merry * sending one bio, and so there is no other context to synchronize 1025130f4520SKenneth D. Merry * with. 1026130f4520SKenneth D. Merry */ 1027130f4520SKenneth D. Merry beio->num_bios_sent = 1; 1028130f4520SKenneth D. Merry beio->send_complete = 1; 1029130f4520SKenneth D. Merry 1030130f4520SKenneth D. Merry binuptime(&beio->ds_t0); 1031130f4520SKenneth D. Merry devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1032130f4520SKenneth D. Merry 10333236151eSAlexander Motin csw = devvn_refthread(be_lun->vn, &dev, &ref); 10343236151eSAlexander Motin if (csw) { 10353236151eSAlexander Motin bio->bio_dev = dev; 10363236151eSAlexander Motin csw->d_strategy(bio); 10373236151eSAlexander Motin dev_relthread(dev, ref); 10383236151eSAlexander Motin } else { 10393236151eSAlexander Motin bio->bio_error = ENXIO; 10403236151eSAlexander Motin ctl_be_block_biodone(bio); 10413236151eSAlexander Motin } 1042130f4520SKenneth D. Merry } 1043130f4520SKenneth D. Merry 1044130f4520SKenneth D. Merry static void 1045ee7f31c0SAlexander Motin ctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, 1046ee7f31c0SAlexander Motin struct ctl_be_block_io *beio, 1047ee7f31c0SAlexander Motin uint64_t off, uint64_t len, int last) 1048ee7f31c0SAlexander Motin { 1049ee7f31c0SAlexander Motin struct bio *bio; 10508f5a226aSAlexander Motin uint64_t maxlen; 10513236151eSAlexander Motin struct cdevsw *csw; 10523236151eSAlexander Motin struct cdev *dev; 10533236151eSAlexander Motin int ref; 1054ee7f31c0SAlexander Motin 10553236151eSAlexander Motin csw = devvn_refthread(be_lun->vn, &dev, &ref); 10560bcd4ab6SAlexander Motin maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize); 1057ee7f31c0SAlexander Motin while (len > 0) { 1058ee7f31c0SAlexander Motin bio = g_alloc_bio(); 1059ee7f31c0SAlexander Motin bio->bio_cmd = BIO_DELETE; 10603236151eSAlexander Motin bio->bio_dev = dev; 1061ee7f31c0SAlexander Motin bio->bio_offset = off; 10628f5a226aSAlexander Motin bio->bio_length = MIN(len, maxlen); 1063ee7f31c0SAlexander Motin bio->bio_data = 0; 1064ee7f31c0SAlexander Motin bio->bio_done = ctl_be_block_biodone; 1065ee7f31c0SAlexander Motin bio->bio_caller1 = beio; 10660bcd4ab6SAlexander Motin bio->bio_pblkno = off / be_lun->cbe_lun.blocksize; 1067ee7f31c0SAlexander Motin 1068ee7f31c0SAlexander Motin off += bio->bio_length; 1069ee7f31c0SAlexander Motin len -= bio->bio_length; 1070ee7f31c0SAlexander Motin 107175c7a1d3SAlexander Motin mtx_lock(&be_lun->io_lock); 1072ee7f31c0SAlexander Motin beio->num_bios_sent++; 1073ee7f31c0SAlexander Motin if (last && len == 0) 1074ee7f31c0SAlexander Motin beio->send_complete = 1; 107575c7a1d3SAlexander Motin mtx_unlock(&be_lun->io_lock); 1076ee7f31c0SAlexander Motin 10773236151eSAlexander Motin if (csw) { 10783236151eSAlexander Motin csw->d_strategy(bio); 10793236151eSAlexander Motin } else { 10803236151eSAlexander Motin bio->bio_error = ENXIO; 10813236151eSAlexander Motin ctl_be_block_biodone(bio); 1082ee7f31c0SAlexander Motin } 1083ee7f31c0SAlexander Motin } 10843236151eSAlexander Motin if (csw) 10853236151eSAlexander Motin dev_relthread(dev, ref); 10863236151eSAlexander Motin } 1087ee7f31c0SAlexander Motin 1088ee7f31c0SAlexander Motin static void 1089ee7f31c0SAlexander Motin ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 1090ee7f31c0SAlexander Motin struct ctl_be_block_io *beio) 1091ee7f31c0SAlexander Motin { 1092ee7f31c0SAlexander Motin union ctl_io *io; 109366df9136SAlexander Motin struct ctl_ptr_len_flags *ptrlen; 1094ee7f31c0SAlexander Motin struct scsi_unmap_desc *buf, *end; 1095ee7f31c0SAlexander Motin uint64_t len; 1096ee7f31c0SAlexander Motin 1097ee7f31c0SAlexander Motin io = beio->io; 1098ee7f31c0SAlexander Motin 1099ee7f31c0SAlexander Motin DPRINTF("entered\n"); 1100ee7f31c0SAlexander Motin 1101ee7f31c0SAlexander Motin binuptime(&beio->ds_t0); 1102ee7f31c0SAlexander Motin devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1103ee7f31c0SAlexander Motin 1104ee7f31c0SAlexander Motin if (beio->io_offset == -1) { 1105ee7f31c0SAlexander Motin beio->io_len = 0; 110666df9136SAlexander Motin ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 110766df9136SAlexander Motin buf = (struct scsi_unmap_desc *)ptrlen->ptr; 110866df9136SAlexander Motin end = buf + ptrlen->len / sizeof(*buf); 1109ee7f31c0SAlexander Motin for (; buf < end; buf++) { 1110ee7f31c0SAlexander Motin len = (uint64_t)scsi_4btoul(buf->length) * 11110bcd4ab6SAlexander Motin be_lun->cbe_lun.blocksize; 1112ee7f31c0SAlexander Motin beio->io_len += len; 1113ee7f31c0SAlexander Motin ctl_be_block_unmap_dev_range(be_lun, beio, 11140bcd4ab6SAlexander Motin scsi_8btou64(buf->lba) * be_lun->cbe_lun.blocksize, 11150bcd4ab6SAlexander Motin len, (end - buf < 2) ? TRUE : FALSE); 1116ee7f31c0SAlexander Motin } 1117ee7f31c0SAlexander Motin } else 1118ee7f31c0SAlexander Motin ctl_be_block_unmap_dev_range(be_lun, beio, 1119ee7f31c0SAlexander Motin beio->io_offset, beio->io_len, TRUE); 1120ee7f31c0SAlexander Motin } 1121ee7f31c0SAlexander Motin 1122ee7f31c0SAlexander Motin static void 1123130f4520SKenneth D. Merry ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 1124130f4520SKenneth D. Merry struct ctl_be_block_io *beio) 1125130f4520SKenneth D. Merry { 112675c7a1d3SAlexander Motin TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 1127130f4520SKenneth D. Merry struct bio *bio; 11283236151eSAlexander Motin struct cdevsw *csw; 11293236151eSAlexander Motin struct cdev *dev; 1130130f4520SKenneth D. Merry off_t cur_offset; 11313236151eSAlexander Motin int i, max_iosize, ref; 1132130f4520SKenneth D. Merry 1133130f4520SKenneth D. Merry DPRINTF("entered\n"); 11343236151eSAlexander Motin csw = devvn_refthread(be_lun->vn, &dev, &ref); 1135130f4520SKenneth D. Merry 1136130f4520SKenneth D. Merry /* 1137130f4520SKenneth D. Merry * We have to limit our I/O size to the maximum supported by the 1138130f4520SKenneth D. Merry * backend device. Hopefully it is MAXPHYS. If the driver doesn't 1139130f4520SKenneth D. Merry * set it properly, use DFLTPHYS. 1140130f4520SKenneth D. Merry */ 11413236151eSAlexander Motin if (csw) { 11423236151eSAlexander Motin max_iosize = dev->si_iosize_max; 1143130f4520SKenneth D. Merry if (max_iosize < PAGE_SIZE) 1144130f4520SKenneth D. Merry max_iosize = DFLTPHYS; 11453236151eSAlexander Motin } else 11463236151eSAlexander Motin max_iosize = DFLTPHYS; 1147130f4520SKenneth D. Merry 1148130f4520SKenneth D. Merry cur_offset = beio->io_offset; 1149130f4520SKenneth D. Merry for (i = 0; i < beio->num_segs; i++) { 1150130f4520SKenneth D. Merry size_t cur_size; 1151130f4520SKenneth D. Merry uint8_t *cur_ptr; 1152130f4520SKenneth D. Merry 1153130f4520SKenneth D. Merry cur_size = beio->sg_segs[i].len; 1154130f4520SKenneth D. Merry cur_ptr = beio->sg_segs[i].addr; 1155130f4520SKenneth D. Merry 1156130f4520SKenneth D. Merry while (cur_size > 0) { 1157130f4520SKenneth D. Merry /* This can't fail, it's a blocking allocation. */ 1158130f4520SKenneth D. Merry bio = g_alloc_bio(); 1159130f4520SKenneth D. Merry 1160130f4520SKenneth D. Merry KASSERT(bio != NULL, ("g_alloc_bio() failed!\n")); 1161130f4520SKenneth D. Merry 1162130f4520SKenneth D. Merry bio->bio_cmd = beio->bio_cmd; 11633236151eSAlexander Motin bio->bio_dev = dev; 1164130f4520SKenneth D. Merry bio->bio_caller1 = beio; 1165130f4520SKenneth D. Merry bio->bio_length = min(cur_size, max_iosize); 1166130f4520SKenneth D. Merry bio->bio_offset = cur_offset; 1167130f4520SKenneth D. Merry bio->bio_data = cur_ptr; 1168130f4520SKenneth D. Merry bio->bio_done = ctl_be_block_biodone; 11690bcd4ab6SAlexander Motin bio->bio_pblkno = cur_offset / be_lun->cbe_lun.blocksize; 1170130f4520SKenneth D. Merry 1171130f4520SKenneth D. Merry cur_offset += bio->bio_length; 1172130f4520SKenneth D. Merry cur_ptr += bio->bio_length; 1173130f4520SKenneth D. Merry cur_size -= bio->bio_length; 1174130f4520SKenneth D. Merry 117575c7a1d3SAlexander Motin TAILQ_INSERT_TAIL(&queue, bio, bio_queue); 1176130f4520SKenneth D. Merry beio->num_bios_sent++; 1177130f4520SKenneth D. Merry } 1178130f4520SKenneth D. Merry } 117975c7a1d3SAlexander Motin beio->send_complete = 1; 1180024932aaSAlexander Motin binuptime(&beio->ds_t0); 1181024932aaSAlexander Motin devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 118275c7a1d3SAlexander Motin 118375c7a1d3SAlexander Motin /* 118475c7a1d3SAlexander Motin * Fire off all allocated requests! 118575c7a1d3SAlexander Motin */ 118675c7a1d3SAlexander Motin while ((bio = TAILQ_FIRST(&queue)) != NULL) { 118775c7a1d3SAlexander Motin TAILQ_REMOVE(&queue, bio, bio_queue); 11883236151eSAlexander Motin if (csw) 11893236151eSAlexander Motin csw->d_strategy(bio); 11903236151eSAlexander Motin else { 11913236151eSAlexander Motin bio->bio_error = ENXIO; 11923236151eSAlexander Motin ctl_be_block_biodone(bio); 119375c7a1d3SAlexander Motin } 1194130f4520SKenneth D. Merry } 11953236151eSAlexander Motin if (csw) 11963236151eSAlexander Motin dev_relthread(dev, ref); 11973236151eSAlexander Motin } 1198130f4520SKenneth D. Merry 1199c3e7ba3eSAlexander Motin static uint64_t 1200c3e7ba3eSAlexander Motin ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname) 1201c3e7ba3eSAlexander Motin { 1202c3e7ba3eSAlexander Motin struct diocgattr_arg arg; 12033236151eSAlexander Motin struct cdevsw *csw; 12043236151eSAlexander Motin struct cdev *dev; 12053236151eSAlexander Motin int error, ref; 1206c3e7ba3eSAlexander Motin 12073236151eSAlexander Motin csw = devvn_refthread(be_lun->vn, &dev, &ref); 12083236151eSAlexander Motin if (csw == NULL) 1209c3e7ba3eSAlexander Motin return (UINT64_MAX); 1210c3e7ba3eSAlexander Motin strlcpy(arg.name, attrname, sizeof(arg.name)); 1211c3e7ba3eSAlexander Motin arg.len = sizeof(arg.value.off); 12123236151eSAlexander Motin if (csw->d_ioctl) { 12133236151eSAlexander Motin error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 12143236151eSAlexander Motin curthread); 12153236151eSAlexander Motin } else 12163236151eSAlexander Motin error = ENODEV; 12173236151eSAlexander Motin dev_relthread(dev, ref); 1218c3e7ba3eSAlexander Motin if (error != 0) 1219c3e7ba3eSAlexander Motin return (UINT64_MAX); 1220c3e7ba3eSAlexander Motin return (arg.value.off); 1221c3e7ba3eSAlexander Motin } 1222c3e7ba3eSAlexander Motin 1223130f4520SKenneth D. Merry static void 12247d0d4342SAlexander Motin ctl_be_block_cw_dispatch_sync(struct ctl_be_block_lun *be_lun, 12257d0d4342SAlexander Motin union ctl_io *io) 12267d0d4342SAlexander Motin { 12270bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 12287d0d4342SAlexander Motin struct ctl_be_block_io *beio; 12297d0d4342SAlexander Motin struct ctl_lba_len_flags *lbalen; 12307d0d4342SAlexander Motin 12317d0d4342SAlexander Motin DPRINTF("entered\n"); 12327d0d4342SAlexander Motin beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 12337d0d4342SAlexander Motin lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 12347d0d4342SAlexander Motin 12350bcd4ab6SAlexander Motin beio->io_len = lbalen->len * cbe_lun->blocksize; 12360bcd4ab6SAlexander Motin beio->io_offset = lbalen->lba * cbe_lun->blocksize; 12377d0d4342SAlexander Motin beio->io_arg = (lbalen->flags & SSC_IMMED) != 0; 12387d0d4342SAlexander Motin beio->bio_cmd = BIO_FLUSH; 12397d0d4342SAlexander Motin beio->ds_trans_type = DEVSTAT_NO_DATA; 12407d0d4342SAlexander Motin DPRINTF("SYNC\n"); 12417d0d4342SAlexander Motin be_lun->lun_flush(be_lun, beio); 12427d0d4342SAlexander Motin } 12437d0d4342SAlexander Motin 12447d0d4342SAlexander Motin static void 1245ee7f31c0SAlexander Motin ctl_be_block_cw_done_ws(struct ctl_be_block_io *beio) 1246ee7f31c0SAlexander Motin { 1247ee7f31c0SAlexander Motin union ctl_io *io; 1248ee7f31c0SAlexander Motin 1249ee7f31c0SAlexander Motin io = beio->io; 1250ee7f31c0SAlexander Motin ctl_free_beio(beio); 1251ead2f117SAlexander Motin if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1252ead2f117SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1253ead2f117SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1254ee7f31c0SAlexander Motin ctl_config_write_done(io); 1255ee7f31c0SAlexander Motin return; 1256ee7f31c0SAlexander Motin } 1257ee7f31c0SAlexander Motin 1258ee7f31c0SAlexander Motin ctl_be_block_config_write(io); 1259ee7f31c0SAlexander Motin } 1260ee7f31c0SAlexander Motin 1261ee7f31c0SAlexander Motin static void 1262ee7f31c0SAlexander Motin ctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun, 1263ee7f31c0SAlexander Motin union ctl_io *io) 1264ee7f31c0SAlexander Motin { 12650bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1266ee7f31c0SAlexander Motin struct ctl_be_block_io *beio; 126766df9136SAlexander Motin struct ctl_lba_len_flags *lbalen; 1268fee04ef7SAlexander Motin uint64_t len_left, lba; 1269fee04ef7SAlexander Motin uint32_t pb, pbo, adj; 1270ee7f31c0SAlexander Motin int i, seglen; 1271ee7f31c0SAlexander Motin uint8_t *buf, *end; 1272ee7f31c0SAlexander Motin 1273ee7f31c0SAlexander Motin DPRINTF("entered\n"); 1274ee7f31c0SAlexander Motin 1275e86a4142SAlexander Motin beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 127611b569f7SAlexander Motin lbalen = ARGS(beio->io); 1277ee7f31c0SAlexander Motin 127864c5167cSAlexander Motin if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB) || 12793406a2a0SAlexander Motin (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR) && be_lun->unmap == NULL)) { 1280ee7f31c0SAlexander Motin ctl_free_beio(beio); 1281ee7f31c0SAlexander Motin ctl_set_invalid_field(&io->scsiio, 1282ee7f31c0SAlexander Motin /*sks_valid*/ 1, 1283ee7f31c0SAlexander Motin /*command*/ 1, 1284ee7f31c0SAlexander Motin /*field*/ 1, 1285ee7f31c0SAlexander Motin /*bit_valid*/ 0, 1286ee7f31c0SAlexander Motin /*bit*/ 0); 1287ee7f31c0SAlexander Motin ctl_config_write_done(io); 1288ee7f31c0SAlexander Motin return; 1289ee7f31c0SAlexander Motin } 1290ee7f31c0SAlexander Motin 12913406a2a0SAlexander Motin if (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR)) { 12920bcd4ab6SAlexander Motin beio->io_offset = lbalen->lba * cbe_lun->blocksize; 12930bcd4ab6SAlexander Motin beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize; 1294ee7f31c0SAlexander Motin beio->bio_cmd = BIO_DELETE; 1295ee7f31c0SAlexander Motin beio->ds_trans_type = DEVSTAT_FREE; 1296ee7f31c0SAlexander Motin 1297ee7f31c0SAlexander Motin be_lun->unmap(be_lun, beio); 1298ee7f31c0SAlexander Motin return; 1299ee7f31c0SAlexander Motin } 1300ee7f31c0SAlexander Motin 1301ee7f31c0SAlexander Motin beio->bio_cmd = BIO_WRITE; 1302ee7f31c0SAlexander Motin beio->ds_trans_type = DEVSTAT_WRITE; 1303ee7f31c0SAlexander Motin 1304ee7f31c0SAlexander Motin DPRINTF("WRITE SAME at LBA %jx len %u\n", 130566df9136SAlexander Motin (uintmax_t)lbalen->lba, lbalen->len); 1306ee7f31c0SAlexander Motin 13070bcd4ab6SAlexander Motin pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp; 13080bcd4ab6SAlexander Motin if (be_lun->cbe_lun.pblockoff > 0) 13090bcd4ab6SAlexander Motin pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff; 1310fee04ef7SAlexander Motin else 1311fee04ef7SAlexander Motin pbo = 0; 13120bcd4ab6SAlexander Motin len_left = (uint64_t)lbalen->len * cbe_lun->blocksize; 1313ee7f31c0SAlexander Motin for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) { 1314ee7f31c0SAlexander Motin 1315ee7f31c0SAlexander Motin /* 1316ee7f31c0SAlexander Motin * Setup the S/G entry for this chunk. 1317ee7f31c0SAlexander Motin */ 131808a7cce5SAlexander Motin seglen = MIN(CTLBLK_MAX_SEG, len_left); 13190bcd4ab6SAlexander Motin if (pb > cbe_lun->blocksize) { 13200bcd4ab6SAlexander Motin adj = ((lbalen->lba + lba) * cbe_lun->blocksize + 132193b8c96cSAlexander Motin seglen - pbo) % pb; 132293b8c96cSAlexander Motin if (seglen > adj) 132393b8c96cSAlexander Motin seglen -= adj; 132493b8c96cSAlexander Motin else 13250bcd4ab6SAlexander Motin seglen -= seglen % cbe_lun->blocksize; 132693b8c96cSAlexander Motin } else 13270bcd4ab6SAlexander Motin seglen -= seglen % cbe_lun->blocksize; 1328ee7f31c0SAlexander Motin beio->sg_segs[i].len = seglen; 1329ee7f31c0SAlexander Motin beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1330ee7f31c0SAlexander Motin 1331ee7f31c0SAlexander Motin DPRINTF("segment %d addr %p len %zd\n", i, 1332ee7f31c0SAlexander Motin beio->sg_segs[i].addr, beio->sg_segs[i].len); 1333ee7f31c0SAlexander Motin 1334ee7f31c0SAlexander Motin beio->num_segs++; 1335ee7f31c0SAlexander Motin len_left -= seglen; 1336ee7f31c0SAlexander Motin 1337ee7f31c0SAlexander Motin buf = beio->sg_segs[i].addr; 1338ee7f31c0SAlexander Motin end = buf + seglen; 13390bcd4ab6SAlexander Motin for (; buf < end; buf += cbe_lun->blocksize) { 13406c2acea5SAlexander Motin if (lbalen->flags & SWS_NDOB) { 13416c2acea5SAlexander Motin memset(buf, 0, cbe_lun->blocksize); 13426c2acea5SAlexander Motin } else { 13436c2acea5SAlexander Motin memcpy(buf, io->scsiio.kern_data_ptr, 13446c2acea5SAlexander Motin cbe_lun->blocksize); 13456c2acea5SAlexander Motin } 134666df9136SAlexander Motin if (lbalen->flags & SWS_LBDATA) 134766df9136SAlexander Motin scsi_ulto4b(lbalen->lba + lba, buf); 1348ee7f31c0SAlexander Motin lba++; 1349ee7f31c0SAlexander Motin } 1350ee7f31c0SAlexander Motin } 1351ee7f31c0SAlexander Motin 13520bcd4ab6SAlexander Motin beio->io_offset = lbalen->lba * cbe_lun->blocksize; 13530bcd4ab6SAlexander Motin beio->io_len = lba * cbe_lun->blocksize; 1354ee7f31c0SAlexander Motin 1355ee7f31c0SAlexander Motin /* We can not do all in one run. Correct and schedule rerun. */ 1356ee7f31c0SAlexander Motin if (len_left > 0) { 135766df9136SAlexander Motin lbalen->lba += lba; 135866df9136SAlexander Motin lbalen->len -= lba; 1359ee7f31c0SAlexander Motin beio->beio_cont = ctl_be_block_cw_done_ws; 1360ee7f31c0SAlexander Motin } 1361ee7f31c0SAlexander Motin 1362ee7f31c0SAlexander Motin be_lun->dispatch(be_lun, beio); 1363ee7f31c0SAlexander Motin } 1364ee7f31c0SAlexander Motin 1365ee7f31c0SAlexander Motin static void 1366ee7f31c0SAlexander Motin ctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun, 1367ee7f31c0SAlexander Motin union ctl_io *io) 1368ee7f31c0SAlexander Motin { 1369ee7f31c0SAlexander Motin struct ctl_be_block_io *beio; 137066df9136SAlexander Motin struct ctl_ptr_len_flags *ptrlen; 1371ee7f31c0SAlexander Motin 1372ee7f31c0SAlexander Motin DPRINTF("entered\n"); 1373ee7f31c0SAlexander Motin 1374e86a4142SAlexander Motin beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 137566df9136SAlexander Motin ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1376ee7f31c0SAlexander Motin 13773406a2a0SAlexander Motin if ((ptrlen->flags & ~SU_ANCHOR) != 0 || be_lun->unmap == NULL) { 1378ee7f31c0SAlexander Motin ctl_free_beio(beio); 1379ee7f31c0SAlexander Motin ctl_set_invalid_field(&io->scsiio, 1380ee7f31c0SAlexander Motin /*sks_valid*/ 0, 1381ee7f31c0SAlexander Motin /*command*/ 1, 1382ee7f31c0SAlexander Motin /*field*/ 0, 1383ee7f31c0SAlexander Motin /*bit_valid*/ 0, 1384ee7f31c0SAlexander Motin /*bit*/ 0); 1385ee7f31c0SAlexander Motin ctl_config_write_done(io); 1386ee7f31c0SAlexander Motin return; 1387ee7f31c0SAlexander Motin } 1388ee7f31c0SAlexander Motin 1389ee7f31c0SAlexander Motin beio->io_len = 0; 1390ee7f31c0SAlexander Motin beio->io_offset = -1; 1391ee7f31c0SAlexander Motin beio->bio_cmd = BIO_DELETE; 1392ee7f31c0SAlexander Motin beio->ds_trans_type = DEVSTAT_FREE; 139366df9136SAlexander Motin DPRINTF("UNMAP\n"); 1394ee7f31c0SAlexander Motin be_lun->unmap(be_lun, beio); 1395ee7f31c0SAlexander Motin } 1396ee7f31c0SAlexander Motin 1397ee7f31c0SAlexander Motin static void 1398ef8daf3fSAlexander Motin ctl_be_block_cr_done(struct ctl_be_block_io *beio) 1399ef8daf3fSAlexander Motin { 1400ef8daf3fSAlexander Motin union ctl_io *io; 1401ef8daf3fSAlexander Motin 1402ef8daf3fSAlexander Motin io = beio->io; 1403ef8daf3fSAlexander Motin ctl_free_beio(beio); 1404ef8daf3fSAlexander Motin ctl_config_read_done(io); 1405ef8daf3fSAlexander Motin } 1406ef8daf3fSAlexander Motin 1407ef8daf3fSAlexander Motin static void 1408ef8daf3fSAlexander Motin ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 1409ef8daf3fSAlexander Motin union ctl_io *io) 1410ef8daf3fSAlexander Motin { 1411ef8daf3fSAlexander Motin struct ctl_be_block_io *beio; 1412ef8daf3fSAlexander Motin struct ctl_be_block_softc *softc; 1413ef8daf3fSAlexander Motin 1414ef8daf3fSAlexander Motin DPRINTF("entered\n"); 1415ef8daf3fSAlexander Motin 1416ef8daf3fSAlexander Motin softc = be_lun->softc; 1417ef8daf3fSAlexander Motin beio = ctl_alloc_beio(softc); 1418ef8daf3fSAlexander Motin beio->io = io; 1419ef8daf3fSAlexander Motin beio->lun = be_lun; 1420ef8daf3fSAlexander Motin beio->beio_cont = ctl_be_block_cr_done; 1421ef8daf3fSAlexander Motin PRIV(io)->ptr = (void *)beio; 1422ef8daf3fSAlexander Motin 1423ef8daf3fSAlexander Motin switch (io->scsiio.cdb[0]) { 1424ef8daf3fSAlexander Motin case SERVICE_ACTION_IN: /* GET LBA STATUS */ 1425ef8daf3fSAlexander Motin beio->bio_cmd = -1; 1426ef8daf3fSAlexander Motin beio->ds_trans_type = DEVSTAT_NO_DATA; 1427ef8daf3fSAlexander Motin beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1428ef8daf3fSAlexander Motin beio->io_len = 0; 1429ef8daf3fSAlexander Motin if (be_lun->get_lba_status) 1430ef8daf3fSAlexander Motin be_lun->get_lba_status(be_lun, beio); 1431ef8daf3fSAlexander Motin else 1432ef8daf3fSAlexander Motin ctl_be_block_cr_done(beio); 1433ef8daf3fSAlexander Motin break; 1434ef8daf3fSAlexander Motin default: 1435ef8daf3fSAlexander Motin panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1436ef8daf3fSAlexander Motin break; 1437ef8daf3fSAlexander Motin } 1438ef8daf3fSAlexander Motin } 1439ef8daf3fSAlexander Motin 1440ef8daf3fSAlexander Motin static void 1441ee7f31c0SAlexander Motin ctl_be_block_cw_done(struct ctl_be_block_io *beio) 1442ee7f31c0SAlexander Motin { 1443ee7f31c0SAlexander Motin union ctl_io *io; 1444ee7f31c0SAlexander Motin 1445ee7f31c0SAlexander Motin io = beio->io; 1446ee7f31c0SAlexander Motin ctl_free_beio(beio); 1447ee7f31c0SAlexander Motin ctl_config_write_done(io); 1448ee7f31c0SAlexander Motin } 1449ee7f31c0SAlexander Motin 1450ee7f31c0SAlexander Motin static void 1451130f4520SKenneth D. Merry ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 1452130f4520SKenneth D. Merry union ctl_io *io) 1453130f4520SKenneth D. Merry { 1454130f4520SKenneth D. Merry struct ctl_be_block_io *beio; 1455130f4520SKenneth D. Merry struct ctl_be_block_softc *softc; 1456130f4520SKenneth D. Merry 1457130f4520SKenneth D. Merry DPRINTF("entered\n"); 1458130f4520SKenneth D. Merry 1459130f4520SKenneth D. Merry softc = be_lun->softc; 1460130f4520SKenneth D. Merry beio = ctl_alloc_beio(softc); 1461130f4520SKenneth D. Merry beio->io = io; 1462130f4520SKenneth D. Merry beio->lun = be_lun; 1463ee7f31c0SAlexander Motin beio->beio_cont = ctl_be_block_cw_done; 14647d0d4342SAlexander Motin switch (io->scsiio.tag_type) { 14657d0d4342SAlexander Motin case CTL_TAG_ORDERED: 14667d0d4342SAlexander Motin beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 14677d0d4342SAlexander Motin break; 14687d0d4342SAlexander Motin case CTL_TAG_HEAD_OF_QUEUE: 14697d0d4342SAlexander Motin beio->ds_tag_type = DEVSTAT_TAG_HEAD; 14707d0d4342SAlexander Motin break; 14717d0d4342SAlexander Motin case CTL_TAG_UNTAGGED: 14727d0d4342SAlexander Motin case CTL_TAG_SIMPLE: 14737d0d4342SAlexander Motin case CTL_TAG_ACA: 14747d0d4342SAlexander Motin default: 14757d0d4342SAlexander Motin beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 14767d0d4342SAlexander Motin break; 14777d0d4342SAlexander Motin } 1478e86a4142SAlexander Motin PRIV(io)->ptr = (void *)beio; 1479130f4520SKenneth D. Merry 1480130f4520SKenneth D. Merry switch (io->scsiio.cdb[0]) { 1481130f4520SKenneth D. Merry case SYNCHRONIZE_CACHE: 1482130f4520SKenneth D. Merry case SYNCHRONIZE_CACHE_16: 14837d0d4342SAlexander Motin ctl_be_block_cw_dispatch_sync(be_lun, io); 1484130f4520SKenneth D. Merry break; 1485ee7f31c0SAlexander Motin case WRITE_SAME_10: 1486ee7f31c0SAlexander Motin case WRITE_SAME_16: 1487ee7f31c0SAlexander Motin ctl_be_block_cw_dispatch_ws(be_lun, io); 1488ee7f31c0SAlexander Motin break; 1489ee7f31c0SAlexander Motin case UNMAP: 1490ee7f31c0SAlexander Motin ctl_be_block_cw_dispatch_unmap(be_lun, io); 1491ee7f31c0SAlexander Motin break; 1492130f4520SKenneth D. Merry default: 1493130f4520SKenneth D. Merry panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1494130f4520SKenneth D. Merry break; 1495130f4520SKenneth D. Merry } 1496130f4520SKenneth D. Merry } 1497130f4520SKenneth D. Merry 149836160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , read, start, "uint64_t"); 149936160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , write, start, "uint64_t"); 150036160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , read, alloc_done, "uint64_t"); 150136160958SMark Johnston SDT_PROBE_DEFINE1(cbb, , write, alloc_done, "uint64_t"); 1502130f4520SKenneth D. Merry 1503130f4520SKenneth D. Merry static void 150408a7cce5SAlexander Motin ctl_be_block_next(struct ctl_be_block_io *beio) 150508a7cce5SAlexander Motin { 150608a7cce5SAlexander Motin struct ctl_be_block_lun *be_lun; 150708a7cce5SAlexander Motin union ctl_io *io; 150808a7cce5SAlexander Motin 150908a7cce5SAlexander Motin io = beio->io; 151008a7cce5SAlexander Motin be_lun = beio->lun; 151108a7cce5SAlexander Motin ctl_free_beio(beio); 1512ead2f117SAlexander Motin if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1513ead2f117SAlexander Motin ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1514ead2f117SAlexander Motin (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 151511b569f7SAlexander Motin ctl_data_submit_done(io); 151608a7cce5SAlexander Motin return; 151708a7cce5SAlexander Motin } 151808a7cce5SAlexander Motin 151908a7cce5SAlexander Motin io->io_hdr.status &= ~CTL_STATUS_MASK; 152008a7cce5SAlexander Motin io->io_hdr.status |= CTL_STATUS_NONE; 152108a7cce5SAlexander Motin 152275c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 152308a7cce5SAlexander Motin STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 152475c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 152508a7cce5SAlexander Motin taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 152608a7cce5SAlexander Motin } 152708a7cce5SAlexander Motin 152808a7cce5SAlexander Motin static void 1529130f4520SKenneth D. Merry ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 1530130f4520SKenneth D. Merry union ctl_io *io) 1531130f4520SKenneth D. Merry { 15320bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1533130f4520SKenneth D. Merry struct ctl_be_block_io *beio; 1534130f4520SKenneth D. Merry struct ctl_be_block_softc *softc; 153511b569f7SAlexander Motin struct ctl_lba_len_flags *lbalen; 1536e86a4142SAlexander Motin struct ctl_ptr_len_flags *bptrlen; 1537e86a4142SAlexander Motin uint64_t len_left, lbas; 1538130f4520SKenneth D. Merry int i; 1539130f4520SKenneth D. Merry 1540130f4520SKenneth D. Merry softc = be_lun->softc; 1541130f4520SKenneth D. Merry 1542130f4520SKenneth D. Merry DPRINTF("entered\n"); 1543130f4520SKenneth D. Merry 154411b569f7SAlexander Motin lbalen = ARGS(io); 154511b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_WRITE) { 154636160958SMark Johnston SDT_PROBE0(cbb, , write, start); 154711b569f7SAlexander Motin } else { 154836160958SMark Johnston SDT_PROBE0(cbb, , read, start); 1549130f4520SKenneth D. Merry } 1550130f4520SKenneth D. Merry 1551130f4520SKenneth D. Merry beio = ctl_alloc_beio(softc); 1552130f4520SKenneth D. Merry beio->io = io; 1553130f4520SKenneth D. Merry beio->lun = be_lun; 1554e86a4142SAlexander Motin bptrlen = PRIV(io); 1555e86a4142SAlexander Motin bptrlen->ptr = (void *)beio; 1556130f4520SKenneth D. Merry 1557130f4520SKenneth D. Merry switch (io->scsiio.tag_type) { 1558130f4520SKenneth D. Merry case CTL_TAG_ORDERED: 1559130f4520SKenneth D. Merry beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1560130f4520SKenneth D. Merry break; 1561130f4520SKenneth D. Merry case CTL_TAG_HEAD_OF_QUEUE: 1562130f4520SKenneth D. Merry beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1563130f4520SKenneth D. Merry break; 1564130f4520SKenneth D. Merry case CTL_TAG_UNTAGGED: 1565130f4520SKenneth D. Merry case CTL_TAG_SIMPLE: 1566130f4520SKenneth D. Merry case CTL_TAG_ACA: 1567130f4520SKenneth D. Merry default: 1568130f4520SKenneth D. Merry beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1569130f4520SKenneth D. Merry break; 1570130f4520SKenneth D. Merry } 1571130f4520SKenneth D. Merry 157211b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_WRITE) { 1573130f4520SKenneth D. Merry beio->bio_cmd = BIO_WRITE; 1574130f4520SKenneth D. Merry beio->ds_trans_type = DEVSTAT_WRITE; 157511b569f7SAlexander Motin } else { 157611b569f7SAlexander Motin beio->bio_cmd = BIO_READ; 157711b569f7SAlexander Motin beio->ds_trans_type = DEVSTAT_READ; 1578130f4520SKenneth D. Merry } 1579130f4520SKenneth D. Merry 158008a7cce5SAlexander Motin DPRINTF("%s at LBA %jx len %u @%ju\n", 1581130f4520SKenneth D. Merry (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", 1582e86a4142SAlexander Motin (uintmax_t)lbalen->lba, lbalen->len, bptrlen->len); 158311b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_COMPARE) 158411b569f7SAlexander Motin lbas = CTLBLK_HALF_IO_SIZE; 158511b569f7SAlexander Motin else 158611b569f7SAlexander Motin lbas = CTLBLK_MAX_IO_SIZE; 15870bcd4ab6SAlexander Motin lbas = MIN(lbalen->len - bptrlen->len, lbas / cbe_lun->blocksize); 15880bcd4ab6SAlexander Motin beio->io_offset = (lbalen->lba + bptrlen->len) * cbe_lun->blocksize; 15890bcd4ab6SAlexander Motin beio->io_len = lbas * cbe_lun->blocksize; 1590e86a4142SAlexander Motin bptrlen->len += lbas; 1591130f4520SKenneth D. Merry 159208a7cce5SAlexander Motin for (i = 0, len_left = beio->io_len; len_left > 0; i++) { 159308a7cce5SAlexander Motin KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", 159408a7cce5SAlexander Motin i, CTLBLK_MAX_SEGS)); 1595130f4520SKenneth D. Merry 1596130f4520SKenneth D. Merry /* 1597130f4520SKenneth D. Merry * Setup the S/G entry for this chunk. 1598130f4520SKenneth D. Merry */ 159908a7cce5SAlexander Motin beio->sg_segs[i].len = min(CTLBLK_MAX_SEG, len_left); 1600130f4520SKenneth D. Merry beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1601130f4520SKenneth D. Merry 1602130f4520SKenneth D. Merry DPRINTF("segment %d addr %p len %zd\n", i, 1603130f4520SKenneth D. Merry beio->sg_segs[i].addr, beio->sg_segs[i].len); 1604130f4520SKenneth D. Merry 160511b569f7SAlexander Motin /* Set up second segment for compare operation. */ 160611b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_COMPARE) { 160711b569f7SAlexander Motin beio->sg_segs[i + CTLBLK_HALF_SEGS].len = 160811b569f7SAlexander Motin beio->sg_segs[i].len; 160911b569f7SAlexander Motin beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = 161011b569f7SAlexander Motin uma_zalloc(be_lun->lun_zone, M_WAITOK); 161111b569f7SAlexander Motin } 161211b569f7SAlexander Motin 1613130f4520SKenneth D. Merry beio->num_segs++; 1614130f4520SKenneth D. Merry len_left -= beio->sg_segs[i].len; 1615130f4520SKenneth D. Merry } 1616e86a4142SAlexander Motin if (bptrlen->len < lbalen->len) 161708a7cce5SAlexander Motin beio->beio_cont = ctl_be_block_next; 161808a7cce5SAlexander Motin io->scsiio.be_move_done = ctl_be_block_move_done; 161911b569f7SAlexander Motin /* For compare we have separate S/G lists for read and datamove. */ 162011b569f7SAlexander Motin if (lbalen->flags & CTL_LLF_COMPARE) 162111b569f7SAlexander Motin io->scsiio.kern_data_ptr = (uint8_t *)&beio->sg_segs[CTLBLK_HALF_SEGS]; 162211b569f7SAlexander Motin else 162308a7cce5SAlexander Motin io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; 162408a7cce5SAlexander Motin io->scsiio.kern_data_len = beio->io_len; 162508a7cce5SAlexander Motin io->scsiio.kern_sg_entries = beio->num_segs; 1626b2221369SAlexander Motin io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 1627130f4520SKenneth D. Merry 1628130f4520SKenneth D. Merry /* 1629130f4520SKenneth D. Merry * For the read case, we need to read the data into our buffers and 1630130f4520SKenneth D. Merry * then we can send it back to the user. For the write case, we 1631130f4520SKenneth D. Merry * need to get the data from the user first. 1632130f4520SKenneth D. Merry */ 1633130f4520SKenneth D. Merry if (beio->bio_cmd == BIO_READ) { 163436160958SMark Johnston SDT_PROBE0(cbb, , read, alloc_done); 1635130f4520SKenneth D. Merry be_lun->dispatch(be_lun, beio); 1636130f4520SKenneth D. Merry } else { 163736160958SMark Johnston SDT_PROBE0(cbb, , write, alloc_done); 1638130f4520SKenneth D. Merry #ifdef CTL_TIME_IO 1639e675024aSAlexander Motin getbinuptime(&io->io_hdr.dma_start_bt); 1640130f4520SKenneth D. Merry #endif 1641130f4520SKenneth D. Merry ctl_datamove(io); 1642130f4520SKenneth D. Merry } 1643130f4520SKenneth D. Merry } 1644130f4520SKenneth D. Merry 1645130f4520SKenneth D. Merry static void 1646130f4520SKenneth D. Merry ctl_be_block_worker(void *context, int pending) 1647130f4520SKenneth D. Merry { 1648ee4ad294SAlexander Motin struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)context; 1649ee4ad294SAlexander Motin struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1650130f4520SKenneth D. Merry union ctl_io *io; 1651130f4520SKenneth D. Merry struct ctl_be_block_io *beio; 1652130f4520SKenneth D. Merry 1653ee4ad294SAlexander Motin DPRINTF("entered\n"); 1654ee4ad294SAlexander Motin /* 1655ee4ad294SAlexander Motin * Fetch and process I/Os from all queues. If we detect LUN 1656648dfc1aSAlexander Motin * CTL_LUN_FLAG_NO_MEDIA status here -- it is result of a race, 1657ee4ad294SAlexander Motin * so make response maximally opaque to not confuse initiator. 1658ee4ad294SAlexander Motin */ 1659ee4ad294SAlexander Motin for (;;) { 1660ee4ad294SAlexander Motin mtx_lock(&be_lun->queue_lock); 1661ee4ad294SAlexander Motin io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue); 1662ee4ad294SAlexander Motin if (io != NULL) { 1663130f4520SKenneth D. Merry DPRINTF("datamove queue\n"); 1664130f4520SKenneth D. Merry STAILQ_REMOVE(&be_lun->datamove_queue, &io->io_hdr, 1665130f4520SKenneth D. Merry ctl_io_hdr, links); 166675c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 1667e86a4142SAlexander Motin beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1668648dfc1aSAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) { 1669ee4ad294SAlexander Motin ctl_set_busy(&io->scsiio); 1670ee4ad294SAlexander Motin ctl_complete_beio(beio); 1671ee4ad294SAlexander Motin return; 1672ee4ad294SAlexander Motin } 1673130f4520SKenneth D. Merry be_lun->dispatch(be_lun, beio); 1674130f4520SKenneth D. Merry continue; 1675130f4520SKenneth D. Merry } 1676130f4520SKenneth D. Merry io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue); 1677130f4520SKenneth D. Merry if (io != NULL) { 1678130f4520SKenneth D. Merry DPRINTF("config write queue\n"); 1679130f4520SKenneth D. Merry STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr, 1680130f4520SKenneth D. Merry ctl_io_hdr, links); 168175c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 1682648dfc1aSAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) { 1683ee4ad294SAlexander Motin ctl_set_busy(&io->scsiio); 1684ee4ad294SAlexander Motin ctl_config_write_done(io); 1685ee4ad294SAlexander Motin return; 1686ee4ad294SAlexander Motin } 1687130f4520SKenneth D. Merry ctl_be_block_cw_dispatch(be_lun, io); 1688ef8daf3fSAlexander Motin continue; 1689ef8daf3fSAlexander Motin } 1690ef8daf3fSAlexander Motin io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue); 1691ef8daf3fSAlexander Motin if (io != NULL) { 1692ef8daf3fSAlexander Motin DPRINTF("config read queue\n"); 1693ef8daf3fSAlexander Motin STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr, 1694ef8daf3fSAlexander Motin ctl_io_hdr, links); 1695ef8daf3fSAlexander Motin mtx_unlock(&be_lun->queue_lock); 1696648dfc1aSAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) { 1697ee4ad294SAlexander Motin ctl_set_busy(&io->scsiio); 1698ee4ad294SAlexander Motin ctl_config_read_done(io); 1699ee4ad294SAlexander Motin return; 1700ee4ad294SAlexander Motin } 1701ef8daf3fSAlexander Motin ctl_be_block_cr_dispatch(be_lun, io); 1702130f4520SKenneth D. Merry continue; 1703130f4520SKenneth D. Merry } 1704130f4520SKenneth D. Merry io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue); 1705130f4520SKenneth D. Merry if (io != NULL) { 1706130f4520SKenneth D. Merry DPRINTF("input queue\n"); 1707130f4520SKenneth D. Merry STAILQ_REMOVE(&be_lun->input_queue, &io->io_hdr, 1708130f4520SKenneth D. Merry ctl_io_hdr, links); 170975c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 1710648dfc1aSAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) { 1711ee4ad294SAlexander Motin ctl_set_busy(&io->scsiio); 1712ee4ad294SAlexander Motin ctl_data_submit_done(io); 1713ee4ad294SAlexander Motin return; 1714ee4ad294SAlexander Motin } 1715130f4520SKenneth D. Merry ctl_be_block_dispatch(be_lun, io); 1716130f4520SKenneth D. Merry continue; 1717130f4520SKenneth D. Merry } 1718130f4520SKenneth D. Merry 1719130f4520SKenneth D. Merry /* 1720130f4520SKenneth D. Merry * If we get here, there is no work left in the queues, so 1721130f4520SKenneth D. Merry * just break out and let the task queue go to sleep. 1722130f4520SKenneth D. Merry */ 1723ee4ad294SAlexander Motin mtx_unlock(&be_lun->queue_lock); 1724130f4520SKenneth D. Merry break; 1725130f4520SKenneth D. Merry } 1726130f4520SKenneth D. Merry } 1727130f4520SKenneth D. Merry 1728130f4520SKenneth D. Merry /* 1729130f4520SKenneth D. Merry * Entry point from CTL to the backend for I/O. We queue everything to a 1730130f4520SKenneth D. Merry * work thread, so this just puts the I/O on a queue and wakes up the 1731130f4520SKenneth D. Merry * thread. 1732130f4520SKenneth D. Merry */ 1733130f4520SKenneth D. Merry static int 1734130f4520SKenneth D. Merry ctl_be_block_submit(union ctl_io *io) 1735130f4520SKenneth D. Merry { 1736130f4520SKenneth D. Merry struct ctl_be_block_lun *be_lun; 17370bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 1738130f4520SKenneth D. Merry 1739130f4520SKenneth D. Merry DPRINTF("entered\n"); 1740130f4520SKenneth D. Merry 17419cbbfd2fSAlexander Motin cbe_lun = CTL_BACKEND_LUN(io); 17420bcd4ab6SAlexander Motin be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 1743130f4520SKenneth D. Merry 1744130f4520SKenneth D. Merry /* 1745130f4520SKenneth D. Merry * Make sure we only get SCSI I/O. 1746130f4520SKenneth D. Merry */ 1747130f4520SKenneth D. Merry KASSERT(io->io_hdr.io_type == CTL_IO_SCSI, ("Non-SCSI I/O (type " 1748130f4520SKenneth D. Merry "%#x) encountered", io->io_hdr.io_type)); 1749130f4520SKenneth D. Merry 1750e86a4142SAlexander Motin PRIV(io)->len = 0; 1751e86a4142SAlexander Motin 175275c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 1753130f4520SKenneth D. Merry STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 175475c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 1755130f4520SKenneth D. Merry taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1756130f4520SKenneth D. Merry 17579c71cd5aSAlexander Motin return (CTL_RETVAL_COMPLETE); 1758130f4520SKenneth D. Merry } 1759130f4520SKenneth D. Merry 1760130f4520SKenneth D. Merry static int 1761130f4520SKenneth D. Merry ctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 1762130f4520SKenneth D. Merry int flag, struct thread *td) 1763130f4520SKenneth D. Merry { 1764130f4520SKenneth D. Merry struct ctl_be_block_softc *softc; 1765130f4520SKenneth D. Merry int error; 1766130f4520SKenneth D. Merry 1767130f4520SKenneth D. Merry softc = &backend_block_softc; 1768130f4520SKenneth D. Merry 1769130f4520SKenneth D. Merry error = 0; 1770130f4520SKenneth D. Merry 1771130f4520SKenneth D. Merry switch (cmd) { 1772130f4520SKenneth D. Merry case CTL_LUN_REQ: { 1773130f4520SKenneth D. Merry struct ctl_lun_req *lun_req; 1774130f4520SKenneth D. Merry 1775130f4520SKenneth D. Merry lun_req = (struct ctl_lun_req *)addr; 1776130f4520SKenneth D. Merry 1777130f4520SKenneth D. Merry switch (lun_req->reqtype) { 1778130f4520SKenneth D. Merry case CTL_LUNREQ_CREATE: 1779130f4520SKenneth D. Merry error = ctl_be_block_create(softc, lun_req); 1780130f4520SKenneth D. Merry break; 1781130f4520SKenneth D. Merry case CTL_LUNREQ_RM: 1782130f4520SKenneth D. Merry error = ctl_be_block_rm(softc, lun_req); 1783130f4520SKenneth D. Merry break; 178481177295SEdward Tomasz Napierala case CTL_LUNREQ_MODIFY: 178581177295SEdward Tomasz Napierala error = ctl_be_block_modify(softc, lun_req); 178681177295SEdward Tomasz Napierala break; 1787130f4520SKenneth D. Merry default: 1788130f4520SKenneth D. Merry lun_req->status = CTL_LUN_ERROR; 1789130f4520SKenneth D. Merry snprintf(lun_req->error_str, sizeof(lun_req->error_str), 179019720f41SAlexander Motin "invalid LUN request type %d", 1791130f4520SKenneth D. Merry lun_req->reqtype); 1792130f4520SKenneth D. Merry break; 1793130f4520SKenneth D. Merry } 1794130f4520SKenneth D. Merry break; 1795130f4520SKenneth D. Merry } 1796130f4520SKenneth D. Merry default: 1797130f4520SKenneth D. Merry error = ENOTTY; 1798130f4520SKenneth D. Merry break; 1799130f4520SKenneth D. Merry } 1800130f4520SKenneth D. Merry 1801130f4520SKenneth D. Merry return (error); 1802130f4520SKenneth D. Merry } 1803130f4520SKenneth D. Merry 1804130f4520SKenneth D. Merry static int 1805130f4520SKenneth D. Merry ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1806130f4520SKenneth D. Merry { 18070bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 1808130f4520SKenneth D. Merry struct ctl_be_block_filedata *file_data; 1809130f4520SKenneth D. Merry struct ctl_lun_create_params *params; 18108951f055SMarcelo Araujo const char *value; 1811130f4520SKenneth D. Merry struct vattr vattr; 181234961f40SAlexander Motin off_t ps, pss, po, pos, us, uss, uo, uos; 1813130f4520SKenneth D. Merry int error; 1814130f4520SKenneth D. Merry 18150bcd4ab6SAlexander Motin cbe_lun = &be_lun->cbe_lun; 1816130f4520SKenneth D. Merry file_data = &be_lun->backend.file; 181719720f41SAlexander Motin params = &be_lun->params; 1818130f4520SKenneth D. Merry 1819130f4520SKenneth D. Merry be_lun->dev_type = CTL_BE_BLOCK_FILE; 1820130f4520SKenneth D. Merry be_lun->dispatch = ctl_be_block_dispatch_file; 1821130f4520SKenneth D. Merry be_lun->lun_flush = ctl_be_block_flush_file; 1822ef8daf3fSAlexander Motin be_lun->get_lba_status = ctl_be_block_gls_file; 182353c146deSAlexander Motin be_lun->getattr = ctl_be_block_getattr_file; 18240bcd4ab6SAlexander Motin be_lun->unmap = NULL; 18250bcd4ab6SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 1826130f4520SKenneth D. Merry 1827130f4520SKenneth D. Merry error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 1828130f4520SKenneth D. Merry if (error != 0) { 1829130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1830130f4520SKenneth D. Merry "error calling VOP_GETATTR() for file %s", 1831130f4520SKenneth D. Merry be_lun->dev_path); 1832130f4520SKenneth D. Merry return (error); 1833130f4520SKenneth D. Merry } 1834130f4520SKenneth D. Merry 1835130f4520SKenneth D. Merry file_data->cred = crhold(curthread->td_ucred); 183681177295SEdward Tomasz Napierala if (params->lun_size_bytes != 0) 183781177295SEdward Tomasz Napierala be_lun->size_bytes = params->lun_size_bytes; 183881177295SEdward Tomasz Napierala else 1839130f4520SKenneth D. Merry be_lun->size_bytes = vattr.va_size; 1840130f4520SKenneth D. Merry 1841130f4520SKenneth D. Merry /* 184220a28d6cSAlexander Motin * For files we can use any logical block size. Prefer 512 bytes 184320a28d6cSAlexander Motin * for compatibility reasons. If file's vattr.va_blocksize 184420a28d6cSAlexander Motin * (preferred I/O block size) is bigger and multiple to chosen 184520a28d6cSAlexander Motin * logical block size -- report it as physical block size. 1846130f4520SKenneth D. Merry */ 1847130f4520SKenneth D. Merry if (params->blocksize_bytes != 0) 18480bcd4ab6SAlexander Motin cbe_lun->blocksize = params->blocksize_bytes; 184991be33dcSAlexander Motin else if (cbe_lun->lun_type == T_CDROM) 185091be33dcSAlexander Motin cbe_lun->blocksize = 2048; 1851130f4520SKenneth D. Merry else 18520bcd4ab6SAlexander Motin cbe_lun->blocksize = 512; 18530bcd4ab6SAlexander Motin be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 18540bcd4ab6SAlexander Motin cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 18550bcd4ab6SAlexander Motin 0 : (be_lun->size_blocks - 1); 185634961f40SAlexander Motin 185734961f40SAlexander Motin us = ps = vattr.va_blocksize; 185834961f40SAlexander Motin uo = po = 0; 185934961f40SAlexander Motin 18608951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); 186134961f40SAlexander Motin if (value != NULL) 186234961f40SAlexander Motin ctl_expand_number(value, &ps); 18638951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "pblockoffset", NULL); 186434961f40SAlexander Motin if (value != NULL) 186534961f40SAlexander Motin ctl_expand_number(value, &po); 18660bcd4ab6SAlexander Motin pss = ps / cbe_lun->blocksize; 18670bcd4ab6SAlexander Motin pos = po / cbe_lun->blocksize; 18680bcd4ab6SAlexander Motin if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 18690bcd4ab6SAlexander Motin ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 18700bcd4ab6SAlexander Motin cbe_lun->pblockexp = fls(pss) - 1; 18710bcd4ab6SAlexander Motin cbe_lun->pblockoff = (pss - pos) % pss; 187234961f40SAlexander Motin } 187334961f40SAlexander Motin 18748951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ublocksize", NULL); 187534961f40SAlexander Motin if (value != NULL) 187634961f40SAlexander Motin ctl_expand_number(value, &us); 18778951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ublockoffset", NULL); 187834961f40SAlexander Motin if (value != NULL) 187934961f40SAlexander Motin ctl_expand_number(value, &uo); 18800bcd4ab6SAlexander Motin uss = us / cbe_lun->blocksize; 18810bcd4ab6SAlexander Motin uos = uo / cbe_lun->blocksize; 18820bcd4ab6SAlexander Motin if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 18830bcd4ab6SAlexander Motin ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 18840bcd4ab6SAlexander Motin cbe_lun->ublockexp = fls(uss) - 1; 18850bcd4ab6SAlexander Motin cbe_lun->ublockoff = (uss - uos) % uss; 188620a28d6cSAlexander Motin } 1887130f4520SKenneth D. Merry 1888130f4520SKenneth D. Merry /* 1889130f4520SKenneth D. Merry * Sanity check. The media size has to be at least one 1890130f4520SKenneth D. Merry * sector long. 1891130f4520SKenneth D. Merry */ 18920bcd4ab6SAlexander Motin if (be_lun->size_bytes < cbe_lun->blocksize) { 1893130f4520SKenneth D. Merry error = EINVAL; 1894130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 1895130f4520SKenneth D. Merry "file %s size %ju < block size %u", be_lun->dev_path, 18960bcd4ab6SAlexander Motin (uintmax_t)be_lun->size_bytes, cbe_lun->blocksize); 1897130f4520SKenneth D. Merry } 1898cb8727e2SAlexander Motin 18990bcd4ab6SAlexander Motin cbe_lun->opttxferlen = CTLBLK_MAX_IO_SIZE / cbe_lun->blocksize; 1900130f4520SKenneth D. Merry return (error); 1901130f4520SKenneth D. Merry } 1902130f4520SKenneth D. Merry 1903130f4520SKenneth D. Merry static int 1904130f4520SKenneth D. Merry ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1905130f4520SKenneth D. Merry { 19060bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1907130f4520SKenneth D. Merry struct ctl_lun_create_params *params; 19083236151eSAlexander Motin struct cdevsw *csw; 1909130f4520SKenneth D. Merry struct cdev *dev; 19108951f055SMarcelo Araujo const char *value; 19113236151eSAlexander Motin int error, atomic, maxio, ref, unmap, tmp; 1912f6295033SAlexander Motin off_t ps, pss, po, pos, us, uss, uo, uos, otmp; 1913130f4520SKenneth D. Merry 191419720f41SAlexander Motin params = &be_lun->params; 1915130f4520SKenneth D. Merry 1916130f4520SKenneth D. Merry be_lun->dev_type = CTL_BE_BLOCK_DEV; 19173236151eSAlexander Motin csw = devvn_refthread(be_lun->vn, &dev, &ref); 19183236151eSAlexander Motin if (csw == NULL) 19193236151eSAlexander Motin return (ENXIO); 19203236151eSAlexander Motin if (strcmp(csw->d_name, "zvol") == 0) { 192167f586a8SAlexander Motin be_lun->dispatch = ctl_be_block_dispatch_zvol; 1922ef8daf3fSAlexander Motin be_lun->get_lba_status = ctl_be_block_gls_zvol; 1923cb8727e2SAlexander Motin atomic = maxio = CTLBLK_MAX_IO_SIZE; 1924cb8727e2SAlexander Motin } else { 192567f586a8SAlexander Motin be_lun->dispatch = ctl_be_block_dispatch_dev; 19260bcd4ab6SAlexander Motin be_lun->get_lba_status = NULL; 1927cb8727e2SAlexander Motin atomic = 0; 19283236151eSAlexander Motin maxio = dev->si_iosize_max; 1929cb8727e2SAlexander Motin if (maxio <= 0) 1930cb8727e2SAlexander Motin maxio = DFLTPHYS; 1931cb8727e2SAlexander Motin if (maxio > CTLBLK_MAX_IO_SIZE) 1932cb8727e2SAlexander Motin maxio = CTLBLK_MAX_IO_SIZE; 1933cb8727e2SAlexander Motin } 193467f586a8SAlexander Motin be_lun->lun_flush = ctl_be_block_flush_dev; 1935c3e7ba3eSAlexander Motin be_lun->getattr = ctl_be_block_getattr_dev; 19360bcd4ab6SAlexander Motin be_lun->unmap = ctl_be_block_unmap_dev; 1937130f4520SKenneth D. Merry 19383236151eSAlexander Motin if (!csw->d_ioctl) { 19393236151eSAlexander Motin dev_relthread(dev, ref); 1940130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 19413236151eSAlexander Motin "no d_ioctl for device %s!", be_lun->dev_path); 1942130f4520SKenneth D. Merry return (ENODEV); 1943130f4520SKenneth D. Merry } 1944130f4520SKenneth D. Merry 19453236151eSAlexander Motin error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD, 1946130f4520SKenneth D. Merry curthread); 1947130f4520SKenneth D. Merry if (error) { 19483236151eSAlexander Motin dev_relthread(dev, ref); 1949130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 195019720f41SAlexander Motin "error %d returned for DIOCGSECTORSIZE ioctl " 195119720f41SAlexander Motin "on %s!", error, be_lun->dev_path); 1952130f4520SKenneth D. Merry return (error); 1953130f4520SKenneth D. Merry } 1954130f4520SKenneth D. Merry 1955130f4520SKenneth D. Merry /* 1956130f4520SKenneth D. Merry * If the user has asked for a blocksize that is greater than the 1957130f4520SKenneth D. Merry * backing device's blocksize, we can do it only if the blocksize 1958130f4520SKenneth D. Merry * the user is asking for is an even multiple of the underlying 1959130f4520SKenneth D. Merry * device's blocksize. 1960130f4520SKenneth D. Merry */ 1961a15bbf15SAlexander Motin if ((params->blocksize_bytes != 0) && 1962a15bbf15SAlexander Motin (params->blocksize_bytes >= tmp)) { 1963a15bbf15SAlexander Motin if (params->blocksize_bytes % tmp == 0) { 19640bcd4ab6SAlexander Motin cbe_lun->blocksize = params->blocksize_bytes; 1965130f4520SKenneth D. Merry } else { 19663236151eSAlexander Motin dev_relthread(dev, ref); 1967130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 196819720f41SAlexander Motin "requested blocksize %u is not an even " 1969130f4520SKenneth D. Merry "multiple of backing device blocksize %u", 1970f6295033SAlexander Motin params->blocksize_bytes, tmp); 1971130f4520SKenneth D. Merry return (EINVAL); 1972130f4520SKenneth D. Merry } 1973a15bbf15SAlexander Motin } else if (params->blocksize_bytes != 0) { 19743236151eSAlexander Motin dev_relthread(dev, ref); 1975130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 197619720f41SAlexander Motin "requested blocksize %u < backing device " 1977f6295033SAlexander Motin "blocksize %u", params->blocksize_bytes, tmp); 1978130f4520SKenneth D. Merry return (EINVAL); 197991be33dcSAlexander Motin } else if (cbe_lun->lun_type == T_CDROM) 198091be33dcSAlexander Motin cbe_lun->blocksize = MAX(tmp, 2048); 198191be33dcSAlexander Motin else 19820bcd4ab6SAlexander Motin cbe_lun->blocksize = tmp; 1983130f4520SKenneth D. Merry 19843236151eSAlexander Motin error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD, 1985130f4520SKenneth D. Merry curthread); 1986130f4520SKenneth D. Merry if (error) { 19873236151eSAlexander Motin dev_relthread(dev, ref); 1988130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 198919720f41SAlexander Motin "error %d returned for DIOCGMEDIASIZE " 199019720f41SAlexander Motin " ioctl on %s!", error, 199181177295SEdward Tomasz Napierala be_lun->dev_path); 1992130f4520SKenneth D. Merry return (error); 1993130f4520SKenneth D. Merry } 1994130f4520SKenneth D. Merry 199581177295SEdward Tomasz Napierala if (params->lun_size_bytes != 0) { 1996f6295033SAlexander Motin if (params->lun_size_bytes > otmp) { 19973236151eSAlexander Motin dev_relthread(dev, ref); 199881177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 199919720f41SAlexander Motin "requested LUN size %ju > backing device " 200019720f41SAlexander Motin "size %ju", 200181177295SEdward Tomasz Napierala (uintmax_t)params->lun_size_bytes, 2002f6295033SAlexander Motin (uintmax_t)otmp); 200381177295SEdward Tomasz Napierala return (EINVAL); 2004130f4520SKenneth D. Merry } 2005130f4520SKenneth D. Merry 200681177295SEdward Tomasz Napierala be_lun->size_bytes = params->lun_size_bytes; 2007a15bbf15SAlexander Motin } else 2008f6295033SAlexander Motin be_lun->size_bytes = otmp; 20090bcd4ab6SAlexander Motin be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 20100bcd4ab6SAlexander Motin cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 20110bcd4ab6SAlexander Motin 0 : (be_lun->size_blocks - 1); 201281177295SEdward Tomasz Napierala 20133236151eSAlexander Motin error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD, 20143236151eSAlexander Motin curthread); 2015f6012722SAlexander Motin if (error) 2016f6012722SAlexander Motin ps = po = 0; 2017f6012722SAlexander Motin else { 20183236151eSAlexander Motin error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po, 20193236151eSAlexander Motin FREAD, curthread); 2020f6012722SAlexander Motin if (error) 2021f6012722SAlexander Motin po = 0; 2022f6012722SAlexander Motin } 202334961f40SAlexander Motin us = ps; 202434961f40SAlexander Motin uo = po; 202534961f40SAlexander Motin 20268951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); 202734961f40SAlexander Motin if (value != NULL) 202834961f40SAlexander Motin ctl_expand_number(value, &ps); 20298951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "pblockoffset", NULL); 203034961f40SAlexander Motin if (value != NULL) 203134961f40SAlexander Motin ctl_expand_number(value, &po); 20320bcd4ab6SAlexander Motin pss = ps / cbe_lun->blocksize; 20330bcd4ab6SAlexander Motin pos = po / cbe_lun->blocksize; 20340bcd4ab6SAlexander Motin if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 20350bcd4ab6SAlexander Motin ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 20360bcd4ab6SAlexander Motin cbe_lun->pblockexp = fls(pss) - 1; 20370bcd4ab6SAlexander Motin cbe_lun->pblockoff = (pss - pos) % pss; 2038f6012722SAlexander Motin } 2039f6012722SAlexander Motin 20408951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ublocksize", NULL); 204134961f40SAlexander Motin if (value != NULL) 204234961f40SAlexander Motin ctl_expand_number(value, &us); 20438951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ublockoffset", NULL); 204434961f40SAlexander Motin if (value != NULL) 204534961f40SAlexander Motin ctl_expand_number(value, &uo); 20460bcd4ab6SAlexander Motin uss = us / cbe_lun->blocksize; 20470bcd4ab6SAlexander Motin uos = uo / cbe_lun->blocksize; 20480bcd4ab6SAlexander Motin if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 20490bcd4ab6SAlexander Motin ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 20500bcd4ab6SAlexander Motin cbe_lun->ublockexp = fls(uss) - 1; 20510bcd4ab6SAlexander Motin cbe_lun->ublockoff = (uss - uos) % uss; 205234961f40SAlexander Motin } 205334961f40SAlexander Motin 20540bcd4ab6SAlexander Motin cbe_lun->atomicblock = atomic / cbe_lun->blocksize; 20550bcd4ab6SAlexander Motin cbe_lun->opttxferlen = maxio / cbe_lun->blocksize; 2056fbc8d4ffSAlexander Motin 2057fbc8d4ffSAlexander Motin if (be_lun->dispatch == ctl_be_block_dispatch_zvol) { 2058fbc8d4ffSAlexander Motin unmap = 1; 2059fbc8d4ffSAlexander Motin } else { 2060fbc8d4ffSAlexander Motin struct diocgattr_arg arg; 2061fbc8d4ffSAlexander Motin 2062fbc8d4ffSAlexander Motin strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name)); 2063fbc8d4ffSAlexander Motin arg.len = sizeof(arg.value.i); 20643236151eSAlexander Motin error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 20653236151eSAlexander Motin curthread); 2066fbc8d4ffSAlexander Motin unmap = (error == 0) ? arg.value.i : 0; 2067fbc8d4ffSAlexander Motin } 20688951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "unmap", NULL); 2069fbc8d4ffSAlexander Motin if (value != NULL) 2070fbc8d4ffSAlexander Motin unmap = (strcmp(value, "on") == 0); 2071fbc8d4ffSAlexander Motin if (unmap) 20720bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 20730bcd4ab6SAlexander Motin else 20740bcd4ab6SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 2075fbc8d4ffSAlexander Motin 20763236151eSAlexander Motin dev_relthread(dev, ref); 207781177295SEdward Tomasz Napierala return (0); 207881177295SEdward Tomasz Napierala } 2079130f4520SKenneth D. Merry 2080130f4520SKenneth D. Merry static int 2081130f4520SKenneth D. Merry ctl_be_block_close(struct ctl_be_block_lun *be_lun) 2082130f4520SKenneth D. Merry { 20830bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 20840bcd4ab6SAlexander Motin int flags; 2085130f4520SKenneth D. Merry 20860bcd4ab6SAlexander Motin if (be_lun->vn) { 20870bcd4ab6SAlexander Motin flags = FREAD; 20880bcd4ab6SAlexander Motin if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0) 20890bcd4ab6SAlexander Motin flags |= FWRITE; 2090130f4520SKenneth D. Merry (void)vn_close(be_lun->vn, flags, NOCRED, curthread); 2091130f4520SKenneth D. Merry be_lun->vn = NULL; 2092130f4520SKenneth D. Merry 2093130f4520SKenneth D. Merry switch (be_lun->dev_type) { 2094130f4520SKenneth D. Merry case CTL_BE_BLOCK_DEV: 2095130f4520SKenneth D. Merry break; 2096130f4520SKenneth D. Merry case CTL_BE_BLOCK_FILE: 2097130f4520SKenneth D. Merry if (be_lun->backend.file.cred != NULL) { 2098130f4520SKenneth D. Merry crfree(be_lun->backend.file.cred); 2099130f4520SKenneth D. Merry be_lun->backend.file.cred = NULL; 2100130f4520SKenneth D. Merry } 2101130f4520SKenneth D. Merry break; 2102130f4520SKenneth D. Merry case CTL_BE_BLOCK_NONE: 2103025a2301SEdward Tomasz Napierala break; 2104130f4520SKenneth D. Merry default: 21055124012aSAlexander Motin panic("Unexpected backend type %d", be_lun->dev_type); 2106130f4520SKenneth D. Merry break; 2107130f4520SKenneth D. Merry } 210819720f41SAlexander Motin be_lun->dev_type = CTL_BE_BLOCK_NONE; 2109130f4520SKenneth D. Merry } 2110130f4520SKenneth D. Merry return (0); 2111130f4520SKenneth D. Merry } 2112130f4520SKenneth D. Merry 2113130f4520SKenneth D. Merry static int 2114648dfc1aSAlexander Motin ctl_be_block_open(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 2115130f4520SKenneth D. Merry { 21160bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2117130f4520SKenneth D. Merry struct nameidata nd; 21188951f055SMarcelo Araujo const char *value; 21190bcd4ab6SAlexander Motin int error, flags; 2120130f4520SKenneth D. Merry 2121130f4520SKenneth D. Merry error = 0; 2122130f4520SKenneth D. Merry if (rootvnode == NULL) { 2123130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 212419720f41SAlexander Motin "Root filesystem is not mounted"); 2125130f4520SKenneth D. Merry return (1); 2126130f4520SKenneth D. Merry } 21278a08cec1SMateusz Guzik pwd_ensure_dirs(); 2128130f4520SKenneth D. Merry 21298951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "file", NULL); 21300bcd4ab6SAlexander Motin if (value == NULL) { 21310bcd4ab6SAlexander Motin snprintf(req->error_str, sizeof(req->error_str), 21320bcd4ab6SAlexander Motin "no file argument specified"); 21330bcd4ab6SAlexander Motin return (1); 21340bcd4ab6SAlexander Motin } 21350bcd4ab6SAlexander Motin free(be_lun->dev_path, M_CTLBLK); 21360bcd4ab6SAlexander Motin be_lun->dev_path = strdup(value, M_CTLBLK); 21370bcd4ab6SAlexander Motin 21380bcd4ab6SAlexander Motin flags = FREAD; 21398951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "readonly", NULL); 214091be33dcSAlexander Motin if (value != NULL) { 214191be33dcSAlexander Motin if (strcmp(value, "on") != 0) 214291be33dcSAlexander Motin flags |= FWRITE; 214391be33dcSAlexander Motin } else if (cbe_lun->lun_type == T_DIRECT) 21440bcd4ab6SAlexander Motin flags |= FWRITE; 21450bcd4ab6SAlexander Motin 2146130f4520SKenneth D. Merry again: 2147130f4520SKenneth D. Merry NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, be_lun->dev_path, curthread); 2148130f4520SKenneth D. Merry error = vn_open(&nd, &flags, 0, NULL); 21490bcd4ab6SAlexander Motin if ((error == EROFS || error == EACCES) && (flags & FWRITE)) { 21500bcd4ab6SAlexander Motin flags &= ~FWRITE; 21510bcd4ab6SAlexander Motin goto again; 21520bcd4ab6SAlexander Motin } 2153130f4520SKenneth D. Merry if (error) { 2154130f4520SKenneth D. Merry /* 2155130f4520SKenneth D. Merry * This is the only reasonable guess we can make as far as 2156130f4520SKenneth D. Merry * path if the user doesn't give us a fully qualified path. 2157130f4520SKenneth D. Merry * If they want to specify a file, they need to specify the 2158130f4520SKenneth D. Merry * full path. 2159130f4520SKenneth D. Merry */ 2160130f4520SKenneth D. Merry if (be_lun->dev_path[0] != '/') { 2161130f4520SKenneth D. Merry char *dev_name; 2162130f4520SKenneth D. Merry 21630bcd4ab6SAlexander Motin asprintf(&dev_name, M_CTLBLK, "/dev/%s", 2164130f4520SKenneth D. Merry be_lun->dev_path); 2165130f4520SKenneth D. Merry free(be_lun->dev_path, M_CTLBLK); 2166130f4520SKenneth D. Merry be_lun->dev_path = dev_name; 2167130f4520SKenneth D. Merry goto again; 2168130f4520SKenneth D. Merry } 2169130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 217019720f41SAlexander Motin "error opening %s: %d", be_lun->dev_path, error); 2171130f4520SKenneth D. Merry return (error); 2172130f4520SKenneth D. Merry } 21730bcd4ab6SAlexander Motin if (flags & FWRITE) 21740bcd4ab6SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_READONLY; 21750bcd4ab6SAlexander Motin else 21760bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 2177130f4520SKenneth D. Merry 2178130f4520SKenneth D. Merry NDFREE(&nd, NDF_ONLY_PNBUF); 2179130f4520SKenneth D. Merry be_lun->vn = nd.ni_vp; 2180130f4520SKenneth D. Merry 2181130f4520SKenneth D. Merry /* We only support disks and files. */ 2182130f4520SKenneth D. Merry if (vn_isdisk(be_lun->vn, &error)) { 2183130f4520SKenneth D. Merry error = ctl_be_block_open_dev(be_lun, req); 2184130f4520SKenneth D. Merry } else if (be_lun->vn->v_type == VREG) { 2185130f4520SKenneth D. Merry error = ctl_be_block_open_file(be_lun, req); 2186130f4520SKenneth D. Merry } else { 2187130f4520SKenneth D. Merry error = EINVAL; 2188130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 2189025a2301SEdward Tomasz Napierala "%s is not a disk or plain file", be_lun->dev_path); 2190130f4520SKenneth D. Merry } 2191b249ce48SMateusz Guzik VOP_UNLOCK(be_lun->vn); 2192130f4520SKenneth D. Merry 2193a15bbf15SAlexander Motin if (error != 0) 2194130f4520SKenneth D. Merry ctl_be_block_close(be_lun); 21950bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 21960bcd4ab6SAlexander Motin if (be_lun->dispatch != ctl_be_block_dispatch_dev) 21970bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 21988951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "serseq", NULL); 21990bcd4ab6SAlexander Motin if (value != NULL && strcmp(value, "on") == 0) 22000bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 22010bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "read") == 0) 22020bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 22030bcd4ab6SAlexander Motin else if (value != NULL && strcmp(value, "off") == 0) 22040bcd4ab6SAlexander Motin cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2205130f4520SKenneth D. Merry return (0); 2206130f4520SKenneth D. Merry } 2207130f4520SKenneth D. Merry 2208130f4520SKenneth D. Merry static int 2209130f4520SKenneth D. Merry ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2210130f4520SKenneth D. Merry { 22110bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 2212130f4520SKenneth D. Merry struct ctl_be_block_lun *be_lun; 2213130f4520SKenneth D. Merry struct ctl_lun_create_params *params; 221457a5db13SAlexander Motin char num_thread_str[16]; 2215130f4520SKenneth D. Merry char tmpstr[32]; 22168951f055SMarcelo Araujo const char *value; 2217fbc8d4ffSAlexander Motin int retval, num_threads; 221857a5db13SAlexander Motin int tmp_num_threads; 2219130f4520SKenneth D. Merry 2220130f4520SKenneth D. Merry params = &req->reqdata.create; 2221130f4520SKenneth D. Merry retval = 0; 222219720f41SAlexander Motin req->status = CTL_LUN_OK; 2223130f4520SKenneth D. Merry 2224130f4520SKenneth D. Merry be_lun = malloc(sizeof(*be_lun), M_CTLBLK, M_ZERO | M_WAITOK); 22250bcd4ab6SAlexander Motin cbe_lun = &be_lun->cbe_lun; 22260bcd4ab6SAlexander Motin cbe_lun->be_lun = be_lun; 222719720f41SAlexander Motin be_lun->params = req->reqdata.create; 2228130f4520SKenneth D. Merry be_lun->softc = softc; 2229130f4520SKenneth D. Merry STAILQ_INIT(&be_lun->input_queue); 2230ef8daf3fSAlexander Motin STAILQ_INIT(&be_lun->config_read_queue); 2231130f4520SKenneth D. Merry STAILQ_INIT(&be_lun->config_write_queue); 2232130f4520SKenneth D. Merry STAILQ_INIT(&be_lun->datamove_queue); 2233130f4520SKenneth D. Merry sprintf(be_lun->lunname, "cblk%d", softc->num_luns); 223475c7a1d3SAlexander Motin mtx_init(&be_lun->io_lock, "cblk io lock", NULL, MTX_DEF); 223575c7a1d3SAlexander Motin mtx_init(&be_lun->queue_lock, "cblk queue lock", NULL, MTX_DEF); 22368951f055SMarcelo Araujo cbe_lun->options = nvlist_clone(req->args_nvl); 223708a7cce5SAlexander Motin be_lun->lun_zone = uma_zcreate(be_lun->lunname, CTLBLK_MAX_SEG, 2238eeb94054SAlexander Motin NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); 2239130f4520SKenneth D. Merry if (be_lun->lun_zone == NULL) { 2240130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 224119720f41SAlexander Motin "error allocating UMA zone"); 2242130f4520SKenneth D. Merry goto bailout_error; 2243130f4520SKenneth D. Merry } 2244130f4520SKenneth D. Merry 2245130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 22460bcd4ab6SAlexander Motin cbe_lun->lun_type = params->device_type; 2247130f4520SKenneth D. Merry else 22480bcd4ab6SAlexander Motin cbe_lun->lun_type = T_DIRECT; 22490bcd4ab6SAlexander Motin be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED; 22507ac58230SAlexander Motin cbe_lun->flags = 0; 22518951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 22527ac58230SAlexander Motin if (value != NULL) { 22537ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 22547ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 22557ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 22567ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2257130f4520SKenneth D. Merry 225891be33dcSAlexander Motin if (cbe_lun->lun_type == T_DIRECT || 225991be33dcSAlexander Motin cbe_lun->lun_type == T_CDROM) { 2260a15bbf15SAlexander Motin be_lun->size_bytes = params->lun_size_bytes; 2261a15bbf15SAlexander Motin if (params->blocksize_bytes != 0) 22620bcd4ab6SAlexander Motin cbe_lun->blocksize = params->blocksize_bytes; 226391be33dcSAlexander Motin else if (cbe_lun->lun_type == T_CDROM) 226491be33dcSAlexander Motin cbe_lun->blocksize = 2048; 2265a15bbf15SAlexander Motin else 22660bcd4ab6SAlexander Motin cbe_lun->blocksize = 512; 22670bcd4ab6SAlexander Motin be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 22680bcd4ab6SAlexander Motin cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 22690bcd4ab6SAlexander Motin 0 : (be_lun->size_blocks - 1); 2270130f4520SKenneth D. Merry 22717ac58230SAlexander Motin if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 22727ac58230SAlexander Motin control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2273648dfc1aSAlexander Motin retval = ctl_be_block_open(be_lun, req); 2274130f4520SKenneth D. Merry if (retval != 0) { 2275130f4520SKenneth D. Merry retval = 0; 227619720f41SAlexander Motin req->status = CTL_LUN_WARNING; 2277130f4520SKenneth D. Merry } 22787ac58230SAlexander Motin } 22790bcd4ab6SAlexander Motin num_threads = cbb_num_threads; 2280130f4520SKenneth D. Merry } else { 2281130f4520SKenneth D. Merry num_threads = 1; 2282130f4520SKenneth D. Merry } 2283130f4520SKenneth D. Merry 22848951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "num_threads", NULL); 228557a5db13SAlexander Motin if (value != NULL) { 228657a5db13SAlexander Motin tmp_num_threads = strtol(value, NULL, 0); 2287130f4520SKenneth D. Merry 2288130f4520SKenneth D. Merry /* 2289130f4520SKenneth D. Merry * We don't let the user specify less than one 2290130f4520SKenneth D. Merry * thread, but hope he's clueful enough not to 2291130f4520SKenneth D. Merry * specify 1000 threads. 2292130f4520SKenneth D. Merry */ 2293130f4520SKenneth D. Merry if (tmp_num_threads < 1) { 2294130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 229519720f41SAlexander Motin "invalid number of threads %s", 229619720f41SAlexander Motin num_thread_str); 2297130f4520SKenneth D. Merry goto bailout_error; 2298130f4520SKenneth D. Merry } 2299130f4520SKenneth D. Merry num_threads = tmp_num_threads; 230057a5db13SAlexander Motin } 2301130f4520SKenneth D. Merry 230219720f41SAlexander Motin if (be_lun->vn == NULL) 2303648dfc1aSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2304130f4520SKenneth D. Merry /* Tell the user the blocksize we ended up using */ 230519720f41SAlexander Motin params->lun_size_bytes = be_lun->size_bytes; 23060bcd4ab6SAlexander Motin params->blocksize_bytes = cbe_lun->blocksize; 2307130f4520SKenneth D. Merry if (params->flags & CTL_LUN_FLAG_ID_REQ) { 23080bcd4ab6SAlexander Motin cbe_lun->req_lun_id = params->req_lun_id; 23090bcd4ab6SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 2310130f4520SKenneth D. Merry } else 23110bcd4ab6SAlexander Motin cbe_lun->req_lun_id = 0; 2312130f4520SKenneth D. Merry 23130bcd4ab6SAlexander Motin cbe_lun->lun_shutdown = ctl_be_block_lun_shutdown; 23140bcd4ab6SAlexander Motin cbe_lun->lun_config_status = ctl_be_block_lun_config_status; 23150bcd4ab6SAlexander Motin cbe_lun->be = &ctl_be_block_driver; 2316130f4520SKenneth D. Merry 2317130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 231871cd87c6SAlan Somers snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%04d", 2319130f4520SKenneth D. Merry softc->num_luns); 23200bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, tmpstr, 23210bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 2322130f4520SKenneth D. Merry 2323130f4520SKenneth D. Merry /* Tell the user what we used for a serial number */ 2324130f4520SKenneth D. Merry strncpy((char *)params->serial_num, tmpstr, 2325e7038eb7SAlexander Motin MIN(sizeof(params->serial_num), sizeof(tmpstr))); 2326130f4520SKenneth D. Merry } else { 23270bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->serial_num, params->serial_num, 23280bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->serial_num), 2329130f4520SKenneth D. Merry sizeof(params->serial_num))); 2330130f4520SKenneth D. Merry } 2331130f4520SKenneth D. Merry if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 233271cd87c6SAlan Somers snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%04d", softc->num_luns); 23330bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, tmpstr, 23340bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 2335130f4520SKenneth D. Merry 2336130f4520SKenneth D. Merry /* Tell the user what we used for a device ID */ 2337130f4520SKenneth D. Merry strncpy((char *)params->device_id, tmpstr, 2338e7038eb7SAlexander Motin MIN(sizeof(params->device_id), sizeof(tmpstr))); 2339130f4520SKenneth D. Merry } else { 23400bcd4ab6SAlexander Motin strncpy((char *)cbe_lun->device_id, params->device_id, 23410bcd4ab6SAlexander Motin MIN(sizeof(cbe_lun->device_id), 2342130f4520SKenneth D. Merry sizeof(params->device_id))); 2343130f4520SKenneth D. Merry } 2344130f4520SKenneth D. Merry 2345130f4520SKenneth D. Merry TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_be_block_worker, be_lun); 2346130f4520SKenneth D. Merry 2347130f4520SKenneth D. Merry be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 2348130f4520SKenneth D. Merry taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 2349130f4520SKenneth D. Merry 2350130f4520SKenneth D. Merry if (be_lun->io_taskqueue == NULL) { 2351130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 235219720f41SAlexander Motin "unable to create taskqueue"); 2353130f4520SKenneth D. Merry goto bailout_error; 2354130f4520SKenneth D. Merry } 2355130f4520SKenneth D. Merry 2356130f4520SKenneth D. Merry /* 2357130f4520SKenneth D. Merry * Note that we start the same number of threads by default for 2358130f4520SKenneth D. Merry * both the file case and the block device case. For the file 2359130f4520SKenneth D. Merry * case, we need multiple threads to allow concurrency, because the 2360130f4520SKenneth D. Merry * vnode interface is designed to be a blocking interface. For the 2361130f4520SKenneth D. Merry * block device case, ZFS zvols at least will block the caller's 2362130f4520SKenneth D. Merry * context in many instances, and so we need multiple threads to 2363130f4520SKenneth D. Merry * overcome that problem. Other block devices don't need as many 2364130f4520SKenneth D. Merry * threads, but they shouldn't cause too many problems. 2365130f4520SKenneth D. Merry * 2366130f4520SKenneth D. Merry * If the user wants to just have a single thread for a block 2367130f4520SKenneth D. Merry * device, he can specify that when the LUN is created, or change 2368130f4520SKenneth D. Merry * the tunable/sysctl to alter the default number of threads. 2369130f4520SKenneth D. Merry */ 2370*12373e95SAlexander Motin retval = taskqueue_start_threads_in_proc(&be_lun->io_taskqueue, 2371130f4520SKenneth D. Merry /*num threads*/num_threads, 2372053db1feSAlexander Motin /*priority*/PUSER, 2373*12373e95SAlexander Motin /*proc*/control_softc->ctl_proc, 2374130f4520SKenneth D. Merry /*thread name*/ 2375130f4520SKenneth D. Merry "%s taskq", be_lun->lunname); 2376130f4520SKenneth D. Merry 2377130f4520SKenneth D. Merry if (retval != 0) 2378130f4520SKenneth D. Merry goto bailout_error; 2379130f4520SKenneth D. Merry 2380130f4520SKenneth D. Merry be_lun->num_threads = num_threads; 2381130f4520SKenneth D. Merry 2382130f4520SKenneth D. Merry mtx_lock(&softc->lock); 2383130f4520SKenneth D. Merry softc->num_luns++; 2384130f4520SKenneth D. Merry STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 2385130f4520SKenneth D. Merry 2386130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2387130f4520SKenneth D. Merry 23880bcd4ab6SAlexander Motin retval = ctl_add_lun(&be_lun->cbe_lun); 2389130f4520SKenneth D. Merry if (retval != 0) { 2390130f4520SKenneth D. Merry mtx_lock(&softc->lock); 2391130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2392130f4520SKenneth D. Merry links); 2393130f4520SKenneth D. Merry softc->num_luns--; 2394130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2395130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 239619720f41SAlexander Motin "ctl_add_lun() returned error %d, see dmesg for " 239719720f41SAlexander Motin "details", retval); 2398130f4520SKenneth D. Merry retval = 0; 2399130f4520SKenneth D. Merry goto bailout_error; 2400130f4520SKenneth D. Merry } 2401130f4520SKenneth D. Merry 2402130f4520SKenneth D. Merry mtx_lock(&softc->lock); 2403130f4520SKenneth D. Merry 2404130f4520SKenneth D. Merry /* 2405130f4520SKenneth D. Merry * Tell the config_status routine that we're waiting so it won't 2406130f4520SKenneth D. Merry * clean up the LUN in the event of an error. 2407130f4520SKenneth D. Merry */ 2408130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2409130f4520SKenneth D. Merry 2410130f4520SKenneth D. Merry while (be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) { 2411130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2412130f4520SKenneth D. Merry if (retval == EINTR) 2413130f4520SKenneth D. Merry break; 2414130f4520SKenneth D. Merry } 2415130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2416130f4520SKenneth D. Merry 2417130f4520SKenneth D. Merry if (be_lun->flags & CTL_BE_BLOCK_LUN_CONFIG_ERR) { 2418130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 241919720f41SAlexander Motin "LUN configuration error, see dmesg for details"); 2420130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2421130f4520SKenneth D. Merry links); 2422130f4520SKenneth D. Merry softc->num_luns--; 2423130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2424130f4520SKenneth D. Merry goto bailout_error; 2425130f4520SKenneth D. Merry } else { 24260bcd4ab6SAlexander Motin params->req_lun_id = cbe_lun->lun_id; 2427130f4520SKenneth D. Merry } 2428130f4520SKenneth D. Merry 2429130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2430130f4520SKenneth D. Merry 2431130f4520SKenneth D. Merry be_lun->disk_stats = devstat_new_entry("cbb", params->req_lun_id, 24320bcd4ab6SAlexander Motin cbe_lun->blocksize, 2433130f4520SKenneth D. Merry DEVSTAT_ALL_SUPPORTED, 24340bcd4ab6SAlexander Motin cbe_lun->lun_type 2435130f4520SKenneth D. Merry | DEVSTAT_TYPE_IF_OTHER, 2436130f4520SKenneth D. Merry DEVSTAT_PRIORITY_OTHER); 2437130f4520SKenneth D. Merry 2438130f4520SKenneth D. Merry return (retval); 2439130f4520SKenneth D. Merry 2440130f4520SKenneth D. Merry bailout_error: 2441130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 2442130f4520SKenneth D. Merry 24439e005bbcSAlexander Motin if (be_lun->io_taskqueue != NULL) 24449e005bbcSAlexander Motin taskqueue_free(be_lun->io_taskqueue); 2445130f4520SKenneth D. Merry ctl_be_block_close(be_lun); 24469e005bbcSAlexander Motin if (be_lun->dev_path != NULL) 2447130f4520SKenneth D. Merry free(be_lun->dev_path, M_CTLBLK); 24489e005bbcSAlexander Motin if (be_lun->lun_zone != NULL) 24499e005bbcSAlexander Motin uma_zdestroy(be_lun->lun_zone); 24508951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 245175c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 245275c7a1d3SAlexander Motin mtx_destroy(&be_lun->io_lock); 2453130f4520SKenneth D. Merry free(be_lun, M_CTLBLK); 2454130f4520SKenneth D. Merry 2455130f4520SKenneth D. Merry return (retval); 2456130f4520SKenneth D. Merry } 2457130f4520SKenneth D. Merry 2458130f4520SKenneth D. Merry static int 2459130f4520SKenneth D. Merry ctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2460130f4520SKenneth D. Merry { 2461130f4520SKenneth D. Merry struct ctl_lun_rm_params *params; 2462130f4520SKenneth D. Merry struct ctl_be_block_lun *be_lun; 2463ee4ad294SAlexander Motin struct ctl_be_lun *cbe_lun; 2464130f4520SKenneth D. Merry int retval; 2465130f4520SKenneth D. Merry 2466130f4520SKenneth D. Merry params = &req->reqdata.rm; 2467130f4520SKenneth D. Merry 2468130f4520SKenneth D. Merry mtx_lock(&softc->lock); 2469130f4520SKenneth D. Merry STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 24700bcd4ab6SAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) 2471130f4520SKenneth D. Merry break; 2472130f4520SKenneth D. Merry } 2473130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2474130f4520SKenneth D. Merry if (be_lun == NULL) { 2475130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 247619720f41SAlexander Motin "LUN %u is not managed by the block backend", 247719720f41SAlexander Motin params->lun_id); 2478130f4520SKenneth D. Merry goto bailout_error; 2479130f4520SKenneth D. Merry } 2480ee4ad294SAlexander Motin cbe_lun = &be_lun->cbe_lun; 2481130f4520SKenneth D. Merry 2482ee4ad294SAlexander Motin retval = ctl_disable_lun(cbe_lun); 2483130f4520SKenneth D. Merry if (retval != 0) { 2484130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 248519720f41SAlexander Motin "error %d returned from ctl_disable_lun() for " 248619720f41SAlexander Motin "LUN %d", retval, params->lun_id); 2487130f4520SKenneth D. Merry goto bailout_error; 2488130f4520SKenneth D. Merry } 2489130f4520SKenneth D. Merry 2490ee4ad294SAlexander Motin if (be_lun->vn != NULL) { 2491648dfc1aSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2492648dfc1aSAlexander Motin ctl_lun_no_media(cbe_lun); 2493ee4ad294SAlexander Motin taskqueue_drain_all(be_lun->io_taskqueue); 2494ee4ad294SAlexander Motin ctl_be_block_close(be_lun); 2495ee4ad294SAlexander Motin } 2496ee4ad294SAlexander Motin 2497ee4ad294SAlexander Motin retval = ctl_invalidate_lun(cbe_lun); 2498130f4520SKenneth D. Merry if (retval != 0) { 2499130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 250019720f41SAlexander Motin "error %d returned from ctl_invalidate_lun() for " 250119720f41SAlexander Motin "LUN %d", retval, params->lun_id); 2502130f4520SKenneth D. Merry goto bailout_error; 2503130f4520SKenneth D. Merry } 2504130f4520SKenneth D. Merry 2505130f4520SKenneth D. Merry mtx_lock(&softc->lock); 2506130f4520SKenneth D. Merry be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2507130f4520SKenneth D. Merry while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2508130f4520SKenneth D. Merry retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2509130f4520SKenneth D. Merry if (retval == EINTR) 2510130f4520SKenneth D. Merry break; 2511130f4520SKenneth D. Merry } 2512130f4520SKenneth D. Merry be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2513130f4520SKenneth D. Merry 2514130f4520SKenneth D. Merry if ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2515130f4520SKenneth D. Merry snprintf(req->error_str, sizeof(req->error_str), 251619720f41SAlexander Motin "interrupted waiting for LUN to be freed"); 2517130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2518130f4520SKenneth D. Merry goto bailout_error; 2519130f4520SKenneth D. Merry } 2520130f4520SKenneth D. Merry 2521130f4520SKenneth D. Merry STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, links); 2522130f4520SKenneth D. Merry 2523130f4520SKenneth D. Merry softc->num_luns--; 2524130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2525130f4520SKenneth D. Merry 2526ee4ad294SAlexander Motin taskqueue_drain_all(be_lun->io_taskqueue); 2527130f4520SKenneth D. Merry taskqueue_free(be_lun->io_taskqueue); 2528130f4520SKenneth D. Merry 2529130f4520SKenneth D. Merry if (be_lun->disk_stats != NULL) 2530130f4520SKenneth D. Merry devstat_remove_entry(be_lun->disk_stats); 2531130f4520SKenneth D. Merry 2532130f4520SKenneth D. Merry uma_zdestroy(be_lun->lun_zone); 2533130f4520SKenneth D. Merry 25348951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 2535130f4520SKenneth D. Merry free(be_lun->dev_path, M_CTLBLK); 253675c7a1d3SAlexander Motin mtx_destroy(&be_lun->queue_lock); 253775c7a1d3SAlexander Motin mtx_destroy(&be_lun->io_lock); 2538130f4520SKenneth D. Merry free(be_lun, M_CTLBLK); 2539130f4520SKenneth D. Merry 2540130f4520SKenneth D. Merry req->status = CTL_LUN_OK; 2541130f4520SKenneth D. Merry return (0); 2542130f4520SKenneth D. Merry 2543130f4520SKenneth D. Merry bailout_error: 2544130f4520SKenneth D. Merry req->status = CTL_LUN_ERROR; 2545130f4520SKenneth D. Merry return (0); 2546130f4520SKenneth D. Merry } 2547130f4520SKenneth D. Merry 254881177295SEdward Tomasz Napierala static int 254981177295SEdward Tomasz Napierala ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 255081177295SEdward Tomasz Napierala { 255181177295SEdward Tomasz Napierala struct ctl_lun_modify_params *params; 255281177295SEdward Tomasz Napierala struct ctl_be_block_lun *be_lun; 2553a3977beaSAlexander Motin struct ctl_be_lun *cbe_lun; 25548951f055SMarcelo Araujo const char *value; 255571d8e97eSAlexander Motin uint64_t oldsize; 25567ac58230SAlexander Motin int error, wasprim; 255781177295SEdward Tomasz Napierala 255881177295SEdward Tomasz Napierala params = &req->reqdata.modify; 255981177295SEdward Tomasz Napierala 256081177295SEdward Tomasz Napierala mtx_lock(&softc->lock); 256181177295SEdward Tomasz Napierala STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 25620bcd4ab6SAlexander Motin if (be_lun->cbe_lun.lun_id == params->lun_id) 256381177295SEdward Tomasz Napierala break; 256481177295SEdward Tomasz Napierala } 256581177295SEdward Tomasz Napierala mtx_unlock(&softc->lock); 256681177295SEdward Tomasz Napierala if (be_lun == NULL) { 256781177295SEdward Tomasz Napierala snprintf(req->error_str, sizeof(req->error_str), 256819720f41SAlexander Motin "LUN %u is not managed by the block backend", 256919720f41SAlexander Motin params->lun_id); 257081177295SEdward Tomasz Napierala goto bailout_error; 257181177295SEdward Tomasz Napierala } 2572a3977beaSAlexander Motin cbe_lun = &be_lun->cbe_lun; 257381177295SEdward Tomasz Napierala 2574a3977beaSAlexander Motin if (params->lun_size_bytes != 0) 257519720f41SAlexander Motin be_lun->params.lun_size_bytes = params->lun_size_bytes; 25768951f055SMarcelo Araujo 25778951f055SMarcelo Araujo nvlist_destroy(cbe_lun->options); 25788951f055SMarcelo Araujo cbe_lun->options = nvlist_clone(req->args_nvl); 257981177295SEdward Tomasz Napierala 25807ac58230SAlexander Motin wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 25818951f055SMarcelo Araujo value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 25827ac58230SAlexander Motin if (value != NULL) { 25837ac58230SAlexander Motin if (strcmp(value, "primary") == 0) 25847ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 25857ac58230SAlexander Motin else 25867ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 25877ac58230SAlexander Motin } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 25887ac58230SAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 25897ac58230SAlexander Motin else 25907ac58230SAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 25917ac58230SAlexander Motin if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 25927ac58230SAlexander Motin if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 25937ac58230SAlexander Motin ctl_lun_primary(cbe_lun); 25947ac58230SAlexander Motin else 25957ac58230SAlexander Motin ctl_lun_secondary(cbe_lun); 25967ac58230SAlexander Motin } 25977ac58230SAlexander Motin 25980bcd4ab6SAlexander Motin oldsize = be_lun->size_blocks; 25997ac58230SAlexander Motin if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 26007ac58230SAlexander Motin control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 260119720f41SAlexander Motin if (be_lun->vn == NULL) 2602648dfc1aSAlexander Motin error = ctl_be_block_open(be_lun, req); 2603b9b4269cSAlexander Motin else if (vn_isdisk(be_lun->vn, &error)) 26044ce7a086SAlexander Motin error = ctl_be_block_open_dev(be_lun, req); 26053d5cb709SAlexander Motin else if (be_lun->vn->v_type == VREG) { 26063d5cb709SAlexander Motin vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 26074ce7a086SAlexander Motin error = ctl_be_block_open_file(be_lun, req); 2608b249ce48SMateusz Guzik VOP_UNLOCK(be_lun->vn); 26093d5cb709SAlexander Motin } else 2610b9b4269cSAlexander Motin error = EINVAL; 2611648dfc1aSAlexander Motin if ((cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) && 26120bcd4ab6SAlexander Motin be_lun->vn != NULL) { 2613648dfc1aSAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_NO_MEDIA; 2614648dfc1aSAlexander Motin ctl_lun_has_media(cbe_lun); 2615648dfc1aSAlexander Motin } else if ((cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) == 0 && 2616648dfc1aSAlexander Motin be_lun->vn == NULL) { 2617648dfc1aSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2618648dfc1aSAlexander Motin ctl_lun_no_media(cbe_lun); 261971d8e97eSAlexander Motin } 2620648dfc1aSAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_EJECTED; 26217ac58230SAlexander Motin } else { 26227ac58230SAlexander Motin if (be_lun->vn != NULL) { 2623648dfc1aSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2624648dfc1aSAlexander Motin ctl_lun_no_media(cbe_lun); 2625ee4ad294SAlexander Motin taskqueue_drain_all(be_lun->io_taskqueue); 26267ac58230SAlexander Motin error = ctl_be_block_close(be_lun); 26277ac58230SAlexander Motin } else 26287ac58230SAlexander Motin error = 0; 26297ac58230SAlexander Motin } 26307ac58230SAlexander Motin if (be_lun->size_blocks != oldsize) 26317ac58230SAlexander Motin ctl_lun_capacity_changed(cbe_lun); 263281177295SEdward Tomasz Napierala 263381177295SEdward Tomasz Napierala /* Tell the user the exact size we ended up using */ 263481177295SEdward Tomasz Napierala params->lun_size_bytes = be_lun->size_bytes; 263581177295SEdward Tomasz Napierala 263619720f41SAlexander Motin req->status = error ? CTL_LUN_WARNING : CTL_LUN_OK; 263781177295SEdward Tomasz Napierala return (0); 263881177295SEdward Tomasz Napierala 263981177295SEdward Tomasz Napierala bailout_error: 264081177295SEdward Tomasz Napierala req->status = CTL_LUN_ERROR; 264181177295SEdward Tomasz Napierala return (0); 264281177295SEdward Tomasz Napierala } 264381177295SEdward Tomasz Napierala 2644130f4520SKenneth D. Merry static void 2645130f4520SKenneth D. Merry ctl_be_block_lun_shutdown(void *be_lun) 2646130f4520SKenneth D. Merry { 264768bf823fSAlexander Motin struct ctl_be_block_lun *lun = be_lun; 264868bf823fSAlexander Motin struct ctl_be_block_softc *softc = lun->softc; 2649130f4520SKenneth D. Merry 2650130f4520SKenneth D. Merry mtx_lock(&softc->lock); 2651130f4520SKenneth D. Merry lun->flags |= CTL_BE_BLOCK_LUN_UNCONFIGURED; 2652130f4520SKenneth D. Merry if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2653130f4520SKenneth D. Merry wakeup(lun); 2654130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2655130f4520SKenneth D. Merry } 2656130f4520SKenneth D. Merry 2657130f4520SKenneth D. Merry static void 2658130f4520SKenneth D. Merry ctl_be_block_lun_config_status(void *be_lun, ctl_lun_config_status status) 2659130f4520SKenneth D. Merry { 2660130f4520SKenneth D. Merry struct ctl_be_block_lun *lun; 2661130f4520SKenneth D. Merry struct ctl_be_block_softc *softc; 2662130f4520SKenneth D. Merry 2663130f4520SKenneth D. Merry lun = (struct ctl_be_block_lun *)be_lun; 2664130f4520SKenneth D. Merry softc = lun->softc; 2665130f4520SKenneth D. Merry 2666130f4520SKenneth D. Merry if (status == CTL_LUN_CONFIG_OK) { 2667130f4520SKenneth D. Merry mtx_lock(&softc->lock); 2668130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2669130f4520SKenneth D. Merry if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2670130f4520SKenneth D. Merry wakeup(lun); 2671130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2672130f4520SKenneth D. Merry 2673130f4520SKenneth D. Merry /* 2674130f4520SKenneth D. Merry * We successfully added the LUN, attempt to enable it. 2675130f4520SKenneth D. Merry */ 26760bcd4ab6SAlexander Motin if (ctl_enable_lun(&lun->cbe_lun) != 0) { 2677130f4520SKenneth D. Merry printf("%s: ctl_enable_lun() failed!\n", __func__); 26780bcd4ab6SAlexander Motin if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 2679130f4520SKenneth D. Merry printf("%s: ctl_invalidate_lun() failed!\n", 2680130f4520SKenneth D. Merry __func__); 2681130f4520SKenneth D. Merry } 2682130f4520SKenneth D. Merry } 2683130f4520SKenneth D. Merry 2684130f4520SKenneth D. Merry return; 2685130f4520SKenneth D. Merry } 2686130f4520SKenneth D. Merry 2687130f4520SKenneth D. Merry 2688130f4520SKenneth D. Merry mtx_lock(&softc->lock); 2689130f4520SKenneth D. Merry lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2690130f4520SKenneth D. Merry lun->flags |= CTL_BE_BLOCK_LUN_CONFIG_ERR; 2691130f4520SKenneth D. Merry wakeup(lun); 2692130f4520SKenneth D. Merry mtx_unlock(&softc->lock); 2693130f4520SKenneth D. Merry } 2694130f4520SKenneth D. Merry 2695130f4520SKenneth D. Merry 2696130f4520SKenneth D. Merry static int 2697130f4520SKenneth D. Merry ctl_be_block_config_write(union ctl_io *io) 2698130f4520SKenneth D. Merry { 2699130f4520SKenneth D. Merry struct ctl_be_block_lun *be_lun; 27000bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 2701130f4520SKenneth D. Merry int retval; 2702130f4520SKenneth D. Merry 2703130f4520SKenneth D. Merry DPRINTF("entered\n"); 2704130f4520SKenneth D. Merry 27059cbbfd2fSAlexander Motin cbe_lun = CTL_BACKEND_LUN(io); 27060bcd4ab6SAlexander Motin be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2707130f4520SKenneth D. Merry 270867cc546dSAlexander Motin retval = 0; 2709130f4520SKenneth D. Merry switch (io->scsiio.cdb[0]) { 2710130f4520SKenneth D. Merry case SYNCHRONIZE_CACHE: 2711130f4520SKenneth D. Merry case SYNCHRONIZE_CACHE_16: 2712ee7f31c0SAlexander Motin case WRITE_SAME_10: 2713ee7f31c0SAlexander Motin case WRITE_SAME_16: 2714ee7f31c0SAlexander Motin case UNMAP: 2715130f4520SKenneth D. Merry /* 2716130f4520SKenneth D. Merry * The upper level CTL code will filter out any CDBs with 2717130f4520SKenneth D. Merry * the immediate bit set and return the proper error. 2718130f4520SKenneth D. Merry * 2719130f4520SKenneth D. Merry * We don't really need to worry about what LBA range the 2720130f4520SKenneth D. Merry * user asked to be synced out. When they issue a sync 2721130f4520SKenneth D. Merry * cache command, we'll sync out the whole thing. 2722130f4520SKenneth D. Merry */ 272375c7a1d3SAlexander Motin mtx_lock(&be_lun->queue_lock); 2724130f4520SKenneth D. Merry STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->io_hdr, 2725130f4520SKenneth D. Merry links); 272675c7a1d3SAlexander Motin mtx_unlock(&be_lun->queue_lock); 2727130f4520SKenneth D. Merry taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 2728130f4520SKenneth D. Merry break; 2729130f4520SKenneth D. Merry case START_STOP_UNIT: { 2730130f4520SKenneth D. Merry struct scsi_start_stop_unit *cdb; 2731648dfc1aSAlexander Motin struct ctl_lun_req req; 2732130f4520SKenneth D. Merry 2733130f4520SKenneth D. Merry cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 273466b69676SAlexander Motin if ((cdb->how & SSS_PC_MASK) != 0) { 273566b69676SAlexander Motin ctl_set_success(&io->scsiio); 273666b69676SAlexander Motin ctl_config_write_done(io); 273766b69676SAlexander Motin break; 273866b69676SAlexander Motin } 2739648dfc1aSAlexander Motin if (cdb->how & SSS_START) { 2740648dfc1aSAlexander Motin if ((cdb->how & SSS_LOEJ) && be_lun->vn == NULL) { 2741648dfc1aSAlexander Motin retval = ctl_be_block_open(be_lun, &req); 2742648dfc1aSAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_EJECTED; 2743648dfc1aSAlexander Motin if (retval == 0) { 2744648dfc1aSAlexander Motin cbe_lun->flags &= ~CTL_LUN_FLAG_NO_MEDIA; 2745648dfc1aSAlexander Motin ctl_lun_has_media(cbe_lun); 2746130f4520SKenneth D. Merry } else { 2747648dfc1aSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2748648dfc1aSAlexander Motin ctl_lun_no_media(cbe_lun); 2749130f4520SKenneth D. Merry } 2750648dfc1aSAlexander Motin } 2751648dfc1aSAlexander Motin ctl_start_lun(cbe_lun); 2752648dfc1aSAlexander Motin } else { 2753648dfc1aSAlexander Motin ctl_stop_lun(cbe_lun); 2754648dfc1aSAlexander Motin if (cdb->how & SSS_LOEJ) { 2755648dfc1aSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2756648dfc1aSAlexander Motin cbe_lun->flags |= CTL_LUN_FLAG_EJECTED; 2757648dfc1aSAlexander Motin ctl_lun_ejected(cbe_lun); 2758648dfc1aSAlexander Motin if (be_lun->vn != NULL) 2759648dfc1aSAlexander Motin ctl_be_block_close(be_lun); 2760648dfc1aSAlexander Motin } 2761648dfc1aSAlexander Motin } 2762648dfc1aSAlexander Motin 2763648dfc1aSAlexander Motin ctl_set_success(&io->scsiio); 2764130f4520SKenneth D. Merry ctl_config_write_done(io); 2765130f4520SKenneth D. Merry break; 2766130f4520SKenneth D. Merry } 276791be33dcSAlexander Motin case PREVENT_ALLOW: 276891be33dcSAlexander Motin ctl_set_success(&io->scsiio); 276991be33dcSAlexander Motin ctl_config_write_done(io); 277091be33dcSAlexander Motin break; 2771130f4520SKenneth D. Merry default: 2772130f4520SKenneth D. Merry ctl_set_invalid_opcode(&io->scsiio); 2773130f4520SKenneth D. Merry ctl_config_write_done(io); 2774130f4520SKenneth D. Merry retval = CTL_RETVAL_COMPLETE; 2775130f4520SKenneth D. Merry break; 2776130f4520SKenneth D. Merry } 2777130f4520SKenneth D. Merry 2778130f4520SKenneth D. Merry return (retval); 2779130f4520SKenneth D. Merry } 2780130f4520SKenneth D. Merry 2781130f4520SKenneth D. Merry static int 2782130f4520SKenneth D. Merry ctl_be_block_config_read(union ctl_io *io) 2783130f4520SKenneth D. Merry { 2784ef8daf3fSAlexander Motin struct ctl_be_block_lun *be_lun; 27850bcd4ab6SAlexander Motin struct ctl_be_lun *cbe_lun; 2786ef8daf3fSAlexander Motin int retval = 0; 2787ef8daf3fSAlexander Motin 2788ef8daf3fSAlexander Motin DPRINTF("entered\n"); 2789ef8daf3fSAlexander Motin 27909cbbfd2fSAlexander Motin cbe_lun = CTL_BACKEND_LUN(io); 27910bcd4ab6SAlexander Motin be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2792ef8daf3fSAlexander Motin 2793ef8daf3fSAlexander Motin switch (io->scsiio.cdb[0]) { 2794ef8daf3fSAlexander Motin case SERVICE_ACTION_IN: 2795ef8daf3fSAlexander Motin if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 2796ef8daf3fSAlexander Motin mtx_lock(&be_lun->queue_lock); 2797ef8daf3fSAlexander Motin STAILQ_INSERT_TAIL(&be_lun->config_read_queue, 2798ef8daf3fSAlexander Motin &io->io_hdr, links); 2799ef8daf3fSAlexander Motin mtx_unlock(&be_lun->queue_lock); 2800ef8daf3fSAlexander Motin taskqueue_enqueue(be_lun->io_taskqueue, 2801ef8daf3fSAlexander Motin &be_lun->io_task); 2802ef8daf3fSAlexander Motin retval = CTL_RETVAL_QUEUED; 2803ef8daf3fSAlexander Motin break; 2804ef8daf3fSAlexander Motin } 2805ef8daf3fSAlexander Motin ctl_set_invalid_field(&io->scsiio, 2806ef8daf3fSAlexander Motin /*sks_valid*/ 1, 2807ef8daf3fSAlexander Motin /*command*/ 1, 2808ef8daf3fSAlexander Motin /*field*/ 1, 2809ef8daf3fSAlexander Motin /*bit_valid*/ 1, 2810ef8daf3fSAlexander Motin /*bit*/ 4); 2811ef8daf3fSAlexander Motin ctl_config_read_done(io); 2812ef8daf3fSAlexander Motin retval = CTL_RETVAL_COMPLETE; 2813ef8daf3fSAlexander Motin break; 2814ef8daf3fSAlexander Motin default: 2815ef8daf3fSAlexander Motin ctl_set_invalid_opcode(&io->scsiio); 2816ef8daf3fSAlexander Motin ctl_config_read_done(io); 2817ef8daf3fSAlexander Motin retval = CTL_RETVAL_COMPLETE; 2818ef8daf3fSAlexander Motin break; 2819ef8daf3fSAlexander Motin } 2820ef8daf3fSAlexander Motin 2821ef8daf3fSAlexander Motin return (retval); 2822130f4520SKenneth D. Merry } 2823130f4520SKenneth D. Merry 2824130f4520SKenneth D. Merry static int 2825130f4520SKenneth D. Merry ctl_be_block_lun_info(void *be_lun, struct sbuf *sb) 2826130f4520SKenneth D. Merry { 2827130f4520SKenneth D. Merry struct ctl_be_block_lun *lun; 2828130f4520SKenneth D. Merry int retval; 2829130f4520SKenneth D. Merry 2830130f4520SKenneth D. Merry lun = (struct ctl_be_block_lun *)be_lun; 2831130f4520SKenneth D. Merry 28322cfbcb9bSAlexander Motin retval = sbuf_printf(sb, "\t<num_threads>"); 2833130f4520SKenneth D. Merry if (retval != 0) 2834130f4520SKenneth D. Merry goto bailout; 2835130f4520SKenneth D. Merry retval = sbuf_printf(sb, "%d", lun->num_threads); 2836130f4520SKenneth D. Merry if (retval != 0) 2837130f4520SKenneth D. Merry goto bailout; 28382cfbcb9bSAlexander Motin retval = sbuf_printf(sb, "</num_threads>\n"); 2839130f4520SKenneth D. Merry 2840130f4520SKenneth D. Merry bailout: 2841130f4520SKenneth D. Merry return (retval); 2842130f4520SKenneth D. Merry } 2843130f4520SKenneth D. Merry 2844c3e7ba3eSAlexander Motin static uint64_t 2845c3e7ba3eSAlexander Motin ctl_be_block_lun_attr(void *be_lun, const char *attrname) 2846c3e7ba3eSAlexander Motin { 2847c3e7ba3eSAlexander Motin struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)be_lun; 2848c3e7ba3eSAlexander Motin 2849c3e7ba3eSAlexander Motin if (lun->getattr == NULL) 2850c3e7ba3eSAlexander Motin return (UINT64_MAX); 2851c3e7ba3eSAlexander Motin return (lun->getattr(lun, attrname)); 2852c3e7ba3eSAlexander Motin } 2853c3e7ba3eSAlexander Motin 28540c629e28SAlexander Motin static int 2855130f4520SKenneth D. Merry ctl_be_block_init(void) 2856130f4520SKenneth D. Merry { 28570c629e28SAlexander Motin struct ctl_be_block_softc *softc = &backend_block_softc; 2858130f4520SKenneth D. Merry 285975c7a1d3SAlexander Motin mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF); 28600c629e28SAlexander Motin softc->beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io), 2861a0e36aeeSEdward Tomasz Napierala NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 2862130f4520SKenneth D. Merry STAILQ_INIT(&softc->lun_list); 28630c629e28SAlexander Motin return (0); 28640c629e28SAlexander Motin } 2865130f4520SKenneth D. Merry 28660c629e28SAlexander Motin 28670c629e28SAlexander Motin static int 28680c629e28SAlexander Motin ctl_be_block_shutdown(void) 28690c629e28SAlexander Motin { 28700c629e28SAlexander Motin struct ctl_be_block_softc *softc = &backend_block_softc; 28710c629e28SAlexander Motin struct ctl_be_block_lun *lun, *next_lun; 28720c629e28SAlexander Motin 28730c629e28SAlexander Motin mtx_lock(&softc->lock); 28740c629e28SAlexander Motin STAILQ_FOREACH_SAFE(lun, &softc->lun_list, links, next_lun) { 28750c629e28SAlexander Motin /* 28760c629e28SAlexander Motin * Drop our lock here. Since ctl_invalidate_lun() can call 28770c629e28SAlexander Motin * back into us, this could potentially lead to a recursive 28780c629e28SAlexander Motin * lock of the same mutex, which would cause a hang. 28790c629e28SAlexander Motin */ 28800c629e28SAlexander Motin mtx_unlock(&softc->lock); 28810c629e28SAlexander Motin ctl_disable_lun(&lun->cbe_lun); 28820c629e28SAlexander Motin ctl_invalidate_lun(&lun->cbe_lun); 28830c629e28SAlexander Motin mtx_lock(&softc->lock); 28840c629e28SAlexander Motin } 28850c629e28SAlexander Motin mtx_unlock(&softc->lock); 28860c629e28SAlexander Motin 28870c629e28SAlexander Motin uma_zdestroy(softc->beio_zone); 28880c629e28SAlexander Motin mtx_destroy(&softc->lock); 28890c629e28SAlexander Motin return (0); 2890130f4520SKenneth D. Merry } 2891