1229997Sken/*- 2229997Sken * Copyright (c) 2003 Silicon Graphics International Corp. 3229997Sken * Copyright (c) 2009-2011 Spectra Logic Corporation 4232604Strasz * Copyright (c) 2012 The FreeBSD Foundation 5288811Smav * Copyright (c) 2014-2015 Alexander Motin <mav@FreeBSD.org> 6229997Sken * All rights reserved. 7229997Sken * 8232604Strasz * Portions of this software were developed by Edward Tomasz Napierala 9232604Strasz * under sponsorship from the FreeBSD Foundation. 10232604Strasz * 11229997Sken * Redistribution and use in source and binary forms, with or without 12229997Sken * modification, are permitted provided that the following conditions 13229997Sken * are met: 14229997Sken * 1. Redistributions of source code must retain the above copyright 15229997Sken * notice, this list of conditions, and the following disclaimer, 16229997Sken * without modification. 17229997Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18229997Sken * substantially similar to the "NO WARRANTY" disclaimer below 19229997Sken * ("Disclaimer") and any redistribution must be conditioned upon 20229997Sken * including a substantially similar Disclaimer requirement for further 21229997Sken * binary redistribution. 22229997Sken * 23229997Sken * NO WARRANTY 24229997Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25229997Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26229997Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 27229997Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 28229997Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32229997Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 33229997Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34229997Sken * POSSIBILITY OF SUCH DAMAGES. 35229997Sken * 36229997Sken * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_block.c#5 $ 37229997Sken */ 38229997Sken/* 39229997Sken * CAM Target Layer driver backend for block devices. 40229997Sken * 41229997Sken * Author: Ken Merry <ken@FreeBSD.org> 42229997Sken */ 43229997Sken#include <sys/cdefs.h> 44229997Sken__FBSDID("$FreeBSD: releng/10.3/sys/cam/ctl/ctl_backend_block.c 290774 2015-11-13 19:21:45Z mav $"); 45229997Sken 46229997Sken#include <opt_kdtrace.h> 47229997Sken 48229997Sken#include <sys/param.h> 49229997Sken#include <sys/systm.h> 50229997Sken#include <sys/kernel.h> 51229997Sken#include <sys/types.h> 52229997Sken#include <sys/kthread.h> 53229997Sken#include <sys/bio.h> 54229997Sken#include <sys/fcntl.h> 55265634Smav#include <sys/limits.h> 56229997Sken#include <sys/lock.h> 57229997Sken#include <sys/mutex.h> 58229997Sken#include <sys/condvar.h> 59229997Sken#include <sys/malloc.h> 60229997Sken#include <sys/conf.h> 61229997Sken#include <sys/ioccom.h> 62229997Sken#include <sys/queue.h> 63229997Sken#include <sys/sbuf.h> 64229997Sken#include <sys/endian.h> 65229997Sken#include <sys/uio.h> 66229997Sken#include <sys/buf.h> 67229997Sken#include <sys/taskqueue.h> 68229997Sken#include <sys/vnode.h> 69229997Sken#include <sys/namei.h> 70229997Sken#include <sys/mount.h> 71229997Sken#include <sys/disk.h> 72229997Sken#include <sys/fcntl.h> 73229997Sken#include <sys/filedesc.h> 74275892Smav#include <sys/filio.h> 75229997Sken#include <sys/proc.h> 76229997Sken#include <sys/pcpu.h> 77229997Sken#include <sys/module.h> 78229997Sken#include <sys/sdt.h> 79229997Sken#include <sys/devicestat.h> 80229997Sken#include <sys/sysctl.h> 81229997Sken 82229997Sken#include <geom/geom.h> 83229997Sken 84229997Sken#include <cam/cam.h> 85229997Sken#include <cam/scsi/scsi_all.h> 86229997Sken#include <cam/scsi/scsi_da.h> 87229997Sken#include <cam/ctl/ctl_io.h> 88229997Sken#include <cam/ctl/ctl.h> 89229997Sken#include <cam/ctl/ctl_backend.h> 90229997Sken#include <cam/ctl/ctl_ioctl.h> 91288732Smav#include <cam/ctl/ctl_ha.h> 92229997Sken#include <cam/ctl/ctl_scsi_all.h> 93288732Smav#include <cam/ctl/ctl_private.h> 94229997Sken#include <cam/ctl/ctl_error.h> 95229997Sken 96229997Sken/* 97265642Smav * The idea here is that we'll allocate enough S/G space to hold a 1MB 98265642Smav * I/O. If we get an I/O larger than that, we'll split it. 99229997Sken */ 100268151Smav#define CTLBLK_HALF_IO_SIZE (512 * 1024) 101268151Smav#define CTLBLK_MAX_IO_SIZE (CTLBLK_HALF_IO_SIZE * 2) 102265642Smav#define CTLBLK_MAX_SEG MAXPHYS 103268151Smav#define CTLBLK_HALF_SEGS MAX(CTLBLK_HALF_IO_SIZE / CTLBLK_MAX_SEG, 1) 104268151Smav#define CTLBLK_MAX_SEGS (CTLBLK_HALF_SEGS * 2) 105229997Sken 106229997Sken#ifdef CTLBLK_DEBUG 107229997Sken#define DPRINTF(fmt, args...) \ 108229997Sken printf("cbb(%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) 109229997Sken#else 110229997Sken#define DPRINTF(fmt, args...) do {} while(0) 111229997Sken#endif 112229997Sken 113268150Smav#define PRIV(io) \ 114268150Smav ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND]) 115268151Smav#define ARGS(io) \ 116268151Smav ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]) 117268150Smav 118229997SkenSDT_PROVIDER_DEFINE(cbb); 119229997Sken 120229997Skentypedef enum { 121229997Sken CTL_BE_BLOCK_LUN_UNCONFIGURED = 0x01, 122229997Sken CTL_BE_BLOCK_LUN_CONFIG_ERR = 0x02, 123229997Sken CTL_BE_BLOCK_LUN_WAITING = 0x04, 124229997Sken} ctl_be_block_lun_flags; 125229997Sken 126229997Skentypedef enum { 127229997Sken CTL_BE_BLOCK_NONE, 128229997Sken CTL_BE_BLOCK_DEV, 129229997Sken CTL_BE_BLOCK_FILE 130229997Sken} ctl_be_block_type; 131229997Sken 132229997Skenstruct ctl_be_block_filedata { 133229997Sken struct ucred *cred; 134229997Sken}; 135229997Sken 136229997Skenunion ctl_be_block_bedata { 137229997Sken struct ctl_be_block_filedata file; 138229997Sken}; 139229997Sken 140229997Skenstruct ctl_be_block_io; 141229997Skenstruct ctl_be_block_lun; 142229997Sken 143229997Skentypedef void (*cbb_dispatch_t)(struct ctl_be_block_lun *be_lun, 144229997Sken struct ctl_be_block_io *beio); 145274732Smavtypedef uint64_t (*cbb_getattr_t)(struct ctl_be_block_lun *be_lun, 146274732Smav const char *attrname); 147229997Sken 148229997Sken/* 149229997Sken * Backend LUN structure. There is a 1:1 mapping between a block device 150229997Sken * and a backend block LUN, and between a backend block LUN and a CTL LUN. 151229997Sken */ 152229997Skenstruct ctl_be_block_lun { 153273315Smav struct ctl_lun_create_params params; 154229997Sken char lunname[32]; 155229997Sken char *dev_path; 156229997Sken ctl_be_block_type dev_type; 157229997Sken struct vnode *vn; 158229997Sken union ctl_be_block_bedata backend; 159229997Sken cbb_dispatch_t dispatch; 160229997Sken cbb_dispatch_t lun_flush; 161265634Smav cbb_dispatch_t unmap; 162275892Smav cbb_dispatch_t get_lba_status; 163274732Smav cbb_getattr_t getattr; 164229997Sken uma_zone_t lun_zone; 165229997Sken uint64_t size_blocks; 166229997Sken uint64_t size_bytes; 167229997Sken struct ctl_be_block_softc *softc; 168229997Sken struct devstat *disk_stats; 169229997Sken ctl_be_block_lun_flags flags; 170229997Sken STAILQ_ENTRY(ctl_be_block_lun) links; 171288727Smav struct ctl_be_lun cbe_lun; 172229997Sken struct taskqueue *io_taskqueue; 173229997Sken struct task io_task; 174229997Sken int num_threads; 175229997Sken STAILQ_HEAD(, ctl_io_hdr) input_queue; 176275892Smav STAILQ_HEAD(, ctl_io_hdr) config_read_queue; 177229997Sken STAILQ_HEAD(, ctl_io_hdr) config_write_queue; 178229997Sken STAILQ_HEAD(, ctl_io_hdr) datamove_queue; 179268549Smav struct mtx_padalign io_lock; 180268549Smav struct mtx_padalign queue_lock; 181229997Sken}; 182229997Sken 183229997Sken/* 184229997Sken * Overall softc structure for the block backend module. 185229997Sken */ 186229997Skenstruct ctl_be_block_softc { 187229997Sken struct mtx lock; 188229997Sken int num_luns; 189229997Sken STAILQ_HEAD(, ctl_be_block_lun) lun_list; 190229997Sken}; 191229997Sken 192229997Skenstatic struct ctl_be_block_softc backend_block_softc; 193229997Sken 194229997Sken/* 195229997Sken * Per-I/O information. 196229997Sken */ 197229997Skenstruct ctl_be_block_io { 198229997Sken union ctl_io *io; 199229997Sken struct ctl_sg_entry sg_segs[CTLBLK_MAX_SEGS]; 200229997Sken struct iovec xiovecs[CTLBLK_MAX_SEGS]; 201229997Sken int bio_cmd; 202229997Sken int num_segs; 203229997Sken int num_bios_sent; 204229997Sken int num_bios_done; 205229997Sken int send_complete; 206229997Sken int num_errors; 207229997Sken struct bintime ds_t0; 208229997Sken devstat_tag_type ds_tag_type; 209229997Sken devstat_trans_flags ds_trans_type; 210229997Sken uint64_t io_len; 211229997Sken uint64_t io_offset; 212286931Smav int io_arg; 213229997Sken struct ctl_be_block_softc *softc; 214229997Sken struct ctl_be_block_lun *lun; 215265634Smav void (*beio_cont)(struct ctl_be_block_io *beio); /* to continue processing */ 216229997Sken}; 217229997Sken 218288732Smavextern struct ctl_softc *control_softc; 219288732Smav 220229997Skenstatic int cbb_num_threads = 14; 221229997SkenTUNABLE_INT("kern.cam.ctl.block.num_threads", &cbb_num_threads); 222229997SkenSYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD, 0, 223229997Sken "CAM Target Layer Block Backend"); 224229997SkenSYSCTL_INT(_kern_cam_ctl_block, OID_AUTO, num_threads, CTLFLAG_RW, 225229997Sken &cbb_num_threads, 0, "Number of threads per backing file"); 226229997Sken 227229997Skenstatic struct ctl_be_block_io *ctl_alloc_beio(struct ctl_be_block_softc *softc); 228229997Skenstatic void ctl_free_beio(struct ctl_be_block_io *beio); 229229997Skenstatic void ctl_complete_beio(struct ctl_be_block_io *beio); 230229997Skenstatic int ctl_be_block_move_done(union ctl_io *io); 231229997Skenstatic void ctl_be_block_biodone(struct bio *bio); 232229997Skenstatic void ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 233229997Sken struct ctl_be_block_io *beio); 234229997Skenstatic void ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 235229997Sken struct ctl_be_block_io *beio); 236275892Smavstatic void ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 237275892Smav struct ctl_be_block_io *beio); 238275893Smavstatic uint64_t ctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, 239275893Smav const char *attrname); 240229997Skenstatic void ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 241229997Sken struct ctl_be_block_io *beio); 242265634Smavstatic void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 243265634Smav struct ctl_be_block_io *beio); 244229997Skenstatic void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 245229997Sken struct ctl_be_block_io *beio); 246274732Smavstatic uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, 247274732Smav const char *attrname); 248275892Smavstatic void ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 249275892Smav union ctl_io *io); 250229997Skenstatic void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 251229997Sken union ctl_io *io); 252229997Skenstatic void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 253229997Sken union ctl_io *io); 254229997Skenstatic void ctl_be_block_worker(void *context, int pending); 255229997Skenstatic int ctl_be_block_submit(union ctl_io *io); 256229997Skenstatic int ctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 257229997Sken int flag, struct thread *td); 258229997Skenstatic int ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, 259229997Sken struct ctl_lun_req *req); 260229997Skenstatic int ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, 261229997Sken struct ctl_lun_req *req); 262229997Skenstatic int ctl_be_block_close(struct ctl_be_block_lun *be_lun); 263288811Smavstatic int ctl_be_block_open(struct ctl_be_block_lun *be_lun, 264229997Sken struct ctl_lun_req *req); 265229997Skenstatic int ctl_be_block_create(struct ctl_be_block_softc *softc, 266229997Sken struct ctl_lun_req *req); 267229997Skenstatic int ctl_be_block_rm(struct ctl_be_block_softc *softc, 268229997Sken struct ctl_lun_req *req); 269232604Straszstatic int ctl_be_block_modify(struct ctl_be_block_softc *softc, 270232604Strasz struct ctl_lun_req *req); 271229997Skenstatic void ctl_be_block_lun_shutdown(void *be_lun); 272229997Skenstatic void ctl_be_block_lun_config_status(void *be_lun, 273229997Sken ctl_lun_config_status status); 274229997Skenstatic int ctl_be_block_config_write(union ctl_io *io); 275229997Skenstatic int ctl_be_block_config_read(union ctl_io *io); 276229997Skenstatic int ctl_be_block_lun_info(void *be_lun, struct sbuf *sb); 277274732Smavstatic uint64_t ctl_be_block_lun_attr(void *be_lun, const char *attrname); 278229997Skenint ctl_be_block_init(void); 279229997Sken 280229997Skenstatic struct ctl_backend_driver ctl_be_block_driver = 281229997Sken{ 282230334Sken .name = "block", 283230334Sken .flags = CTL_BE_FLAG_HAS_CONFIG, 284230334Sken .init = ctl_be_block_init, 285230334Sken .data_submit = ctl_be_block_submit, 286230334Sken .data_move_done = ctl_be_block_move_done, 287230334Sken .config_read = ctl_be_block_config_read, 288230334Sken .config_write = ctl_be_block_config_write, 289230334Sken .ioctl = ctl_be_block_ioctl, 290274732Smav .lun_info = ctl_be_block_lun_info, 291274732Smav .lun_attr = ctl_be_block_lun_attr 292229997Sken}; 293229997Sken 294229997SkenMALLOC_DEFINE(M_CTLBLK, "ctlblk", "Memory used for CTL block backend"); 295229997SkenCTL_BACKEND_DECLARE(cbb, ctl_be_block_driver); 296229997Sken 297265494Straszstatic uma_zone_t beio_zone; 298265494Strasz 299229997Skenstatic struct ctl_be_block_io * 300229997Skenctl_alloc_beio(struct ctl_be_block_softc *softc) 301229997Sken{ 302229997Sken struct ctl_be_block_io *beio; 303229997Sken 304265494Strasz beio = uma_zalloc(beio_zone, M_WAITOK | M_ZERO); 305265494Strasz beio->softc = softc; 306229997Sken return (beio); 307229997Sken} 308229997Sken 309229997Skenstatic void 310229997Skenctl_free_beio(struct ctl_be_block_io *beio) 311229997Sken{ 312229997Sken int duplicate_free; 313229997Sken int i; 314229997Sken 315229997Sken duplicate_free = 0; 316229997Sken 317229997Sken for (i = 0; i < beio->num_segs; i++) { 318229997Sken if (beio->sg_segs[i].addr == NULL) 319229997Sken duplicate_free++; 320229997Sken 321229997Sken uma_zfree(beio->lun->lun_zone, beio->sg_segs[i].addr); 322229997Sken beio->sg_segs[i].addr = NULL; 323268151Smav 324268151Smav /* For compare we had two equal S/G lists. */ 325268151Smav if (ARGS(beio->io)->flags & CTL_LLF_COMPARE) { 326268151Smav uma_zfree(beio->lun->lun_zone, 327268151Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr); 328268151Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = NULL; 329268151Smav } 330229997Sken } 331229997Sken 332229997Sken if (duplicate_free > 0) { 333229997Sken printf("%s: %d duplicate frees out of %d segments\n", __func__, 334229997Sken duplicate_free, beio->num_segs); 335229997Sken } 336229997Sken 337265494Strasz uma_zfree(beio_zone, beio); 338229997Sken} 339229997Sken 340229997Skenstatic void 341229997Skenctl_complete_beio(struct ctl_be_block_io *beio) 342229997Sken{ 343268549Smav union ctl_io *io = beio->io; 344229997Sken 345265634Smav if (beio->beio_cont != NULL) { 346265634Smav beio->beio_cont(beio); 347265634Smav } else { 348265634Smav ctl_free_beio(beio); 349268151Smav ctl_data_submit_done(io); 350265634Smav } 351229997Sken} 352229997Sken 353288763Smavstatic size_t 354288763Smavcmp(uint8_t *a, uint8_t *b, size_t size) 355288763Smav{ 356288763Smav size_t i; 357288763Smav 358288763Smav for (i = 0; i < size; i++) { 359288763Smav if (a[i] != b[i]) 360288763Smav break; 361288763Smav } 362288763Smav return (i); 363288763Smav} 364288763Smav 365288763Smavstatic void 366288763Smavctl_be_block_compare(union ctl_io *io) 367288763Smav{ 368288763Smav struct ctl_be_block_io *beio; 369288763Smav uint64_t off, res; 370288763Smav int i; 371288763Smav uint8_t info[8]; 372288763Smav 373288763Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 374288763Smav off = 0; 375288763Smav for (i = 0; i < beio->num_segs; i++) { 376288763Smav res = cmp(beio->sg_segs[i].addr, 377288763Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr, 378288763Smav beio->sg_segs[i].len); 379288763Smav off += res; 380288763Smav if (res < beio->sg_segs[i].len) 381288763Smav break; 382288763Smav } 383288763Smav if (i < beio->num_segs) { 384288763Smav scsi_u64to8b(off, info); 385288763Smav ctl_set_sense(&io->scsiio, /*current_error*/ 1, 386288763Smav /*sense_key*/ SSD_KEY_MISCOMPARE, 387288763Smav /*asc*/ 0x1D, /*ascq*/ 0x00, 388288763Smav /*type*/ SSD_ELEM_INFO, 389288763Smav /*size*/ sizeof(info), /*data*/ &info, 390288763Smav /*type*/ SSD_ELEM_NONE); 391288763Smav } else 392288763Smav ctl_set_success(&io->scsiio); 393288763Smav} 394288763Smav 395229997Skenstatic int 396229997Skenctl_be_block_move_done(union ctl_io *io) 397229997Sken{ 398229997Sken struct ctl_be_block_io *beio; 399229997Sken struct ctl_be_block_lun *be_lun; 400268151Smav struct ctl_lba_len_flags *lbalen; 401229997Sken#ifdef CTL_TIME_IO 402229997Sken struct bintime cur_bt; 403268151Smav#endif 404229997Sken 405268150Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 406229997Sken be_lun = beio->lun; 407229997Sken 408229997Sken DPRINTF("entered\n"); 409229997Sken 410229997Sken#ifdef CTL_TIME_IO 411288798Smav getbinuptime(&cur_bt); 412229997Sken bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 413229997Sken bintime_add(&io->io_hdr.dma_bt, &cur_bt); 414288798Smav#endif 415229997Sken io->io_hdr.num_dmas++; 416268151Smav io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 417229997Sken 418229997Sken /* 419229997Sken * We set status at this point for read commands, and write 420229997Sken * commands with errors. 421229997Sken */ 422275881Smav if (io->io_hdr.flags & CTL_FLAG_ABORT) { 423275881Smav ; 424275881Smav } else if ((io->io_hdr.port_status == 0) && 425268151Smav ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 426268151Smav lbalen = ARGS(beio->io); 427268151Smav if (lbalen->flags & CTL_LLF_READ) { 428268151Smav ctl_set_success(&io->scsiio); 429268151Smav } else if (lbalen->flags & CTL_LLF_COMPARE) { 430268151Smav /* We have two data blocks ready for comparison. */ 431288763Smav ctl_be_block_compare(io); 432268151Smav } 433275881Smav } else if ((io->io_hdr.port_status != 0) && 434275881Smav ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 435275881Smav (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 436229997Sken /* 437229997Sken * For hardware error sense keys, the sense key 438229997Sken * specific value is defined to be a retry count, 439229997Sken * but we use it to pass back an internal FETD 440229997Sken * error code. XXX KDM Hopefully the FETD is only 441229997Sken * using 16 bits for an error code, since that's 442229997Sken * all the space we have in the sks field. 443229997Sken */ 444229997Sken ctl_set_internal_failure(&io->scsiio, 445229997Sken /*sks_valid*/ 1, 446229997Sken /*retry_count*/ 447229997Sken io->io_hdr.port_status); 448229997Sken } 449229997Sken 450229997Sken /* 451229997Sken * If this is a read, or a write with errors, it is done. 452229997Sken */ 453229997Sken if ((beio->bio_cmd == BIO_READ) 454229997Sken || ((io->io_hdr.flags & CTL_FLAG_ABORT) != 0) 455229997Sken || ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE)) { 456229997Sken ctl_complete_beio(beio); 457229997Sken return (0); 458229997Sken } 459229997Sken 460229997Sken /* 461229997Sken * At this point, we have a write and the DMA completed 462229997Sken * successfully. We now have to queue it to the task queue to 463229997Sken * execute the backend I/O. That is because we do blocking 464229997Sken * memory allocations, and in the file backing case, blocking I/O. 465229997Sken * This move done routine is generally called in the SIM's 466229997Sken * interrupt context, and therefore we cannot block. 467229997Sken */ 468268549Smav mtx_lock(&be_lun->queue_lock); 469229997Sken STAILQ_INSERT_TAIL(&be_lun->datamove_queue, &io->io_hdr, links); 470268549Smav mtx_unlock(&be_lun->queue_lock); 471229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 472229997Sken 473229997Sken return (0); 474229997Sken} 475229997Sken 476229997Skenstatic void 477229997Skenctl_be_block_biodone(struct bio *bio) 478229997Sken{ 479229997Sken struct ctl_be_block_io *beio; 480229997Sken struct ctl_be_block_lun *be_lun; 481229997Sken union ctl_io *io; 482262299Smav int error; 483229997Sken 484229997Sken beio = bio->bio_caller1; 485229997Sken be_lun = beio->lun; 486229997Sken io = beio->io; 487229997Sken 488229997Sken DPRINTF("entered\n"); 489229997Sken 490262299Smav error = bio->bio_error; 491268549Smav mtx_lock(&be_lun->io_lock); 492262299Smav if (error != 0) 493229997Sken beio->num_errors++; 494229997Sken 495229997Sken beio->num_bios_done++; 496229997Sken 497229997Sken /* 498229997Sken * XXX KDM will this cause WITNESS to complain? Holding a lock 499229997Sken * during the free might cause it to complain. 500229997Sken */ 501229997Sken g_destroy_bio(bio); 502229997Sken 503229997Sken /* 504229997Sken * If the send complete bit isn't set, or we aren't the last I/O to 505229997Sken * complete, then we're done. 506229997Sken */ 507229997Sken if ((beio->send_complete == 0) 508229997Sken || (beio->num_bios_done < beio->num_bios_sent)) { 509268549Smav mtx_unlock(&be_lun->io_lock); 510229997Sken return; 511229997Sken } 512229997Sken 513229997Sken /* 514229997Sken * At this point, we've verified that we are the last I/O to 515229997Sken * complete, so it's safe to drop the lock. 516229997Sken */ 517268549Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 518268549Smav beio->ds_tag_type, beio->ds_trans_type, 519268549Smav /*now*/ NULL, /*then*/&beio->ds_t0); 520268549Smav mtx_unlock(&be_lun->io_lock); 521229997Sken 522229997Sken /* 523229997Sken * If there are any errors from the backing device, we fail the 524229997Sken * entire I/O with a medium error. 525229997Sken */ 526229997Sken if (beio->num_errors > 0) { 527262299Smav if (error == EOPNOTSUPP) { 528262299Smav ctl_set_invalid_opcode(&io->scsiio); 529282862Smav } else if (error == ENOSPC || error == EDQUOT) { 530274004Smav ctl_set_space_alloc_fail(&io->scsiio); 531288750Smav } else if (error == EROFS || error == EACCES) { 532288750Smav ctl_set_hw_write_protected(&io->scsiio); 533262299Smav } else if (beio->bio_cmd == BIO_FLUSH) { 534229997Sken /* XXX KDM is there is a better error here? */ 535229997Sken ctl_set_internal_failure(&io->scsiio, 536229997Sken /*sks_valid*/ 1, 537229997Sken /*retry_count*/ 0xbad2); 538288765Smav } else { 539288765Smav ctl_set_medium_error(&io->scsiio, 540288765Smav beio->bio_cmd == BIO_READ); 541288765Smav } 542229997Sken ctl_complete_beio(beio); 543229997Sken return; 544229997Sken } 545229997Sken 546229997Sken /* 547268151Smav * If this is a write, a flush, a delete or verify, we're all done. 548229997Sken * If this is a read, we can now send the data to the user. 549229997Sken */ 550229997Sken if ((beio->bio_cmd == BIO_WRITE) 551265634Smav || (beio->bio_cmd == BIO_FLUSH) 552268151Smav || (beio->bio_cmd == BIO_DELETE) 553268151Smav || (ARGS(io)->flags & CTL_LLF_VERIFY)) { 554229997Sken ctl_set_success(&io->scsiio); 555229997Sken ctl_complete_beio(beio); 556229997Sken } else { 557275881Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 558288774Smav beio->beio_cont == NULL) { 559275881Smav ctl_set_success(&io->scsiio); 560288774Smav ctl_serseq_done(io); 561288774Smav } 562229997Sken#ifdef CTL_TIME_IO 563288798Smav getbinuptime(&io->io_hdr.dma_start_bt); 564288798Smav#endif 565229997Sken ctl_datamove(io); 566229997Sken } 567229997Sken} 568229997Sken 569229997Skenstatic void 570229997Skenctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 571229997Sken struct ctl_be_block_io *beio) 572229997Sken{ 573268549Smav union ctl_io *io = beio->io; 574229997Sken struct mount *mountpoint; 575241896Skib int error, lock_flags; 576229997Sken 577229997Sken DPRINTF("entered\n"); 578229997Sken 579268549Smav binuptime(&beio->ds_t0); 580268549Smav mtx_lock(&be_lun->io_lock); 581268549Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 582268549Smav mtx_unlock(&be_lun->io_lock); 583229997Sken 584268549Smav (void) vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 585229997Sken 586288799Smav if (MNT_SHARED_WRITES(mountpoint) || 587288799Smav ((mountpoint == NULL) && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 588229997Sken lock_flags = LK_SHARED; 589229997Sken else 590229997Sken lock_flags = LK_EXCLUSIVE; 591229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 592286931Smav error = VOP_FSYNC(be_lun->vn, beio->io_arg ? MNT_NOWAIT : MNT_WAIT, 593286931Smav curthread); 594229997Sken VOP_UNLOCK(be_lun->vn, 0); 595229997Sken 596229997Sken vn_finished_write(mountpoint); 597229997Sken 598268549Smav mtx_lock(&be_lun->io_lock); 599268549Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 600268549Smav beio->ds_tag_type, beio->ds_trans_type, 601268549Smav /*now*/ NULL, /*then*/&beio->ds_t0); 602268549Smav mtx_unlock(&be_lun->io_lock); 603268549Smav 604229997Sken if (error == 0) 605229997Sken ctl_set_success(&io->scsiio); 606229997Sken else { 607229997Sken /* XXX KDM is there is a better error here? */ 608229997Sken ctl_set_internal_failure(&io->scsiio, 609229997Sken /*sks_valid*/ 1, 610229997Sken /*retry_count*/ 0xbad1); 611229997Sken } 612229997Sken 613229997Sken ctl_complete_beio(beio); 614229997Sken} 615229997Sken 616260817SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_start, "uint64_t"); 617260817SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_start, "uint64_t"); 618260817SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_done,"uint64_t"); 619260817SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_done, "uint64_t"); 620229997Sken 621229997Skenstatic void 622229997Skenctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 623229997Sken struct ctl_be_block_io *beio) 624229997Sken{ 625229997Sken struct ctl_be_block_filedata *file_data; 626229997Sken union ctl_io *io; 627229997Sken struct uio xuio; 628229997Sken struct iovec *xiovec; 629288764Smav size_t s; 630288764Smav int error, flags, i; 631229997Sken 632229997Sken DPRINTF("entered\n"); 633229997Sken 634229997Sken file_data = &be_lun->backend.file; 635229997Sken io = beio->io; 636272616Smav flags = 0; 637272616Smav if (ARGS(io)->flags & CTL_LLF_DPO) 638272616Smav flags |= IO_DIRECT; 639272616Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 640272616Smav flags |= IO_SYNC; 641229997Sken 642268151Smav bzero(&xuio, sizeof(xuio)); 643229997Sken if (beio->bio_cmd == BIO_READ) { 644229997Sken SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 645268151Smav xuio.uio_rw = UIO_READ; 646229997Sken } else { 647229997Sken SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 648268151Smav xuio.uio_rw = UIO_WRITE; 649229997Sken } 650229997Sken xuio.uio_offset = beio->io_offset; 651229997Sken xuio.uio_resid = beio->io_len; 652229997Sken xuio.uio_segflg = UIO_SYSSPACE; 653229997Sken xuio.uio_iov = beio->xiovecs; 654229997Sken xuio.uio_iovcnt = beio->num_segs; 655229997Sken xuio.uio_td = curthread; 656229997Sken 657229997Sken for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 658229997Sken xiovec->iov_base = beio->sg_segs[i].addr; 659229997Sken xiovec->iov_len = beio->sg_segs[i].len; 660229997Sken } 661229997Sken 662268549Smav binuptime(&beio->ds_t0); 663268549Smav mtx_lock(&be_lun->io_lock); 664268549Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 665268549Smav mtx_unlock(&be_lun->io_lock); 666268549Smav 667229997Sken if (beio->bio_cmd == BIO_READ) { 668229997Sken vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 669229997Sken 670229997Sken /* 671229997Sken * UFS pays attention to IO_DIRECT for reads. If the 672229997Sken * DIRECTIO option is configured into the kernel, it calls 673229997Sken * ffs_rawread(). But that only works for single-segment 674229997Sken * uios with user space addresses. In our case, with a 675229997Sken * kernel uio, it still reads into the buffer cache, but it 676229997Sken * will just try to release the buffer from the cache later 677229997Sken * on in ffs_read(). 678229997Sken * 679229997Sken * ZFS does not pay attention to IO_DIRECT for reads. 680229997Sken * 681229997Sken * UFS does not pay attention to IO_SYNC for reads. 682229997Sken * 683229997Sken * ZFS pays attention to IO_SYNC (which translates into the 684229997Sken * Solaris define FRSYNC for zfs_read()) for reads. It 685229997Sken * attempts to sync the file before reading. 686229997Sken */ 687272616Smav error = VOP_READ(be_lun->vn, &xuio, flags, file_data->cred); 688229997Sken 689229997Sken VOP_UNLOCK(be_lun->vn, 0); 690268151Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 691288764Smav if (error == 0 && xuio.uio_resid > 0) { 692288764Smav /* 693288764Smav * If we red less then requested (EOF), then 694288764Smav * we should clean the rest of the buffer. 695288764Smav */ 696288764Smav s = beio->io_len - xuio.uio_resid; 697288764Smav for (i = 0; i < beio->num_segs; i++) { 698288764Smav if (s >= beio->sg_segs[i].len) { 699288764Smav s -= beio->sg_segs[i].len; 700288764Smav continue; 701288764Smav } 702288764Smav bzero((uint8_t *)beio->sg_segs[i].addr + s, 703288764Smav beio->sg_segs[i].len - s); 704288764Smav s = 0; 705288764Smav } 706288764Smav } 707229997Sken } else { 708229997Sken struct mount *mountpoint; 709229997Sken int lock_flags; 710229997Sken 711229997Sken (void)vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 712229997Sken 713288799Smav if (MNT_SHARED_WRITES(mountpoint) || ((mountpoint == NULL) 714229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 715229997Sken lock_flags = LK_SHARED; 716229997Sken else 717229997Sken lock_flags = LK_EXCLUSIVE; 718229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 719229997Sken 720229997Sken /* 721229997Sken * UFS pays attention to IO_DIRECT for writes. The write 722229997Sken * is done asynchronously. (Normally the write would just 723229997Sken * get put into cache. 724229997Sken * 725229997Sken * UFS pays attention to IO_SYNC for writes. It will 726229997Sken * attempt to write the buffer out synchronously if that 727229997Sken * flag is set. 728229997Sken * 729229997Sken * ZFS does not pay attention to IO_DIRECT for writes. 730229997Sken * 731229997Sken * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC) 732229997Sken * for writes. It will flush the transaction from the 733229997Sken * cache before returning. 734229997Sken */ 735272616Smav error = VOP_WRITE(be_lun->vn, &xuio, flags, file_data->cred); 736229997Sken VOP_UNLOCK(be_lun->vn, 0); 737229997Sken 738229997Sken vn_finished_write(mountpoint); 739268151Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 740229997Sken } 741229997Sken 742268549Smav mtx_lock(&be_lun->io_lock); 743268549Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 744268549Smav beio->ds_tag_type, beio->ds_trans_type, 745268549Smav /*now*/ NULL, /*then*/&beio->ds_t0); 746268549Smav mtx_unlock(&be_lun->io_lock); 747268549Smav 748229997Sken /* 749229997Sken * If we got an error, set the sense data to "MEDIUM ERROR" and 750229997Sken * return the I/O to the user. 751229997Sken */ 752229997Sken if (error != 0) { 753282862Smav if (error == ENOSPC || error == EDQUOT) { 754274004Smav ctl_set_space_alloc_fail(&io->scsiio); 755288750Smav } else if (error == EROFS || error == EACCES) { 756288750Smav ctl_set_hw_write_protected(&io->scsiio); 757288765Smav } else { 758288765Smav ctl_set_medium_error(&io->scsiio, 759288765Smav beio->bio_cmd == BIO_READ); 760288765Smav } 761229997Sken ctl_complete_beio(beio); 762229997Sken return; 763229997Sken } 764229997Sken 765229997Sken /* 766269226Smav * If this is a write or a verify, we're all done. 767229997Sken * If this is a read, we can now send the data to the user. 768229997Sken */ 769269226Smav if ((beio->bio_cmd == BIO_WRITE) || 770269226Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 771229997Sken ctl_set_success(&io->scsiio); 772229997Sken ctl_complete_beio(beio); 773229997Sken } else { 774275881Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 775288774Smav beio->beio_cont == NULL) { 776275881Smav ctl_set_success(&io->scsiio); 777288774Smav ctl_serseq_done(io); 778288774Smav } 779229997Sken#ifdef CTL_TIME_IO 780288798Smav getbinuptime(&io->io_hdr.dma_start_bt); 781288798Smav#endif 782229997Sken ctl_datamove(io); 783229997Sken } 784229997Sken} 785229997Sken 786229997Skenstatic void 787275892Smavctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 788275892Smav struct ctl_be_block_io *beio) 789275892Smav{ 790275892Smav union ctl_io *io = beio->io; 791275892Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 792275892Smav struct scsi_get_lba_status_data *data; 793275892Smav off_t roff, off; 794275892Smav int error, status; 795275892Smav 796275892Smav DPRINTF("entered\n"); 797275892Smav 798288727Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 799275892Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 800275892Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off, 801275892Smav 0, curthread->td_ucred, curthread); 802275892Smav if (error == 0 && off > roff) 803275892Smav status = 0; /* mapped up to off */ 804275892Smav else { 805275892Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off, 806275892Smav 0, curthread->td_ucred, curthread); 807275892Smav if (error == 0 && off > roff) 808275892Smav status = 1; /* deallocated up to off */ 809275892Smav else { 810275892Smav status = 0; /* unknown up to the end */ 811275892Smav off = be_lun->size_bytes; 812275892Smav } 813275892Smav } 814275892Smav VOP_UNLOCK(be_lun->vn, 0); 815275892Smav 816275892Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 817275892Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 818288727Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 819288727Smav lbalen->lba), data->descr[0].length); 820275892Smav data->descr[0].status = status; 821275892Smav 822275892Smav ctl_complete_beio(beio); 823275892Smav} 824275892Smav 825275893Smavstatic uint64_t 826275893Smavctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, const char *attrname) 827275893Smav{ 828275893Smav struct vattr vattr; 829275893Smav struct statfs statfs; 830288706Smav uint64_t val; 831275893Smav int error; 832275893Smav 833288706Smav val = UINT64_MAX; 834275893Smav if (be_lun->vn == NULL) 835288706Smav return (val); 836288706Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 837275893Smav if (strcmp(attrname, "blocksused") == 0) { 838275893Smav error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 839288706Smav if (error == 0) 840288727Smav val = vattr.va_bytes / be_lun->cbe_lun.blocksize; 841275893Smav } 842288706Smav if (strcmp(attrname, "blocksavail") == 0 && 843288706Smav (be_lun->vn->v_iflag & VI_DOOMED) == 0) { 844275893Smav error = VFS_STATFS(be_lun->vn->v_mount, &statfs); 845288706Smav if (error == 0) 846288721Smav val = statfs.f_bavail * statfs.f_bsize / 847288727Smav be_lun->cbe_lun.blocksize; 848275893Smav } 849288706Smav VOP_UNLOCK(be_lun->vn, 0); 850288706Smav return (val); 851275893Smav} 852275893Smav 853275892Smavstatic void 854269429Smavctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, 855269429Smav struct ctl_be_block_io *beio) 856269429Smav{ 857269429Smav union ctl_io *io; 858288733Smav struct cdevsw *csw; 859288733Smav struct cdev *dev; 860269429Smav struct uio xuio; 861269429Smav struct iovec *xiovec; 862288733Smav int error, flags, i, ref; 863269429Smav 864269429Smav DPRINTF("entered\n"); 865269429Smav 866269429Smav io = beio->io; 867272616Smav flags = 0; 868272616Smav if (ARGS(io)->flags & CTL_LLF_DPO) 869272616Smav flags |= IO_DIRECT; 870272616Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 871272616Smav flags |= IO_SYNC; 872269429Smav 873269429Smav bzero(&xuio, sizeof(xuio)); 874269429Smav if (beio->bio_cmd == BIO_READ) { 875269429Smav SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 876269429Smav xuio.uio_rw = UIO_READ; 877269429Smav } else { 878269429Smav SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 879269429Smav xuio.uio_rw = UIO_WRITE; 880269429Smav } 881269429Smav xuio.uio_offset = beio->io_offset; 882269429Smav xuio.uio_resid = beio->io_len; 883269429Smav xuio.uio_segflg = UIO_SYSSPACE; 884269429Smav xuio.uio_iov = beio->xiovecs; 885269429Smav xuio.uio_iovcnt = beio->num_segs; 886269429Smav xuio.uio_td = curthread; 887269429Smav 888269429Smav for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 889269429Smav xiovec->iov_base = beio->sg_segs[i].addr; 890269429Smav xiovec->iov_len = beio->sg_segs[i].len; 891269429Smav } 892269429Smav 893269429Smav binuptime(&beio->ds_t0); 894269429Smav mtx_lock(&be_lun->io_lock); 895269429Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 896269429Smav mtx_unlock(&be_lun->io_lock); 897269429Smav 898288733Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 899288733Smav if (csw) { 900288733Smav if (beio->bio_cmd == BIO_READ) 901288733Smav error = csw->d_read(dev, &xuio, flags); 902288733Smav else 903288733Smav error = csw->d_write(dev, &xuio, flags); 904288733Smav dev_relthread(dev, ref); 905288733Smav } else 906288733Smav error = ENXIO; 907288733Smav 908288733Smav if (beio->bio_cmd == BIO_READ) 909269429Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 910288733Smav else 911269429Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 912269429Smav 913269429Smav mtx_lock(&be_lun->io_lock); 914269429Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 915269429Smav beio->ds_tag_type, beio->ds_trans_type, 916269429Smav /*now*/ NULL, /*then*/&beio->ds_t0); 917269429Smav mtx_unlock(&be_lun->io_lock); 918269429Smav 919269429Smav /* 920269429Smav * If we got an error, set the sense data to "MEDIUM ERROR" and 921269429Smav * return the I/O to the user. 922269429Smav */ 923269429Smav if (error != 0) { 924282862Smav if (error == ENOSPC || error == EDQUOT) { 925274004Smav ctl_set_space_alloc_fail(&io->scsiio); 926288750Smav } else if (error == EROFS || error == EACCES) { 927288750Smav ctl_set_hw_write_protected(&io->scsiio); 928288765Smav } else { 929288765Smav ctl_set_medium_error(&io->scsiio, 930288765Smav beio->bio_cmd == BIO_READ); 931288765Smav } 932269429Smav ctl_complete_beio(beio); 933269429Smav return; 934269429Smav } 935269429Smav 936269429Smav /* 937269429Smav * If this is a write or a verify, we're all done. 938269429Smav * If this is a read, we can now send the data to the user. 939269429Smav */ 940269429Smav if ((beio->bio_cmd == BIO_WRITE) || 941269429Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 942269429Smav ctl_set_success(&io->scsiio); 943269429Smav ctl_complete_beio(beio); 944269429Smav } else { 945275881Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 946288774Smav beio->beio_cont == NULL) { 947275881Smav ctl_set_success(&io->scsiio); 948288774Smav ctl_serseq_done(io); 949288774Smav } 950269429Smav#ifdef CTL_TIME_IO 951288798Smav getbinuptime(&io->io_hdr.dma_start_bt); 952288798Smav#endif 953269429Smav ctl_datamove(io); 954269429Smav } 955269429Smav} 956269429Smav 957269429Smavstatic void 958275892Smavctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, 959275892Smav struct ctl_be_block_io *beio) 960275892Smav{ 961275892Smav union ctl_io *io = beio->io; 962288733Smav struct cdevsw *csw; 963288733Smav struct cdev *dev; 964275892Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 965275892Smav struct scsi_get_lba_status_data *data; 966275892Smav off_t roff, off; 967288733Smav int error, ref, status; 968275892Smav 969275892Smav DPRINTF("entered\n"); 970275892Smav 971288733Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 972288733Smav if (csw == NULL) { 973288733Smav status = 0; /* unknown up to the end */ 974288733Smav off = be_lun->size_bytes; 975288733Smav goto done; 976288733Smav } 977288727Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 978288733Smav error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD, 979288733Smav curthread); 980275892Smav if (error == 0 && off > roff) 981275892Smav status = 0; /* mapped up to off */ 982275892Smav else { 983288733Smav error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD, 984288733Smav curthread); 985275892Smav if (error == 0 && off > roff) 986275892Smav status = 1; /* deallocated up to off */ 987275892Smav else { 988275892Smav status = 0; /* unknown up to the end */ 989275892Smav off = be_lun->size_bytes; 990275892Smav } 991275892Smav } 992288733Smav dev_relthread(dev, ref); 993275892Smav 994288733Smavdone: 995275892Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 996275892Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 997288727Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 998288727Smav lbalen->lba), data->descr[0].length); 999275892Smav data->descr[0].status = status; 1000275892Smav 1001275892Smav ctl_complete_beio(beio); 1002275892Smav} 1003275892Smav 1004275892Smavstatic void 1005229997Skenctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 1006229997Sken struct ctl_be_block_io *beio) 1007229997Sken{ 1008229997Sken struct bio *bio; 1009288733Smav struct cdevsw *csw; 1010288733Smav struct cdev *dev; 1011288733Smav int ref; 1012229997Sken 1013229997Sken DPRINTF("entered\n"); 1014229997Sken 1015229997Sken /* This can't fail, it's a blocking allocation. */ 1016229997Sken bio = g_alloc_bio(); 1017229997Sken 1018229997Sken bio->bio_cmd = BIO_FLUSH; 1019229997Sken bio->bio_offset = 0; 1020229997Sken bio->bio_data = 0; 1021229997Sken bio->bio_done = ctl_be_block_biodone; 1022229997Sken bio->bio_caller1 = beio; 1023229997Sken bio->bio_pblkno = 0; 1024229997Sken 1025229997Sken /* 1026229997Sken * We don't need to acquire the LUN lock here, because we are only 1027229997Sken * sending one bio, and so there is no other context to synchronize 1028229997Sken * with. 1029229997Sken */ 1030229997Sken beio->num_bios_sent = 1; 1031229997Sken beio->send_complete = 1; 1032229997Sken 1033229997Sken binuptime(&beio->ds_t0); 1034268549Smav mtx_lock(&be_lun->io_lock); 1035229997Sken devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1036268549Smav mtx_unlock(&be_lun->io_lock); 1037229997Sken 1038288733Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1039288733Smav if (csw) { 1040288733Smav bio->bio_dev = dev; 1041288733Smav csw->d_strategy(bio); 1042288733Smav dev_relthread(dev, ref); 1043288733Smav } else { 1044288733Smav bio->bio_error = ENXIO; 1045288733Smav ctl_be_block_biodone(bio); 1046288733Smav } 1047229997Sken} 1048229997Sken 1049229997Skenstatic void 1050265634Smavctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, 1051265634Smav struct ctl_be_block_io *beio, 1052265634Smav uint64_t off, uint64_t len, int last) 1053265634Smav{ 1054265634Smav struct bio *bio; 1055265634Smav uint64_t maxlen; 1056288733Smav struct cdevsw *csw; 1057288733Smav struct cdev *dev; 1058288733Smav int ref; 1059265634Smav 1060288733Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1061288727Smav maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize); 1062265634Smav while (len > 0) { 1063265634Smav bio = g_alloc_bio(); 1064265634Smav bio->bio_cmd = BIO_DELETE; 1065288733Smav bio->bio_dev = dev; 1066265634Smav bio->bio_offset = off; 1067265634Smav bio->bio_length = MIN(len, maxlen); 1068265634Smav bio->bio_data = 0; 1069265634Smav bio->bio_done = ctl_be_block_biodone; 1070265634Smav bio->bio_caller1 = beio; 1071288727Smav bio->bio_pblkno = off / be_lun->cbe_lun.blocksize; 1072265634Smav 1073265634Smav off += bio->bio_length; 1074265634Smav len -= bio->bio_length; 1075265634Smav 1076268549Smav mtx_lock(&be_lun->io_lock); 1077265634Smav beio->num_bios_sent++; 1078265634Smav if (last && len == 0) 1079265634Smav beio->send_complete = 1; 1080268549Smav mtx_unlock(&be_lun->io_lock); 1081265634Smav 1082288733Smav if (csw) { 1083288733Smav csw->d_strategy(bio); 1084288733Smav } else { 1085288733Smav bio->bio_error = ENXIO; 1086288733Smav ctl_be_block_biodone(bio); 1087288733Smav } 1088265634Smav } 1089288733Smav if (csw) 1090288733Smav dev_relthread(dev, ref); 1091265634Smav} 1092265634Smav 1093265634Smavstatic void 1094265634Smavctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 1095265634Smav struct ctl_be_block_io *beio) 1096265634Smav{ 1097265634Smav union ctl_io *io; 1098268149Smav struct ctl_ptr_len_flags *ptrlen; 1099265634Smav struct scsi_unmap_desc *buf, *end; 1100265634Smav uint64_t len; 1101265634Smav 1102265634Smav io = beio->io; 1103265634Smav 1104265634Smav DPRINTF("entered\n"); 1105265634Smav 1106265634Smav binuptime(&beio->ds_t0); 1107268549Smav mtx_lock(&be_lun->io_lock); 1108265634Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1109268549Smav mtx_unlock(&be_lun->io_lock); 1110265634Smav 1111265634Smav if (beio->io_offset == -1) { 1112265634Smav beio->io_len = 0; 1113268149Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1114268149Smav buf = (struct scsi_unmap_desc *)ptrlen->ptr; 1115268149Smav end = buf + ptrlen->len / sizeof(*buf); 1116265634Smav for (; buf < end; buf++) { 1117265634Smav len = (uint64_t)scsi_4btoul(buf->length) * 1118288727Smav be_lun->cbe_lun.blocksize; 1119265634Smav beio->io_len += len; 1120265634Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1121288727Smav scsi_8btou64(buf->lba) * be_lun->cbe_lun.blocksize, 1122288727Smav len, (end - buf < 2) ? TRUE : FALSE); 1123265634Smav } 1124265634Smav } else 1125265634Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1126265634Smav beio->io_offset, beio->io_len, TRUE); 1127265634Smav} 1128265634Smav 1129265634Smavstatic void 1130229997Skenctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 1131229997Sken struct ctl_be_block_io *beio) 1132229997Sken{ 1133268549Smav TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 1134229997Sken struct bio *bio; 1135288733Smav struct cdevsw *csw; 1136288733Smav struct cdev *dev; 1137229997Sken off_t cur_offset; 1138288733Smav int i, max_iosize, ref; 1139229997Sken 1140229997Sken DPRINTF("entered\n"); 1141288733Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1142229997Sken 1143229997Sken /* 1144229997Sken * We have to limit our I/O size to the maximum supported by the 1145229997Sken * backend device. Hopefully it is MAXPHYS. If the driver doesn't 1146229997Sken * set it properly, use DFLTPHYS. 1147229997Sken */ 1148288733Smav if (csw) { 1149288733Smav max_iosize = dev->si_iosize_max; 1150288733Smav if (max_iosize < PAGE_SIZE) 1151288733Smav max_iosize = DFLTPHYS; 1152288733Smav } else 1153229997Sken max_iosize = DFLTPHYS; 1154229997Sken 1155229997Sken cur_offset = beio->io_offset; 1156229997Sken for (i = 0; i < beio->num_segs; i++) { 1157229997Sken size_t cur_size; 1158229997Sken uint8_t *cur_ptr; 1159229997Sken 1160229997Sken cur_size = beio->sg_segs[i].len; 1161229997Sken cur_ptr = beio->sg_segs[i].addr; 1162229997Sken 1163229997Sken while (cur_size > 0) { 1164229997Sken /* This can't fail, it's a blocking allocation. */ 1165229997Sken bio = g_alloc_bio(); 1166229997Sken 1167229997Sken KASSERT(bio != NULL, ("g_alloc_bio() failed!\n")); 1168229997Sken 1169229997Sken bio->bio_cmd = beio->bio_cmd; 1170288733Smav bio->bio_dev = dev; 1171229997Sken bio->bio_caller1 = beio; 1172229997Sken bio->bio_length = min(cur_size, max_iosize); 1173229997Sken bio->bio_offset = cur_offset; 1174229997Sken bio->bio_data = cur_ptr; 1175229997Sken bio->bio_done = ctl_be_block_biodone; 1176288727Smav bio->bio_pblkno = cur_offset / be_lun->cbe_lun.blocksize; 1177229997Sken 1178229997Sken cur_offset += bio->bio_length; 1179229997Sken cur_ptr += bio->bio_length; 1180229997Sken cur_size -= bio->bio_length; 1181229997Sken 1182268549Smav TAILQ_INSERT_TAIL(&queue, bio, bio_queue); 1183229997Sken beio->num_bios_sent++; 1184229997Sken } 1185229997Sken } 1186268549Smav binuptime(&beio->ds_t0); 1187268549Smav mtx_lock(&be_lun->io_lock); 1188268549Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1189268549Smav beio->send_complete = 1; 1190268549Smav mtx_unlock(&be_lun->io_lock); 1191268549Smav 1192268549Smav /* 1193268549Smav * Fire off all allocated requests! 1194268549Smav */ 1195268549Smav while ((bio = TAILQ_FIRST(&queue)) != NULL) { 1196268549Smav TAILQ_REMOVE(&queue, bio, bio_queue); 1197288733Smav if (csw) 1198288733Smav csw->d_strategy(bio); 1199288733Smav else { 1200288733Smav bio->bio_error = ENXIO; 1201288733Smav ctl_be_block_biodone(bio); 1202288733Smav } 1203268549Smav } 1204288733Smav if (csw) 1205288733Smav dev_relthread(dev, ref); 1206229997Sken} 1207229997Sken 1208274732Smavstatic uint64_t 1209274732Smavctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname) 1210274732Smav{ 1211274732Smav struct diocgattr_arg arg; 1212288733Smav struct cdevsw *csw; 1213288733Smav struct cdev *dev; 1214288733Smav int error, ref; 1215274732Smav 1216288733Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1217288733Smav if (csw == NULL) 1218274732Smav return (UINT64_MAX); 1219274732Smav strlcpy(arg.name, attrname, sizeof(arg.name)); 1220274732Smav arg.len = sizeof(arg.value.off); 1221288733Smav if (csw->d_ioctl) { 1222288733Smav error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 1223288733Smav curthread); 1224288733Smav } else 1225288733Smav error = ENODEV; 1226288733Smav dev_relthread(dev, ref); 1227274732Smav if (error != 0) 1228274732Smav return (UINT64_MAX); 1229274732Smav return (arg.value.off); 1230274732Smav} 1231274732Smav 1232229997Skenstatic void 1233286931Smavctl_be_block_cw_dispatch_sync(struct ctl_be_block_lun *be_lun, 1234286931Smav union ctl_io *io) 1235286931Smav{ 1236288727Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1237286931Smav struct ctl_be_block_io *beio; 1238286931Smav struct ctl_lba_len_flags *lbalen; 1239286931Smav 1240286931Smav DPRINTF("entered\n"); 1241286931Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1242286931Smav lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1243286931Smav 1244288727Smav beio->io_len = lbalen->len * cbe_lun->blocksize; 1245288727Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1246286931Smav beio->io_arg = (lbalen->flags & SSC_IMMED) != 0; 1247286931Smav beio->bio_cmd = BIO_FLUSH; 1248286931Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1249286931Smav DPRINTF("SYNC\n"); 1250286931Smav be_lun->lun_flush(be_lun, beio); 1251286931Smav} 1252286931Smav 1253286931Smavstatic void 1254265634Smavctl_be_block_cw_done_ws(struct ctl_be_block_io *beio) 1255265634Smav{ 1256265634Smav union ctl_io *io; 1257265634Smav 1258265634Smav io = beio->io; 1259265634Smav ctl_free_beio(beio); 1260268261Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1261268261Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1262268261Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1263265634Smav ctl_config_write_done(io); 1264265634Smav return; 1265265634Smav } 1266265634Smav 1267265634Smav ctl_be_block_config_write(io); 1268265634Smav} 1269265634Smav 1270265634Smavstatic void 1271265634Smavctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun, 1272265634Smav union ctl_io *io) 1273265634Smav{ 1274288727Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1275265634Smav struct ctl_be_block_io *beio; 1276268149Smav struct ctl_lba_len_flags *lbalen; 1277279004Smav uint64_t len_left, lba; 1278279004Smav uint32_t pb, pbo, adj; 1279265634Smav int i, seglen; 1280265634Smav uint8_t *buf, *end; 1281265634Smav 1282265634Smav DPRINTF("entered\n"); 1283265634Smav 1284268150Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1285268151Smav lbalen = ARGS(beio->io); 1286265634Smav 1287272632Smav if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB) || 1288270108Smav (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR) && be_lun->unmap == NULL)) { 1289265634Smav ctl_free_beio(beio); 1290265634Smav ctl_set_invalid_field(&io->scsiio, 1291265634Smav /*sks_valid*/ 1, 1292265634Smav /*command*/ 1, 1293265634Smav /*field*/ 1, 1294265634Smav /*bit_valid*/ 0, 1295265634Smav /*bit*/ 0); 1296265634Smav ctl_config_write_done(io); 1297265634Smav return; 1298265634Smav } 1299265634Smav 1300270108Smav if (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR)) { 1301288727Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1302288727Smav beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize; 1303265634Smav beio->bio_cmd = BIO_DELETE; 1304265634Smav beio->ds_trans_type = DEVSTAT_FREE; 1305265634Smav 1306265634Smav be_lun->unmap(be_lun, beio); 1307265634Smav return; 1308265634Smav } 1309265634Smav 1310265634Smav beio->bio_cmd = BIO_WRITE; 1311265634Smav beio->ds_trans_type = DEVSTAT_WRITE; 1312265634Smav 1313265634Smav DPRINTF("WRITE SAME at LBA %jx len %u\n", 1314268149Smav (uintmax_t)lbalen->lba, lbalen->len); 1315265634Smav 1316288727Smav pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp; 1317288727Smav if (be_lun->cbe_lun.pblockoff > 0) 1318288727Smav pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff; 1319279004Smav else 1320279004Smav pbo = 0; 1321288727Smav len_left = (uint64_t)lbalen->len * cbe_lun->blocksize; 1322265634Smav for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) { 1323265634Smav 1324265634Smav /* 1325265634Smav * Setup the S/G entry for this chunk. 1326265634Smav */ 1327265642Smav seglen = MIN(CTLBLK_MAX_SEG, len_left); 1328288727Smav if (pb > cbe_lun->blocksize) { 1329288727Smav adj = ((lbalen->lba + lba) * cbe_lun->blocksize + 1330278999Smav seglen - pbo) % pb; 1331278999Smav if (seglen > adj) 1332278999Smav seglen -= adj; 1333278999Smav else 1334288727Smav seglen -= seglen % cbe_lun->blocksize; 1335278999Smav } else 1336288727Smav seglen -= seglen % cbe_lun->blocksize; 1337265634Smav beio->sg_segs[i].len = seglen; 1338265634Smav beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1339265634Smav 1340265634Smav DPRINTF("segment %d addr %p len %zd\n", i, 1341265634Smav beio->sg_segs[i].addr, beio->sg_segs[i].len); 1342265634Smav 1343265634Smav beio->num_segs++; 1344265634Smav len_left -= seglen; 1345265634Smav 1346265634Smav buf = beio->sg_segs[i].addr; 1347265634Smav end = buf + seglen; 1348288727Smav for (; buf < end; buf += cbe_lun->blocksize) { 1349288794Smav if (lbalen->flags & SWS_NDOB) { 1350288794Smav memset(buf, 0, cbe_lun->blocksize); 1351288794Smav } else { 1352288794Smav memcpy(buf, io->scsiio.kern_data_ptr, 1353288794Smav cbe_lun->blocksize); 1354288794Smav } 1355268149Smav if (lbalen->flags & SWS_LBDATA) 1356268149Smav scsi_ulto4b(lbalen->lba + lba, buf); 1357265634Smav lba++; 1358265634Smav } 1359265634Smav } 1360265634Smav 1361288727Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1362288727Smav beio->io_len = lba * cbe_lun->blocksize; 1363265634Smav 1364265634Smav /* We can not do all in one run. Correct and schedule rerun. */ 1365265634Smav if (len_left > 0) { 1366268149Smav lbalen->lba += lba; 1367268149Smav lbalen->len -= lba; 1368265634Smav beio->beio_cont = ctl_be_block_cw_done_ws; 1369265634Smav } 1370265634Smav 1371265634Smav be_lun->dispatch(be_lun, beio); 1372265634Smav} 1373265634Smav 1374265634Smavstatic void 1375265634Smavctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun, 1376265634Smav union ctl_io *io) 1377265634Smav{ 1378265634Smav struct ctl_be_block_io *beio; 1379268149Smav struct ctl_ptr_len_flags *ptrlen; 1380265634Smav 1381265634Smav DPRINTF("entered\n"); 1382265634Smav 1383268150Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1384268149Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1385265634Smav 1386270108Smav if ((ptrlen->flags & ~SU_ANCHOR) != 0 || be_lun->unmap == NULL) { 1387265634Smav ctl_free_beio(beio); 1388265634Smav ctl_set_invalid_field(&io->scsiio, 1389265634Smav /*sks_valid*/ 0, 1390265634Smav /*command*/ 1, 1391265634Smav /*field*/ 0, 1392265634Smav /*bit_valid*/ 0, 1393265634Smav /*bit*/ 0); 1394265634Smav ctl_config_write_done(io); 1395265634Smav return; 1396265634Smav } 1397265634Smav 1398265634Smav beio->io_len = 0; 1399265634Smav beio->io_offset = -1; 1400265634Smav beio->bio_cmd = BIO_DELETE; 1401265634Smav beio->ds_trans_type = DEVSTAT_FREE; 1402268149Smav DPRINTF("UNMAP\n"); 1403265634Smav be_lun->unmap(be_lun, beio); 1404265634Smav} 1405265634Smav 1406265634Smavstatic void 1407275892Smavctl_be_block_cr_done(struct ctl_be_block_io *beio) 1408275892Smav{ 1409275892Smav union ctl_io *io; 1410275892Smav 1411275892Smav io = beio->io; 1412275892Smav ctl_free_beio(beio); 1413275892Smav ctl_config_read_done(io); 1414275892Smav} 1415275892Smav 1416275892Smavstatic void 1417275892Smavctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 1418275892Smav union ctl_io *io) 1419275892Smav{ 1420275892Smav struct ctl_be_block_io *beio; 1421275892Smav struct ctl_be_block_softc *softc; 1422275892Smav 1423275892Smav DPRINTF("entered\n"); 1424275892Smav 1425275892Smav softc = be_lun->softc; 1426275892Smav beio = ctl_alloc_beio(softc); 1427275892Smav beio->io = io; 1428275892Smav beio->lun = be_lun; 1429275892Smav beio->beio_cont = ctl_be_block_cr_done; 1430275892Smav PRIV(io)->ptr = (void *)beio; 1431275892Smav 1432275892Smav switch (io->scsiio.cdb[0]) { 1433275892Smav case SERVICE_ACTION_IN: /* GET LBA STATUS */ 1434275892Smav beio->bio_cmd = -1; 1435275892Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1436275892Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1437275892Smav beio->io_len = 0; 1438275892Smav if (be_lun->get_lba_status) 1439275892Smav be_lun->get_lba_status(be_lun, beio); 1440275892Smav else 1441275892Smav ctl_be_block_cr_done(beio); 1442275892Smav break; 1443275892Smav default: 1444275892Smav panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1445275892Smav break; 1446275892Smav } 1447275892Smav} 1448275892Smav 1449275892Smavstatic void 1450265634Smavctl_be_block_cw_done(struct ctl_be_block_io *beio) 1451265634Smav{ 1452265634Smav union ctl_io *io; 1453265634Smav 1454265634Smav io = beio->io; 1455265634Smav ctl_free_beio(beio); 1456265634Smav ctl_config_write_done(io); 1457265634Smav} 1458265634Smav 1459265634Smavstatic void 1460229997Skenctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 1461229997Sken union ctl_io *io) 1462229997Sken{ 1463229997Sken struct ctl_be_block_io *beio; 1464229997Sken struct ctl_be_block_softc *softc; 1465229997Sken 1466229997Sken DPRINTF("entered\n"); 1467229997Sken 1468229997Sken softc = be_lun->softc; 1469229997Sken beio = ctl_alloc_beio(softc); 1470229997Sken beio->io = io; 1471229997Sken beio->lun = be_lun; 1472265634Smav beio->beio_cont = ctl_be_block_cw_done; 1473286931Smav switch (io->scsiio.tag_type) { 1474286931Smav case CTL_TAG_ORDERED: 1475286931Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1476286931Smav break; 1477286931Smav case CTL_TAG_HEAD_OF_QUEUE: 1478286931Smav beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1479286931Smav break; 1480286931Smav case CTL_TAG_UNTAGGED: 1481286931Smav case CTL_TAG_SIMPLE: 1482286931Smav case CTL_TAG_ACA: 1483286931Smav default: 1484286931Smav beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1485286931Smav break; 1486286931Smav } 1487268150Smav PRIV(io)->ptr = (void *)beio; 1488229997Sken 1489229997Sken switch (io->scsiio.cdb[0]) { 1490229997Sken case SYNCHRONIZE_CACHE: 1491229997Sken case SYNCHRONIZE_CACHE_16: 1492286931Smav ctl_be_block_cw_dispatch_sync(be_lun, io); 1493229997Sken break; 1494265634Smav case WRITE_SAME_10: 1495265634Smav case WRITE_SAME_16: 1496265634Smav ctl_be_block_cw_dispatch_ws(be_lun, io); 1497265634Smav break; 1498265634Smav case UNMAP: 1499265634Smav ctl_be_block_cw_dispatch_unmap(be_lun, io); 1500265634Smav break; 1501229997Sken default: 1502229997Sken panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1503229997Sken break; 1504229997Sken } 1505229997Sken} 1506229997Sken 1507260817SavgSDT_PROBE_DEFINE1(cbb, kernel, read, start, "uint64_t"); 1508260817SavgSDT_PROBE_DEFINE1(cbb, kernel, write, start, "uint64_t"); 1509260817SavgSDT_PROBE_DEFINE1(cbb, kernel, read, alloc_done, "uint64_t"); 1510260817SavgSDT_PROBE_DEFINE1(cbb, kernel, write, alloc_done, "uint64_t"); 1511229997Sken 1512229997Skenstatic void 1513265642Smavctl_be_block_next(struct ctl_be_block_io *beio) 1514265642Smav{ 1515265642Smav struct ctl_be_block_lun *be_lun; 1516265642Smav union ctl_io *io; 1517265642Smav 1518265642Smav io = beio->io; 1519265642Smav be_lun = beio->lun; 1520265642Smav ctl_free_beio(beio); 1521268261Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1522268261Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1523268261Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1524268151Smav ctl_data_submit_done(io); 1525265642Smav return; 1526265642Smav } 1527265642Smav 1528265642Smav io->io_hdr.status &= ~CTL_STATUS_MASK; 1529265642Smav io->io_hdr.status |= CTL_STATUS_NONE; 1530265642Smav 1531268549Smav mtx_lock(&be_lun->queue_lock); 1532265642Smav STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1533268549Smav mtx_unlock(&be_lun->queue_lock); 1534265642Smav taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1535265642Smav} 1536265642Smav 1537265642Smavstatic void 1538229997Skenctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 1539229997Sken union ctl_io *io) 1540229997Sken{ 1541288727Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1542229997Sken struct ctl_be_block_io *beio; 1543229997Sken struct ctl_be_block_softc *softc; 1544268151Smav struct ctl_lba_len_flags *lbalen; 1545268150Smav struct ctl_ptr_len_flags *bptrlen; 1546268150Smav uint64_t len_left, lbas; 1547229997Sken int i; 1548229997Sken 1549229997Sken softc = be_lun->softc; 1550229997Sken 1551229997Sken DPRINTF("entered\n"); 1552229997Sken 1553268151Smav lbalen = ARGS(io); 1554268151Smav if (lbalen->flags & CTL_LLF_WRITE) { 1555268151Smav SDT_PROBE(cbb, kernel, write, start, 0, 0, 0, 0, 0); 1556268151Smav } else { 1557229997Sken SDT_PROBE(cbb, kernel, read, start, 0, 0, 0, 0, 0); 1558229997Sken } 1559229997Sken 1560229997Sken beio = ctl_alloc_beio(softc); 1561229997Sken beio->io = io; 1562229997Sken beio->lun = be_lun; 1563268150Smav bptrlen = PRIV(io); 1564268150Smav bptrlen->ptr = (void *)beio; 1565229997Sken 1566229997Sken switch (io->scsiio.tag_type) { 1567229997Sken case CTL_TAG_ORDERED: 1568229997Sken beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1569229997Sken break; 1570229997Sken case CTL_TAG_HEAD_OF_QUEUE: 1571229997Sken beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1572229997Sken break; 1573229997Sken case CTL_TAG_UNTAGGED: 1574229997Sken case CTL_TAG_SIMPLE: 1575229997Sken case CTL_TAG_ACA: 1576229997Sken default: 1577229997Sken beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1578229997Sken break; 1579229997Sken } 1580229997Sken 1581268151Smav if (lbalen->flags & CTL_LLF_WRITE) { 1582268151Smav beio->bio_cmd = BIO_WRITE; 1583268151Smav beio->ds_trans_type = DEVSTAT_WRITE; 1584268151Smav } else { 1585229997Sken beio->bio_cmd = BIO_READ; 1586229997Sken beio->ds_trans_type = DEVSTAT_READ; 1587229997Sken } 1588229997Sken 1589265642Smav DPRINTF("%s at LBA %jx len %u @%ju\n", 1590229997Sken (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", 1591268150Smav (uintmax_t)lbalen->lba, lbalen->len, bptrlen->len); 1592268151Smav if (lbalen->flags & CTL_LLF_COMPARE) 1593268151Smav lbas = CTLBLK_HALF_IO_SIZE; 1594268151Smav else 1595268151Smav lbas = CTLBLK_MAX_IO_SIZE; 1596288727Smav lbas = MIN(lbalen->len - bptrlen->len, lbas / cbe_lun->blocksize); 1597288727Smav beio->io_offset = (lbalen->lba + bptrlen->len) * cbe_lun->blocksize; 1598288727Smav beio->io_len = lbas * cbe_lun->blocksize; 1599268150Smav bptrlen->len += lbas; 1600229997Sken 1601265642Smav for (i = 0, len_left = beio->io_len; len_left > 0; i++) { 1602265642Smav KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", 1603265642Smav i, CTLBLK_MAX_SEGS)); 1604229997Sken 1605229997Sken /* 1606229997Sken * Setup the S/G entry for this chunk. 1607229997Sken */ 1608265642Smav beio->sg_segs[i].len = min(CTLBLK_MAX_SEG, len_left); 1609229997Sken beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1610229997Sken 1611229997Sken DPRINTF("segment %d addr %p len %zd\n", i, 1612229997Sken beio->sg_segs[i].addr, beio->sg_segs[i].len); 1613229997Sken 1614268151Smav /* Set up second segment for compare operation. */ 1615268151Smav if (lbalen->flags & CTL_LLF_COMPARE) { 1616268151Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].len = 1617268151Smav beio->sg_segs[i].len; 1618268151Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = 1619268151Smav uma_zalloc(be_lun->lun_zone, M_WAITOK); 1620268151Smav } 1621268151Smav 1622229997Sken beio->num_segs++; 1623229997Sken len_left -= beio->sg_segs[i].len; 1624229997Sken } 1625268150Smav if (bptrlen->len < lbalen->len) 1626265642Smav beio->beio_cont = ctl_be_block_next; 1627265642Smav io->scsiio.be_move_done = ctl_be_block_move_done; 1628268151Smav /* For compare we have separate S/G lists for read and datamove. */ 1629268151Smav if (lbalen->flags & CTL_LLF_COMPARE) 1630268151Smav io->scsiio.kern_data_ptr = (uint8_t *)&beio->sg_segs[CTLBLK_HALF_SEGS]; 1631268151Smav else 1632268151Smav io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; 1633265642Smav io->scsiio.kern_data_len = beio->io_len; 1634265642Smav io->scsiio.kern_data_resid = 0; 1635265642Smav io->scsiio.kern_sg_entries = beio->num_segs; 1636288781Smav io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 1637229997Sken 1638229997Sken /* 1639229997Sken * For the read case, we need to read the data into our buffers and 1640229997Sken * then we can send it back to the user. For the write case, we 1641229997Sken * need to get the data from the user first. 1642229997Sken */ 1643229997Sken if (beio->bio_cmd == BIO_READ) { 1644229997Sken SDT_PROBE(cbb, kernel, read, alloc_done, 0, 0, 0, 0, 0); 1645229997Sken be_lun->dispatch(be_lun, beio); 1646229997Sken } else { 1647229997Sken SDT_PROBE(cbb, kernel, write, alloc_done, 0, 0, 0, 0, 0); 1648229997Sken#ifdef CTL_TIME_IO 1649288798Smav getbinuptime(&io->io_hdr.dma_start_bt); 1650288798Smav#endif 1651229997Sken ctl_datamove(io); 1652229997Sken } 1653229997Sken} 1654229997Sken 1655229997Skenstatic void 1656229997Skenctl_be_block_worker(void *context, int pending) 1657229997Sken{ 1658288734Smav struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)context; 1659288734Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1660229997Sken union ctl_io *io; 1661288734Smav struct ctl_be_block_io *beio; 1662229997Sken 1663229997Sken DPRINTF("entered\n"); 1664288734Smav /* 1665288734Smav * Fetch and process I/Os from all queues. If we detect LUN 1666288811Smav * CTL_LUN_FLAG_NO_MEDIA status here -- it is result of a race, 1667288734Smav * so make response maximally opaque to not confuse initiator. 1668288734Smav */ 1669229997Sken for (;;) { 1670288734Smav mtx_lock(&be_lun->queue_lock); 1671229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue); 1672229997Sken if (io != NULL) { 1673229997Sken DPRINTF("datamove queue\n"); 1674229997Sken STAILQ_REMOVE(&be_lun->datamove_queue, &io->io_hdr, 1675229997Sken ctl_io_hdr, links); 1676268549Smav mtx_unlock(&be_lun->queue_lock); 1677268150Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1678288811Smav if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) { 1679288734Smav ctl_set_busy(&io->scsiio); 1680288734Smav ctl_complete_beio(beio); 1681288734Smav return; 1682288734Smav } 1683229997Sken be_lun->dispatch(be_lun, beio); 1684229997Sken continue; 1685229997Sken } 1686229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue); 1687229997Sken if (io != NULL) { 1688229997Sken DPRINTF("config write queue\n"); 1689229997Sken STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr, 1690229997Sken ctl_io_hdr, links); 1691268549Smav mtx_unlock(&be_lun->queue_lock); 1692288811Smav if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) { 1693288734Smav ctl_set_busy(&io->scsiio); 1694288734Smav ctl_config_write_done(io); 1695288734Smav return; 1696288734Smav } 1697229997Sken ctl_be_block_cw_dispatch(be_lun, io); 1698229997Sken continue; 1699229997Sken } 1700275892Smav io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue); 1701275892Smav if (io != NULL) { 1702275892Smav DPRINTF("config read queue\n"); 1703275892Smav STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr, 1704275892Smav ctl_io_hdr, links); 1705275892Smav mtx_unlock(&be_lun->queue_lock); 1706288811Smav if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) { 1707288734Smav ctl_set_busy(&io->scsiio); 1708288734Smav ctl_config_read_done(io); 1709288734Smav return; 1710288734Smav } 1711275892Smav ctl_be_block_cr_dispatch(be_lun, io); 1712275892Smav continue; 1713275892Smav } 1714229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue); 1715229997Sken if (io != NULL) { 1716229997Sken DPRINTF("input queue\n"); 1717229997Sken STAILQ_REMOVE(&be_lun->input_queue, &io->io_hdr, 1718229997Sken ctl_io_hdr, links); 1719268549Smav mtx_unlock(&be_lun->queue_lock); 1720288811Smav if (cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) { 1721288734Smav ctl_set_busy(&io->scsiio); 1722288734Smav ctl_data_submit_done(io); 1723288734Smav return; 1724288734Smav } 1725229997Sken ctl_be_block_dispatch(be_lun, io); 1726229997Sken continue; 1727229997Sken } 1728229997Sken 1729229997Sken /* 1730229997Sken * If we get here, there is no work left in the queues, so 1731229997Sken * just break out and let the task queue go to sleep. 1732229997Sken */ 1733288734Smav mtx_unlock(&be_lun->queue_lock); 1734229997Sken break; 1735229997Sken } 1736229997Sken} 1737229997Sken 1738229997Sken/* 1739229997Sken * Entry point from CTL to the backend for I/O. We queue everything to a 1740229997Sken * work thread, so this just puts the I/O on a queue and wakes up the 1741229997Sken * thread. 1742229997Sken */ 1743229997Skenstatic int 1744229997Skenctl_be_block_submit(union ctl_io *io) 1745229997Sken{ 1746229997Sken struct ctl_be_block_lun *be_lun; 1747288727Smav struct ctl_be_lun *cbe_lun; 1748229997Sken 1749229997Sken DPRINTF("entered\n"); 1750229997Sken 1751288727Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 1752229997Sken CTL_PRIV_BACKEND_LUN].ptr; 1753288727Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 1754229997Sken 1755229997Sken /* 1756229997Sken * Make sure we only get SCSI I/O. 1757229997Sken */ 1758229997Sken KASSERT(io->io_hdr.io_type == CTL_IO_SCSI, ("Non-SCSI I/O (type " 1759229997Sken "%#x) encountered", io->io_hdr.io_type)); 1760229997Sken 1761268150Smav PRIV(io)->len = 0; 1762268150Smav 1763268549Smav mtx_lock(&be_lun->queue_lock); 1764229997Sken STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1765268549Smav mtx_unlock(&be_lun->queue_lock); 1766229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1767229997Sken 1768268148Smav return (CTL_RETVAL_COMPLETE); 1769229997Sken} 1770229997Sken 1771229997Skenstatic int 1772229997Skenctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 1773229997Sken int flag, struct thread *td) 1774229997Sken{ 1775229997Sken struct ctl_be_block_softc *softc; 1776229997Sken int error; 1777229997Sken 1778229997Sken softc = &backend_block_softc; 1779229997Sken 1780229997Sken error = 0; 1781229997Sken 1782229997Sken switch (cmd) { 1783229997Sken case CTL_LUN_REQ: { 1784229997Sken struct ctl_lun_req *lun_req; 1785229997Sken 1786229997Sken lun_req = (struct ctl_lun_req *)addr; 1787229997Sken 1788229997Sken switch (lun_req->reqtype) { 1789229997Sken case CTL_LUNREQ_CREATE: 1790229997Sken error = ctl_be_block_create(softc, lun_req); 1791229997Sken break; 1792229997Sken case CTL_LUNREQ_RM: 1793229997Sken error = ctl_be_block_rm(softc, lun_req); 1794229997Sken break; 1795232604Strasz case CTL_LUNREQ_MODIFY: 1796232604Strasz error = ctl_be_block_modify(softc, lun_req); 1797232604Strasz break; 1798229997Sken default: 1799229997Sken lun_req->status = CTL_LUN_ERROR; 1800229997Sken snprintf(lun_req->error_str, sizeof(lun_req->error_str), 1801273315Smav "invalid LUN request type %d", 1802229997Sken lun_req->reqtype); 1803229997Sken break; 1804229997Sken } 1805229997Sken break; 1806229997Sken } 1807229997Sken default: 1808229997Sken error = ENOTTY; 1809229997Sken break; 1810229997Sken } 1811229997Sken 1812229997Sken return (error); 1813229997Sken} 1814229997Sken 1815229997Skenstatic int 1816229997Skenctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1817229997Sken{ 1818288727Smav struct ctl_be_lun *cbe_lun; 1819229997Sken struct ctl_be_block_filedata *file_data; 1820229997Sken struct ctl_lun_create_params *params; 1821276179Smav char *value; 1822229997Sken struct vattr vattr; 1823276179Smav off_t ps, pss, po, pos, us, uss, uo, uos; 1824229997Sken int error; 1825229997Sken 1826288727Smav cbe_lun = &be_lun->cbe_lun; 1827229997Sken file_data = &be_lun->backend.file; 1828273315Smav params = &be_lun->params; 1829229997Sken 1830229997Sken be_lun->dev_type = CTL_BE_BLOCK_FILE; 1831229997Sken be_lun->dispatch = ctl_be_block_dispatch_file; 1832229997Sken be_lun->lun_flush = ctl_be_block_flush_file; 1833275892Smav be_lun->get_lba_status = ctl_be_block_gls_file; 1834275893Smav be_lun->getattr = ctl_be_block_getattr_file; 1835288727Smav be_lun->unmap = NULL; 1836288727Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 1837229997Sken 1838229997Sken error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 1839229997Sken if (error != 0) { 1840229997Sken snprintf(req->error_str, sizeof(req->error_str), 1841229997Sken "error calling VOP_GETATTR() for file %s", 1842229997Sken be_lun->dev_path); 1843229997Sken return (error); 1844229997Sken } 1845229997Sken 1846229997Sken file_data->cred = crhold(curthread->td_ucred); 1847232604Strasz if (params->lun_size_bytes != 0) 1848232604Strasz be_lun->size_bytes = params->lun_size_bytes; 1849232604Strasz else 1850232604Strasz be_lun->size_bytes = vattr.va_size; 1851229997Sken 1852229997Sken /* 1853273322Smav * For files we can use any logical block size. Prefer 512 bytes 1854273322Smav * for compatibility reasons. If file's vattr.va_blocksize 1855273322Smav * (preferred I/O block size) is bigger and multiple to chosen 1856273322Smav * logical block size -- report it as physical block size. 1857229997Sken */ 1858229997Sken if (params->blocksize_bytes != 0) 1859288727Smav cbe_lun->blocksize = params->blocksize_bytes; 1860288810Smav else if (cbe_lun->lun_type == T_CDROM) 1861288810Smav cbe_lun->blocksize = 2048; 1862229997Sken else 1863288727Smav cbe_lun->blocksize = 512; 1864288727Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 1865288727Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 1866288727Smav 0 : (be_lun->size_blocks - 1); 1867276179Smav 1868276179Smav us = ps = vattr.va_blocksize; 1869276179Smav uo = po = 0; 1870276179Smav 1871288727Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 1872276179Smav if (value != NULL) 1873276179Smav ctl_expand_number(value, &ps); 1874288727Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 1875276179Smav if (value != NULL) 1876276179Smav ctl_expand_number(value, &po); 1877288727Smav pss = ps / cbe_lun->blocksize; 1878288727Smav pos = po / cbe_lun->blocksize; 1879288727Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 1880288727Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 1881288727Smav cbe_lun->pblockexp = fls(pss) - 1; 1882288727Smav cbe_lun->pblockoff = (pss - pos) % pss; 1883273322Smav } 1884229997Sken 1885288727Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 1886276179Smav if (value != NULL) 1887276179Smav ctl_expand_number(value, &us); 1888288727Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 1889276179Smav if (value != NULL) 1890276179Smav ctl_expand_number(value, &uo); 1891288727Smav uss = us / cbe_lun->blocksize; 1892288727Smav uos = uo / cbe_lun->blocksize; 1893288727Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 1894288727Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 1895288727Smav cbe_lun->ublockexp = fls(uss) - 1; 1896288727Smav cbe_lun->ublockoff = (uss - uos) % uss; 1897276179Smav } 1898276179Smav 1899229997Sken /* 1900229997Sken * Sanity check. The media size has to be at least one 1901229997Sken * sector long. 1902229997Sken */ 1903288727Smav if (be_lun->size_bytes < cbe_lun->blocksize) { 1904229997Sken error = EINVAL; 1905229997Sken snprintf(req->error_str, sizeof(req->error_str), 1906229997Sken "file %s size %ju < block size %u", be_lun->dev_path, 1907288727Smav (uintmax_t)be_lun->size_bytes, cbe_lun->blocksize); 1908229997Sken } 1909276237Smav 1910288727Smav cbe_lun->opttxferlen = CTLBLK_MAX_IO_SIZE / cbe_lun->blocksize; 1911229997Sken return (error); 1912229997Sken} 1913229997Sken 1914229997Skenstatic int 1915229997Skenctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1916229997Sken{ 1917288727Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1918229997Sken struct ctl_lun_create_params *params; 1919288733Smav struct cdevsw *csw; 1920229997Sken struct cdev *dev; 1921276179Smav char *value; 1922288733Smav int error, atomic, maxio, ref, unmap, tmp; 1923288722Smav off_t ps, pss, po, pos, us, uss, uo, uos, otmp; 1924229997Sken 1925273315Smav params = &be_lun->params; 1926229997Sken 1927229997Sken be_lun->dev_type = CTL_BE_BLOCK_DEV; 1928288733Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1929288733Smav if (csw == NULL) 1930288733Smav return (ENXIO); 1931288733Smav if (strcmp(csw->d_name, "zvol") == 0) { 1932269429Smav be_lun->dispatch = ctl_be_block_dispatch_zvol; 1933275892Smav be_lun->get_lba_status = ctl_be_block_gls_zvol; 1934276237Smav atomic = maxio = CTLBLK_MAX_IO_SIZE; 1935276237Smav } else { 1936269429Smav be_lun->dispatch = ctl_be_block_dispatch_dev; 1937288727Smav be_lun->get_lba_status = NULL; 1938276237Smav atomic = 0; 1939288733Smav maxio = dev->si_iosize_max; 1940276237Smav if (maxio <= 0) 1941276237Smav maxio = DFLTPHYS; 1942276237Smav if (maxio > CTLBLK_MAX_IO_SIZE) 1943276237Smav maxio = CTLBLK_MAX_IO_SIZE; 1944276237Smav } 1945269429Smav be_lun->lun_flush = ctl_be_block_flush_dev; 1946274732Smav be_lun->getattr = ctl_be_block_getattr_dev; 1947288727Smav be_lun->unmap = ctl_be_block_unmap_dev; 1948229997Sken 1949288733Smav if (!csw->d_ioctl) { 1950288733Smav dev_relthread(dev, ref); 1951229997Sken snprintf(req->error_str, sizeof(req->error_str), 1952288733Smav "no d_ioctl for device %s!", be_lun->dev_path); 1953229997Sken return (ENODEV); 1954229997Sken } 1955229997Sken 1956288733Smav error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD, 1957229997Sken curthread); 1958229997Sken if (error) { 1959288733Smav dev_relthread(dev, ref); 1960229997Sken snprintf(req->error_str, sizeof(req->error_str), 1961273315Smav "error %d returned for DIOCGSECTORSIZE ioctl " 1962273315Smav "on %s!", error, be_lun->dev_path); 1963229997Sken return (error); 1964229997Sken } 1965229997Sken 1966229997Sken /* 1967229997Sken * If the user has asked for a blocksize that is greater than the 1968229997Sken * backing device's blocksize, we can do it only if the blocksize 1969229997Sken * the user is asking for is an even multiple of the underlying 1970229997Sken * device's blocksize. 1971229997Sken */ 1972288721Smav if ((params->blocksize_bytes != 0) && 1973288721Smav (params->blocksize_bytes >= tmp)) { 1974288721Smav if (params->blocksize_bytes % tmp == 0) { 1975288727Smav cbe_lun->blocksize = params->blocksize_bytes; 1976229997Sken } else { 1977288733Smav dev_relthread(dev, ref); 1978229997Sken snprintf(req->error_str, sizeof(req->error_str), 1979273315Smav "requested blocksize %u is not an even " 1980229997Sken "multiple of backing device blocksize %u", 1981288722Smav params->blocksize_bytes, tmp); 1982229997Sken return (EINVAL); 1983229997Sken } 1984288721Smav } else if (params->blocksize_bytes != 0) { 1985288733Smav dev_relthread(dev, ref); 1986229997Sken snprintf(req->error_str, sizeof(req->error_str), 1987273315Smav "requested blocksize %u < backing device " 1988288722Smav "blocksize %u", params->blocksize_bytes, tmp); 1989229997Sken return (EINVAL); 1990288810Smav } else if (cbe_lun->lun_type == T_CDROM) 1991288810Smav cbe_lun->blocksize = MAX(tmp, 2048); 1992288810Smav else 1993288727Smav cbe_lun->blocksize = tmp; 1994229997Sken 1995288733Smav error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD, 1996288733Smav curthread); 1997229997Sken if (error) { 1998288733Smav dev_relthread(dev, ref); 1999229997Sken snprintf(req->error_str, sizeof(req->error_str), 2000273315Smav "error %d returned for DIOCGMEDIASIZE " 2001273315Smav " ioctl on %s!", error, 2002232604Strasz be_lun->dev_path); 2003229997Sken return (error); 2004229997Sken } 2005229997Sken 2006232604Strasz if (params->lun_size_bytes != 0) { 2007288722Smav if (params->lun_size_bytes > otmp) { 2008288733Smav dev_relthread(dev, ref); 2009232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2010273315Smav "requested LUN size %ju > backing device " 2011273315Smav "size %ju", 2012232604Strasz (uintmax_t)params->lun_size_bytes, 2013288722Smav (uintmax_t)otmp); 2014232604Strasz return (EINVAL); 2015232604Strasz } 2016232604Strasz 2017232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2018288721Smav } else 2019288722Smav be_lun->size_bytes = otmp; 2020288727Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2021288727Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2022288727Smav 0 : (be_lun->size_blocks - 1); 2023232604Strasz 2024288733Smav error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD, 2025288733Smav curthread); 2026264727Smav if (error) 2027264727Smav ps = po = 0; 2028264727Smav else { 2029288733Smav error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po, 2030288733Smav FREAD, curthread); 2031264727Smav if (error) 2032264727Smav po = 0; 2033264727Smav } 2034276179Smav us = ps; 2035276179Smav uo = po; 2036276179Smav 2037288727Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 2038276179Smav if (value != NULL) 2039276179Smav ctl_expand_number(value, &ps); 2040288727Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 2041276179Smav if (value != NULL) 2042276179Smav ctl_expand_number(value, &po); 2043288727Smav pss = ps / cbe_lun->blocksize; 2044288727Smav pos = po / cbe_lun->blocksize; 2045288727Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 2046288727Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 2047288727Smav cbe_lun->pblockexp = fls(pss) - 1; 2048288727Smav cbe_lun->pblockoff = (pss - pos) % pss; 2049264727Smav } 2050264727Smav 2051288727Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 2052276179Smav if (value != NULL) 2053276179Smav ctl_expand_number(value, &us); 2054288727Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 2055276179Smav if (value != NULL) 2056276179Smav ctl_expand_number(value, &uo); 2057288727Smav uss = us / cbe_lun->blocksize; 2058288727Smav uos = uo / cbe_lun->blocksize; 2059288727Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 2060288727Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 2061288727Smav cbe_lun->ublockexp = fls(uss) - 1; 2062288727Smav cbe_lun->ublockoff = (uss - uos) % uss; 2063276179Smav } 2064276179Smav 2065288727Smav cbe_lun->atomicblock = atomic / cbe_lun->blocksize; 2066288727Smav cbe_lun->opttxferlen = maxio / cbe_lun->blocksize; 2067279005Smav 2068279005Smav if (be_lun->dispatch == ctl_be_block_dispatch_zvol) { 2069279005Smav unmap = 1; 2070279005Smav } else { 2071279005Smav struct diocgattr_arg arg; 2072279005Smav 2073279005Smav strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name)); 2074279005Smav arg.len = sizeof(arg.value.i); 2075288733Smav error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 2076288733Smav curthread); 2077279005Smav unmap = (error == 0) ? arg.value.i : 0; 2078279005Smav } 2079288727Smav value = ctl_get_opt(&cbe_lun->options, "unmap"); 2080279005Smav if (value != NULL) 2081279005Smav unmap = (strcmp(value, "on") == 0); 2082279005Smav if (unmap) 2083288727Smav cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 2084288727Smav else 2085288727Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 2086279005Smav 2087288733Smav dev_relthread(dev, ref); 2088229997Sken return (0); 2089229997Sken} 2090229997Sken 2091229997Skenstatic int 2092229997Skenctl_be_block_close(struct ctl_be_block_lun *be_lun) 2093229997Sken{ 2094288727Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2095288727Smav int flags; 2096288727Smav 2097229997Sken if (be_lun->vn) { 2098288727Smav flags = FREAD; 2099288727Smav if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0) 2100288727Smav flags |= FWRITE; 2101229997Sken (void)vn_close(be_lun->vn, flags, NOCRED, curthread); 2102229997Sken be_lun->vn = NULL; 2103229997Sken 2104229997Sken switch (be_lun->dev_type) { 2105229997Sken case CTL_BE_BLOCK_DEV: 2106229997Sken break; 2107229997Sken case CTL_BE_BLOCK_FILE: 2108229997Sken if (be_lun->backend.file.cred != NULL) { 2109229997Sken crfree(be_lun->backend.file.cred); 2110229997Sken be_lun->backend.file.cred = NULL; 2111229997Sken } 2112229997Sken break; 2113229997Sken case CTL_BE_BLOCK_NONE: 2114259304Strasz break; 2115229997Sken default: 2116290774Smav panic("Unexpected backend type %d", be_lun->dev_type); 2117229997Sken break; 2118229997Sken } 2119273315Smav be_lun->dev_type = CTL_BE_BLOCK_NONE; 2120229997Sken } 2121229997Sken return (0); 2122229997Sken} 2123229997Sken 2124229997Skenstatic int 2125288811Smavctl_be_block_open(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 2126229997Sken{ 2127288727Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2128229997Sken struct nameidata nd; 2129288727Smav char *value; 2130288727Smav int error, flags; 2131229997Sken 2132229997Sken error = 0; 2133229997Sken if (rootvnode == NULL) { 2134229997Sken snprintf(req->error_str, sizeof(req->error_str), 2135273315Smav "Root filesystem is not mounted"); 2136229997Sken return (1); 2137229997Sken } 2138229997Sken if (!curthread->td_proc->p_fd->fd_cdir) { 2139229997Sken curthread->td_proc->p_fd->fd_cdir = rootvnode; 2140229997Sken VREF(rootvnode); 2141229997Sken } 2142229997Sken if (!curthread->td_proc->p_fd->fd_rdir) { 2143229997Sken curthread->td_proc->p_fd->fd_rdir = rootvnode; 2144229997Sken VREF(rootvnode); 2145229997Sken } 2146229997Sken if (!curthread->td_proc->p_fd->fd_jdir) { 2147229997Sken curthread->td_proc->p_fd->fd_jdir = rootvnode; 2148229997Sken VREF(rootvnode); 2149229997Sken } 2150229997Sken 2151288727Smav value = ctl_get_opt(&cbe_lun->options, "file"); 2152288727Smav if (value == NULL) { 2153288727Smav snprintf(req->error_str, sizeof(req->error_str), 2154288727Smav "no file argument specified"); 2155288727Smav return (1); 2156288727Smav } 2157288727Smav free(be_lun->dev_path, M_CTLBLK); 2158288727Smav be_lun->dev_path = strdup(value, M_CTLBLK); 2159288727Smav 2160288727Smav flags = FREAD; 2161288727Smav value = ctl_get_opt(&cbe_lun->options, "readonly"); 2162288810Smav if (value != NULL) { 2163288810Smav if (strcmp(value, "on") != 0) 2164288810Smav flags |= FWRITE; 2165288810Smav } else if (cbe_lun->lun_type == T_DIRECT) 2166288727Smav flags |= FWRITE; 2167288727Smav 2168288727Smavagain: 2169229997Sken NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, be_lun->dev_path, curthread); 2170229997Sken error = vn_open(&nd, &flags, 0, NULL); 2171288727Smav if ((error == EROFS || error == EACCES) && (flags & FWRITE)) { 2172288727Smav flags &= ~FWRITE; 2173288727Smav goto again; 2174288727Smav } 2175229997Sken if (error) { 2176229997Sken /* 2177229997Sken * This is the only reasonable guess we can make as far as 2178229997Sken * path if the user doesn't give us a fully qualified path. 2179229997Sken * If they want to specify a file, they need to specify the 2180229997Sken * full path. 2181229997Sken */ 2182229997Sken if (be_lun->dev_path[0] != '/') { 2183229997Sken char *dev_name; 2184229997Sken 2185288727Smav asprintf(&dev_name, M_CTLBLK, "/dev/%s", 2186288727Smav be_lun->dev_path); 2187288727Smav free(be_lun->dev_path, M_CTLBLK); 2188288727Smav be_lun->dev_path = dev_name; 2189288727Smav goto again; 2190229997Sken } 2191229997Sken snprintf(req->error_str, sizeof(req->error_str), 2192273315Smav "error opening %s: %d", be_lun->dev_path, error); 2193229997Sken return (error); 2194229997Sken } 2195288727Smav if (flags & FWRITE) 2196288727Smav cbe_lun->flags &= ~CTL_LUN_FLAG_READONLY; 2197288727Smav else 2198288727Smav cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 2199229997Sken 2200229997Sken NDFREE(&nd, NDF_ONLY_PNBUF); 2201229997Sken be_lun->vn = nd.ni_vp; 2202229997Sken 2203229997Sken /* We only support disks and files. */ 2204229997Sken if (vn_isdisk(be_lun->vn, &error)) { 2205229997Sken error = ctl_be_block_open_dev(be_lun, req); 2206229997Sken } else if (be_lun->vn->v_type == VREG) { 2207229997Sken error = ctl_be_block_open_file(be_lun, req); 2208229997Sken } else { 2209229997Sken error = EINVAL; 2210229997Sken snprintf(req->error_str, sizeof(req->error_str), 2211259304Strasz "%s is not a disk or plain file", be_lun->dev_path); 2212229997Sken } 2213229997Sken VOP_UNLOCK(be_lun->vn, 0); 2214229997Sken 2215288721Smav if (error != 0) 2216229997Sken ctl_be_block_close(be_lun); 2217288727Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2218288727Smav if (be_lun->dispatch != ctl_be_block_dispatch_dev) 2219288727Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2220288727Smav value = ctl_get_opt(&cbe_lun->options, "serseq"); 2221288727Smav if (value != NULL && strcmp(value, "on") == 0) 2222288727Smav cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 2223288727Smav else if (value != NULL && strcmp(value, "read") == 0) 2224288727Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2225288727Smav else if (value != NULL && strcmp(value, "off") == 0) 2226288727Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2227229997Sken return (0); 2228229997Sken} 2229229997Sken 2230229997Skenstatic int 2231229997Skenctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2232229997Sken{ 2233288727Smav struct ctl_be_lun *cbe_lun; 2234229997Sken struct ctl_be_block_lun *be_lun; 2235229997Sken struct ctl_lun_create_params *params; 2236268143Smav char num_thread_str[16]; 2237229997Sken char tmpstr[32]; 2238268143Smav char *value; 2239279005Smav int retval, num_threads; 2240268143Smav int tmp_num_threads; 2241229997Sken 2242229997Sken params = &req->reqdata.create; 2243229997Sken retval = 0; 2244273315Smav req->status = CTL_LUN_OK; 2245229997Sken 2246229997Sken be_lun = malloc(sizeof(*be_lun), M_CTLBLK, M_ZERO | M_WAITOK); 2247288727Smav cbe_lun = &be_lun->cbe_lun; 2248288727Smav cbe_lun->be_lun = be_lun; 2249273315Smav be_lun->params = req->reqdata.create; 2250229997Sken be_lun->softc = softc; 2251229997Sken STAILQ_INIT(&be_lun->input_queue); 2252275892Smav STAILQ_INIT(&be_lun->config_read_queue); 2253229997Sken STAILQ_INIT(&be_lun->config_write_queue); 2254229997Sken STAILQ_INIT(&be_lun->datamove_queue); 2255229997Sken sprintf(be_lun->lunname, "cblk%d", softc->num_luns); 2256268549Smav mtx_init(&be_lun->io_lock, "cblk io lock", NULL, MTX_DEF); 2257268549Smav mtx_init(&be_lun->queue_lock, "cblk queue lock", NULL, MTX_DEF); 2258288727Smav ctl_init_opts(&cbe_lun->options, 2259268678Smav req->num_be_args, req->kern_be_args); 2260265642Smav be_lun->lun_zone = uma_zcreate(be_lun->lunname, CTLBLK_MAX_SEG, 2261260476Smav NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); 2262229997Sken if (be_lun->lun_zone == NULL) { 2263229997Sken snprintf(req->error_str, sizeof(req->error_str), 2264273315Smav "error allocating UMA zone"); 2265229997Sken goto bailout_error; 2266229997Sken } 2267229997Sken 2268229997Sken if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 2269288727Smav cbe_lun->lun_type = params->device_type; 2270229997Sken else 2271288727Smav cbe_lun->lun_type = T_DIRECT; 2272288727Smav be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED; 2273288732Smav cbe_lun->flags = 0; 2274288732Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2275288732Smav if (value != NULL) { 2276288732Smav if (strcmp(value, "primary") == 0) 2277288732Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2278288732Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2279288732Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2280229997Sken 2281288810Smav if (cbe_lun->lun_type == T_DIRECT || 2282288810Smav cbe_lun->lun_type == T_CDROM) { 2283288721Smav be_lun->size_bytes = params->lun_size_bytes; 2284288721Smav if (params->blocksize_bytes != 0) 2285288727Smav cbe_lun->blocksize = params->blocksize_bytes; 2286288810Smav else if (cbe_lun->lun_type == T_CDROM) 2287288810Smav cbe_lun->blocksize = 2048; 2288288721Smav else 2289288727Smav cbe_lun->blocksize = 512; 2290288727Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2291288727Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2292288727Smav 0 : (be_lun->size_blocks - 1); 2293229997Sken 2294288732Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2295288732Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2296288811Smav retval = ctl_be_block_open(be_lun, req); 2297288732Smav if (retval != 0) { 2298288732Smav retval = 0; 2299288732Smav req->status = CTL_LUN_WARNING; 2300288732Smav } 2301229997Sken } 2302288727Smav num_threads = cbb_num_threads; 2303229997Sken } else { 2304229997Sken num_threads = 1; 2305229997Sken } 2306229997Sken 2307288727Smav value = ctl_get_opt(&cbe_lun->options, "num_threads"); 2308268143Smav if (value != NULL) { 2309268143Smav tmp_num_threads = strtol(value, NULL, 0); 2310229997Sken 2311268143Smav /* 2312268143Smav * We don't let the user specify less than one 2313268143Smav * thread, but hope he's clueful enough not to 2314268143Smav * specify 1000 threads. 2315268143Smav */ 2316268143Smav if (tmp_num_threads < 1) { 2317268143Smav snprintf(req->error_str, sizeof(req->error_str), 2318273315Smav "invalid number of threads %s", 2319273315Smav num_thread_str); 2320268143Smav goto bailout_error; 2321229997Sken } 2322268143Smav num_threads = tmp_num_threads; 2323229997Sken } 2324229997Sken 2325273315Smav if (be_lun->vn == NULL) 2326288811Smav cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2327229997Sken /* Tell the user the blocksize we ended up using */ 2328273315Smav params->lun_size_bytes = be_lun->size_bytes; 2329288727Smav params->blocksize_bytes = cbe_lun->blocksize; 2330229997Sken if (params->flags & CTL_LUN_FLAG_ID_REQ) { 2331288727Smav cbe_lun->req_lun_id = params->req_lun_id; 2332288727Smav cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 2333229997Sken } else 2334288727Smav cbe_lun->req_lun_id = 0; 2335229997Sken 2336288727Smav cbe_lun->lun_shutdown = ctl_be_block_lun_shutdown; 2337288727Smav cbe_lun->lun_config_status = ctl_be_block_lun_config_status; 2338288727Smav cbe_lun->be = &ctl_be_block_driver; 2339229997Sken 2340229997Sken if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 2341229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 2342229997Sken softc->num_luns); 2343288727Smav strncpy((char *)cbe_lun->serial_num, tmpstr, 2344288727Smav MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 2345229997Sken 2346229997Sken /* Tell the user what we used for a serial number */ 2347229997Sken strncpy((char *)params->serial_num, tmpstr, 2348276616Smav MIN(sizeof(params->serial_num), sizeof(tmpstr))); 2349229997Sken } else { 2350288727Smav strncpy((char *)cbe_lun->serial_num, params->serial_num, 2351288727Smav MIN(sizeof(cbe_lun->serial_num), 2352229997Sken sizeof(params->serial_num))); 2353229997Sken } 2354229997Sken if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 2355229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 2356288727Smav strncpy((char *)cbe_lun->device_id, tmpstr, 2357288727Smav MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 2358229997Sken 2359229997Sken /* Tell the user what we used for a device ID */ 2360229997Sken strncpy((char *)params->device_id, tmpstr, 2361276616Smav MIN(sizeof(params->device_id), sizeof(tmpstr))); 2362229997Sken } else { 2363288727Smav strncpy((char *)cbe_lun->device_id, params->device_id, 2364288727Smav MIN(sizeof(cbe_lun->device_id), 2365276616Smav sizeof(params->device_id))); 2366229997Sken } 2367229997Sken 2368229997Sken TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_be_block_worker, be_lun); 2369229997Sken 2370229997Sken be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 2371229997Sken taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 2372229997Sken 2373229997Sken if (be_lun->io_taskqueue == NULL) { 2374229997Sken snprintf(req->error_str, sizeof(req->error_str), 2375273315Smav "unable to create taskqueue"); 2376229997Sken goto bailout_error; 2377229997Sken } 2378229997Sken 2379229997Sken /* 2380229997Sken * Note that we start the same number of threads by default for 2381229997Sken * both the file case and the block device case. For the file 2382229997Sken * case, we need multiple threads to allow concurrency, because the 2383229997Sken * vnode interface is designed to be a blocking interface. For the 2384229997Sken * block device case, ZFS zvols at least will block the caller's 2385229997Sken * context in many instances, and so we need multiple threads to 2386229997Sken * overcome that problem. Other block devices don't need as many 2387229997Sken * threads, but they shouldn't cause too many problems. 2388229997Sken * 2389229997Sken * If the user wants to just have a single thread for a block 2390229997Sken * device, he can specify that when the LUN is created, or change 2391229997Sken * the tunable/sysctl to alter the default number of threads. 2392229997Sken */ 2393229997Sken retval = taskqueue_start_threads(&be_lun->io_taskqueue, 2394229997Sken /*num threads*/num_threads, 2395229997Sken /*priority*/PWAIT, 2396229997Sken /*thread name*/ 2397229997Sken "%s taskq", be_lun->lunname); 2398229997Sken 2399229997Sken if (retval != 0) 2400229997Sken goto bailout_error; 2401229997Sken 2402229997Sken be_lun->num_threads = num_threads; 2403229997Sken 2404229997Sken mtx_lock(&softc->lock); 2405229997Sken softc->num_luns++; 2406229997Sken STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 2407229997Sken 2408229997Sken mtx_unlock(&softc->lock); 2409229997Sken 2410288727Smav retval = ctl_add_lun(&be_lun->cbe_lun); 2411229997Sken if (retval != 0) { 2412229997Sken mtx_lock(&softc->lock); 2413229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2414229997Sken links); 2415229997Sken softc->num_luns--; 2416229997Sken mtx_unlock(&softc->lock); 2417229997Sken snprintf(req->error_str, sizeof(req->error_str), 2418273315Smav "ctl_add_lun() returned error %d, see dmesg for " 2419273315Smav "details", retval); 2420229997Sken retval = 0; 2421229997Sken goto bailout_error; 2422229997Sken } 2423229997Sken 2424229997Sken mtx_lock(&softc->lock); 2425229997Sken 2426229997Sken /* 2427229997Sken * Tell the config_status routine that we're waiting so it won't 2428229997Sken * clean up the LUN in the event of an error. 2429229997Sken */ 2430229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2431229997Sken 2432229997Sken while (be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) { 2433229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2434229997Sken if (retval == EINTR) 2435229997Sken break; 2436229997Sken } 2437229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2438229997Sken 2439229997Sken if (be_lun->flags & CTL_BE_BLOCK_LUN_CONFIG_ERR) { 2440229997Sken snprintf(req->error_str, sizeof(req->error_str), 2441273315Smav "LUN configuration error, see dmesg for details"); 2442229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2443229997Sken links); 2444229997Sken softc->num_luns--; 2445229997Sken mtx_unlock(&softc->lock); 2446229997Sken goto bailout_error; 2447229997Sken } else { 2448288727Smav params->req_lun_id = cbe_lun->lun_id; 2449229997Sken } 2450229997Sken 2451229997Sken mtx_unlock(&softc->lock); 2452229997Sken 2453229997Sken be_lun->disk_stats = devstat_new_entry("cbb", params->req_lun_id, 2454288727Smav cbe_lun->blocksize, 2455229997Sken DEVSTAT_ALL_SUPPORTED, 2456288727Smav cbe_lun->lun_type 2457229997Sken | DEVSTAT_TYPE_IF_OTHER, 2458229997Sken DEVSTAT_PRIORITY_OTHER); 2459229997Sken 2460229997Sken return (retval); 2461229997Sken 2462229997Skenbailout_error: 2463229997Sken req->status = CTL_LUN_ERROR; 2464229997Sken 2465267754Smav if (be_lun->io_taskqueue != NULL) 2466267754Smav taskqueue_free(be_lun->io_taskqueue); 2467229997Sken ctl_be_block_close(be_lun); 2468267754Smav if (be_lun->dev_path != NULL) 2469267754Smav free(be_lun->dev_path, M_CTLBLK); 2470267754Smav if (be_lun->lun_zone != NULL) 2471267754Smav uma_zdestroy(be_lun->lun_zone); 2472288727Smav ctl_free_opts(&cbe_lun->options); 2473268549Smav mtx_destroy(&be_lun->queue_lock); 2474268549Smav mtx_destroy(&be_lun->io_lock); 2475229997Sken free(be_lun, M_CTLBLK); 2476229997Sken 2477229997Sken return (retval); 2478229997Sken} 2479229997Sken 2480229997Skenstatic int 2481229997Skenctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2482229997Sken{ 2483229997Sken struct ctl_lun_rm_params *params; 2484229997Sken struct ctl_be_block_lun *be_lun; 2485288734Smav struct ctl_be_lun *cbe_lun; 2486229997Sken int retval; 2487229997Sken 2488229997Sken params = &req->reqdata.rm; 2489229997Sken 2490229997Sken mtx_lock(&softc->lock); 2491229997Sken STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2492288727Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2493229997Sken break; 2494229997Sken } 2495229997Sken mtx_unlock(&softc->lock); 2496229997Sken if (be_lun == NULL) { 2497229997Sken snprintf(req->error_str, sizeof(req->error_str), 2498273315Smav "LUN %u is not managed by the block backend", 2499273315Smav params->lun_id); 2500229997Sken goto bailout_error; 2501229997Sken } 2502288734Smav cbe_lun = &be_lun->cbe_lun; 2503229997Sken 2504288734Smav retval = ctl_disable_lun(cbe_lun); 2505229997Sken if (retval != 0) { 2506229997Sken snprintf(req->error_str, sizeof(req->error_str), 2507273315Smav "error %d returned from ctl_disable_lun() for " 2508273315Smav "LUN %d", retval, params->lun_id); 2509229997Sken goto bailout_error; 2510288734Smav } 2511229997Sken 2512288734Smav if (be_lun->vn != NULL) { 2513288811Smav cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2514288811Smav ctl_lun_no_media(cbe_lun); 2515288734Smav taskqueue_drain_all(be_lun->io_taskqueue); 2516288734Smav ctl_be_block_close(be_lun); 2517229997Sken } 2518229997Sken 2519288734Smav retval = ctl_invalidate_lun(cbe_lun); 2520229997Sken if (retval != 0) { 2521229997Sken snprintf(req->error_str, sizeof(req->error_str), 2522273315Smav "error %d returned from ctl_invalidate_lun() for " 2523273315Smav "LUN %d", retval, params->lun_id); 2524229997Sken goto bailout_error; 2525229997Sken } 2526229997Sken 2527229997Sken mtx_lock(&softc->lock); 2528229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2529229997Sken while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2530229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2531229997Sken if (retval == EINTR) 2532229997Sken break; 2533229997Sken } 2534229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2535229997Sken 2536229997Sken if ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2537229997Sken snprintf(req->error_str, sizeof(req->error_str), 2538273315Smav "interrupted waiting for LUN to be freed"); 2539229997Sken mtx_unlock(&softc->lock); 2540229997Sken goto bailout_error; 2541229997Sken } 2542229997Sken 2543229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, links); 2544229997Sken 2545229997Sken softc->num_luns--; 2546229997Sken mtx_unlock(&softc->lock); 2547229997Sken 2548288734Smav taskqueue_drain_all(be_lun->io_taskqueue); 2549229997Sken taskqueue_free(be_lun->io_taskqueue); 2550229997Sken 2551229997Sken if (be_lun->disk_stats != NULL) 2552229997Sken devstat_remove_entry(be_lun->disk_stats); 2553229997Sken 2554229997Sken uma_zdestroy(be_lun->lun_zone); 2555229997Sken 2556288734Smav ctl_free_opts(&cbe_lun->options); 2557229997Sken free(be_lun->dev_path, M_CTLBLK); 2558268549Smav mtx_destroy(&be_lun->queue_lock); 2559268549Smav mtx_destroy(&be_lun->io_lock); 2560229997Sken free(be_lun, M_CTLBLK); 2561229997Sken 2562229997Sken req->status = CTL_LUN_OK; 2563229997Sken return (0); 2564229997Sken 2565229997Skenbailout_error: 2566229997Sken req->status = CTL_LUN_ERROR; 2567229997Sken return (0); 2568229997Sken} 2569229997Sken 2570232604Straszstatic int 2571232604Straszctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2572232604Strasz{ 2573232604Strasz struct ctl_lun_modify_params *params; 2574232604Strasz struct ctl_be_block_lun *be_lun; 2575288728Smav struct ctl_be_lun *cbe_lun; 2576288732Smav char *value; 2577271928Smav uint64_t oldsize; 2578288732Smav int error, wasprim; 2579232604Strasz 2580232604Strasz params = &req->reqdata.modify; 2581232604Strasz 2582232604Strasz mtx_lock(&softc->lock); 2583232604Strasz STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2584288727Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2585232604Strasz break; 2586232604Strasz } 2587232604Strasz mtx_unlock(&softc->lock); 2588232604Strasz if (be_lun == NULL) { 2589232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2590273315Smav "LUN %u is not managed by the block backend", 2591273315Smav params->lun_id); 2592232604Strasz goto bailout_error; 2593232604Strasz } 2594288728Smav cbe_lun = &be_lun->cbe_lun; 2595232604Strasz 2596288728Smav if (params->lun_size_bytes != 0) 2597288728Smav be_lun->params.lun_size_bytes = params->lun_size_bytes; 2598288728Smav ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 2599232604Strasz 2600288732Smav wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 2601288732Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2602288732Smav if (value != NULL) { 2603288732Smav if (strcmp(value, "primary") == 0) 2604288732Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2605288732Smav else 2606288732Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2607288732Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2608288732Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2609232604Strasz else 2610288732Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2611288732Smav if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 2612288732Smav if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 2613288732Smav ctl_lun_primary(cbe_lun); 2614288732Smav else 2615288732Smav ctl_lun_secondary(cbe_lun); 2616288732Smav } 2617232604Strasz 2618288732Smav oldsize = be_lun->size_blocks; 2619288732Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2620288732Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2621288732Smav if (be_lun->vn == NULL) 2622288811Smav error = ctl_be_block_open(be_lun, req); 2623288732Smav else if (vn_isdisk(be_lun->vn, &error)) 2624288787Smav error = ctl_be_block_open_dev(be_lun, req); 2625289363Smav else if (be_lun->vn->v_type == VREG) { 2626289363Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 2627288787Smav error = ctl_be_block_open_file(be_lun, req); 2628289363Smav VOP_UNLOCK(be_lun->vn, 0); 2629289363Smav } else 2630288732Smav error = EINVAL; 2631288811Smav if ((cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) && 2632288732Smav be_lun->vn != NULL) { 2633288811Smav cbe_lun->flags &= ~CTL_LUN_FLAG_NO_MEDIA; 2634288811Smav ctl_lun_has_media(cbe_lun); 2635288811Smav } else if ((cbe_lun->flags & CTL_LUN_FLAG_NO_MEDIA) == 0 && 2636288811Smav be_lun->vn == NULL) { 2637288811Smav cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2638288811Smav ctl_lun_no_media(cbe_lun); 2639288732Smav } 2640288811Smav cbe_lun->flags &= ~CTL_LUN_FLAG_EJECTED; 2641288732Smav } else { 2642288732Smav if (be_lun->vn != NULL) { 2643288811Smav cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2644288811Smav ctl_lun_no_media(cbe_lun); 2645288734Smav taskqueue_drain_all(be_lun->io_taskqueue); 2646288732Smav error = ctl_be_block_close(be_lun); 2647288732Smav } else 2648288732Smav error = 0; 2649288732Smav } 2650288727Smav if (be_lun->size_blocks != oldsize) 2651288728Smav ctl_lun_capacity_changed(cbe_lun); 2652232604Strasz 2653232604Strasz /* Tell the user the exact size we ended up using */ 2654232604Strasz params->lun_size_bytes = be_lun->size_bytes; 2655232604Strasz 2656273315Smav req->status = error ? CTL_LUN_WARNING : CTL_LUN_OK; 2657232604Strasz return (0); 2658232604Strasz 2659232604Straszbailout_error: 2660232604Strasz req->status = CTL_LUN_ERROR; 2661232604Strasz return (0); 2662232604Strasz} 2663232604Strasz 2664229997Skenstatic void 2665229997Skenctl_be_block_lun_shutdown(void *be_lun) 2666229997Sken{ 2667229997Sken struct ctl_be_block_lun *lun; 2668229997Sken struct ctl_be_block_softc *softc; 2669229997Sken 2670229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2671229997Sken softc = lun->softc; 2672229997Sken 2673229997Sken mtx_lock(&softc->lock); 2674229997Sken lun->flags |= CTL_BE_BLOCK_LUN_UNCONFIGURED; 2675229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2676229997Sken wakeup(lun); 2677229997Sken mtx_unlock(&softc->lock); 2678229997Sken} 2679229997Sken 2680229997Skenstatic void 2681229997Skenctl_be_block_lun_config_status(void *be_lun, ctl_lun_config_status status) 2682229997Sken{ 2683229997Sken struct ctl_be_block_lun *lun; 2684229997Sken struct ctl_be_block_softc *softc; 2685229997Sken 2686229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2687229997Sken softc = lun->softc; 2688229997Sken 2689229997Sken if (status == CTL_LUN_CONFIG_OK) { 2690229997Sken mtx_lock(&softc->lock); 2691229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2692229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2693229997Sken wakeup(lun); 2694229997Sken mtx_unlock(&softc->lock); 2695229997Sken 2696229997Sken /* 2697229997Sken * We successfully added the LUN, attempt to enable it. 2698229997Sken */ 2699288727Smav if (ctl_enable_lun(&lun->cbe_lun) != 0) { 2700229997Sken printf("%s: ctl_enable_lun() failed!\n", __func__); 2701288727Smav if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 2702229997Sken printf("%s: ctl_invalidate_lun() failed!\n", 2703229997Sken __func__); 2704229997Sken } 2705229997Sken } 2706229997Sken 2707229997Sken return; 2708229997Sken } 2709229997Sken 2710229997Sken 2711229997Sken mtx_lock(&softc->lock); 2712229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2713229997Sken lun->flags |= CTL_BE_BLOCK_LUN_CONFIG_ERR; 2714229997Sken wakeup(lun); 2715229997Sken mtx_unlock(&softc->lock); 2716229997Sken} 2717229997Sken 2718229997Sken 2719229997Skenstatic int 2720229997Skenctl_be_block_config_write(union ctl_io *io) 2721229997Sken{ 2722229997Sken struct ctl_be_block_lun *be_lun; 2723288727Smav struct ctl_be_lun *cbe_lun; 2724229997Sken int retval; 2725229997Sken 2726229997Sken DPRINTF("entered\n"); 2727229997Sken 2728288727Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2729229997Sken CTL_PRIV_BACKEND_LUN].ptr; 2730288727Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2731229997Sken 2732288799Smav retval = 0; 2733229997Sken switch (io->scsiio.cdb[0]) { 2734229997Sken case SYNCHRONIZE_CACHE: 2735229997Sken case SYNCHRONIZE_CACHE_16: 2736265634Smav case WRITE_SAME_10: 2737265634Smav case WRITE_SAME_16: 2738265634Smav case UNMAP: 2739229997Sken /* 2740229997Sken * The upper level CTL code will filter out any CDBs with 2741229997Sken * the immediate bit set and return the proper error. 2742229997Sken * 2743229997Sken * We don't really need to worry about what LBA range the 2744229997Sken * user asked to be synced out. When they issue a sync 2745229997Sken * cache command, we'll sync out the whole thing. 2746229997Sken */ 2747268549Smav mtx_lock(&be_lun->queue_lock); 2748229997Sken STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->io_hdr, 2749229997Sken links); 2750268549Smav mtx_unlock(&be_lun->queue_lock); 2751229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 2752229997Sken break; 2753229997Sken case START_STOP_UNIT: { 2754229997Sken struct scsi_start_stop_unit *cdb; 2755288811Smav struct ctl_lun_req req; 2756229997Sken 2757229997Sken cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 2758288816Smav if ((cdb->how & SSS_PC_MASK) != 0) { 2759288816Smav ctl_set_success(&io->scsiio); 2760288816Smav ctl_config_write_done(io); 2761288816Smav break; 2762288816Smav } 2763288811Smav if (cdb->how & SSS_START) { 2764288811Smav if ((cdb->how & SSS_LOEJ) && be_lun->vn == NULL) { 2765288811Smav retval = ctl_be_block_open(be_lun, &req); 2766288811Smav cbe_lun->flags &= ~CTL_LUN_FLAG_EJECTED; 2767288811Smav if (retval == 0) { 2768288811Smav cbe_lun->flags &= ~CTL_LUN_FLAG_NO_MEDIA; 2769288811Smav ctl_lun_has_media(cbe_lun); 2770288811Smav } else { 2771288811Smav cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2772288811Smav ctl_lun_no_media(cbe_lun); 2773288811Smav } 2774288811Smav } 2775288811Smav ctl_start_lun(cbe_lun); 2776229997Sken } else { 2777288811Smav ctl_stop_lun(cbe_lun); 2778288811Smav if (cdb->how & SSS_LOEJ) { 2779288811Smav cbe_lun->flags |= CTL_LUN_FLAG_NO_MEDIA; 2780288811Smav cbe_lun->flags |= CTL_LUN_FLAG_EJECTED; 2781288811Smav ctl_lun_ejected(cbe_lun); 2782288811Smav if (be_lun->vn != NULL) 2783288811Smav ctl_be_block_close(be_lun); 2784288811Smav } 2785229997Sken } 2786288811Smav 2787288811Smav ctl_set_success(&io->scsiio); 2788229997Sken ctl_config_write_done(io); 2789229997Sken break; 2790229997Sken } 2791288810Smav case PREVENT_ALLOW: 2792288810Smav ctl_set_success(&io->scsiio); 2793288810Smav ctl_config_write_done(io); 2794288810Smav break; 2795229997Sken default: 2796229997Sken ctl_set_invalid_opcode(&io->scsiio); 2797229997Sken ctl_config_write_done(io); 2798229997Sken retval = CTL_RETVAL_COMPLETE; 2799229997Sken break; 2800229997Sken } 2801229997Sken 2802229997Sken return (retval); 2803229997Sken} 2804229997Sken 2805229997Skenstatic int 2806229997Skenctl_be_block_config_read(union ctl_io *io) 2807229997Sken{ 2808275892Smav struct ctl_be_block_lun *be_lun; 2809288727Smav struct ctl_be_lun *cbe_lun; 2810275892Smav int retval = 0; 2811275892Smav 2812275892Smav DPRINTF("entered\n"); 2813275892Smav 2814288727Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2815275892Smav CTL_PRIV_BACKEND_LUN].ptr; 2816288727Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2817275892Smav 2818275892Smav switch (io->scsiio.cdb[0]) { 2819275892Smav case SERVICE_ACTION_IN: 2820275892Smav if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 2821275892Smav mtx_lock(&be_lun->queue_lock); 2822275892Smav STAILQ_INSERT_TAIL(&be_lun->config_read_queue, 2823275892Smav &io->io_hdr, links); 2824275892Smav mtx_unlock(&be_lun->queue_lock); 2825275892Smav taskqueue_enqueue(be_lun->io_taskqueue, 2826275892Smav &be_lun->io_task); 2827275892Smav retval = CTL_RETVAL_QUEUED; 2828275892Smav break; 2829275892Smav } 2830275892Smav ctl_set_invalid_field(&io->scsiio, 2831275892Smav /*sks_valid*/ 1, 2832275892Smav /*command*/ 1, 2833275892Smav /*field*/ 1, 2834275892Smav /*bit_valid*/ 1, 2835275892Smav /*bit*/ 4); 2836275892Smav ctl_config_read_done(io); 2837275892Smav retval = CTL_RETVAL_COMPLETE; 2838275892Smav break; 2839275892Smav default: 2840275892Smav ctl_set_invalid_opcode(&io->scsiio); 2841275892Smav ctl_config_read_done(io); 2842275892Smav retval = CTL_RETVAL_COMPLETE; 2843275892Smav break; 2844275892Smav } 2845275892Smav 2846275892Smav return (retval); 2847229997Sken} 2848229997Sken 2849229997Skenstatic int 2850229997Skenctl_be_block_lun_info(void *be_lun, struct sbuf *sb) 2851229997Sken{ 2852229997Sken struct ctl_be_block_lun *lun; 2853229997Sken int retval; 2854229997Sken 2855229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2856229997Sken 2857268555Smav retval = sbuf_printf(sb, "\t<num_threads>"); 2858229997Sken if (retval != 0) 2859229997Sken goto bailout; 2860229997Sken retval = sbuf_printf(sb, "%d", lun->num_threads); 2861229997Sken if (retval != 0) 2862229997Sken goto bailout; 2863268555Smav retval = sbuf_printf(sb, "</num_threads>\n"); 2864229997Sken 2865229997Skenbailout: 2866229997Sken return (retval); 2867229997Sken} 2868229997Sken 2869274732Smavstatic uint64_t 2870274732Smavctl_be_block_lun_attr(void *be_lun, const char *attrname) 2871274732Smav{ 2872274732Smav struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)be_lun; 2873274732Smav 2874274732Smav if (lun->getattr == NULL) 2875274732Smav return (UINT64_MAX); 2876274732Smav return (lun->getattr(lun, attrname)); 2877274732Smav} 2878274732Smav 2879229997Skenint 2880229997Skenctl_be_block_init(void) 2881229997Sken{ 2882229997Sken struct ctl_be_block_softc *softc; 2883229997Sken int retval; 2884229997Sken 2885229997Sken softc = &backend_block_softc; 2886229997Sken retval = 0; 2887229997Sken 2888268549Smav mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF); 2889265494Strasz beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io), 2890265494Strasz NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 2891229997Sken STAILQ_INIT(&softc->lun_list); 2892229997Sken 2893229997Sken return (retval); 2894229997Sken} 2895