ctl_backend_block.c revision 288020
1229997Sken/*- 2229997Sken * Copyright (c) 2003 Silicon Graphics International Corp. 3229997Sken * Copyright (c) 2009-2011 Spectra Logic Corporation 4232604Strasz * Copyright (c) 2012 The FreeBSD Foundation 5229997Sken * All rights reserved. 6229997Sken * 7232604Strasz * Portions of this software were developed by Edward Tomasz Napierala 8232604Strasz * under sponsorship from the FreeBSD Foundation. 9232604Strasz * 10229997Sken * Redistribution and use in source and binary forms, with or without 11229997Sken * modification, are permitted provided that the following conditions 12229997Sken * are met: 13229997Sken * 1. Redistributions of source code must retain the above copyright 14229997Sken * notice, this list of conditions, and the following disclaimer, 15229997Sken * without modification. 16229997Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 17229997Sken * substantially similar to the "NO WARRANTY" disclaimer below 18229997Sken * ("Disclaimer") and any redistribution must be conditioned upon 19229997Sken * including a substantially similar Disclaimer requirement for further 20229997Sken * binary redistribution. 21229997Sken * 22229997Sken * NO WARRANTY 23229997Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24229997Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25229997Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 26229997Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27229997Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 31229997Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 32229997Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33229997Sken * POSSIBILITY OF SUCH DAMAGES. 34229997Sken * 35229997Sken * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_block.c#5 $ 36229997Sken */ 37229997Sken/* 38229997Sken * CAM Target Layer driver backend for block devices. 39229997Sken * 40229997Sken * Author: Ken Merry <ken@FreeBSD.org> 41229997Sken */ 42229997Sken#include <sys/cdefs.h> 43229997Sken__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_backend_block.c 288020 2015-09-20 10:40:30Z mav $"); 44229997Sken 45229997Sken#include <sys/param.h> 46229997Sken#include <sys/systm.h> 47229997Sken#include <sys/kernel.h> 48229997Sken#include <sys/types.h> 49229997Sken#include <sys/kthread.h> 50229997Sken#include <sys/bio.h> 51229997Sken#include <sys/fcntl.h> 52264274Smav#include <sys/limits.h> 53229997Sken#include <sys/lock.h> 54229997Sken#include <sys/mutex.h> 55229997Sken#include <sys/condvar.h> 56229997Sken#include <sys/malloc.h> 57229997Sken#include <sys/conf.h> 58229997Sken#include <sys/ioccom.h> 59229997Sken#include <sys/queue.h> 60229997Sken#include <sys/sbuf.h> 61229997Sken#include <sys/endian.h> 62229997Sken#include <sys/uio.h> 63229997Sken#include <sys/buf.h> 64229997Sken#include <sys/taskqueue.h> 65229997Sken#include <sys/vnode.h> 66229997Sken#include <sys/namei.h> 67229997Sken#include <sys/mount.h> 68229997Sken#include <sys/disk.h> 69229997Sken#include <sys/fcntl.h> 70229997Sken#include <sys/filedesc.h> 71275474Smav#include <sys/filio.h> 72229997Sken#include <sys/proc.h> 73229997Sken#include <sys/pcpu.h> 74229997Sken#include <sys/module.h> 75229997Sken#include <sys/sdt.h> 76229997Sken#include <sys/devicestat.h> 77229997Sken#include <sys/sysctl.h> 78229997Sken 79229997Sken#include <geom/geom.h> 80229997Sken 81229997Sken#include <cam/cam.h> 82229997Sken#include <cam/scsi/scsi_all.h> 83229997Sken#include <cam/scsi/scsi_da.h> 84229997Sken#include <cam/ctl/ctl_io.h> 85229997Sken#include <cam/ctl/ctl.h> 86229997Sken#include <cam/ctl/ctl_backend.h> 87229997Sken#include <cam/ctl/ctl_ioctl.h> 88287621Smav#include <cam/ctl/ctl_ha.h> 89229997Sken#include <cam/ctl/ctl_scsi_all.h> 90287621Smav#include <cam/ctl/ctl_private.h> 91229997Sken#include <cam/ctl/ctl_error.h> 92229997Sken 93229997Sken/* 94264886Smav * The idea here is that we'll allocate enough S/G space to hold a 1MB 95264886Smav * I/O. If we get an I/O larger than that, we'll split it. 96229997Sken */ 97267537Smav#define CTLBLK_HALF_IO_SIZE (512 * 1024) 98267537Smav#define CTLBLK_MAX_IO_SIZE (CTLBLK_HALF_IO_SIZE * 2) 99264886Smav#define CTLBLK_MAX_SEG MAXPHYS 100267537Smav#define CTLBLK_HALF_SEGS MAX(CTLBLK_HALF_IO_SIZE / CTLBLK_MAX_SEG, 1) 101267537Smav#define CTLBLK_MAX_SEGS (CTLBLK_HALF_SEGS * 2) 102229997Sken 103229997Sken#ifdef CTLBLK_DEBUG 104229997Sken#define DPRINTF(fmt, args...) \ 105229997Sken printf("cbb(%s:%d): " fmt, __FUNCTION__, __LINE__, ##args) 106229997Sken#else 107229997Sken#define DPRINTF(fmt, args...) do {} while(0) 108229997Sken#endif 109229997Sken 110267519Smav#define PRIV(io) \ 111267519Smav ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND]) 112267537Smav#define ARGS(io) \ 113267537Smav ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]) 114267519Smav 115229997SkenSDT_PROVIDER_DEFINE(cbb); 116229997Sken 117229997Skentypedef enum { 118229997Sken CTL_BE_BLOCK_LUN_UNCONFIGURED = 0x01, 119229997Sken CTL_BE_BLOCK_LUN_CONFIG_ERR = 0x02, 120229997Sken CTL_BE_BLOCK_LUN_WAITING = 0x04, 121229997Sken} ctl_be_block_lun_flags; 122229997Sken 123229997Skentypedef enum { 124229997Sken CTL_BE_BLOCK_NONE, 125229997Sken CTL_BE_BLOCK_DEV, 126229997Sken CTL_BE_BLOCK_FILE 127229997Sken} ctl_be_block_type; 128229997Sken 129229997Skenstruct ctl_be_block_filedata { 130229997Sken struct ucred *cred; 131229997Sken}; 132229997Sken 133229997Skenunion ctl_be_block_bedata { 134229997Sken struct ctl_be_block_filedata file; 135229997Sken}; 136229997Sken 137229997Skenstruct ctl_be_block_io; 138229997Skenstruct ctl_be_block_lun; 139229997Sken 140229997Skentypedef void (*cbb_dispatch_t)(struct ctl_be_block_lun *be_lun, 141229997Sken struct ctl_be_block_io *beio); 142274154Smavtypedef uint64_t (*cbb_getattr_t)(struct ctl_be_block_lun *be_lun, 143274154Smav const char *attrname); 144229997Sken 145229997Sken/* 146229997Sken * Backend LUN structure. There is a 1:1 mapping between a block device 147229997Sken * and a backend block LUN, and between a backend block LUN and a CTL LUN. 148229997Sken */ 149229997Skenstruct ctl_be_block_lun { 150272911Smav struct ctl_lun_create_params params; 151229997Sken char lunname[32]; 152229997Sken char *dev_path; 153229997Sken ctl_be_block_type dev_type; 154229997Sken struct vnode *vn; 155229997Sken union ctl_be_block_bedata backend; 156229997Sken cbb_dispatch_t dispatch; 157229997Sken cbb_dispatch_t lun_flush; 158264274Smav cbb_dispatch_t unmap; 159275474Smav cbb_dispatch_t get_lba_status; 160274154Smav cbb_getattr_t getattr; 161229997Sken uma_zone_t lun_zone; 162229997Sken uint64_t size_blocks; 163229997Sken uint64_t size_bytes; 164229997Sken struct ctl_be_block_softc *softc; 165229997Sken struct devstat *disk_stats; 166229997Sken ctl_be_block_lun_flags flags; 167229997Sken STAILQ_ENTRY(ctl_be_block_lun) links; 168287499Smav struct ctl_be_lun cbe_lun; 169229997Sken struct taskqueue *io_taskqueue; 170229997Sken struct task io_task; 171229997Sken int num_threads; 172229997Sken STAILQ_HEAD(, ctl_io_hdr) input_queue; 173275474Smav STAILQ_HEAD(, ctl_io_hdr) config_read_queue; 174229997Sken STAILQ_HEAD(, ctl_io_hdr) config_write_queue; 175229997Sken STAILQ_HEAD(, ctl_io_hdr) datamove_queue; 176267877Smav struct mtx_padalign io_lock; 177267877Smav struct mtx_padalign queue_lock; 178229997Sken}; 179229997Sken 180229997Sken/* 181229997Sken * Overall softc structure for the block backend module. 182229997Sken */ 183229997Skenstruct ctl_be_block_softc { 184229997Sken struct mtx lock; 185229997Sken int num_luns; 186229997Sken STAILQ_HEAD(, ctl_be_block_lun) lun_list; 187229997Sken}; 188229997Sken 189229997Skenstatic struct ctl_be_block_softc backend_block_softc; 190229997Sken 191229997Sken/* 192229997Sken * Per-I/O information. 193229997Sken */ 194229997Skenstruct ctl_be_block_io { 195229997Sken union ctl_io *io; 196229997Sken struct ctl_sg_entry sg_segs[CTLBLK_MAX_SEGS]; 197229997Sken struct iovec xiovecs[CTLBLK_MAX_SEGS]; 198229997Sken int bio_cmd; 199229997Sken int num_segs; 200229997Sken int num_bios_sent; 201229997Sken int num_bios_done; 202229997Sken int send_complete; 203229997Sken int num_errors; 204229997Sken struct bintime ds_t0; 205229997Sken devstat_tag_type ds_tag_type; 206229997Sken devstat_trans_flags ds_trans_type; 207229997Sken uint64_t io_len; 208229997Sken uint64_t io_offset; 209286353Smav int io_arg; 210229997Sken struct ctl_be_block_softc *softc; 211229997Sken struct ctl_be_block_lun *lun; 212264274Smav void (*beio_cont)(struct ctl_be_block_io *beio); /* to continue processing */ 213229997Sken}; 214229997Sken 215287621Smavextern struct ctl_softc *control_softc; 216287621Smav 217229997Skenstatic int cbb_num_threads = 14; 218229997SkenSYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD, 0, 219229997Sken "CAM Target Layer Block Backend"); 220267992ShselaskySYSCTL_INT(_kern_cam_ctl_block, OID_AUTO, num_threads, CTLFLAG_RWTUN, 221229997Sken &cbb_num_threads, 0, "Number of threads per backing file"); 222229997Sken 223229997Skenstatic struct ctl_be_block_io *ctl_alloc_beio(struct ctl_be_block_softc *softc); 224229997Skenstatic void ctl_free_beio(struct ctl_be_block_io *beio); 225229997Skenstatic void ctl_complete_beio(struct ctl_be_block_io *beio); 226229997Skenstatic int ctl_be_block_move_done(union ctl_io *io); 227229997Skenstatic void ctl_be_block_biodone(struct bio *bio); 228229997Skenstatic void ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 229229997Sken struct ctl_be_block_io *beio); 230229997Skenstatic void ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 231229997Sken struct ctl_be_block_io *beio); 232275474Smavstatic void ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 233275474Smav struct ctl_be_block_io *beio); 234275481Smavstatic uint64_t ctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, 235275481Smav const char *attrname); 236229997Skenstatic void ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 237229997Sken struct ctl_be_block_io *beio); 238264274Smavstatic void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 239264274Smav struct ctl_be_block_io *beio); 240229997Skenstatic void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 241229997Sken struct ctl_be_block_io *beio); 242274154Smavstatic uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, 243274154Smav const char *attrname); 244275474Smavstatic void ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 245275474Smav union ctl_io *io); 246229997Skenstatic void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 247229997Sken union ctl_io *io); 248229997Skenstatic void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 249229997Sken union ctl_io *io); 250229997Skenstatic void ctl_be_block_worker(void *context, int pending); 251229997Skenstatic int ctl_be_block_submit(union ctl_io *io); 252229997Skenstatic int ctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 253229997Sken int flag, struct thread *td); 254229997Skenstatic int ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, 255229997Sken struct ctl_lun_req *req); 256229997Skenstatic int ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, 257229997Sken struct ctl_lun_req *req); 258229997Skenstatic int ctl_be_block_close(struct ctl_be_block_lun *be_lun); 259229997Skenstatic int ctl_be_block_open(struct ctl_be_block_softc *softc, 260229997Sken struct ctl_be_block_lun *be_lun, 261229997Sken struct ctl_lun_req *req); 262229997Skenstatic int ctl_be_block_create(struct ctl_be_block_softc *softc, 263229997Sken struct ctl_lun_req *req); 264229997Skenstatic int ctl_be_block_rm(struct ctl_be_block_softc *softc, 265229997Sken struct ctl_lun_req *req); 266232604Straszstatic int ctl_be_block_modify_file(struct ctl_be_block_lun *be_lun, 267232604Strasz struct ctl_lun_req *req); 268232604Straszstatic int ctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun, 269232604Strasz struct ctl_lun_req *req); 270232604Straszstatic int ctl_be_block_modify(struct ctl_be_block_softc *softc, 271232604Strasz struct ctl_lun_req *req); 272229997Skenstatic void ctl_be_block_lun_shutdown(void *be_lun); 273229997Skenstatic void ctl_be_block_lun_config_status(void *be_lun, 274229997Sken ctl_lun_config_status status); 275229997Skenstatic int ctl_be_block_config_write(union ctl_io *io); 276229997Skenstatic int ctl_be_block_config_read(union ctl_io *io); 277229997Skenstatic int ctl_be_block_lun_info(void *be_lun, struct sbuf *sb); 278274154Smavstatic uint64_t ctl_be_block_lun_attr(void *be_lun, const char *attrname); 279229997Skenint ctl_be_block_init(void); 280229997Sken 281229997Skenstatic struct ctl_backend_driver ctl_be_block_driver = 282229997Sken{ 283230334Sken .name = "block", 284230334Sken .flags = CTL_BE_FLAG_HAS_CONFIG, 285230334Sken .init = ctl_be_block_init, 286230334Sken .data_submit = ctl_be_block_submit, 287230334Sken .data_move_done = ctl_be_block_move_done, 288230334Sken .config_read = ctl_be_block_config_read, 289230334Sken .config_write = ctl_be_block_config_write, 290230334Sken .ioctl = ctl_be_block_ioctl, 291274154Smav .lun_info = ctl_be_block_lun_info, 292274154Smav .lun_attr = ctl_be_block_lun_attr 293229997Sken}; 294229997Sken 295229997SkenMALLOC_DEFINE(M_CTLBLK, "ctlblk", "Memory used for CTL block backend"); 296229997SkenCTL_BACKEND_DECLARE(cbb, ctl_be_block_driver); 297229997Sken 298264020Straszstatic uma_zone_t beio_zone; 299264020Strasz 300229997Skenstatic struct ctl_be_block_io * 301229997Skenctl_alloc_beio(struct ctl_be_block_softc *softc) 302229997Sken{ 303229997Sken struct ctl_be_block_io *beio; 304229997Sken 305264020Strasz beio = uma_zalloc(beio_zone, M_WAITOK | M_ZERO); 306264020Strasz beio->softc = softc; 307229997Sken return (beio); 308229997Sken} 309229997Sken 310229997Skenstatic void 311229997Skenctl_free_beio(struct ctl_be_block_io *beio) 312229997Sken{ 313229997Sken int duplicate_free; 314229997Sken int i; 315229997Sken 316229997Sken duplicate_free = 0; 317229997Sken 318229997Sken for (i = 0; i < beio->num_segs; i++) { 319229997Sken if (beio->sg_segs[i].addr == NULL) 320229997Sken duplicate_free++; 321229997Sken 322229997Sken uma_zfree(beio->lun->lun_zone, beio->sg_segs[i].addr); 323229997Sken beio->sg_segs[i].addr = NULL; 324267537Smav 325267537Smav /* For compare we had two equal S/G lists. */ 326267537Smav if (ARGS(beio->io)->flags & CTL_LLF_COMPARE) { 327267537Smav uma_zfree(beio->lun->lun_zone, 328267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr); 329267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = NULL; 330267537Smav } 331229997Sken } 332229997Sken 333229997Sken if (duplicate_free > 0) { 334229997Sken printf("%s: %d duplicate frees out of %d segments\n", __func__, 335229997Sken duplicate_free, beio->num_segs); 336229997Sken } 337229997Sken 338264020Strasz uma_zfree(beio_zone, beio); 339229997Sken} 340229997Sken 341229997Skenstatic void 342229997Skenctl_complete_beio(struct ctl_be_block_io *beio) 343229997Sken{ 344267877Smav union ctl_io *io = beio->io; 345229997Sken 346264274Smav if (beio->beio_cont != NULL) { 347264274Smav beio->beio_cont(beio); 348264274Smav } else { 349264274Smav ctl_free_beio(beio); 350267537Smav ctl_data_submit_done(io); 351264274Smav } 352229997Sken} 353229997Sken 354287868Smavstatic size_t 355287868Smavcmp(uint8_t *a, uint8_t *b, size_t size) 356287868Smav{ 357287868Smav size_t i; 358287868Smav 359287868Smav for (i = 0; i < size; i++) { 360287868Smav if (a[i] != b[i]) 361287868Smav break; 362287868Smav } 363287868Smav return (i); 364287868Smav} 365287868Smav 366287868Smavstatic void 367287868Smavctl_be_block_compare(union ctl_io *io) 368287868Smav{ 369287868Smav struct ctl_be_block_io *beio; 370287868Smav uint64_t off, res; 371287868Smav int i; 372287868Smav uint8_t info[8]; 373287868Smav 374287868Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 375287868Smav off = 0; 376287868Smav for (i = 0; i < beio->num_segs; i++) { 377287868Smav res = cmp(beio->sg_segs[i].addr, 378287868Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr, 379287868Smav beio->sg_segs[i].len); 380287868Smav off += res; 381287868Smav if (res < beio->sg_segs[i].len) 382287868Smav break; 383287868Smav } 384287868Smav if (i < beio->num_segs) { 385287868Smav scsi_u64to8b(off, info); 386287868Smav ctl_set_sense(&io->scsiio, /*current_error*/ 1, 387287868Smav /*sense_key*/ SSD_KEY_MISCOMPARE, 388287868Smav /*asc*/ 0x1D, /*ascq*/ 0x00, 389287868Smav /*type*/ SSD_ELEM_INFO, 390287868Smav /*size*/ sizeof(info), /*data*/ &info, 391287868Smav /*type*/ SSD_ELEM_NONE); 392287868Smav } else 393287868Smav ctl_set_success(&io->scsiio); 394287868Smav} 395287868Smav 396229997Skenstatic int 397229997Skenctl_be_block_move_done(union ctl_io *io) 398229997Sken{ 399229997Sken struct ctl_be_block_io *beio; 400229997Sken struct ctl_be_block_lun *be_lun; 401267537Smav struct ctl_lba_len_flags *lbalen; 402229997Sken#ifdef CTL_TIME_IO 403229997Sken struct bintime cur_bt; 404267537Smav#endif 405229997Sken 406267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 407229997Sken be_lun = beio->lun; 408229997Sken 409229997Sken DPRINTF("entered\n"); 410229997Sken 411229997Sken#ifdef CTL_TIME_IO 412229997Sken getbintime(&cur_bt); 413229997Sken bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 414229997Sken bintime_add(&io->io_hdr.dma_bt, &cur_bt); 415229997Sken io->io_hdr.num_dmas++; 416229997Sken#endif 417267537Smav io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 418229997Sken 419229997Sken /* 420229997Sken * We set status at this point for read commands, and write 421229997Sken * commands with errors. 422229997Sken */ 423275058Smav if (io->io_hdr.flags & CTL_FLAG_ABORT) { 424275058Smav ; 425275058Smav } else if ((io->io_hdr.port_status == 0) && 426267537Smav ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 427267537Smav lbalen = ARGS(beio->io); 428267537Smav if (lbalen->flags & CTL_LLF_READ) { 429267537Smav ctl_set_success(&io->scsiio); 430267537Smav } else if (lbalen->flags & CTL_LLF_COMPARE) { 431267537Smav /* We have two data blocks ready for comparison. */ 432287868Smav ctl_be_block_compare(io); 433267537Smav } 434275058Smav } else if ((io->io_hdr.port_status != 0) && 435275058Smav ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 436275058Smav (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 437229997Sken /* 438229997Sken * For hardware error sense keys, the sense key 439229997Sken * specific value is defined to be a retry count, 440229997Sken * but we use it to pass back an internal FETD 441229997Sken * error code. XXX KDM Hopefully the FETD is only 442229997Sken * using 16 bits for an error code, since that's 443229997Sken * all the space we have in the sks field. 444229997Sken */ 445229997Sken ctl_set_internal_failure(&io->scsiio, 446229997Sken /*sks_valid*/ 1, 447229997Sken /*retry_count*/ 448229997Sken io->io_hdr.port_status); 449229997Sken } 450229997Sken 451229997Sken /* 452229997Sken * If this is a read, or a write with errors, it is done. 453229997Sken */ 454229997Sken if ((beio->bio_cmd == BIO_READ) 455229997Sken || ((io->io_hdr.flags & CTL_FLAG_ABORT) != 0) 456229997Sken || ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE)) { 457229997Sken ctl_complete_beio(beio); 458229997Sken return (0); 459229997Sken } 460229997Sken 461229997Sken /* 462229997Sken * At this point, we have a write and the DMA completed 463229997Sken * successfully. We now have to queue it to the task queue to 464229997Sken * execute the backend I/O. That is because we do blocking 465229997Sken * memory allocations, and in the file backing case, blocking I/O. 466229997Sken * This move done routine is generally called in the SIM's 467229997Sken * interrupt context, and therefore we cannot block. 468229997Sken */ 469267877Smav mtx_lock(&be_lun->queue_lock); 470229997Sken /* 471229997Sken * XXX KDM make sure that links is okay to use at this point. 472229997Sken * Otherwise, we either need to add another field to ctl_io_hdr, 473229997Sken * or deal with resource allocation here. 474229997Sken */ 475229997Sken STAILQ_INSERT_TAIL(&be_lun->datamove_queue, &io->io_hdr, links); 476267877Smav mtx_unlock(&be_lun->queue_lock); 477229997Sken 478229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 479229997Sken 480229997Sken return (0); 481229997Sken} 482229997Sken 483229997Skenstatic void 484229997Skenctl_be_block_biodone(struct bio *bio) 485229997Sken{ 486229997Sken struct ctl_be_block_io *beio; 487229997Sken struct ctl_be_block_lun *be_lun; 488229997Sken union ctl_io *io; 489261538Smav int error; 490229997Sken 491229997Sken beio = bio->bio_caller1; 492229997Sken be_lun = beio->lun; 493229997Sken io = beio->io; 494229997Sken 495229997Sken DPRINTF("entered\n"); 496229997Sken 497261538Smav error = bio->bio_error; 498267877Smav mtx_lock(&be_lun->io_lock); 499261538Smav if (error != 0) 500229997Sken beio->num_errors++; 501229997Sken 502229997Sken beio->num_bios_done++; 503229997Sken 504229997Sken /* 505229997Sken * XXX KDM will this cause WITNESS to complain? Holding a lock 506229997Sken * during the free might cause it to complain. 507229997Sken */ 508229997Sken g_destroy_bio(bio); 509229997Sken 510229997Sken /* 511229997Sken * If the send complete bit isn't set, or we aren't the last I/O to 512229997Sken * complete, then we're done. 513229997Sken */ 514229997Sken if ((beio->send_complete == 0) 515229997Sken || (beio->num_bios_done < beio->num_bios_sent)) { 516267877Smav mtx_unlock(&be_lun->io_lock); 517229997Sken return; 518229997Sken } 519229997Sken 520229997Sken /* 521229997Sken * At this point, we've verified that we are the last I/O to 522229997Sken * complete, so it's safe to drop the lock. 523229997Sken */ 524267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 525267877Smav beio->ds_tag_type, beio->ds_trans_type, 526267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 527267877Smav mtx_unlock(&be_lun->io_lock); 528229997Sken 529229997Sken /* 530229997Sken * If there are any errors from the backing device, we fail the 531229997Sken * entire I/O with a medium error. 532229997Sken */ 533229997Sken if (beio->num_errors > 0) { 534261538Smav if (error == EOPNOTSUPP) { 535261538Smav ctl_set_invalid_opcode(&io->scsiio); 536282565Smav } else if (error == ENOSPC || error == EDQUOT) { 537273809Smav ctl_set_space_alloc_fail(&io->scsiio); 538287760Smav } else if (error == EROFS || error == EACCES) { 539287760Smav ctl_set_hw_write_protected(&io->scsiio); 540261538Smav } else if (beio->bio_cmd == BIO_FLUSH) { 541229997Sken /* XXX KDM is there is a better error here? */ 542229997Sken ctl_set_internal_failure(&io->scsiio, 543229997Sken /*sks_valid*/ 1, 544229997Sken /*retry_count*/ 0xbad2); 545287912Smav } else { 546287912Smav ctl_set_medium_error(&io->scsiio, 547287912Smav beio->bio_cmd == BIO_READ); 548287912Smav } 549229997Sken ctl_complete_beio(beio); 550229997Sken return; 551229997Sken } 552229997Sken 553229997Sken /* 554267537Smav * If this is a write, a flush, a delete or verify, we're all done. 555229997Sken * If this is a read, we can now send the data to the user. 556229997Sken */ 557229997Sken if ((beio->bio_cmd == BIO_WRITE) 558264274Smav || (beio->bio_cmd == BIO_FLUSH) 559267537Smav || (beio->bio_cmd == BIO_DELETE) 560267537Smav || (ARGS(io)->flags & CTL_LLF_VERIFY)) { 561229997Sken ctl_set_success(&io->scsiio); 562229997Sken ctl_complete_beio(beio); 563229997Sken } else { 564275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 565287967Smav beio->beio_cont == NULL) { 566275058Smav ctl_set_success(&io->scsiio); 567287967Smav ctl_serseq_done(io); 568287967Smav } 569229997Sken#ifdef CTL_TIME_IO 570229997Sken getbintime(&io->io_hdr.dma_start_bt); 571229997Sken#endif 572229997Sken ctl_datamove(io); 573229997Sken } 574229997Sken} 575229997Sken 576229997Skenstatic void 577229997Skenctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 578229997Sken struct ctl_be_block_io *beio) 579229997Sken{ 580267877Smav union ctl_io *io = beio->io; 581229997Sken struct mount *mountpoint; 582241896Skib int error, lock_flags; 583229997Sken 584229997Sken DPRINTF("entered\n"); 585229997Sken 586267877Smav binuptime(&beio->ds_t0); 587267877Smav mtx_lock(&be_lun->io_lock); 588267877Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 589267877Smav mtx_unlock(&be_lun->io_lock); 590229997Sken 591267877Smav (void) vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 592229997Sken 593229997Sken if (MNT_SHARED_WRITES(mountpoint) 594229997Sken || ((mountpoint == NULL) 595229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 596229997Sken lock_flags = LK_SHARED; 597229997Sken else 598229997Sken lock_flags = LK_EXCLUSIVE; 599229997Sken 600229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 601229997Sken 602286353Smav error = VOP_FSYNC(be_lun->vn, beio->io_arg ? MNT_NOWAIT : MNT_WAIT, 603286353Smav curthread); 604229997Sken VOP_UNLOCK(be_lun->vn, 0); 605229997Sken 606229997Sken vn_finished_write(mountpoint); 607229997Sken 608267877Smav mtx_lock(&be_lun->io_lock); 609267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 610267877Smav beio->ds_tag_type, beio->ds_trans_type, 611267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 612267877Smav mtx_unlock(&be_lun->io_lock); 613267877Smav 614229997Sken if (error == 0) 615229997Sken ctl_set_success(&io->scsiio); 616229997Sken else { 617229997Sken /* XXX KDM is there is a better error here? */ 618229997Sken ctl_set_internal_failure(&io->scsiio, 619229997Sken /*sks_valid*/ 1, 620229997Sken /*retry_count*/ 0xbad1); 621229997Sken } 622229997Sken 623229997Sken ctl_complete_beio(beio); 624229997Sken} 625229997Sken 626258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_start, "uint64_t"); 627258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_start, "uint64_t"); 628258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_done,"uint64_t"); 629258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_done, "uint64_t"); 630229997Sken 631229997Skenstatic void 632229997Skenctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 633229997Sken struct ctl_be_block_io *beio) 634229997Sken{ 635229997Sken struct ctl_be_block_filedata *file_data; 636229997Sken union ctl_io *io; 637229997Sken struct uio xuio; 638229997Sken struct iovec *xiovec; 639287875Smav size_t s; 640287875Smav int error, flags, i; 641229997Sken 642229997Sken DPRINTF("entered\n"); 643229997Sken 644229997Sken file_data = &be_lun->backend.file; 645229997Sken io = beio->io; 646271309Smav flags = 0; 647271309Smav if (ARGS(io)->flags & CTL_LLF_DPO) 648271309Smav flags |= IO_DIRECT; 649271309Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 650271309Smav flags |= IO_SYNC; 651229997Sken 652267537Smav bzero(&xuio, sizeof(xuio)); 653229997Sken if (beio->bio_cmd == BIO_READ) { 654229997Sken SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 655267537Smav xuio.uio_rw = UIO_READ; 656229997Sken } else { 657229997Sken SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 658267537Smav xuio.uio_rw = UIO_WRITE; 659229997Sken } 660229997Sken xuio.uio_offset = beio->io_offset; 661229997Sken xuio.uio_resid = beio->io_len; 662229997Sken xuio.uio_segflg = UIO_SYSSPACE; 663229997Sken xuio.uio_iov = beio->xiovecs; 664229997Sken xuio.uio_iovcnt = beio->num_segs; 665229997Sken xuio.uio_td = curthread; 666229997Sken 667229997Sken for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 668229997Sken xiovec->iov_base = beio->sg_segs[i].addr; 669229997Sken xiovec->iov_len = beio->sg_segs[i].len; 670229997Sken } 671229997Sken 672267877Smav binuptime(&beio->ds_t0); 673267877Smav mtx_lock(&be_lun->io_lock); 674267877Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 675267877Smav mtx_unlock(&be_lun->io_lock); 676267877Smav 677229997Sken if (beio->bio_cmd == BIO_READ) { 678229997Sken vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 679229997Sken 680229997Sken /* 681229997Sken * UFS pays attention to IO_DIRECT for reads. If the 682229997Sken * DIRECTIO option is configured into the kernel, it calls 683229997Sken * ffs_rawread(). But that only works for single-segment 684229997Sken * uios with user space addresses. In our case, with a 685229997Sken * kernel uio, it still reads into the buffer cache, but it 686229997Sken * will just try to release the buffer from the cache later 687229997Sken * on in ffs_read(). 688229997Sken * 689229997Sken * ZFS does not pay attention to IO_DIRECT for reads. 690229997Sken * 691229997Sken * UFS does not pay attention to IO_SYNC for reads. 692229997Sken * 693229997Sken * ZFS pays attention to IO_SYNC (which translates into the 694229997Sken * Solaris define FRSYNC for zfs_read()) for reads. It 695229997Sken * attempts to sync the file before reading. 696229997Sken */ 697271309Smav error = VOP_READ(be_lun->vn, &xuio, flags, file_data->cred); 698229997Sken 699229997Sken VOP_UNLOCK(be_lun->vn, 0); 700267537Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 701287875Smav if (error == 0 && xuio.uio_resid > 0) { 702287875Smav /* 703287875Smav * If we red less then requested (EOF), then 704287875Smav * we should clean the rest of the buffer. 705287875Smav */ 706287875Smav s = beio->io_len - xuio.uio_resid; 707287875Smav for (i = 0; i < beio->num_segs; i++) { 708287875Smav if (s >= beio->sg_segs[i].len) { 709287875Smav s -= beio->sg_segs[i].len; 710287875Smav continue; 711287875Smav } 712287875Smav bzero((uint8_t *)beio->sg_segs[i].addr + s, 713287875Smav beio->sg_segs[i].len - s); 714287875Smav s = 0; 715287875Smav } 716287875Smav } 717229997Sken } else { 718229997Sken struct mount *mountpoint; 719229997Sken int lock_flags; 720229997Sken 721229997Sken (void)vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 722229997Sken 723229997Sken if (MNT_SHARED_WRITES(mountpoint) 724229997Sken || ((mountpoint == NULL) 725229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 726229997Sken lock_flags = LK_SHARED; 727229997Sken else 728229997Sken lock_flags = LK_EXCLUSIVE; 729229997Sken 730229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 731229997Sken 732229997Sken /* 733229997Sken * UFS pays attention to IO_DIRECT for writes. The write 734229997Sken * is done asynchronously. (Normally the write would just 735229997Sken * get put into cache. 736229997Sken * 737229997Sken * UFS pays attention to IO_SYNC for writes. It will 738229997Sken * attempt to write the buffer out synchronously if that 739229997Sken * flag is set. 740229997Sken * 741229997Sken * ZFS does not pay attention to IO_DIRECT for writes. 742229997Sken * 743229997Sken * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC) 744229997Sken * for writes. It will flush the transaction from the 745229997Sken * cache before returning. 746229997Sken */ 747271309Smav error = VOP_WRITE(be_lun->vn, &xuio, flags, file_data->cred); 748229997Sken VOP_UNLOCK(be_lun->vn, 0); 749229997Sken 750229997Sken vn_finished_write(mountpoint); 751267537Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 752229997Sken } 753229997Sken 754267877Smav mtx_lock(&be_lun->io_lock); 755267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 756267877Smav beio->ds_tag_type, beio->ds_trans_type, 757267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 758267877Smav mtx_unlock(&be_lun->io_lock); 759267877Smav 760229997Sken /* 761229997Sken * If we got an error, set the sense data to "MEDIUM ERROR" and 762229997Sken * return the I/O to the user. 763229997Sken */ 764229997Sken if (error != 0) { 765282565Smav if (error == ENOSPC || error == EDQUOT) { 766273809Smav ctl_set_space_alloc_fail(&io->scsiio); 767287760Smav } else if (error == EROFS || error == EACCES) { 768287760Smav ctl_set_hw_write_protected(&io->scsiio); 769287912Smav } else { 770287912Smav ctl_set_medium_error(&io->scsiio, 771287912Smav beio->bio_cmd == BIO_READ); 772287912Smav } 773229997Sken ctl_complete_beio(beio); 774229997Sken return; 775229997Sken } 776229997Sken 777229997Sken /* 778269122Smav * If this is a write or a verify, we're all done. 779229997Sken * If this is a read, we can now send the data to the user. 780229997Sken */ 781269122Smav if ((beio->bio_cmd == BIO_WRITE) || 782269122Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 783229997Sken ctl_set_success(&io->scsiio); 784229997Sken ctl_complete_beio(beio); 785229997Sken } else { 786275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 787287967Smav beio->beio_cont == NULL) { 788275058Smav ctl_set_success(&io->scsiio); 789287967Smav ctl_serseq_done(io); 790287967Smav } 791229997Sken#ifdef CTL_TIME_IO 792229997Sken getbintime(&io->io_hdr.dma_start_bt); 793229997Sken#endif 794229997Sken ctl_datamove(io); 795229997Sken } 796229997Sken} 797229997Sken 798229997Skenstatic void 799275474Smavctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 800275474Smav struct ctl_be_block_io *beio) 801275474Smav{ 802275474Smav union ctl_io *io = beio->io; 803275474Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 804275474Smav struct scsi_get_lba_status_data *data; 805275474Smav off_t roff, off; 806275474Smav int error, status; 807275474Smav 808275474Smav DPRINTF("entered\n"); 809275474Smav 810287499Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 811275474Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 812275474Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off, 813275474Smav 0, curthread->td_ucred, curthread); 814275474Smav if (error == 0 && off > roff) 815275474Smav status = 0; /* mapped up to off */ 816275474Smav else { 817275474Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off, 818275474Smav 0, curthread->td_ucred, curthread); 819275474Smav if (error == 0 && off > roff) 820275474Smav status = 1; /* deallocated up to off */ 821275474Smav else { 822275474Smav status = 0; /* unknown up to the end */ 823275474Smav off = be_lun->size_bytes; 824275474Smav } 825275474Smav } 826275474Smav VOP_UNLOCK(be_lun->vn, 0); 827275474Smav 828275474Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 829275474Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 830287499Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 831287499Smav lbalen->lba), data->descr[0].length); 832275474Smav data->descr[0].status = status; 833275474Smav 834275474Smav ctl_complete_beio(beio); 835275474Smav} 836275474Smav 837275481Smavstatic uint64_t 838275481Smavctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, const char *attrname) 839275481Smav{ 840275481Smav struct vattr vattr; 841275481Smav struct statfs statfs; 842285030Smav uint64_t val; 843275481Smav int error; 844275481Smav 845285030Smav val = UINT64_MAX; 846275481Smav if (be_lun->vn == NULL) 847285030Smav return (val); 848285030Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 849275481Smav if (strcmp(attrname, "blocksused") == 0) { 850275481Smav error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 851285030Smav if (error == 0) 852287499Smav val = vattr.va_bytes / be_lun->cbe_lun.blocksize; 853275481Smav } 854285030Smav if (strcmp(attrname, "blocksavail") == 0 && 855285030Smav (be_lun->vn->v_iflag & VI_DOOMED) == 0) { 856275481Smav error = VFS_STATFS(be_lun->vn->v_mount, &statfs); 857285030Smav if (error == 0) 858286811Smav val = statfs.f_bavail * statfs.f_bsize / 859287499Smav be_lun->cbe_lun.blocksize; 860275481Smav } 861285030Smav VOP_UNLOCK(be_lun->vn, 0); 862285030Smav return (val); 863275481Smav} 864275481Smav 865275474Smavstatic void 866269123Smavctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, 867269123Smav struct ctl_be_block_io *beio) 868269123Smav{ 869269123Smav union ctl_io *io; 870287664Smav struct cdevsw *csw; 871287664Smav struct cdev *dev; 872269123Smav struct uio xuio; 873269123Smav struct iovec *xiovec; 874287664Smav int error, flags, i, ref; 875269123Smav 876269123Smav DPRINTF("entered\n"); 877269123Smav 878269123Smav io = beio->io; 879271309Smav flags = 0; 880271309Smav if (ARGS(io)->flags & CTL_LLF_DPO) 881271309Smav flags |= IO_DIRECT; 882271309Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 883271309Smav flags |= IO_SYNC; 884269123Smav 885269123Smav bzero(&xuio, sizeof(xuio)); 886269123Smav if (beio->bio_cmd == BIO_READ) { 887269123Smav SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 888269123Smav xuio.uio_rw = UIO_READ; 889269123Smav } else { 890269123Smav SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 891269123Smav xuio.uio_rw = UIO_WRITE; 892269123Smav } 893269123Smav xuio.uio_offset = beio->io_offset; 894269123Smav xuio.uio_resid = beio->io_len; 895269123Smav xuio.uio_segflg = UIO_SYSSPACE; 896269123Smav xuio.uio_iov = beio->xiovecs; 897269123Smav xuio.uio_iovcnt = beio->num_segs; 898269123Smav xuio.uio_td = curthread; 899269123Smav 900269123Smav for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 901269123Smav xiovec->iov_base = beio->sg_segs[i].addr; 902269123Smav xiovec->iov_len = beio->sg_segs[i].len; 903269123Smav } 904269123Smav 905269123Smav binuptime(&beio->ds_t0); 906269123Smav mtx_lock(&be_lun->io_lock); 907269123Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 908269123Smav mtx_unlock(&be_lun->io_lock); 909269123Smav 910287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 911287664Smav if (csw) { 912287664Smav if (beio->bio_cmd == BIO_READ) 913287664Smav error = csw->d_read(dev, &xuio, flags); 914287664Smav else 915287664Smav error = csw->d_write(dev, &xuio, flags); 916287664Smav dev_relthread(dev, ref); 917287664Smav } else 918287664Smav error = ENXIO; 919287664Smav 920287664Smav if (beio->bio_cmd == BIO_READ) 921269123Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 922287664Smav else 923269123Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 924269123Smav 925269123Smav mtx_lock(&be_lun->io_lock); 926269123Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 927269123Smav beio->ds_tag_type, beio->ds_trans_type, 928269123Smav /*now*/ NULL, /*then*/&beio->ds_t0); 929269123Smav mtx_unlock(&be_lun->io_lock); 930269123Smav 931269123Smav /* 932269123Smav * If we got an error, set the sense data to "MEDIUM ERROR" and 933269123Smav * return the I/O to the user. 934269123Smav */ 935269123Smav if (error != 0) { 936282565Smav if (error == ENOSPC || error == EDQUOT) { 937273809Smav ctl_set_space_alloc_fail(&io->scsiio); 938287760Smav } else if (error == EROFS || error == EACCES) { 939287760Smav ctl_set_hw_write_protected(&io->scsiio); 940287912Smav } else { 941287912Smav ctl_set_medium_error(&io->scsiio, 942287912Smav beio->bio_cmd == BIO_READ); 943287912Smav } 944269123Smav ctl_complete_beio(beio); 945269123Smav return; 946269123Smav } 947269123Smav 948269123Smav /* 949269123Smav * If this is a write or a verify, we're all done. 950269123Smav * If this is a read, we can now send the data to the user. 951269123Smav */ 952269123Smav if ((beio->bio_cmd == BIO_WRITE) || 953269123Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 954269123Smav ctl_set_success(&io->scsiio); 955269123Smav ctl_complete_beio(beio); 956269123Smav } else { 957275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 958287967Smav beio->beio_cont == NULL) { 959275058Smav ctl_set_success(&io->scsiio); 960287967Smav ctl_serseq_done(io); 961287967Smav } 962269123Smav#ifdef CTL_TIME_IO 963269123Smav getbintime(&io->io_hdr.dma_start_bt); 964269123Smav#endif 965269123Smav ctl_datamove(io); 966269123Smav } 967269123Smav} 968269123Smav 969269123Smavstatic void 970275474Smavctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, 971275474Smav struct ctl_be_block_io *beio) 972275474Smav{ 973275474Smav union ctl_io *io = beio->io; 974287664Smav struct cdevsw *csw; 975287664Smav struct cdev *dev; 976275474Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 977275474Smav struct scsi_get_lba_status_data *data; 978275474Smav off_t roff, off; 979287664Smav int error, ref, status; 980275474Smav 981275474Smav DPRINTF("entered\n"); 982275474Smav 983287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 984287664Smav if (csw == NULL) { 985287664Smav status = 0; /* unknown up to the end */ 986287664Smav off = be_lun->size_bytes; 987287664Smav goto done; 988287664Smav } 989287499Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 990287664Smav error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD, 991287664Smav curthread); 992275474Smav if (error == 0 && off > roff) 993275474Smav status = 0; /* mapped up to off */ 994275474Smav else { 995287664Smav error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD, 996287664Smav curthread); 997275474Smav if (error == 0 && off > roff) 998275474Smav status = 1; /* deallocated up to off */ 999275474Smav else { 1000275474Smav status = 0; /* unknown up to the end */ 1001275474Smav off = be_lun->size_bytes; 1002275474Smav } 1003275474Smav } 1004287664Smav dev_relthread(dev, ref); 1005275474Smav 1006287664Smavdone: 1007275474Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 1008275474Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 1009287499Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 1010287499Smav lbalen->lba), data->descr[0].length); 1011275474Smav data->descr[0].status = status; 1012275474Smav 1013275474Smav ctl_complete_beio(beio); 1014275474Smav} 1015275474Smav 1016275474Smavstatic void 1017229997Skenctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 1018229997Sken struct ctl_be_block_io *beio) 1019229997Sken{ 1020229997Sken struct bio *bio; 1021229997Sken union ctl_io *io; 1022287664Smav struct cdevsw *csw; 1023287664Smav struct cdev *dev; 1024287664Smav int ref; 1025229997Sken 1026229997Sken io = beio->io; 1027229997Sken 1028229997Sken DPRINTF("entered\n"); 1029229997Sken 1030229997Sken /* This can't fail, it's a blocking allocation. */ 1031229997Sken bio = g_alloc_bio(); 1032229997Sken 1033229997Sken bio->bio_cmd = BIO_FLUSH; 1034229997Sken bio->bio_offset = 0; 1035229997Sken bio->bio_data = 0; 1036229997Sken bio->bio_done = ctl_be_block_biodone; 1037229997Sken bio->bio_caller1 = beio; 1038229997Sken bio->bio_pblkno = 0; 1039229997Sken 1040229997Sken /* 1041229997Sken * We don't need to acquire the LUN lock here, because we are only 1042229997Sken * sending one bio, and so there is no other context to synchronize 1043229997Sken * with. 1044229997Sken */ 1045229997Sken beio->num_bios_sent = 1; 1046229997Sken beio->send_complete = 1; 1047229997Sken 1048229997Sken binuptime(&beio->ds_t0); 1049267877Smav mtx_lock(&be_lun->io_lock); 1050229997Sken devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1051267877Smav mtx_unlock(&be_lun->io_lock); 1052229997Sken 1053287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1054287664Smav if (csw) { 1055287664Smav bio->bio_dev = dev; 1056287664Smav csw->d_strategy(bio); 1057287664Smav dev_relthread(dev, ref); 1058287664Smav } else { 1059287664Smav bio->bio_error = ENXIO; 1060287664Smav ctl_be_block_biodone(bio); 1061287664Smav } 1062229997Sken} 1063229997Sken 1064229997Skenstatic void 1065264274Smavctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, 1066264274Smav struct ctl_be_block_io *beio, 1067264274Smav uint64_t off, uint64_t len, int last) 1068264274Smav{ 1069264274Smav struct bio *bio; 1070264296Smav uint64_t maxlen; 1071287664Smav struct cdevsw *csw; 1072287664Smav struct cdev *dev; 1073287664Smav int ref; 1074264274Smav 1075287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1076287499Smav maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize); 1077264274Smav while (len > 0) { 1078264274Smav bio = g_alloc_bio(); 1079264274Smav bio->bio_cmd = BIO_DELETE; 1080287664Smav bio->bio_dev = dev; 1081264274Smav bio->bio_offset = off; 1082264296Smav bio->bio_length = MIN(len, maxlen); 1083264274Smav bio->bio_data = 0; 1084264274Smav bio->bio_done = ctl_be_block_biodone; 1085264274Smav bio->bio_caller1 = beio; 1086287499Smav bio->bio_pblkno = off / be_lun->cbe_lun.blocksize; 1087264274Smav 1088264274Smav off += bio->bio_length; 1089264274Smav len -= bio->bio_length; 1090264274Smav 1091267877Smav mtx_lock(&be_lun->io_lock); 1092264274Smav beio->num_bios_sent++; 1093264274Smav if (last && len == 0) 1094264274Smav beio->send_complete = 1; 1095267877Smav mtx_unlock(&be_lun->io_lock); 1096264274Smav 1097287664Smav if (csw) { 1098287664Smav csw->d_strategy(bio); 1099287664Smav } else { 1100287664Smav bio->bio_error = ENXIO; 1101287664Smav ctl_be_block_biodone(bio); 1102287664Smav } 1103264274Smav } 1104287664Smav if (csw) 1105287664Smav dev_relthread(dev, ref); 1106264274Smav} 1107264274Smav 1108264274Smavstatic void 1109264274Smavctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 1110264274Smav struct ctl_be_block_io *beio) 1111264274Smav{ 1112264274Smav union ctl_io *io; 1113267515Smav struct ctl_ptr_len_flags *ptrlen; 1114264274Smav struct scsi_unmap_desc *buf, *end; 1115264274Smav uint64_t len; 1116264274Smav 1117264274Smav io = beio->io; 1118264274Smav 1119264274Smav DPRINTF("entered\n"); 1120264274Smav 1121264274Smav binuptime(&beio->ds_t0); 1122267877Smav mtx_lock(&be_lun->io_lock); 1123264274Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1124267877Smav mtx_unlock(&be_lun->io_lock); 1125264274Smav 1126264274Smav if (beio->io_offset == -1) { 1127264274Smav beio->io_len = 0; 1128267515Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1129267515Smav buf = (struct scsi_unmap_desc *)ptrlen->ptr; 1130267515Smav end = buf + ptrlen->len / sizeof(*buf); 1131264274Smav for (; buf < end; buf++) { 1132264274Smav len = (uint64_t)scsi_4btoul(buf->length) * 1133287499Smav be_lun->cbe_lun.blocksize; 1134264274Smav beio->io_len += len; 1135264274Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1136287499Smav scsi_8btou64(buf->lba) * be_lun->cbe_lun.blocksize, 1137287499Smav len, (end - buf < 2) ? TRUE : FALSE); 1138264274Smav } 1139264274Smav } else 1140264274Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1141264274Smav beio->io_offset, beio->io_len, TRUE); 1142264274Smav} 1143264274Smav 1144264274Smavstatic void 1145229997Skenctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 1146229997Sken struct ctl_be_block_io *beio) 1147229997Sken{ 1148267877Smav TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 1149229997Sken struct bio *bio; 1150287664Smav struct cdevsw *csw; 1151287664Smav struct cdev *dev; 1152229997Sken off_t cur_offset; 1153287664Smav int i, max_iosize, ref; 1154229997Sken 1155229997Sken DPRINTF("entered\n"); 1156287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1157229997Sken 1158229997Sken /* 1159229997Sken * We have to limit our I/O size to the maximum supported by the 1160229997Sken * backend device. Hopefully it is MAXPHYS. If the driver doesn't 1161229997Sken * set it properly, use DFLTPHYS. 1162229997Sken */ 1163287664Smav if (csw) { 1164287664Smav max_iosize = dev->si_iosize_max; 1165287664Smav if (max_iosize < PAGE_SIZE) 1166287664Smav max_iosize = DFLTPHYS; 1167287664Smav } else 1168229997Sken max_iosize = DFLTPHYS; 1169229997Sken 1170229997Sken cur_offset = beio->io_offset; 1171229997Sken for (i = 0; i < beio->num_segs; i++) { 1172229997Sken size_t cur_size; 1173229997Sken uint8_t *cur_ptr; 1174229997Sken 1175229997Sken cur_size = beio->sg_segs[i].len; 1176229997Sken cur_ptr = beio->sg_segs[i].addr; 1177229997Sken 1178229997Sken while (cur_size > 0) { 1179229997Sken /* This can't fail, it's a blocking allocation. */ 1180229997Sken bio = g_alloc_bio(); 1181229997Sken 1182229997Sken KASSERT(bio != NULL, ("g_alloc_bio() failed!\n")); 1183229997Sken 1184229997Sken bio->bio_cmd = beio->bio_cmd; 1185287664Smav bio->bio_dev = dev; 1186229997Sken bio->bio_caller1 = beio; 1187229997Sken bio->bio_length = min(cur_size, max_iosize); 1188229997Sken bio->bio_offset = cur_offset; 1189229997Sken bio->bio_data = cur_ptr; 1190229997Sken bio->bio_done = ctl_be_block_biodone; 1191287499Smav bio->bio_pblkno = cur_offset / be_lun->cbe_lun.blocksize; 1192229997Sken 1193229997Sken cur_offset += bio->bio_length; 1194229997Sken cur_ptr += bio->bio_length; 1195229997Sken cur_size -= bio->bio_length; 1196229997Sken 1197267877Smav TAILQ_INSERT_TAIL(&queue, bio, bio_queue); 1198229997Sken beio->num_bios_sent++; 1199229997Sken } 1200229997Sken } 1201267877Smav binuptime(&beio->ds_t0); 1202267877Smav mtx_lock(&be_lun->io_lock); 1203267877Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1204267877Smav beio->send_complete = 1; 1205267877Smav mtx_unlock(&be_lun->io_lock); 1206267877Smav 1207267877Smav /* 1208267877Smav * Fire off all allocated requests! 1209267877Smav */ 1210267877Smav while ((bio = TAILQ_FIRST(&queue)) != NULL) { 1211267877Smav TAILQ_REMOVE(&queue, bio, bio_queue); 1212287664Smav if (csw) 1213287664Smav csw->d_strategy(bio); 1214287664Smav else { 1215287664Smav bio->bio_error = ENXIO; 1216287664Smav ctl_be_block_biodone(bio); 1217287664Smav } 1218267877Smav } 1219287664Smav if (csw) 1220287664Smav dev_relthread(dev, ref); 1221229997Sken} 1222229997Sken 1223274154Smavstatic uint64_t 1224274154Smavctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname) 1225274154Smav{ 1226274154Smav struct diocgattr_arg arg; 1227287664Smav struct cdevsw *csw; 1228287664Smav struct cdev *dev; 1229287664Smav int error, ref; 1230274154Smav 1231287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1232287664Smav if (csw == NULL) 1233274154Smav return (UINT64_MAX); 1234274154Smav strlcpy(arg.name, attrname, sizeof(arg.name)); 1235274154Smav arg.len = sizeof(arg.value.off); 1236287664Smav if (csw->d_ioctl) { 1237287664Smav error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 1238287664Smav curthread); 1239287664Smav } else 1240287664Smav error = ENODEV; 1241287664Smav dev_relthread(dev, ref); 1242274154Smav if (error != 0) 1243274154Smav return (UINT64_MAX); 1244274154Smav return (arg.value.off); 1245274154Smav} 1246274154Smav 1247229997Skenstatic void 1248286353Smavctl_be_block_cw_dispatch_sync(struct ctl_be_block_lun *be_lun, 1249286353Smav union ctl_io *io) 1250286353Smav{ 1251287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1252286353Smav struct ctl_be_block_io *beio; 1253286353Smav struct ctl_lba_len_flags *lbalen; 1254286353Smav 1255286353Smav DPRINTF("entered\n"); 1256286353Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1257286353Smav lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1258286353Smav 1259287499Smav beio->io_len = lbalen->len * cbe_lun->blocksize; 1260287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1261286353Smav beio->io_arg = (lbalen->flags & SSC_IMMED) != 0; 1262286353Smav beio->bio_cmd = BIO_FLUSH; 1263286353Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1264286353Smav DPRINTF("SYNC\n"); 1265286353Smav be_lun->lun_flush(be_lun, beio); 1266286353Smav} 1267286353Smav 1268286353Smavstatic void 1269264274Smavctl_be_block_cw_done_ws(struct ctl_be_block_io *beio) 1270264274Smav{ 1271264274Smav union ctl_io *io; 1272264274Smav 1273264274Smav io = beio->io; 1274264274Smav ctl_free_beio(beio); 1275267641Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1276267641Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1277267641Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1278264274Smav ctl_config_write_done(io); 1279264274Smav return; 1280264274Smav } 1281264274Smav 1282264274Smav ctl_be_block_config_write(io); 1283264274Smav} 1284264274Smav 1285264274Smavstatic void 1286264274Smavctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun, 1287264274Smav union ctl_io *io) 1288264274Smav{ 1289287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1290264274Smav struct ctl_be_block_io *beio; 1291267515Smav struct ctl_lba_len_flags *lbalen; 1292278625Smav uint64_t len_left, lba; 1293278625Smav uint32_t pb, pbo, adj; 1294264274Smav int i, seglen; 1295264274Smav uint8_t *buf, *end; 1296264274Smav 1297264274Smav DPRINTF("entered\n"); 1298264274Smav 1299267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1300267537Smav lbalen = ARGS(beio->io); 1301264274Smav 1302271839Smav if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB) || 1303269622Smav (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR) && be_lun->unmap == NULL)) { 1304264274Smav ctl_free_beio(beio); 1305264274Smav ctl_set_invalid_field(&io->scsiio, 1306264274Smav /*sks_valid*/ 1, 1307264274Smav /*command*/ 1, 1308264274Smav /*field*/ 1, 1309264274Smav /*bit_valid*/ 0, 1310264274Smav /*bit*/ 0); 1311264274Smav ctl_config_write_done(io); 1312264274Smav return; 1313264274Smav } 1314264274Smav 1315269622Smav if (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR)) { 1316287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1317287499Smav beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize; 1318264274Smav beio->bio_cmd = BIO_DELETE; 1319264274Smav beio->ds_trans_type = DEVSTAT_FREE; 1320264274Smav 1321264274Smav be_lun->unmap(be_lun, beio); 1322264274Smav return; 1323264274Smav } 1324264274Smav 1325264274Smav beio->bio_cmd = BIO_WRITE; 1326264274Smav beio->ds_trans_type = DEVSTAT_WRITE; 1327264274Smav 1328264274Smav DPRINTF("WRITE SAME at LBA %jx len %u\n", 1329267515Smav (uintmax_t)lbalen->lba, lbalen->len); 1330264274Smav 1331287499Smav pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp; 1332287499Smav if (be_lun->cbe_lun.pblockoff > 0) 1333287499Smav pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff; 1334278625Smav else 1335278625Smav pbo = 0; 1336287499Smav len_left = (uint64_t)lbalen->len * cbe_lun->blocksize; 1337264274Smav for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) { 1338264274Smav 1339264274Smav /* 1340264274Smav * Setup the S/G entry for this chunk. 1341264274Smav */ 1342264886Smav seglen = MIN(CTLBLK_MAX_SEG, len_left); 1343287499Smav if (pb > cbe_lun->blocksize) { 1344287499Smav adj = ((lbalen->lba + lba) * cbe_lun->blocksize + 1345278619Smav seglen - pbo) % pb; 1346278619Smav if (seglen > adj) 1347278619Smav seglen -= adj; 1348278619Smav else 1349287499Smav seglen -= seglen % cbe_lun->blocksize; 1350278619Smav } else 1351287499Smav seglen -= seglen % cbe_lun->blocksize; 1352264274Smav beio->sg_segs[i].len = seglen; 1353264274Smav beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1354264274Smav 1355264274Smav DPRINTF("segment %d addr %p len %zd\n", i, 1356264274Smav beio->sg_segs[i].addr, beio->sg_segs[i].len); 1357264274Smav 1358264274Smav beio->num_segs++; 1359264274Smav len_left -= seglen; 1360264274Smav 1361264274Smav buf = beio->sg_segs[i].addr; 1362264274Smav end = buf + seglen; 1363287499Smav for (; buf < end; buf += cbe_lun->blocksize) { 1364287499Smav memcpy(buf, io->scsiio.kern_data_ptr, cbe_lun->blocksize); 1365267515Smav if (lbalen->flags & SWS_LBDATA) 1366267515Smav scsi_ulto4b(lbalen->lba + lba, buf); 1367264274Smav lba++; 1368264274Smav } 1369264274Smav } 1370264274Smav 1371287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1372287499Smav beio->io_len = lba * cbe_lun->blocksize; 1373264274Smav 1374264274Smav /* We can not do all in one run. Correct and schedule rerun. */ 1375264274Smav if (len_left > 0) { 1376267515Smav lbalen->lba += lba; 1377267515Smav lbalen->len -= lba; 1378264274Smav beio->beio_cont = ctl_be_block_cw_done_ws; 1379264274Smav } 1380264274Smav 1381264274Smav be_lun->dispatch(be_lun, beio); 1382264274Smav} 1383264274Smav 1384264274Smavstatic void 1385264274Smavctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun, 1386264274Smav union ctl_io *io) 1387264274Smav{ 1388264274Smav struct ctl_be_block_io *beio; 1389267515Smav struct ctl_ptr_len_flags *ptrlen; 1390264274Smav 1391264274Smav DPRINTF("entered\n"); 1392264274Smav 1393267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1394267515Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1395264274Smav 1396269622Smav if ((ptrlen->flags & ~SU_ANCHOR) != 0 || be_lun->unmap == NULL) { 1397264274Smav ctl_free_beio(beio); 1398264274Smav ctl_set_invalid_field(&io->scsiio, 1399264274Smav /*sks_valid*/ 0, 1400264274Smav /*command*/ 1, 1401264274Smav /*field*/ 0, 1402264274Smav /*bit_valid*/ 0, 1403264274Smav /*bit*/ 0); 1404264274Smav ctl_config_write_done(io); 1405264274Smav return; 1406264274Smav } 1407264274Smav 1408264274Smav beio->io_len = 0; 1409264274Smav beio->io_offset = -1; 1410264274Smav beio->bio_cmd = BIO_DELETE; 1411264274Smav beio->ds_trans_type = DEVSTAT_FREE; 1412267515Smav DPRINTF("UNMAP\n"); 1413264274Smav be_lun->unmap(be_lun, beio); 1414264274Smav} 1415264274Smav 1416264274Smavstatic void 1417275474Smavctl_be_block_cr_done(struct ctl_be_block_io *beio) 1418275474Smav{ 1419275474Smav union ctl_io *io; 1420275474Smav 1421275474Smav io = beio->io; 1422275474Smav ctl_free_beio(beio); 1423275474Smav ctl_config_read_done(io); 1424275474Smav} 1425275474Smav 1426275474Smavstatic void 1427275474Smavctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 1428275474Smav union ctl_io *io) 1429275474Smav{ 1430275474Smav struct ctl_be_block_io *beio; 1431275474Smav struct ctl_be_block_softc *softc; 1432275474Smav 1433275474Smav DPRINTF("entered\n"); 1434275474Smav 1435275474Smav softc = be_lun->softc; 1436275474Smav beio = ctl_alloc_beio(softc); 1437275474Smav beio->io = io; 1438275474Smav beio->lun = be_lun; 1439275474Smav beio->beio_cont = ctl_be_block_cr_done; 1440275474Smav PRIV(io)->ptr = (void *)beio; 1441275474Smav 1442275474Smav switch (io->scsiio.cdb[0]) { 1443275474Smav case SERVICE_ACTION_IN: /* GET LBA STATUS */ 1444275474Smav beio->bio_cmd = -1; 1445275474Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1446275474Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1447275474Smav beio->io_len = 0; 1448275474Smav if (be_lun->get_lba_status) 1449275474Smav be_lun->get_lba_status(be_lun, beio); 1450275474Smav else 1451275474Smav ctl_be_block_cr_done(beio); 1452275474Smav break; 1453275474Smav default: 1454275474Smav panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1455275474Smav break; 1456275474Smav } 1457275474Smav} 1458275474Smav 1459275474Smavstatic void 1460264274Smavctl_be_block_cw_done(struct ctl_be_block_io *beio) 1461264274Smav{ 1462264274Smav union ctl_io *io; 1463264274Smav 1464264274Smav io = beio->io; 1465264274Smav ctl_free_beio(beio); 1466264274Smav ctl_config_write_done(io); 1467264274Smav} 1468264274Smav 1469264274Smavstatic void 1470229997Skenctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 1471229997Sken union ctl_io *io) 1472229997Sken{ 1473229997Sken struct ctl_be_block_io *beio; 1474229997Sken struct ctl_be_block_softc *softc; 1475229997Sken 1476229997Sken DPRINTF("entered\n"); 1477229997Sken 1478229997Sken softc = be_lun->softc; 1479229997Sken beio = ctl_alloc_beio(softc); 1480229997Sken beio->io = io; 1481229997Sken beio->lun = be_lun; 1482264274Smav beio->beio_cont = ctl_be_block_cw_done; 1483286353Smav switch (io->scsiio.tag_type) { 1484286353Smav case CTL_TAG_ORDERED: 1485286353Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1486286353Smav break; 1487286353Smav case CTL_TAG_HEAD_OF_QUEUE: 1488286353Smav beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1489286353Smav break; 1490286353Smav case CTL_TAG_UNTAGGED: 1491286353Smav case CTL_TAG_SIMPLE: 1492286353Smav case CTL_TAG_ACA: 1493286353Smav default: 1494286353Smav beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1495286353Smav break; 1496286353Smav } 1497267519Smav PRIV(io)->ptr = (void *)beio; 1498229997Sken 1499229997Sken switch (io->scsiio.cdb[0]) { 1500229997Sken case SYNCHRONIZE_CACHE: 1501229997Sken case SYNCHRONIZE_CACHE_16: 1502286353Smav ctl_be_block_cw_dispatch_sync(be_lun, io); 1503229997Sken break; 1504264274Smav case WRITE_SAME_10: 1505264274Smav case WRITE_SAME_16: 1506264274Smav ctl_be_block_cw_dispatch_ws(be_lun, io); 1507264274Smav break; 1508264274Smav case UNMAP: 1509264274Smav ctl_be_block_cw_dispatch_unmap(be_lun, io); 1510264274Smav break; 1511229997Sken default: 1512229997Sken panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1513229997Sken break; 1514229997Sken } 1515229997Sken} 1516229997Sken 1517258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, start, "uint64_t"); 1518258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, start, "uint64_t"); 1519258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, alloc_done, "uint64_t"); 1520258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, alloc_done, "uint64_t"); 1521229997Sken 1522229997Skenstatic void 1523264886Smavctl_be_block_next(struct ctl_be_block_io *beio) 1524264886Smav{ 1525264886Smav struct ctl_be_block_lun *be_lun; 1526264886Smav union ctl_io *io; 1527264886Smav 1528264886Smav io = beio->io; 1529264886Smav be_lun = beio->lun; 1530264886Smav ctl_free_beio(beio); 1531267641Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1532267641Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1533267641Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1534267537Smav ctl_data_submit_done(io); 1535264886Smav return; 1536264886Smav } 1537264886Smav 1538264886Smav io->io_hdr.status &= ~CTL_STATUS_MASK; 1539264886Smav io->io_hdr.status |= CTL_STATUS_NONE; 1540264886Smav 1541267877Smav mtx_lock(&be_lun->queue_lock); 1542264886Smav /* 1543264886Smav * XXX KDM make sure that links is okay to use at this point. 1544264886Smav * Otherwise, we either need to add another field to ctl_io_hdr, 1545264886Smav * or deal with resource allocation here. 1546264886Smav */ 1547264886Smav STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1548267877Smav mtx_unlock(&be_lun->queue_lock); 1549264886Smav 1550264886Smav taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1551264886Smav} 1552264886Smav 1553264886Smavstatic void 1554229997Skenctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 1555229997Sken union ctl_io *io) 1556229997Sken{ 1557287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1558229997Sken struct ctl_be_block_io *beio; 1559229997Sken struct ctl_be_block_softc *softc; 1560267537Smav struct ctl_lba_len_flags *lbalen; 1561267519Smav struct ctl_ptr_len_flags *bptrlen; 1562267519Smav uint64_t len_left, lbas; 1563229997Sken int i; 1564229997Sken 1565229997Sken softc = be_lun->softc; 1566229997Sken 1567229997Sken DPRINTF("entered\n"); 1568229997Sken 1569267537Smav lbalen = ARGS(io); 1570267537Smav if (lbalen->flags & CTL_LLF_WRITE) { 1571267537Smav SDT_PROBE(cbb, kernel, write, start, 0, 0, 0, 0, 0); 1572267537Smav } else { 1573229997Sken SDT_PROBE(cbb, kernel, read, start, 0, 0, 0, 0, 0); 1574229997Sken } 1575229997Sken 1576229997Sken beio = ctl_alloc_beio(softc); 1577229997Sken beio->io = io; 1578229997Sken beio->lun = be_lun; 1579267519Smav bptrlen = PRIV(io); 1580267519Smav bptrlen->ptr = (void *)beio; 1581229997Sken 1582229997Sken switch (io->scsiio.tag_type) { 1583229997Sken case CTL_TAG_ORDERED: 1584229997Sken beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1585229997Sken break; 1586229997Sken case CTL_TAG_HEAD_OF_QUEUE: 1587229997Sken beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1588229997Sken break; 1589229997Sken case CTL_TAG_UNTAGGED: 1590229997Sken case CTL_TAG_SIMPLE: 1591229997Sken case CTL_TAG_ACA: 1592229997Sken default: 1593229997Sken beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1594229997Sken break; 1595229997Sken } 1596229997Sken 1597267537Smav if (lbalen->flags & CTL_LLF_WRITE) { 1598267537Smav beio->bio_cmd = BIO_WRITE; 1599267537Smav beio->ds_trans_type = DEVSTAT_WRITE; 1600267537Smav } else { 1601229997Sken beio->bio_cmd = BIO_READ; 1602229997Sken beio->ds_trans_type = DEVSTAT_READ; 1603229997Sken } 1604229997Sken 1605264886Smav DPRINTF("%s at LBA %jx len %u @%ju\n", 1606229997Sken (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", 1607267519Smav (uintmax_t)lbalen->lba, lbalen->len, bptrlen->len); 1608267537Smav if (lbalen->flags & CTL_LLF_COMPARE) 1609267537Smav lbas = CTLBLK_HALF_IO_SIZE; 1610267537Smav else 1611267537Smav lbas = CTLBLK_MAX_IO_SIZE; 1612287499Smav lbas = MIN(lbalen->len - bptrlen->len, lbas / cbe_lun->blocksize); 1613287499Smav beio->io_offset = (lbalen->lba + bptrlen->len) * cbe_lun->blocksize; 1614287499Smav beio->io_len = lbas * cbe_lun->blocksize; 1615267519Smav bptrlen->len += lbas; 1616229997Sken 1617264886Smav for (i = 0, len_left = beio->io_len; len_left > 0; i++) { 1618264886Smav KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", 1619264886Smav i, CTLBLK_MAX_SEGS)); 1620229997Sken 1621229997Sken /* 1622229997Sken * Setup the S/G entry for this chunk. 1623229997Sken */ 1624264886Smav beio->sg_segs[i].len = min(CTLBLK_MAX_SEG, len_left); 1625229997Sken beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1626229997Sken 1627229997Sken DPRINTF("segment %d addr %p len %zd\n", i, 1628229997Sken beio->sg_segs[i].addr, beio->sg_segs[i].len); 1629229997Sken 1630267537Smav /* Set up second segment for compare operation. */ 1631267537Smav if (lbalen->flags & CTL_LLF_COMPARE) { 1632267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].len = 1633267537Smav beio->sg_segs[i].len; 1634267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = 1635267537Smav uma_zalloc(be_lun->lun_zone, M_WAITOK); 1636267537Smav } 1637267537Smav 1638229997Sken beio->num_segs++; 1639229997Sken len_left -= beio->sg_segs[i].len; 1640229997Sken } 1641267519Smav if (bptrlen->len < lbalen->len) 1642264886Smav beio->beio_cont = ctl_be_block_next; 1643264886Smav io->scsiio.be_move_done = ctl_be_block_move_done; 1644267537Smav /* For compare we have separate S/G lists for read and datamove. */ 1645267537Smav if (lbalen->flags & CTL_LLF_COMPARE) 1646267537Smav io->scsiio.kern_data_ptr = (uint8_t *)&beio->sg_segs[CTLBLK_HALF_SEGS]; 1647267537Smav else 1648267537Smav io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; 1649264886Smav io->scsiio.kern_data_len = beio->io_len; 1650264886Smav io->scsiio.kern_data_resid = 0; 1651264886Smav io->scsiio.kern_sg_entries = beio->num_segs; 1652288020Smav io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 1653229997Sken 1654229997Sken /* 1655229997Sken * For the read case, we need to read the data into our buffers and 1656229997Sken * then we can send it back to the user. For the write case, we 1657229997Sken * need to get the data from the user first. 1658229997Sken */ 1659229997Sken if (beio->bio_cmd == BIO_READ) { 1660229997Sken SDT_PROBE(cbb, kernel, read, alloc_done, 0, 0, 0, 0, 0); 1661229997Sken be_lun->dispatch(be_lun, beio); 1662229997Sken } else { 1663229997Sken SDT_PROBE(cbb, kernel, write, alloc_done, 0, 0, 0, 0, 0); 1664229997Sken#ifdef CTL_TIME_IO 1665229997Sken getbintime(&io->io_hdr.dma_start_bt); 1666229997Sken#endif 1667229997Sken ctl_datamove(io); 1668229997Sken } 1669229997Sken} 1670229997Sken 1671229997Skenstatic void 1672229997Skenctl_be_block_worker(void *context, int pending) 1673229997Sken{ 1674287670Smav struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)context; 1675287670Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1676229997Sken union ctl_io *io; 1677287670Smav struct ctl_be_block_io *beio; 1678229997Sken 1679229997Sken DPRINTF("entered\n"); 1680287670Smav /* 1681287670Smav * Fetch and process I/Os from all queues. If we detect LUN 1682287670Smav * CTL_LUN_FLAG_OFFLINE status here -- it is result of a race, 1683287670Smav * so make response maximally opaque to not confuse initiator. 1684287670Smav */ 1685229997Sken for (;;) { 1686287670Smav mtx_lock(&be_lun->queue_lock); 1687229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue); 1688229997Sken if (io != NULL) { 1689229997Sken DPRINTF("datamove queue\n"); 1690229997Sken STAILQ_REMOVE(&be_lun->datamove_queue, &io->io_hdr, 1691229997Sken ctl_io_hdr, links); 1692267877Smav mtx_unlock(&be_lun->queue_lock); 1693267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1694287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1695287670Smav ctl_set_busy(&io->scsiio); 1696287670Smav ctl_complete_beio(beio); 1697287670Smav return; 1698287670Smav } 1699229997Sken be_lun->dispatch(be_lun, beio); 1700229997Sken continue; 1701229997Sken } 1702229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue); 1703229997Sken if (io != NULL) { 1704229997Sken DPRINTF("config write queue\n"); 1705229997Sken STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr, 1706229997Sken ctl_io_hdr, links); 1707267877Smav mtx_unlock(&be_lun->queue_lock); 1708287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1709287670Smav ctl_set_busy(&io->scsiio); 1710287670Smav ctl_config_write_done(io); 1711287670Smav return; 1712287670Smav } 1713229997Sken ctl_be_block_cw_dispatch(be_lun, io); 1714229997Sken continue; 1715229997Sken } 1716275474Smav io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue); 1717275474Smav if (io != NULL) { 1718275474Smav DPRINTF("config read queue\n"); 1719275474Smav STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr, 1720275474Smav ctl_io_hdr, links); 1721275474Smav mtx_unlock(&be_lun->queue_lock); 1722287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1723287670Smav ctl_set_busy(&io->scsiio); 1724287670Smav ctl_config_read_done(io); 1725287670Smav return; 1726287670Smav } 1727275474Smav ctl_be_block_cr_dispatch(be_lun, io); 1728275474Smav continue; 1729275474Smav } 1730229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue); 1731229997Sken if (io != NULL) { 1732229997Sken DPRINTF("input queue\n"); 1733229997Sken STAILQ_REMOVE(&be_lun->input_queue, &io->io_hdr, 1734229997Sken ctl_io_hdr, links); 1735267877Smav mtx_unlock(&be_lun->queue_lock); 1736287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1737287670Smav ctl_set_busy(&io->scsiio); 1738287670Smav ctl_data_submit_done(io); 1739287670Smav return; 1740287670Smav } 1741229997Sken ctl_be_block_dispatch(be_lun, io); 1742229997Sken continue; 1743229997Sken } 1744229997Sken 1745229997Sken /* 1746229997Sken * If we get here, there is no work left in the queues, so 1747229997Sken * just break out and let the task queue go to sleep. 1748229997Sken */ 1749287670Smav mtx_unlock(&be_lun->queue_lock); 1750229997Sken break; 1751229997Sken } 1752229997Sken} 1753229997Sken 1754229997Sken/* 1755229997Sken * Entry point from CTL to the backend for I/O. We queue everything to a 1756229997Sken * work thread, so this just puts the I/O on a queue and wakes up the 1757229997Sken * thread. 1758229997Sken */ 1759229997Skenstatic int 1760229997Skenctl_be_block_submit(union ctl_io *io) 1761229997Sken{ 1762229997Sken struct ctl_be_block_lun *be_lun; 1763287499Smav struct ctl_be_lun *cbe_lun; 1764229997Sken 1765229997Sken DPRINTF("entered\n"); 1766229997Sken 1767287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 1768229997Sken CTL_PRIV_BACKEND_LUN].ptr; 1769287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 1770229997Sken 1771229997Sken /* 1772229997Sken * Make sure we only get SCSI I/O. 1773229997Sken */ 1774229997Sken KASSERT(io->io_hdr.io_type == CTL_IO_SCSI, ("Non-SCSI I/O (type " 1775229997Sken "%#x) encountered", io->io_hdr.io_type)); 1776229997Sken 1777267519Smav PRIV(io)->len = 0; 1778267519Smav 1779267877Smav mtx_lock(&be_lun->queue_lock); 1780229997Sken /* 1781229997Sken * XXX KDM make sure that links is okay to use at this point. 1782229997Sken * Otherwise, we either need to add another field to ctl_io_hdr, 1783229997Sken * or deal with resource allocation here. 1784229997Sken */ 1785229997Sken STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1786267877Smav mtx_unlock(&be_lun->queue_lock); 1787229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1788229997Sken 1789267514Smav return (CTL_RETVAL_COMPLETE); 1790229997Sken} 1791229997Sken 1792229997Skenstatic int 1793229997Skenctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 1794229997Sken int flag, struct thread *td) 1795229997Sken{ 1796229997Sken struct ctl_be_block_softc *softc; 1797229997Sken int error; 1798229997Sken 1799229997Sken softc = &backend_block_softc; 1800229997Sken 1801229997Sken error = 0; 1802229997Sken 1803229997Sken switch (cmd) { 1804229997Sken case CTL_LUN_REQ: { 1805229997Sken struct ctl_lun_req *lun_req; 1806229997Sken 1807229997Sken lun_req = (struct ctl_lun_req *)addr; 1808229997Sken 1809229997Sken switch (lun_req->reqtype) { 1810229997Sken case CTL_LUNREQ_CREATE: 1811229997Sken error = ctl_be_block_create(softc, lun_req); 1812229997Sken break; 1813229997Sken case CTL_LUNREQ_RM: 1814229997Sken error = ctl_be_block_rm(softc, lun_req); 1815229997Sken break; 1816232604Strasz case CTL_LUNREQ_MODIFY: 1817232604Strasz error = ctl_be_block_modify(softc, lun_req); 1818232604Strasz break; 1819229997Sken default: 1820229997Sken lun_req->status = CTL_LUN_ERROR; 1821229997Sken snprintf(lun_req->error_str, sizeof(lun_req->error_str), 1822272911Smav "invalid LUN request type %d", 1823229997Sken lun_req->reqtype); 1824229997Sken break; 1825229997Sken } 1826229997Sken break; 1827229997Sken } 1828229997Sken default: 1829229997Sken error = ENOTTY; 1830229997Sken break; 1831229997Sken } 1832229997Sken 1833229997Sken return (error); 1834229997Sken} 1835229997Sken 1836229997Skenstatic int 1837229997Skenctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1838229997Sken{ 1839287499Smav struct ctl_be_lun *cbe_lun; 1840229997Sken struct ctl_be_block_filedata *file_data; 1841229997Sken struct ctl_lun_create_params *params; 1842275865Smav char *value; 1843229997Sken struct vattr vattr; 1844275865Smav off_t ps, pss, po, pos, us, uss, uo, uos; 1845229997Sken int error; 1846229997Sken 1847229997Sken error = 0; 1848287499Smav cbe_lun = &be_lun->cbe_lun; 1849229997Sken file_data = &be_lun->backend.file; 1850272911Smav params = &be_lun->params; 1851229997Sken 1852229997Sken be_lun->dev_type = CTL_BE_BLOCK_FILE; 1853229997Sken be_lun->dispatch = ctl_be_block_dispatch_file; 1854229997Sken be_lun->lun_flush = ctl_be_block_flush_file; 1855275474Smav be_lun->get_lba_status = ctl_be_block_gls_file; 1856275481Smav be_lun->getattr = ctl_be_block_getattr_file; 1857287499Smav be_lun->unmap = NULL; 1858287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 1859229997Sken 1860229997Sken error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 1861229997Sken if (error != 0) { 1862229997Sken snprintf(req->error_str, sizeof(req->error_str), 1863229997Sken "error calling VOP_GETATTR() for file %s", 1864229997Sken be_lun->dev_path); 1865229997Sken return (error); 1866229997Sken } 1867229997Sken 1868229997Sken /* 1869229997Sken * Verify that we have the ability to upgrade to exclusive 1870229997Sken * access on this file so we can trap errors at open instead 1871229997Sken * of reporting them during first access. 1872229997Sken */ 1873229997Sken if (VOP_ISLOCKED(be_lun->vn) != LK_EXCLUSIVE) { 1874229997Sken vn_lock(be_lun->vn, LK_UPGRADE | LK_RETRY); 1875229997Sken if (be_lun->vn->v_iflag & VI_DOOMED) { 1876229997Sken error = EBADF; 1877229997Sken snprintf(req->error_str, sizeof(req->error_str), 1878229997Sken "error locking file %s", be_lun->dev_path); 1879229997Sken return (error); 1880229997Sken } 1881229997Sken } 1882229997Sken 1883229997Sken file_data->cred = crhold(curthread->td_ucred); 1884232604Strasz if (params->lun_size_bytes != 0) 1885232604Strasz be_lun->size_bytes = params->lun_size_bytes; 1886232604Strasz else 1887232604Strasz be_lun->size_bytes = vattr.va_size; 1888229997Sken 1889229997Sken /* 1890273029Smav * For files we can use any logical block size. Prefer 512 bytes 1891273029Smav * for compatibility reasons. If file's vattr.va_blocksize 1892273029Smav * (preferred I/O block size) is bigger and multiple to chosen 1893273029Smav * logical block size -- report it as physical block size. 1894229997Sken */ 1895229997Sken if (params->blocksize_bytes != 0) 1896287499Smav cbe_lun->blocksize = params->blocksize_bytes; 1897229997Sken else 1898287499Smav cbe_lun->blocksize = 512; 1899287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 1900287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 1901287499Smav 0 : (be_lun->size_blocks - 1); 1902275865Smav 1903275865Smav us = ps = vattr.va_blocksize; 1904275865Smav uo = po = 0; 1905275865Smav 1906287499Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 1907275865Smav if (value != NULL) 1908275865Smav ctl_expand_number(value, &ps); 1909287499Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 1910275865Smav if (value != NULL) 1911275865Smav ctl_expand_number(value, &po); 1912287499Smav pss = ps / cbe_lun->blocksize; 1913287499Smav pos = po / cbe_lun->blocksize; 1914287499Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 1915287499Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 1916287499Smav cbe_lun->pblockexp = fls(pss) - 1; 1917287499Smav cbe_lun->pblockoff = (pss - pos) % pss; 1918273029Smav } 1919229997Sken 1920287499Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 1921275865Smav if (value != NULL) 1922275865Smav ctl_expand_number(value, &us); 1923287499Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 1924275865Smav if (value != NULL) 1925275865Smav ctl_expand_number(value, &uo); 1926287499Smav uss = us / cbe_lun->blocksize; 1927287499Smav uos = uo / cbe_lun->blocksize; 1928287499Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 1929287499Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 1930287499Smav cbe_lun->ublockexp = fls(uss) - 1; 1931287499Smav cbe_lun->ublockoff = (uss - uos) % uss; 1932275865Smav } 1933275865Smav 1934229997Sken /* 1935229997Sken * Sanity check. The media size has to be at least one 1936229997Sken * sector long. 1937229997Sken */ 1938287499Smav if (be_lun->size_bytes < cbe_lun->blocksize) { 1939229997Sken error = EINVAL; 1940229997Sken snprintf(req->error_str, sizeof(req->error_str), 1941229997Sken "file %s size %ju < block size %u", be_lun->dev_path, 1942287499Smav (uintmax_t)be_lun->size_bytes, cbe_lun->blocksize); 1943229997Sken } 1944275920Smav 1945287499Smav cbe_lun->opttxferlen = CTLBLK_MAX_IO_SIZE / cbe_lun->blocksize; 1946229997Sken return (error); 1947229997Sken} 1948229997Sken 1949229997Skenstatic int 1950229997Skenctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1951229997Sken{ 1952287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1953229997Sken struct ctl_lun_create_params *params; 1954287664Smav struct cdevsw *csw; 1955229997Sken struct cdev *dev; 1956275865Smav char *value; 1957287664Smav int error, atomic, maxio, ref, unmap, tmp; 1958287221Smav off_t ps, pss, po, pos, us, uss, uo, uos, otmp; 1959229997Sken 1960272911Smav params = &be_lun->params; 1961229997Sken 1962229997Sken be_lun->dev_type = CTL_BE_BLOCK_DEV; 1963287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1964287664Smav if (csw == NULL) 1965287664Smav return (ENXIO); 1966287664Smav if (strcmp(csw->d_name, "zvol") == 0) { 1967269123Smav be_lun->dispatch = ctl_be_block_dispatch_zvol; 1968275474Smav be_lun->get_lba_status = ctl_be_block_gls_zvol; 1969275920Smav atomic = maxio = CTLBLK_MAX_IO_SIZE; 1970275920Smav } else { 1971269123Smav be_lun->dispatch = ctl_be_block_dispatch_dev; 1972287499Smav be_lun->get_lba_status = NULL; 1973275920Smav atomic = 0; 1974287664Smav maxio = dev->si_iosize_max; 1975275920Smav if (maxio <= 0) 1976275920Smav maxio = DFLTPHYS; 1977275920Smav if (maxio > CTLBLK_MAX_IO_SIZE) 1978275920Smav maxio = CTLBLK_MAX_IO_SIZE; 1979275920Smav } 1980269123Smav be_lun->lun_flush = ctl_be_block_flush_dev; 1981274154Smav be_lun->getattr = ctl_be_block_getattr_dev; 1982287499Smav be_lun->unmap = ctl_be_block_unmap_dev; 1983229997Sken 1984287664Smav if (!csw->d_ioctl) { 1985287664Smav dev_relthread(dev, ref); 1986229997Sken snprintf(req->error_str, sizeof(req->error_str), 1987287664Smav "no d_ioctl for device %s!", be_lun->dev_path); 1988229997Sken return (ENODEV); 1989229997Sken } 1990229997Sken 1991287664Smav error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD, 1992229997Sken curthread); 1993229997Sken if (error) { 1994287664Smav dev_relthread(dev, ref); 1995229997Sken snprintf(req->error_str, sizeof(req->error_str), 1996272911Smav "error %d returned for DIOCGSECTORSIZE ioctl " 1997272911Smav "on %s!", error, be_lun->dev_path); 1998229997Sken return (error); 1999229997Sken } 2000229997Sken 2001229997Sken /* 2002229997Sken * If the user has asked for a blocksize that is greater than the 2003229997Sken * backing device's blocksize, we can do it only if the blocksize 2004229997Sken * the user is asking for is an even multiple of the underlying 2005229997Sken * device's blocksize. 2006229997Sken */ 2007286811Smav if ((params->blocksize_bytes != 0) && 2008286811Smav (params->blocksize_bytes >= tmp)) { 2009286811Smav if (params->blocksize_bytes % tmp == 0) { 2010287499Smav cbe_lun->blocksize = params->blocksize_bytes; 2011229997Sken } else { 2012287664Smav dev_relthread(dev, ref); 2013229997Sken snprintf(req->error_str, sizeof(req->error_str), 2014272911Smav "requested blocksize %u is not an even " 2015229997Sken "multiple of backing device blocksize %u", 2016287221Smav params->blocksize_bytes, tmp); 2017229997Sken return (EINVAL); 2018229997Sken } 2019286811Smav } else if (params->blocksize_bytes != 0) { 2020287664Smav dev_relthread(dev, ref); 2021229997Sken snprintf(req->error_str, sizeof(req->error_str), 2022272911Smav "requested blocksize %u < backing device " 2023287221Smav "blocksize %u", params->blocksize_bytes, tmp); 2024229997Sken return (EINVAL); 2025286811Smav } else 2026287499Smav cbe_lun->blocksize = tmp; 2027229997Sken 2028287664Smav error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD, 2029287664Smav curthread); 2030229997Sken if (error) { 2031287664Smav dev_relthread(dev, ref); 2032229997Sken snprintf(req->error_str, sizeof(req->error_str), 2033272911Smav "error %d returned for DIOCGMEDIASIZE " 2034272911Smav " ioctl on %s!", error, 2035232604Strasz be_lun->dev_path); 2036229997Sken return (error); 2037229997Sken } 2038229997Sken 2039232604Strasz if (params->lun_size_bytes != 0) { 2040287221Smav if (params->lun_size_bytes > otmp) { 2041287664Smav dev_relthread(dev, ref); 2042232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2043272911Smav "requested LUN size %ju > backing device " 2044272911Smav "size %ju", 2045232604Strasz (uintmax_t)params->lun_size_bytes, 2046287221Smav (uintmax_t)otmp); 2047232604Strasz return (EINVAL); 2048232604Strasz } 2049232604Strasz 2050232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2051286811Smav } else 2052287221Smav be_lun->size_bytes = otmp; 2053287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2054287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2055287499Smav 0 : (be_lun->size_blocks - 1); 2056232604Strasz 2057287664Smav error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD, 2058287664Smav curthread); 2059264191Smav if (error) 2060264191Smav ps = po = 0; 2061264191Smav else { 2062287664Smav error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po, 2063287664Smav FREAD, curthread); 2064264191Smav if (error) 2065264191Smav po = 0; 2066264191Smav } 2067275865Smav us = ps; 2068275865Smav uo = po; 2069275865Smav 2070287499Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 2071275865Smav if (value != NULL) 2072275865Smav ctl_expand_number(value, &ps); 2073287499Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 2074275865Smav if (value != NULL) 2075275865Smav ctl_expand_number(value, &po); 2076287499Smav pss = ps / cbe_lun->blocksize; 2077287499Smav pos = po / cbe_lun->blocksize; 2078287499Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 2079287499Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 2080287499Smav cbe_lun->pblockexp = fls(pss) - 1; 2081287499Smav cbe_lun->pblockoff = (pss - pos) % pss; 2082264191Smav } 2083264191Smav 2084287499Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 2085275865Smav if (value != NULL) 2086275865Smav ctl_expand_number(value, &us); 2087287499Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 2088275865Smav if (value != NULL) 2089275865Smav ctl_expand_number(value, &uo); 2090287499Smav uss = us / cbe_lun->blocksize; 2091287499Smav uos = uo / cbe_lun->blocksize; 2092287499Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 2093287499Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 2094287499Smav cbe_lun->ublockexp = fls(uss) - 1; 2095287499Smav cbe_lun->ublockoff = (uss - uos) % uss; 2096275865Smav } 2097275865Smav 2098287499Smav cbe_lun->atomicblock = atomic / cbe_lun->blocksize; 2099287499Smav cbe_lun->opttxferlen = maxio / cbe_lun->blocksize; 2100278672Smav 2101278672Smav if (be_lun->dispatch == ctl_be_block_dispatch_zvol) { 2102278672Smav unmap = 1; 2103278672Smav } else { 2104278672Smav struct diocgattr_arg arg; 2105278672Smav 2106278672Smav strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name)); 2107278672Smav arg.len = sizeof(arg.value.i); 2108287664Smav error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 2109287664Smav curthread); 2110278672Smav unmap = (error == 0) ? arg.value.i : 0; 2111278672Smav } 2112287499Smav value = ctl_get_opt(&cbe_lun->options, "unmap"); 2113278672Smav if (value != NULL) 2114278672Smav unmap = (strcmp(value, "on") == 0); 2115278672Smav if (unmap) 2116287499Smav cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 2117287499Smav else 2118287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 2119278672Smav 2120287664Smav dev_relthread(dev, ref); 2121229997Sken return (0); 2122229997Sken} 2123229997Sken 2124229997Skenstatic int 2125229997Skenctl_be_block_close(struct ctl_be_block_lun *be_lun) 2126229997Sken{ 2127287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2128287499Smav int flags; 2129287499Smav 2130229997Sken if (be_lun->vn) { 2131287499Smav flags = FREAD; 2132287499Smav if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0) 2133287499Smav flags |= FWRITE; 2134229997Sken (void)vn_close(be_lun->vn, flags, NOCRED, curthread); 2135229997Sken be_lun->vn = NULL; 2136229997Sken 2137229997Sken switch (be_lun->dev_type) { 2138229997Sken case CTL_BE_BLOCK_DEV: 2139229997Sken break; 2140229997Sken case CTL_BE_BLOCK_FILE: 2141229997Sken if (be_lun->backend.file.cred != NULL) { 2142229997Sken crfree(be_lun->backend.file.cred); 2143229997Sken be_lun->backend.file.cred = NULL; 2144229997Sken } 2145229997Sken break; 2146229997Sken case CTL_BE_BLOCK_NONE: 2147258871Strasz break; 2148229997Sken default: 2149229997Sken panic("Unexpected backend type."); 2150229997Sken break; 2151229997Sken } 2152272911Smav be_lun->dev_type = CTL_BE_BLOCK_NONE; 2153229997Sken } 2154229997Sken return (0); 2155229997Sken} 2156229997Sken 2157229997Skenstatic int 2158229997Skenctl_be_block_open(struct ctl_be_block_softc *softc, 2159287499Smav struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 2160229997Sken{ 2161287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2162229997Sken struct nameidata nd; 2163287499Smav char *value; 2164287499Smav int error, flags; 2165229997Sken 2166229997Sken error = 0; 2167229997Sken if (rootvnode == NULL) { 2168229997Sken snprintf(req->error_str, sizeof(req->error_str), 2169272911Smav "Root filesystem is not mounted"); 2170229997Sken return (1); 2171229997Sken } 2172285391Smjg pwd_ensure_dirs(); 2173229997Sken 2174287499Smav value = ctl_get_opt(&cbe_lun->options, "file"); 2175287499Smav if (value == NULL) { 2176287499Smav snprintf(req->error_str, sizeof(req->error_str), 2177287499Smav "no file argument specified"); 2178287499Smav return (1); 2179287499Smav } 2180287499Smav free(be_lun->dev_path, M_CTLBLK); 2181287499Smav be_lun->dev_path = strdup(value, M_CTLBLK); 2182287499Smav 2183287499Smav flags = FREAD; 2184287499Smav value = ctl_get_opt(&cbe_lun->options, "readonly"); 2185287499Smav if (value == NULL || strcmp(value, "on") != 0) 2186287499Smav flags |= FWRITE; 2187287499Smav 2188287499Smavagain: 2189229997Sken NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, be_lun->dev_path, curthread); 2190229997Sken error = vn_open(&nd, &flags, 0, NULL); 2191287499Smav if ((error == EROFS || error == EACCES) && (flags & FWRITE)) { 2192287499Smav flags &= ~FWRITE; 2193287499Smav goto again; 2194287499Smav } 2195229997Sken if (error) { 2196229997Sken /* 2197229997Sken * This is the only reasonable guess we can make as far as 2198229997Sken * path if the user doesn't give us a fully qualified path. 2199229997Sken * If they want to specify a file, they need to specify the 2200229997Sken * full path. 2201229997Sken */ 2202229997Sken if (be_lun->dev_path[0] != '/') { 2203229997Sken char *dev_name; 2204229997Sken 2205287499Smav asprintf(&dev_name, M_CTLBLK, "/dev/%s", 2206287499Smav be_lun->dev_path); 2207287499Smav free(be_lun->dev_path, M_CTLBLK); 2208287499Smav be_lun->dev_path = dev_name; 2209287499Smav goto again; 2210229997Sken } 2211229997Sken snprintf(req->error_str, sizeof(req->error_str), 2212272911Smav "error opening %s: %d", be_lun->dev_path, error); 2213229997Sken return (error); 2214229997Sken } 2215287499Smav if (flags & FWRITE) 2216287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_READONLY; 2217287499Smav else 2218287499Smav cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 2219229997Sken 2220229997Sken NDFREE(&nd, NDF_ONLY_PNBUF); 2221229997Sken be_lun->vn = nd.ni_vp; 2222229997Sken 2223229997Sken /* We only support disks and files. */ 2224229997Sken if (vn_isdisk(be_lun->vn, &error)) { 2225229997Sken error = ctl_be_block_open_dev(be_lun, req); 2226229997Sken } else if (be_lun->vn->v_type == VREG) { 2227229997Sken error = ctl_be_block_open_file(be_lun, req); 2228229997Sken } else { 2229229997Sken error = EINVAL; 2230229997Sken snprintf(req->error_str, sizeof(req->error_str), 2231258871Strasz "%s is not a disk or plain file", be_lun->dev_path); 2232229997Sken } 2233229997Sken VOP_UNLOCK(be_lun->vn, 0); 2234229997Sken 2235286811Smav if (error != 0) 2236229997Sken ctl_be_block_close(be_lun); 2237287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2238287499Smav if (be_lun->dispatch != ctl_be_block_dispatch_dev) 2239287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2240287499Smav value = ctl_get_opt(&cbe_lun->options, "serseq"); 2241287499Smav if (value != NULL && strcmp(value, "on") == 0) 2242287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 2243287499Smav else if (value != NULL && strcmp(value, "read") == 0) 2244287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2245287499Smav else if (value != NULL && strcmp(value, "off") == 0) 2246287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2247229997Sken return (0); 2248229997Sken} 2249229997Sken 2250229997Skenstatic int 2251229997Skenctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2252229997Sken{ 2253287499Smav struct ctl_be_lun *cbe_lun; 2254229997Sken struct ctl_be_block_lun *be_lun; 2255229997Sken struct ctl_lun_create_params *params; 2256267481Smav char num_thread_str[16]; 2257229997Sken char tmpstr[32]; 2258267481Smav char *value; 2259278672Smav int retval, num_threads; 2260267481Smav int tmp_num_threads; 2261229997Sken 2262229997Sken params = &req->reqdata.create; 2263229997Sken retval = 0; 2264272911Smav req->status = CTL_LUN_OK; 2265229997Sken 2266229997Sken be_lun = malloc(sizeof(*be_lun), M_CTLBLK, M_ZERO | M_WAITOK); 2267287499Smav cbe_lun = &be_lun->cbe_lun; 2268287499Smav cbe_lun->be_lun = be_lun; 2269272911Smav be_lun->params = req->reqdata.create; 2270229997Sken be_lun->softc = softc; 2271229997Sken STAILQ_INIT(&be_lun->input_queue); 2272275474Smav STAILQ_INIT(&be_lun->config_read_queue); 2273229997Sken STAILQ_INIT(&be_lun->config_write_queue); 2274229997Sken STAILQ_INIT(&be_lun->datamove_queue); 2275229997Sken sprintf(be_lun->lunname, "cblk%d", softc->num_luns); 2276267877Smav mtx_init(&be_lun->io_lock, "cblk io lock", NULL, MTX_DEF); 2277267877Smav mtx_init(&be_lun->queue_lock, "cblk queue lock", NULL, MTX_DEF); 2278287499Smav ctl_init_opts(&cbe_lun->options, 2279268280Smav req->num_be_args, req->kern_be_args); 2280264886Smav be_lun->lun_zone = uma_zcreate(be_lun->lunname, CTLBLK_MAX_SEG, 2281256995Smav NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); 2282229997Sken if (be_lun->lun_zone == NULL) { 2283229997Sken snprintf(req->error_str, sizeof(req->error_str), 2284272911Smav "error allocating UMA zone"); 2285229997Sken goto bailout_error; 2286229997Sken } 2287229997Sken 2288229997Sken if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 2289287499Smav cbe_lun->lun_type = params->device_type; 2290229997Sken else 2291287499Smav cbe_lun->lun_type = T_DIRECT; 2292287499Smav be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED; 2293287621Smav cbe_lun->flags = 0; 2294287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2295287621Smav if (value != NULL) { 2296287621Smav if (strcmp(value, "primary") == 0) 2297287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2298287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2299287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2300229997Sken 2301287499Smav if (cbe_lun->lun_type == T_DIRECT) { 2302286811Smav be_lun->size_bytes = params->lun_size_bytes; 2303286811Smav if (params->blocksize_bytes != 0) 2304287499Smav cbe_lun->blocksize = params->blocksize_bytes; 2305286811Smav else 2306287499Smav cbe_lun->blocksize = 512; 2307287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2308287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2309287499Smav 0 : (be_lun->size_blocks - 1); 2310229997Sken 2311287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2312287621Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2313287621Smav retval = ctl_be_block_open(softc, be_lun, req); 2314287621Smav if (retval != 0) { 2315287621Smav retval = 0; 2316287621Smav req->status = CTL_LUN_WARNING; 2317287621Smav } 2318229997Sken } 2319287499Smav num_threads = cbb_num_threads; 2320229997Sken } else { 2321229997Sken num_threads = 1; 2322229997Sken } 2323229997Sken 2324229997Sken /* 2325229997Sken * XXX This searching loop might be refactored to be combined with 2326229997Sken * the loop above, 2327229997Sken */ 2328287499Smav value = ctl_get_opt(&cbe_lun->options, "num_threads"); 2329267481Smav if (value != NULL) { 2330267481Smav tmp_num_threads = strtol(value, NULL, 0); 2331229997Sken 2332267481Smav /* 2333267481Smav * We don't let the user specify less than one 2334267481Smav * thread, but hope he's clueful enough not to 2335267481Smav * specify 1000 threads. 2336267481Smav */ 2337267481Smav if (tmp_num_threads < 1) { 2338267481Smav snprintf(req->error_str, sizeof(req->error_str), 2339272911Smav "invalid number of threads %s", 2340272911Smav num_thread_str); 2341267481Smav goto bailout_error; 2342229997Sken } 2343267481Smav num_threads = tmp_num_threads; 2344229997Sken } 2345229997Sken 2346272911Smav if (be_lun->vn == NULL) 2347287499Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2348229997Sken /* Tell the user the blocksize we ended up using */ 2349272911Smav params->lun_size_bytes = be_lun->size_bytes; 2350287499Smav params->blocksize_bytes = cbe_lun->blocksize; 2351229997Sken if (params->flags & CTL_LUN_FLAG_ID_REQ) { 2352287499Smav cbe_lun->req_lun_id = params->req_lun_id; 2353287499Smav cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 2354229997Sken } else 2355287499Smav cbe_lun->req_lun_id = 0; 2356229997Sken 2357287499Smav cbe_lun->lun_shutdown = ctl_be_block_lun_shutdown; 2358287499Smav cbe_lun->lun_config_status = ctl_be_block_lun_config_status; 2359287499Smav cbe_lun->be = &ctl_be_block_driver; 2360229997Sken 2361229997Sken if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 2362229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 2363229997Sken softc->num_luns); 2364287499Smav strncpy((char *)cbe_lun->serial_num, tmpstr, 2365287499Smav MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 2366229997Sken 2367229997Sken /* Tell the user what we used for a serial number */ 2368229997Sken strncpy((char *)params->serial_num, tmpstr, 2369275953Smav MIN(sizeof(params->serial_num), sizeof(tmpstr))); 2370229997Sken } else { 2371287499Smav strncpy((char *)cbe_lun->serial_num, params->serial_num, 2372287499Smav MIN(sizeof(cbe_lun->serial_num), 2373229997Sken sizeof(params->serial_num))); 2374229997Sken } 2375229997Sken if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 2376229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 2377287499Smav strncpy((char *)cbe_lun->device_id, tmpstr, 2378287499Smav MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 2379229997Sken 2380229997Sken /* Tell the user what we used for a device ID */ 2381229997Sken strncpy((char *)params->device_id, tmpstr, 2382275953Smav MIN(sizeof(params->device_id), sizeof(tmpstr))); 2383229997Sken } else { 2384287499Smav strncpy((char *)cbe_lun->device_id, params->device_id, 2385287499Smav MIN(sizeof(cbe_lun->device_id), 2386275953Smav sizeof(params->device_id))); 2387229997Sken } 2388229997Sken 2389229997Sken TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_be_block_worker, be_lun); 2390229997Sken 2391229997Sken be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 2392229997Sken taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 2393229997Sken 2394229997Sken if (be_lun->io_taskqueue == NULL) { 2395229997Sken snprintf(req->error_str, sizeof(req->error_str), 2396272911Smav "unable to create taskqueue"); 2397229997Sken goto bailout_error; 2398229997Sken } 2399229997Sken 2400229997Sken /* 2401229997Sken * Note that we start the same number of threads by default for 2402229997Sken * both the file case and the block device case. For the file 2403229997Sken * case, we need multiple threads to allow concurrency, because the 2404229997Sken * vnode interface is designed to be a blocking interface. For the 2405229997Sken * block device case, ZFS zvols at least will block the caller's 2406229997Sken * context in many instances, and so we need multiple threads to 2407229997Sken * overcome that problem. Other block devices don't need as many 2408229997Sken * threads, but they shouldn't cause too many problems. 2409229997Sken * 2410229997Sken * If the user wants to just have a single thread for a block 2411229997Sken * device, he can specify that when the LUN is created, or change 2412229997Sken * the tunable/sysctl to alter the default number of threads. 2413229997Sken */ 2414229997Sken retval = taskqueue_start_threads(&be_lun->io_taskqueue, 2415229997Sken /*num threads*/num_threads, 2416229997Sken /*priority*/PWAIT, 2417229997Sken /*thread name*/ 2418229997Sken "%s taskq", be_lun->lunname); 2419229997Sken 2420229997Sken if (retval != 0) 2421229997Sken goto bailout_error; 2422229997Sken 2423229997Sken be_lun->num_threads = num_threads; 2424229997Sken 2425229997Sken mtx_lock(&softc->lock); 2426229997Sken softc->num_luns++; 2427229997Sken STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 2428229997Sken 2429229997Sken mtx_unlock(&softc->lock); 2430229997Sken 2431287499Smav retval = ctl_add_lun(&be_lun->cbe_lun); 2432229997Sken if (retval != 0) { 2433229997Sken mtx_lock(&softc->lock); 2434229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2435229997Sken links); 2436229997Sken softc->num_luns--; 2437229997Sken mtx_unlock(&softc->lock); 2438229997Sken snprintf(req->error_str, sizeof(req->error_str), 2439272911Smav "ctl_add_lun() returned error %d, see dmesg for " 2440272911Smav "details", retval); 2441229997Sken retval = 0; 2442229997Sken goto bailout_error; 2443229997Sken } 2444229997Sken 2445229997Sken mtx_lock(&softc->lock); 2446229997Sken 2447229997Sken /* 2448229997Sken * Tell the config_status routine that we're waiting so it won't 2449229997Sken * clean up the LUN in the event of an error. 2450229997Sken */ 2451229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2452229997Sken 2453229997Sken while (be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) { 2454229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2455229997Sken if (retval == EINTR) 2456229997Sken break; 2457229997Sken } 2458229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2459229997Sken 2460229997Sken if (be_lun->flags & CTL_BE_BLOCK_LUN_CONFIG_ERR) { 2461229997Sken snprintf(req->error_str, sizeof(req->error_str), 2462272911Smav "LUN configuration error, see dmesg for details"); 2463229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2464229997Sken links); 2465229997Sken softc->num_luns--; 2466229997Sken mtx_unlock(&softc->lock); 2467229997Sken goto bailout_error; 2468229997Sken } else { 2469287499Smav params->req_lun_id = cbe_lun->lun_id; 2470229997Sken } 2471229997Sken 2472229997Sken mtx_unlock(&softc->lock); 2473229997Sken 2474229997Sken be_lun->disk_stats = devstat_new_entry("cbb", params->req_lun_id, 2475287499Smav cbe_lun->blocksize, 2476229997Sken DEVSTAT_ALL_SUPPORTED, 2477287499Smav cbe_lun->lun_type 2478229997Sken | DEVSTAT_TYPE_IF_OTHER, 2479229997Sken DEVSTAT_PRIORITY_OTHER); 2480229997Sken 2481229997Sken return (retval); 2482229997Sken 2483229997Skenbailout_error: 2484229997Sken req->status = CTL_LUN_ERROR; 2485229997Sken 2486267429Smav if (be_lun->io_taskqueue != NULL) 2487267429Smav taskqueue_free(be_lun->io_taskqueue); 2488229997Sken ctl_be_block_close(be_lun); 2489267429Smav if (be_lun->dev_path != NULL) 2490267429Smav free(be_lun->dev_path, M_CTLBLK); 2491267429Smav if (be_lun->lun_zone != NULL) 2492267429Smav uma_zdestroy(be_lun->lun_zone); 2493287499Smav ctl_free_opts(&cbe_lun->options); 2494267877Smav mtx_destroy(&be_lun->queue_lock); 2495267877Smav mtx_destroy(&be_lun->io_lock); 2496229997Sken free(be_lun, M_CTLBLK); 2497229997Sken 2498229997Sken return (retval); 2499229997Sken} 2500229997Sken 2501229997Skenstatic int 2502229997Skenctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2503229997Sken{ 2504229997Sken struct ctl_lun_rm_params *params; 2505229997Sken struct ctl_be_block_lun *be_lun; 2506287670Smav struct ctl_be_lun *cbe_lun; 2507229997Sken int retval; 2508229997Sken 2509229997Sken params = &req->reqdata.rm; 2510229997Sken 2511229997Sken mtx_lock(&softc->lock); 2512229997Sken STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2513287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2514229997Sken break; 2515229997Sken } 2516229997Sken mtx_unlock(&softc->lock); 2517229997Sken 2518229997Sken if (be_lun == NULL) { 2519229997Sken snprintf(req->error_str, sizeof(req->error_str), 2520272911Smav "LUN %u is not managed by the block backend", 2521272911Smav params->lun_id); 2522229997Sken goto bailout_error; 2523229997Sken } 2524287670Smav cbe_lun = &be_lun->cbe_lun; 2525229997Sken 2526287670Smav retval = ctl_disable_lun(cbe_lun); 2527229997Sken if (retval != 0) { 2528229997Sken snprintf(req->error_str, sizeof(req->error_str), 2529272911Smav "error %d returned from ctl_disable_lun() for " 2530272911Smav "LUN %d", retval, params->lun_id); 2531229997Sken goto bailout_error; 2532287670Smav } 2533229997Sken 2534287670Smav if (be_lun->vn != NULL) { 2535287670Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2536287670Smav ctl_lun_offline(cbe_lun); 2537287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2538287670Smav ctl_be_block_close(be_lun); 2539229997Sken } 2540229997Sken 2541287670Smav retval = ctl_invalidate_lun(cbe_lun); 2542229997Sken if (retval != 0) { 2543229997Sken snprintf(req->error_str, sizeof(req->error_str), 2544272911Smav "error %d returned from ctl_invalidate_lun() for " 2545272911Smav "LUN %d", retval, params->lun_id); 2546229997Sken goto bailout_error; 2547229997Sken } 2548229997Sken 2549229997Sken mtx_lock(&softc->lock); 2550229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2551229997Sken while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2552229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2553229997Sken if (retval == EINTR) 2554229997Sken break; 2555229997Sken } 2556229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2557229997Sken 2558229997Sken if ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2559229997Sken snprintf(req->error_str, sizeof(req->error_str), 2560272911Smav "interrupted waiting for LUN to be freed"); 2561229997Sken mtx_unlock(&softc->lock); 2562229997Sken goto bailout_error; 2563229997Sken } 2564229997Sken 2565229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, links); 2566229997Sken 2567229997Sken softc->num_luns--; 2568229997Sken mtx_unlock(&softc->lock); 2569229997Sken 2570287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2571229997Sken taskqueue_free(be_lun->io_taskqueue); 2572229997Sken 2573229997Sken if (be_lun->disk_stats != NULL) 2574229997Sken devstat_remove_entry(be_lun->disk_stats); 2575229997Sken 2576229997Sken uma_zdestroy(be_lun->lun_zone); 2577229997Sken 2578287670Smav ctl_free_opts(&cbe_lun->options); 2579229997Sken free(be_lun->dev_path, M_CTLBLK); 2580267877Smav mtx_destroy(&be_lun->queue_lock); 2581267877Smav mtx_destroy(&be_lun->io_lock); 2582229997Sken free(be_lun, M_CTLBLK); 2583229997Sken 2584229997Sken req->status = CTL_LUN_OK; 2585229997Sken 2586229997Sken return (0); 2587229997Sken 2588229997Skenbailout_error: 2589229997Sken 2590229997Sken req->status = CTL_LUN_ERROR; 2591229997Sken 2592229997Sken return (0); 2593229997Sken} 2594229997Sken 2595232604Straszstatic int 2596232604Straszctl_be_block_modify_file(struct ctl_be_block_lun *be_lun, 2597232604Strasz struct ctl_lun_req *req) 2598232604Strasz{ 2599287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2600232604Strasz struct vattr vattr; 2601232604Strasz int error; 2602272911Smav struct ctl_lun_create_params *params = &be_lun->params; 2603232604Strasz 2604232604Strasz if (params->lun_size_bytes != 0) { 2605232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2606232604Strasz } else { 2607271794Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 2608232604Strasz error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 2609271794Smav VOP_UNLOCK(be_lun->vn, 0); 2610232604Strasz if (error != 0) { 2611232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2612232604Strasz "error calling VOP_GETATTR() for file %s", 2613232604Strasz be_lun->dev_path); 2614232604Strasz return (error); 2615232604Strasz } 2616232604Strasz be_lun->size_bytes = vattr.va_size; 2617232604Strasz } 2618287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2619287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2620287499Smav 0 : (be_lun->size_blocks - 1); 2621232604Strasz return (0); 2622232604Strasz} 2623232604Strasz 2624232604Straszstatic int 2625232604Straszctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun, 2626232604Strasz struct ctl_lun_req *req) 2627232604Strasz{ 2628287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2629272911Smav struct ctl_lun_create_params *params = &be_lun->params; 2630287664Smav struct cdevsw *csw; 2631287664Smav struct cdev *dev; 2632232604Strasz uint64_t size_bytes; 2633287664Smav int error, ref; 2634232604Strasz 2635287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 2636287664Smav if (csw == NULL) 2637287664Smav return (ENXIO); 2638287664Smav if (csw->d_ioctl == NULL) { 2639287664Smav dev_relthread(dev, ref); 2640232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2641272911Smav "no d_ioctl for device %s!", be_lun->dev_path); 2642232604Strasz return (ENODEV); 2643232604Strasz } 2644232604Strasz 2645287664Smav error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&size_bytes, FREAD, 2646287664Smav curthread); 2647287664Smav dev_relthread(dev, ref); 2648232604Strasz if (error) { 2649232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2650272911Smav "error %d returned for DIOCGMEDIASIZE ioctl " 2651272911Smav "on %s!", error, be_lun->dev_path); 2652232604Strasz return (error); 2653232604Strasz } 2654232604Strasz 2655232604Strasz if (params->lun_size_bytes != 0) { 2656232604Strasz if (params->lun_size_bytes > size_bytes) { 2657232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2658272911Smav "requested LUN size %ju > backing device " 2659272911Smav "size %ju", 2660232604Strasz (uintmax_t)params->lun_size_bytes, 2661232604Strasz (uintmax_t)size_bytes); 2662232604Strasz return (EINVAL); 2663232604Strasz } 2664232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2665232604Strasz } else { 2666232604Strasz be_lun->size_bytes = size_bytes; 2667232604Strasz } 2668287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2669287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2670287499Smav 0 : (be_lun->size_blocks - 1); 2671232604Strasz return (0); 2672232604Strasz} 2673232604Strasz 2674232604Straszstatic int 2675232604Straszctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2676232604Strasz{ 2677232604Strasz struct ctl_lun_modify_params *params; 2678232604Strasz struct ctl_be_block_lun *be_lun; 2679287500Smav struct ctl_be_lun *cbe_lun; 2680287621Smav char *value; 2681271794Smav uint64_t oldsize; 2682287621Smav int error, wasprim; 2683232604Strasz 2684232604Strasz params = &req->reqdata.modify; 2685232604Strasz 2686232604Strasz mtx_lock(&softc->lock); 2687232604Strasz STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2688287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2689232604Strasz break; 2690232604Strasz } 2691232604Strasz mtx_unlock(&softc->lock); 2692232604Strasz 2693232604Strasz if (be_lun == NULL) { 2694232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2695272911Smav "LUN %u is not managed by the block backend", 2696272911Smav params->lun_id); 2697232604Strasz goto bailout_error; 2698232604Strasz } 2699287500Smav cbe_lun = &be_lun->cbe_lun; 2700232604Strasz 2701287500Smav if (params->lun_size_bytes != 0) 2702287500Smav be_lun->params.lun_size_bytes = params->lun_size_bytes; 2703287500Smav ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 2704232604Strasz 2705287621Smav wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 2706287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2707287621Smav if (value != NULL) { 2708287621Smav if (strcmp(value, "primary") == 0) 2709287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2710287621Smav else 2711287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2712287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2713287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2714232604Strasz else 2715287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2716287621Smav if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 2717287621Smav if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 2718287621Smav ctl_lun_primary(cbe_lun); 2719287621Smav else 2720287621Smav ctl_lun_secondary(cbe_lun); 2721287621Smav } 2722232604Strasz 2723287621Smav oldsize = be_lun->size_blocks; 2724287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2725287621Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2726287621Smav if (be_lun->vn == NULL) 2727287621Smav error = ctl_be_block_open(softc, be_lun, req); 2728287621Smav else if (vn_isdisk(be_lun->vn, &error)) 2729287621Smav error = ctl_be_block_modify_dev(be_lun, req); 2730287621Smav else if (be_lun->vn->v_type == VREG) 2731287621Smav error = ctl_be_block_modify_file(be_lun, req); 2732287621Smav else 2733287621Smav error = EINVAL; 2734287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) && 2735287621Smav be_lun->vn != NULL) { 2736287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE; 2737287621Smav ctl_lun_online(cbe_lun); 2738287621Smav } 2739287621Smav } else { 2740287621Smav if (be_lun->vn != NULL) { 2741287621Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2742287621Smav ctl_lun_offline(cbe_lun); 2743287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2744287621Smav error = ctl_be_block_close(be_lun); 2745287621Smav } else 2746287621Smav error = 0; 2747287621Smav } 2748287499Smav if (be_lun->size_blocks != oldsize) 2749287500Smav ctl_lun_capacity_changed(cbe_lun); 2750232604Strasz 2751232604Strasz /* Tell the user the exact size we ended up using */ 2752232604Strasz params->lun_size_bytes = be_lun->size_bytes; 2753232604Strasz 2754272911Smav req->status = error ? CTL_LUN_WARNING : CTL_LUN_OK; 2755232604Strasz return (0); 2756232604Strasz 2757232604Straszbailout_error: 2758232604Strasz req->status = CTL_LUN_ERROR; 2759232604Strasz return (0); 2760232604Strasz} 2761232604Strasz 2762229997Skenstatic void 2763229997Skenctl_be_block_lun_shutdown(void *be_lun) 2764229997Sken{ 2765229997Sken struct ctl_be_block_lun *lun; 2766229997Sken struct ctl_be_block_softc *softc; 2767229997Sken 2768229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2769229997Sken 2770229997Sken softc = lun->softc; 2771229997Sken 2772229997Sken mtx_lock(&softc->lock); 2773229997Sken lun->flags |= CTL_BE_BLOCK_LUN_UNCONFIGURED; 2774229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2775229997Sken wakeup(lun); 2776229997Sken mtx_unlock(&softc->lock); 2777229997Sken 2778229997Sken} 2779229997Sken 2780229997Skenstatic void 2781229997Skenctl_be_block_lun_config_status(void *be_lun, ctl_lun_config_status status) 2782229997Sken{ 2783229997Sken struct ctl_be_block_lun *lun; 2784229997Sken struct ctl_be_block_softc *softc; 2785229997Sken 2786229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2787229997Sken softc = lun->softc; 2788229997Sken 2789229997Sken if (status == CTL_LUN_CONFIG_OK) { 2790229997Sken mtx_lock(&softc->lock); 2791229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2792229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2793229997Sken wakeup(lun); 2794229997Sken mtx_unlock(&softc->lock); 2795229997Sken 2796229997Sken /* 2797229997Sken * We successfully added the LUN, attempt to enable it. 2798229997Sken */ 2799287499Smav if (ctl_enable_lun(&lun->cbe_lun) != 0) { 2800229997Sken printf("%s: ctl_enable_lun() failed!\n", __func__); 2801287499Smav if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 2802229997Sken printf("%s: ctl_invalidate_lun() failed!\n", 2803229997Sken __func__); 2804229997Sken } 2805229997Sken } 2806229997Sken 2807229997Sken return; 2808229997Sken } 2809229997Sken 2810229997Sken 2811229997Sken mtx_lock(&softc->lock); 2812229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2813229997Sken lun->flags |= CTL_BE_BLOCK_LUN_CONFIG_ERR; 2814229997Sken wakeup(lun); 2815229997Sken mtx_unlock(&softc->lock); 2816229997Sken} 2817229997Sken 2818229997Sken 2819229997Skenstatic int 2820229997Skenctl_be_block_config_write(union ctl_io *io) 2821229997Sken{ 2822229997Sken struct ctl_be_block_lun *be_lun; 2823287499Smav struct ctl_be_lun *cbe_lun; 2824229997Sken int retval; 2825229997Sken 2826229997Sken retval = 0; 2827229997Sken 2828229997Sken DPRINTF("entered\n"); 2829229997Sken 2830287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2831229997Sken CTL_PRIV_BACKEND_LUN].ptr; 2832287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2833229997Sken 2834229997Sken switch (io->scsiio.cdb[0]) { 2835229997Sken case SYNCHRONIZE_CACHE: 2836229997Sken case SYNCHRONIZE_CACHE_16: 2837264274Smav case WRITE_SAME_10: 2838264274Smav case WRITE_SAME_16: 2839264274Smav case UNMAP: 2840229997Sken /* 2841229997Sken * The upper level CTL code will filter out any CDBs with 2842229997Sken * the immediate bit set and return the proper error. 2843229997Sken * 2844229997Sken * We don't really need to worry about what LBA range the 2845229997Sken * user asked to be synced out. When they issue a sync 2846229997Sken * cache command, we'll sync out the whole thing. 2847229997Sken */ 2848267877Smav mtx_lock(&be_lun->queue_lock); 2849229997Sken STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->io_hdr, 2850229997Sken links); 2851267877Smav mtx_unlock(&be_lun->queue_lock); 2852229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 2853229997Sken break; 2854229997Sken case START_STOP_UNIT: { 2855229997Sken struct scsi_start_stop_unit *cdb; 2856229997Sken 2857229997Sken cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 2858229997Sken 2859229997Sken if (cdb->how & SSS_START) 2860287499Smav retval = ctl_start_lun(cbe_lun); 2861229997Sken else { 2862287499Smav retval = ctl_stop_lun(cbe_lun); 2863229997Sken /* 2864229997Sken * XXX KDM Copan-specific offline behavior. 2865229997Sken * Figure out a reasonable way to port this? 2866229997Sken */ 2867229997Sken#ifdef NEEDTOPORT 2868229997Sken if ((retval == 0) 2869229997Sken && (cdb->byte2 & SSS_ONOFFLINE)) 2870287499Smav retval = ctl_lun_offline(cbe_lun); 2871229997Sken#endif 2872229997Sken } 2873229997Sken 2874229997Sken /* 2875229997Sken * In general, the above routines should not fail. They 2876229997Sken * just set state for the LUN. So we've got something 2877229997Sken * pretty wrong here if we can't start or stop the LUN. 2878229997Sken */ 2879229997Sken if (retval != 0) { 2880229997Sken ctl_set_internal_failure(&io->scsiio, 2881229997Sken /*sks_valid*/ 1, 2882229997Sken /*retry_count*/ 0xf051); 2883229997Sken retval = CTL_RETVAL_COMPLETE; 2884229997Sken } else { 2885229997Sken ctl_set_success(&io->scsiio); 2886229997Sken } 2887229997Sken ctl_config_write_done(io); 2888229997Sken break; 2889229997Sken } 2890229997Sken default: 2891229997Sken ctl_set_invalid_opcode(&io->scsiio); 2892229997Sken ctl_config_write_done(io); 2893229997Sken retval = CTL_RETVAL_COMPLETE; 2894229997Sken break; 2895229997Sken } 2896229997Sken 2897229997Sken return (retval); 2898229997Sken} 2899229997Sken 2900229997Skenstatic int 2901229997Skenctl_be_block_config_read(union ctl_io *io) 2902229997Sken{ 2903275474Smav struct ctl_be_block_lun *be_lun; 2904287499Smav struct ctl_be_lun *cbe_lun; 2905275474Smav int retval = 0; 2906275474Smav 2907275474Smav DPRINTF("entered\n"); 2908275474Smav 2909287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2910275474Smav CTL_PRIV_BACKEND_LUN].ptr; 2911287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2912275474Smav 2913275474Smav switch (io->scsiio.cdb[0]) { 2914275474Smav case SERVICE_ACTION_IN: 2915275474Smav if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 2916275474Smav mtx_lock(&be_lun->queue_lock); 2917275474Smav STAILQ_INSERT_TAIL(&be_lun->config_read_queue, 2918275474Smav &io->io_hdr, links); 2919275474Smav mtx_unlock(&be_lun->queue_lock); 2920275474Smav taskqueue_enqueue(be_lun->io_taskqueue, 2921275474Smav &be_lun->io_task); 2922275474Smav retval = CTL_RETVAL_QUEUED; 2923275474Smav break; 2924275474Smav } 2925275474Smav ctl_set_invalid_field(&io->scsiio, 2926275474Smav /*sks_valid*/ 1, 2927275474Smav /*command*/ 1, 2928275474Smav /*field*/ 1, 2929275474Smav /*bit_valid*/ 1, 2930275474Smav /*bit*/ 4); 2931275474Smav ctl_config_read_done(io); 2932275474Smav retval = CTL_RETVAL_COMPLETE; 2933275474Smav break; 2934275474Smav default: 2935275474Smav ctl_set_invalid_opcode(&io->scsiio); 2936275474Smav ctl_config_read_done(io); 2937275474Smav retval = CTL_RETVAL_COMPLETE; 2938275474Smav break; 2939275474Smav } 2940275474Smav 2941275474Smav return (retval); 2942229997Sken} 2943229997Sken 2944229997Skenstatic int 2945229997Skenctl_be_block_lun_info(void *be_lun, struct sbuf *sb) 2946229997Sken{ 2947229997Sken struct ctl_be_block_lun *lun; 2948229997Sken int retval; 2949229997Sken 2950229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2951229997Sken retval = 0; 2952229997Sken 2953268283Smav retval = sbuf_printf(sb, "\t<num_threads>"); 2954229997Sken 2955229997Sken if (retval != 0) 2956229997Sken goto bailout; 2957229997Sken 2958229997Sken retval = sbuf_printf(sb, "%d", lun->num_threads); 2959229997Sken 2960229997Sken if (retval != 0) 2961229997Sken goto bailout; 2962229997Sken 2963268283Smav retval = sbuf_printf(sb, "</num_threads>\n"); 2964229997Sken 2965229997Skenbailout: 2966229997Sken 2967229997Sken return (retval); 2968229997Sken} 2969229997Sken 2970274154Smavstatic uint64_t 2971274154Smavctl_be_block_lun_attr(void *be_lun, const char *attrname) 2972274154Smav{ 2973274154Smav struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)be_lun; 2974274154Smav 2975274154Smav if (lun->getattr == NULL) 2976274154Smav return (UINT64_MAX); 2977274154Smav return (lun->getattr(lun, attrname)); 2978274154Smav} 2979274154Smav 2980229997Skenint 2981229997Skenctl_be_block_init(void) 2982229997Sken{ 2983229997Sken struct ctl_be_block_softc *softc; 2984229997Sken int retval; 2985229997Sken 2986229997Sken softc = &backend_block_softc; 2987229997Sken retval = 0; 2988229997Sken 2989267877Smav mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF); 2990264020Strasz beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io), 2991264020Strasz NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 2992229997Sken STAILQ_INIT(&softc->lun_list); 2993229997Sken 2994229997Sken return (retval); 2995229997Sken} 2996