ctl_backend_block.c revision 287912
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 287912 2015-09-17 12:52:18Z 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) && 565275058Smav beio->beio_cont == NULL) 566275058Smav ctl_set_success(&io->scsiio); 567229997Sken#ifdef CTL_TIME_IO 568229997Sken getbintime(&io->io_hdr.dma_start_bt); 569229997Sken#endif 570229997Sken ctl_datamove(io); 571229997Sken } 572229997Sken} 573229997Sken 574229997Skenstatic void 575229997Skenctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 576229997Sken struct ctl_be_block_io *beio) 577229997Sken{ 578267877Smav union ctl_io *io = beio->io; 579229997Sken struct mount *mountpoint; 580241896Skib int error, lock_flags; 581229997Sken 582229997Sken DPRINTF("entered\n"); 583229997Sken 584267877Smav binuptime(&beio->ds_t0); 585267877Smav mtx_lock(&be_lun->io_lock); 586267877Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 587267877Smav mtx_unlock(&be_lun->io_lock); 588229997Sken 589267877Smav (void) vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 590229997Sken 591229997Sken if (MNT_SHARED_WRITES(mountpoint) 592229997Sken || ((mountpoint == NULL) 593229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 594229997Sken lock_flags = LK_SHARED; 595229997Sken else 596229997Sken lock_flags = LK_EXCLUSIVE; 597229997Sken 598229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 599229997Sken 600286353Smav error = VOP_FSYNC(be_lun->vn, beio->io_arg ? MNT_NOWAIT : MNT_WAIT, 601286353Smav curthread); 602229997Sken VOP_UNLOCK(be_lun->vn, 0); 603229997Sken 604229997Sken vn_finished_write(mountpoint); 605229997Sken 606267877Smav mtx_lock(&be_lun->io_lock); 607267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 608267877Smav beio->ds_tag_type, beio->ds_trans_type, 609267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 610267877Smav mtx_unlock(&be_lun->io_lock); 611267877Smav 612229997Sken if (error == 0) 613229997Sken ctl_set_success(&io->scsiio); 614229997Sken else { 615229997Sken /* XXX KDM is there is a better error here? */ 616229997Sken ctl_set_internal_failure(&io->scsiio, 617229997Sken /*sks_valid*/ 1, 618229997Sken /*retry_count*/ 0xbad1); 619229997Sken } 620229997Sken 621229997Sken ctl_complete_beio(beio); 622229997Sken} 623229997Sken 624258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_start, "uint64_t"); 625258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_start, "uint64_t"); 626258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_done,"uint64_t"); 627258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_done, "uint64_t"); 628229997Sken 629229997Skenstatic void 630229997Skenctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 631229997Sken struct ctl_be_block_io *beio) 632229997Sken{ 633229997Sken struct ctl_be_block_filedata *file_data; 634229997Sken union ctl_io *io; 635229997Sken struct uio xuio; 636229997Sken struct iovec *xiovec; 637287875Smav size_t s; 638287875Smav int error, flags, i; 639229997Sken 640229997Sken DPRINTF("entered\n"); 641229997Sken 642229997Sken file_data = &be_lun->backend.file; 643229997Sken io = beio->io; 644271309Smav flags = 0; 645271309Smav if (ARGS(io)->flags & CTL_LLF_DPO) 646271309Smav flags |= IO_DIRECT; 647271309Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 648271309Smav flags |= IO_SYNC; 649229997Sken 650267537Smav bzero(&xuio, sizeof(xuio)); 651229997Sken if (beio->bio_cmd == BIO_READ) { 652229997Sken SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 653267537Smav xuio.uio_rw = UIO_READ; 654229997Sken } else { 655229997Sken SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 656267537Smav xuio.uio_rw = UIO_WRITE; 657229997Sken } 658229997Sken xuio.uio_offset = beio->io_offset; 659229997Sken xuio.uio_resid = beio->io_len; 660229997Sken xuio.uio_segflg = UIO_SYSSPACE; 661229997Sken xuio.uio_iov = beio->xiovecs; 662229997Sken xuio.uio_iovcnt = beio->num_segs; 663229997Sken xuio.uio_td = curthread; 664229997Sken 665229997Sken for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 666229997Sken xiovec->iov_base = beio->sg_segs[i].addr; 667229997Sken xiovec->iov_len = beio->sg_segs[i].len; 668229997Sken } 669229997Sken 670267877Smav binuptime(&beio->ds_t0); 671267877Smav mtx_lock(&be_lun->io_lock); 672267877Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 673267877Smav mtx_unlock(&be_lun->io_lock); 674267877Smav 675229997Sken if (beio->bio_cmd == BIO_READ) { 676229997Sken vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 677229997Sken 678229997Sken /* 679229997Sken * UFS pays attention to IO_DIRECT for reads. If the 680229997Sken * DIRECTIO option is configured into the kernel, it calls 681229997Sken * ffs_rawread(). But that only works for single-segment 682229997Sken * uios with user space addresses. In our case, with a 683229997Sken * kernel uio, it still reads into the buffer cache, but it 684229997Sken * will just try to release the buffer from the cache later 685229997Sken * on in ffs_read(). 686229997Sken * 687229997Sken * ZFS does not pay attention to IO_DIRECT for reads. 688229997Sken * 689229997Sken * UFS does not pay attention to IO_SYNC for reads. 690229997Sken * 691229997Sken * ZFS pays attention to IO_SYNC (which translates into the 692229997Sken * Solaris define FRSYNC for zfs_read()) for reads. It 693229997Sken * attempts to sync the file before reading. 694229997Sken */ 695271309Smav error = VOP_READ(be_lun->vn, &xuio, flags, file_data->cred); 696229997Sken 697229997Sken VOP_UNLOCK(be_lun->vn, 0); 698267537Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 699287875Smav if (error == 0 && xuio.uio_resid > 0) { 700287875Smav /* 701287875Smav * If we red less then requested (EOF), then 702287875Smav * we should clean the rest of the buffer. 703287875Smav */ 704287875Smav s = beio->io_len - xuio.uio_resid; 705287875Smav for (i = 0; i < beio->num_segs; i++) { 706287875Smav if (s >= beio->sg_segs[i].len) { 707287875Smav s -= beio->sg_segs[i].len; 708287875Smav continue; 709287875Smav } 710287875Smav bzero((uint8_t *)beio->sg_segs[i].addr + s, 711287875Smav beio->sg_segs[i].len - s); 712287875Smav s = 0; 713287875Smav } 714287875Smav } 715229997Sken } else { 716229997Sken struct mount *mountpoint; 717229997Sken int lock_flags; 718229997Sken 719229997Sken (void)vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 720229997Sken 721229997Sken if (MNT_SHARED_WRITES(mountpoint) 722229997Sken || ((mountpoint == NULL) 723229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 724229997Sken lock_flags = LK_SHARED; 725229997Sken else 726229997Sken lock_flags = LK_EXCLUSIVE; 727229997Sken 728229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 729229997Sken 730229997Sken /* 731229997Sken * UFS pays attention to IO_DIRECT for writes. The write 732229997Sken * is done asynchronously. (Normally the write would just 733229997Sken * get put into cache. 734229997Sken * 735229997Sken * UFS pays attention to IO_SYNC for writes. It will 736229997Sken * attempt to write the buffer out synchronously if that 737229997Sken * flag is set. 738229997Sken * 739229997Sken * ZFS does not pay attention to IO_DIRECT for writes. 740229997Sken * 741229997Sken * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC) 742229997Sken * for writes. It will flush the transaction from the 743229997Sken * cache before returning. 744229997Sken */ 745271309Smav error = VOP_WRITE(be_lun->vn, &xuio, flags, file_data->cred); 746229997Sken VOP_UNLOCK(be_lun->vn, 0); 747229997Sken 748229997Sken vn_finished_write(mountpoint); 749267537Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 750229997Sken } 751229997Sken 752267877Smav mtx_lock(&be_lun->io_lock); 753267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 754267877Smav beio->ds_tag_type, beio->ds_trans_type, 755267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 756267877Smav mtx_unlock(&be_lun->io_lock); 757267877Smav 758229997Sken /* 759229997Sken * If we got an error, set the sense data to "MEDIUM ERROR" and 760229997Sken * return the I/O to the user. 761229997Sken */ 762229997Sken if (error != 0) { 763282565Smav if (error == ENOSPC || error == EDQUOT) { 764273809Smav ctl_set_space_alloc_fail(&io->scsiio); 765287760Smav } else if (error == EROFS || error == EACCES) { 766287760Smav ctl_set_hw_write_protected(&io->scsiio); 767287912Smav } else { 768287912Smav ctl_set_medium_error(&io->scsiio, 769287912Smav beio->bio_cmd == BIO_READ); 770287912Smav } 771229997Sken ctl_complete_beio(beio); 772229997Sken return; 773229997Sken } 774229997Sken 775229997Sken /* 776269122Smav * If this is a write or a verify, we're all done. 777229997Sken * If this is a read, we can now send the data to the user. 778229997Sken */ 779269122Smav if ((beio->bio_cmd == BIO_WRITE) || 780269122Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 781229997Sken ctl_set_success(&io->scsiio); 782229997Sken ctl_complete_beio(beio); 783229997Sken } else { 784275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 785275058Smav beio->beio_cont == NULL) 786275058Smav ctl_set_success(&io->scsiio); 787229997Sken#ifdef CTL_TIME_IO 788229997Sken getbintime(&io->io_hdr.dma_start_bt); 789229997Sken#endif 790229997Sken ctl_datamove(io); 791229997Sken } 792229997Sken} 793229997Sken 794229997Skenstatic void 795275474Smavctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 796275474Smav struct ctl_be_block_io *beio) 797275474Smav{ 798275474Smav union ctl_io *io = beio->io; 799275474Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 800275474Smav struct scsi_get_lba_status_data *data; 801275474Smav off_t roff, off; 802275474Smav int error, status; 803275474Smav 804275474Smav DPRINTF("entered\n"); 805275474Smav 806287499Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 807275474Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 808275474Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off, 809275474Smav 0, curthread->td_ucred, curthread); 810275474Smav if (error == 0 && off > roff) 811275474Smav status = 0; /* mapped up to off */ 812275474Smav else { 813275474Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off, 814275474Smav 0, curthread->td_ucred, curthread); 815275474Smav if (error == 0 && off > roff) 816275474Smav status = 1; /* deallocated up to off */ 817275474Smav else { 818275474Smav status = 0; /* unknown up to the end */ 819275474Smav off = be_lun->size_bytes; 820275474Smav } 821275474Smav } 822275474Smav VOP_UNLOCK(be_lun->vn, 0); 823275474Smav 824275474Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 825275474Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 826287499Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 827287499Smav lbalen->lba), data->descr[0].length); 828275474Smav data->descr[0].status = status; 829275474Smav 830275474Smav ctl_complete_beio(beio); 831275474Smav} 832275474Smav 833275481Smavstatic uint64_t 834275481Smavctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, const char *attrname) 835275481Smav{ 836275481Smav struct vattr vattr; 837275481Smav struct statfs statfs; 838285030Smav uint64_t val; 839275481Smav int error; 840275481Smav 841285030Smav val = UINT64_MAX; 842275481Smav if (be_lun->vn == NULL) 843285030Smav return (val); 844285030Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 845275481Smav if (strcmp(attrname, "blocksused") == 0) { 846275481Smav error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 847285030Smav if (error == 0) 848287499Smav val = vattr.va_bytes / be_lun->cbe_lun.blocksize; 849275481Smav } 850285030Smav if (strcmp(attrname, "blocksavail") == 0 && 851285030Smav (be_lun->vn->v_iflag & VI_DOOMED) == 0) { 852275481Smav error = VFS_STATFS(be_lun->vn->v_mount, &statfs); 853285030Smav if (error == 0) 854286811Smav val = statfs.f_bavail * statfs.f_bsize / 855287499Smav be_lun->cbe_lun.blocksize; 856275481Smav } 857285030Smav VOP_UNLOCK(be_lun->vn, 0); 858285030Smav return (val); 859275481Smav} 860275481Smav 861275474Smavstatic void 862269123Smavctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, 863269123Smav struct ctl_be_block_io *beio) 864269123Smav{ 865269123Smav union ctl_io *io; 866287664Smav struct cdevsw *csw; 867287664Smav struct cdev *dev; 868269123Smav struct uio xuio; 869269123Smav struct iovec *xiovec; 870287664Smav int error, flags, i, ref; 871269123Smav 872269123Smav DPRINTF("entered\n"); 873269123Smav 874269123Smav io = beio->io; 875271309Smav flags = 0; 876271309Smav if (ARGS(io)->flags & CTL_LLF_DPO) 877271309Smav flags |= IO_DIRECT; 878271309Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 879271309Smav flags |= IO_SYNC; 880269123Smav 881269123Smav bzero(&xuio, sizeof(xuio)); 882269123Smav if (beio->bio_cmd == BIO_READ) { 883269123Smav SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 884269123Smav xuio.uio_rw = UIO_READ; 885269123Smav } else { 886269123Smav SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 887269123Smav xuio.uio_rw = UIO_WRITE; 888269123Smav } 889269123Smav xuio.uio_offset = beio->io_offset; 890269123Smav xuio.uio_resid = beio->io_len; 891269123Smav xuio.uio_segflg = UIO_SYSSPACE; 892269123Smav xuio.uio_iov = beio->xiovecs; 893269123Smav xuio.uio_iovcnt = beio->num_segs; 894269123Smav xuio.uio_td = curthread; 895269123Smav 896269123Smav for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 897269123Smav xiovec->iov_base = beio->sg_segs[i].addr; 898269123Smav xiovec->iov_len = beio->sg_segs[i].len; 899269123Smav } 900269123Smav 901269123Smav binuptime(&beio->ds_t0); 902269123Smav mtx_lock(&be_lun->io_lock); 903269123Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 904269123Smav mtx_unlock(&be_lun->io_lock); 905269123Smav 906287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 907287664Smav if (csw) { 908287664Smav if (beio->bio_cmd == BIO_READ) 909287664Smav error = csw->d_read(dev, &xuio, flags); 910287664Smav else 911287664Smav error = csw->d_write(dev, &xuio, flags); 912287664Smav dev_relthread(dev, ref); 913287664Smav } else 914287664Smav error = ENXIO; 915287664Smav 916287664Smav if (beio->bio_cmd == BIO_READ) 917269123Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 918287664Smav else 919269123Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 920269123Smav 921269123Smav mtx_lock(&be_lun->io_lock); 922269123Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 923269123Smav beio->ds_tag_type, beio->ds_trans_type, 924269123Smav /*now*/ NULL, /*then*/&beio->ds_t0); 925269123Smav mtx_unlock(&be_lun->io_lock); 926269123Smav 927269123Smav /* 928269123Smav * If we got an error, set the sense data to "MEDIUM ERROR" and 929269123Smav * return the I/O to the user. 930269123Smav */ 931269123Smav if (error != 0) { 932282565Smav if (error == ENOSPC || error == EDQUOT) { 933273809Smav ctl_set_space_alloc_fail(&io->scsiio); 934287760Smav } else if (error == EROFS || error == EACCES) { 935287760Smav ctl_set_hw_write_protected(&io->scsiio); 936287912Smav } else { 937287912Smav ctl_set_medium_error(&io->scsiio, 938287912Smav beio->bio_cmd == BIO_READ); 939287912Smav } 940269123Smav ctl_complete_beio(beio); 941269123Smav return; 942269123Smav } 943269123Smav 944269123Smav /* 945269123Smav * If this is a write or a verify, we're all done. 946269123Smav * If this is a read, we can now send the data to the user. 947269123Smav */ 948269123Smav if ((beio->bio_cmd == BIO_WRITE) || 949269123Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 950269123Smav ctl_set_success(&io->scsiio); 951269123Smav ctl_complete_beio(beio); 952269123Smav } else { 953275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 954275058Smav beio->beio_cont == NULL) 955275058Smav ctl_set_success(&io->scsiio); 956269123Smav#ifdef CTL_TIME_IO 957269123Smav getbintime(&io->io_hdr.dma_start_bt); 958269123Smav#endif 959269123Smav ctl_datamove(io); 960269123Smav } 961269123Smav} 962269123Smav 963269123Smavstatic void 964275474Smavctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, 965275474Smav struct ctl_be_block_io *beio) 966275474Smav{ 967275474Smav union ctl_io *io = beio->io; 968287664Smav struct cdevsw *csw; 969287664Smav struct cdev *dev; 970275474Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 971275474Smav struct scsi_get_lba_status_data *data; 972275474Smav off_t roff, off; 973287664Smav int error, ref, status; 974275474Smav 975275474Smav DPRINTF("entered\n"); 976275474Smav 977287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 978287664Smav if (csw == NULL) { 979287664Smav status = 0; /* unknown up to the end */ 980287664Smav off = be_lun->size_bytes; 981287664Smav goto done; 982287664Smav } 983287499Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 984287664Smav error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD, 985287664Smav curthread); 986275474Smav if (error == 0 && off > roff) 987275474Smav status = 0; /* mapped up to off */ 988275474Smav else { 989287664Smav error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD, 990287664Smav curthread); 991275474Smav if (error == 0 && off > roff) 992275474Smav status = 1; /* deallocated up to off */ 993275474Smav else { 994275474Smav status = 0; /* unknown up to the end */ 995275474Smav off = be_lun->size_bytes; 996275474Smav } 997275474Smav } 998287664Smav dev_relthread(dev, ref); 999275474Smav 1000287664Smavdone: 1001275474Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 1002275474Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 1003287499Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 1004287499Smav lbalen->lba), data->descr[0].length); 1005275474Smav data->descr[0].status = status; 1006275474Smav 1007275474Smav ctl_complete_beio(beio); 1008275474Smav} 1009275474Smav 1010275474Smavstatic void 1011229997Skenctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 1012229997Sken struct ctl_be_block_io *beio) 1013229997Sken{ 1014229997Sken struct bio *bio; 1015229997Sken union ctl_io *io; 1016287664Smav struct cdevsw *csw; 1017287664Smav struct cdev *dev; 1018287664Smav int ref; 1019229997Sken 1020229997Sken io = beio->io; 1021229997Sken 1022229997Sken DPRINTF("entered\n"); 1023229997Sken 1024229997Sken /* This can't fail, it's a blocking allocation. */ 1025229997Sken bio = g_alloc_bio(); 1026229997Sken 1027229997Sken bio->bio_cmd = BIO_FLUSH; 1028229997Sken bio->bio_offset = 0; 1029229997Sken bio->bio_data = 0; 1030229997Sken bio->bio_done = ctl_be_block_biodone; 1031229997Sken bio->bio_caller1 = beio; 1032229997Sken bio->bio_pblkno = 0; 1033229997Sken 1034229997Sken /* 1035229997Sken * We don't need to acquire the LUN lock here, because we are only 1036229997Sken * sending one bio, and so there is no other context to synchronize 1037229997Sken * with. 1038229997Sken */ 1039229997Sken beio->num_bios_sent = 1; 1040229997Sken beio->send_complete = 1; 1041229997Sken 1042229997Sken binuptime(&beio->ds_t0); 1043267877Smav mtx_lock(&be_lun->io_lock); 1044229997Sken devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1045267877Smav mtx_unlock(&be_lun->io_lock); 1046229997Sken 1047287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1048287664Smav if (csw) { 1049287664Smav bio->bio_dev = dev; 1050287664Smav csw->d_strategy(bio); 1051287664Smav dev_relthread(dev, ref); 1052287664Smav } else { 1053287664Smav bio->bio_error = ENXIO; 1054287664Smav ctl_be_block_biodone(bio); 1055287664Smav } 1056229997Sken} 1057229997Sken 1058229997Skenstatic void 1059264274Smavctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, 1060264274Smav struct ctl_be_block_io *beio, 1061264274Smav uint64_t off, uint64_t len, int last) 1062264274Smav{ 1063264274Smav struct bio *bio; 1064264296Smav uint64_t maxlen; 1065287664Smav struct cdevsw *csw; 1066287664Smav struct cdev *dev; 1067287664Smav int ref; 1068264274Smav 1069287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1070287499Smav maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize); 1071264274Smav while (len > 0) { 1072264274Smav bio = g_alloc_bio(); 1073264274Smav bio->bio_cmd = BIO_DELETE; 1074287664Smav bio->bio_dev = dev; 1075264274Smav bio->bio_offset = off; 1076264296Smav bio->bio_length = MIN(len, maxlen); 1077264274Smav bio->bio_data = 0; 1078264274Smav bio->bio_done = ctl_be_block_biodone; 1079264274Smav bio->bio_caller1 = beio; 1080287499Smav bio->bio_pblkno = off / be_lun->cbe_lun.blocksize; 1081264274Smav 1082264274Smav off += bio->bio_length; 1083264274Smav len -= bio->bio_length; 1084264274Smav 1085267877Smav mtx_lock(&be_lun->io_lock); 1086264274Smav beio->num_bios_sent++; 1087264274Smav if (last && len == 0) 1088264274Smav beio->send_complete = 1; 1089267877Smav mtx_unlock(&be_lun->io_lock); 1090264274Smav 1091287664Smav if (csw) { 1092287664Smav csw->d_strategy(bio); 1093287664Smav } else { 1094287664Smav bio->bio_error = ENXIO; 1095287664Smav ctl_be_block_biodone(bio); 1096287664Smav } 1097264274Smav } 1098287664Smav if (csw) 1099287664Smav dev_relthread(dev, ref); 1100264274Smav} 1101264274Smav 1102264274Smavstatic void 1103264274Smavctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 1104264274Smav struct ctl_be_block_io *beio) 1105264274Smav{ 1106264274Smav union ctl_io *io; 1107267515Smav struct ctl_ptr_len_flags *ptrlen; 1108264274Smav struct scsi_unmap_desc *buf, *end; 1109264274Smav uint64_t len; 1110264274Smav 1111264274Smav io = beio->io; 1112264274Smav 1113264274Smav DPRINTF("entered\n"); 1114264274Smav 1115264274Smav binuptime(&beio->ds_t0); 1116267877Smav mtx_lock(&be_lun->io_lock); 1117264274Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1118267877Smav mtx_unlock(&be_lun->io_lock); 1119264274Smav 1120264274Smav if (beio->io_offset == -1) { 1121264274Smav beio->io_len = 0; 1122267515Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1123267515Smav buf = (struct scsi_unmap_desc *)ptrlen->ptr; 1124267515Smav end = buf + ptrlen->len / sizeof(*buf); 1125264274Smav for (; buf < end; buf++) { 1126264274Smav len = (uint64_t)scsi_4btoul(buf->length) * 1127287499Smav be_lun->cbe_lun.blocksize; 1128264274Smav beio->io_len += len; 1129264274Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1130287499Smav scsi_8btou64(buf->lba) * be_lun->cbe_lun.blocksize, 1131287499Smav len, (end - buf < 2) ? TRUE : FALSE); 1132264274Smav } 1133264274Smav } else 1134264274Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1135264274Smav beio->io_offset, beio->io_len, TRUE); 1136264274Smav} 1137264274Smav 1138264274Smavstatic void 1139229997Skenctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 1140229997Sken struct ctl_be_block_io *beio) 1141229997Sken{ 1142267877Smav TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 1143229997Sken struct bio *bio; 1144287664Smav struct cdevsw *csw; 1145287664Smav struct cdev *dev; 1146229997Sken off_t cur_offset; 1147287664Smav int i, max_iosize, ref; 1148229997Sken 1149229997Sken DPRINTF("entered\n"); 1150287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1151229997Sken 1152229997Sken /* 1153229997Sken * We have to limit our I/O size to the maximum supported by the 1154229997Sken * backend device. Hopefully it is MAXPHYS. If the driver doesn't 1155229997Sken * set it properly, use DFLTPHYS. 1156229997Sken */ 1157287664Smav if (csw) { 1158287664Smav max_iosize = dev->si_iosize_max; 1159287664Smav if (max_iosize < PAGE_SIZE) 1160287664Smav max_iosize = DFLTPHYS; 1161287664Smav } else 1162229997Sken max_iosize = DFLTPHYS; 1163229997Sken 1164229997Sken cur_offset = beio->io_offset; 1165229997Sken for (i = 0; i < beio->num_segs; i++) { 1166229997Sken size_t cur_size; 1167229997Sken uint8_t *cur_ptr; 1168229997Sken 1169229997Sken cur_size = beio->sg_segs[i].len; 1170229997Sken cur_ptr = beio->sg_segs[i].addr; 1171229997Sken 1172229997Sken while (cur_size > 0) { 1173229997Sken /* This can't fail, it's a blocking allocation. */ 1174229997Sken bio = g_alloc_bio(); 1175229997Sken 1176229997Sken KASSERT(bio != NULL, ("g_alloc_bio() failed!\n")); 1177229997Sken 1178229997Sken bio->bio_cmd = beio->bio_cmd; 1179287664Smav bio->bio_dev = dev; 1180229997Sken bio->bio_caller1 = beio; 1181229997Sken bio->bio_length = min(cur_size, max_iosize); 1182229997Sken bio->bio_offset = cur_offset; 1183229997Sken bio->bio_data = cur_ptr; 1184229997Sken bio->bio_done = ctl_be_block_biodone; 1185287499Smav bio->bio_pblkno = cur_offset / be_lun->cbe_lun.blocksize; 1186229997Sken 1187229997Sken cur_offset += bio->bio_length; 1188229997Sken cur_ptr += bio->bio_length; 1189229997Sken cur_size -= bio->bio_length; 1190229997Sken 1191267877Smav TAILQ_INSERT_TAIL(&queue, bio, bio_queue); 1192229997Sken beio->num_bios_sent++; 1193229997Sken } 1194229997Sken } 1195267877Smav binuptime(&beio->ds_t0); 1196267877Smav mtx_lock(&be_lun->io_lock); 1197267877Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1198267877Smav beio->send_complete = 1; 1199267877Smav mtx_unlock(&be_lun->io_lock); 1200267877Smav 1201267877Smav /* 1202267877Smav * Fire off all allocated requests! 1203267877Smav */ 1204267877Smav while ((bio = TAILQ_FIRST(&queue)) != NULL) { 1205267877Smav TAILQ_REMOVE(&queue, bio, bio_queue); 1206287664Smav if (csw) 1207287664Smav csw->d_strategy(bio); 1208287664Smav else { 1209287664Smav bio->bio_error = ENXIO; 1210287664Smav ctl_be_block_biodone(bio); 1211287664Smav } 1212267877Smav } 1213287664Smav if (csw) 1214287664Smav dev_relthread(dev, ref); 1215229997Sken} 1216229997Sken 1217274154Smavstatic uint64_t 1218274154Smavctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname) 1219274154Smav{ 1220274154Smav struct diocgattr_arg arg; 1221287664Smav struct cdevsw *csw; 1222287664Smav struct cdev *dev; 1223287664Smav int error, ref; 1224274154Smav 1225287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1226287664Smav if (csw == NULL) 1227274154Smav return (UINT64_MAX); 1228274154Smav strlcpy(arg.name, attrname, sizeof(arg.name)); 1229274154Smav arg.len = sizeof(arg.value.off); 1230287664Smav if (csw->d_ioctl) { 1231287664Smav error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 1232287664Smav curthread); 1233287664Smav } else 1234287664Smav error = ENODEV; 1235287664Smav dev_relthread(dev, ref); 1236274154Smav if (error != 0) 1237274154Smav return (UINT64_MAX); 1238274154Smav return (arg.value.off); 1239274154Smav} 1240274154Smav 1241229997Skenstatic void 1242286353Smavctl_be_block_cw_dispatch_sync(struct ctl_be_block_lun *be_lun, 1243286353Smav union ctl_io *io) 1244286353Smav{ 1245287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1246286353Smav struct ctl_be_block_io *beio; 1247286353Smav struct ctl_lba_len_flags *lbalen; 1248286353Smav 1249286353Smav DPRINTF("entered\n"); 1250286353Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1251286353Smav lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1252286353Smav 1253287499Smav beio->io_len = lbalen->len * cbe_lun->blocksize; 1254287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1255286353Smav beio->io_arg = (lbalen->flags & SSC_IMMED) != 0; 1256286353Smav beio->bio_cmd = BIO_FLUSH; 1257286353Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1258286353Smav DPRINTF("SYNC\n"); 1259286353Smav be_lun->lun_flush(be_lun, beio); 1260286353Smav} 1261286353Smav 1262286353Smavstatic void 1263264274Smavctl_be_block_cw_done_ws(struct ctl_be_block_io *beio) 1264264274Smav{ 1265264274Smav union ctl_io *io; 1266264274Smav 1267264274Smav io = beio->io; 1268264274Smav ctl_free_beio(beio); 1269267641Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1270267641Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1271267641Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1272264274Smav ctl_config_write_done(io); 1273264274Smav return; 1274264274Smav } 1275264274Smav 1276264274Smav ctl_be_block_config_write(io); 1277264274Smav} 1278264274Smav 1279264274Smavstatic void 1280264274Smavctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun, 1281264274Smav union ctl_io *io) 1282264274Smav{ 1283287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1284264274Smav struct ctl_be_block_io *beio; 1285267515Smav struct ctl_lba_len_flags *lbalen; 1286278625Smav uint64_t len_left, lba; 1287278625Smav uint32_t pb, pbo, adj; 1288264274Smav int i, seglen; 1289264274Smav uint8_t *buf, *end; 1290264274Smav 1291264274Smav DPRINTF("entered\n"); 1292264274Smav 1293267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1294267537Smav lbalen = ARGS(beio->io); 1295264274Smav 1296271839Smav if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB) || 1297269622Smav (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR) && be_lun->unmap == NULL)) { 1298264274Smav ctl_free_beio(beio); 1299264274Smav ctl_set_invalid_field(&io->scsiio, 1300264274Smav /*sks_valid*/ 1, 1301264274Smav /*command*/ 1, 1302264274Smav /*field*/ 1, 1303264274Smav /*bit_valid*/ 0, 1304264274Smav /*bit*/ 0); 1305264274Smav ctl_config_write_done(io); 1306264274Smav return; 1307264274Smav } 1308264274Smav 1309269622Smav if (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR)) { 1310287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1311287499Smav beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize; 1312264274Smav beio->bio_cmd = BIO_DELETE; 1313264274Smav beio->ds_trans_type = DEVSTAT_FREE; 1314264274Smav 1315264274Smav be_lun->unmap(be_lun, beio); 1316264274Smav return; 1317264274Smav } 1318264274Smav 1319264274Smav beio->bio_cmd = BIO_WRITE; 1320264274Smav beio->ds_trans_type = DEVSTAT_WRITE; 1321264274Smav 1322264274Smav DPRINTF("WRITE SAME at LBA %jx len %u\n", 1323267515Smav (uintmax_t)lbalen->lba, lbalen->len); 1324264274Smav 1325287499Smav pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp; 1326287499Smav if (be_lun->cbe_lun.pblockoff > 0) 1327287499Smav pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff; 1328278625Smav else 1329278625Smav pbo = 0; 1330287499Smav len_left = (uint64_t)lbalen->len * cbe_lun->blocksize; 1331264274Smav for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) { 1332264274Smav 1333264274Smav /* 1334264274Smav * Setup the S/G entry for this chunk. 1335264274Smav */ 1336264886Smav seglen = MIN(CTLBLK_MAX_SEG, len_left); 1337287499Smav if (pb > cbe_lun->blocksize) { 1338287499Smav adj = ((lbalen->lba + lba) * cbe_lun->blocksize + 1339278619Smav seglen - pbo) % pb; 1340278619Smav if (seglen > adj) 1341278619Smav seglen -= adj; 1342278619Smav else 1343287499Smav seglen -= seglen % cbe_lun->blocksize; 1344278619Smav } else 1345287499Smav seglen -= seglen % cbe_lun->blocksize; 1346264274Smav beio->sg_segs[i].len = seglen; 1347264274Smav beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1348264274Smav 1349264274Smav DPRINTF("segment %d addr %p len %zd\n", i, 1350264274Smav beio->sg_segs[i].addr, beio->sg_segs[i].len); 1351264274Smav 1352264274Smav beio->num_segs++; 1353264274Smav len_left -= seglen; 1354264274Smav 1355264274Smav buf = beio->sg_segs[i].addr; 1356264274Smav end = buf + seglen; 1357287499Smav for (; buf < end; buf += cbe_lun->blocksize) { 1358287499Smav memcpy(buf, io->scsiio.kern_data_ptr, cbe_lun->blocksize); 1359267515Smav if (lbalen->flags & SWS_LBDATA) 1360267515Smav scsi_ulto4b(lbalen->lba + lba, buf); 1361264274Smav lba++; 1362264274Smav } 1363264274Smav } 1364264274Smav 1365287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1366287499Smav beio->io_len = lba * cbe_lun->blocksize; 1367264274Smav 1368264274Smav /* We can not do all in one run. Correct and schedule rerun. */ 1369264274Smav if (len_left > 0) { 1370267515Smav lbalen->lba += lba; 1371267515Smav lbalen->len -= lba; 1372264274Smav beio->beio_cont = ctl_be_block_cw_done_ws; 1373264274Smav } 1374264274Smav 1375264274Smav be_lun->dispatch(be_lun, beio); 1376264274Smav} 1377264274Smav 1378264274Smavstatic void 1379264274Smavctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun, 1380264274Smav union ctl_io *io) 1381264274Smav{ 1382264274Smav struct ctl_be_block_io *beio; 1383267515Smav struct ctl_ptr_len_flags *ptrlen; 1384264274Smav 1385264274Smav DPRINTF("entered\n"); 1386264274Smav 1387267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1388267515Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1389264274Smav 1390269622Smav if ((ptrlen->flags & ~SU_ANCHOR) != 0 || be_lun->unmap == NULL) { 1391264274Smav ctl_free_beio(beio); 1392264274Smav ctl_set_invalid_field(&io->scsiio, 1393264274Smav /*sks_valid*/ 0, 1394264274Smav /*command*/ 1, 1395264274Smav /*field*/ 0, 1396264274Smav /*bit_valid*/ 0, 1397264274Smav /*bit*/ 0); 1398264274Smav ctl_config_write_done(io); 1399264274Smav return; 1400264274Smav } 1401264274Smav 1402264274Smav beio->io_len = 0; 1403264274Smav beio->io_offset = -1; 1404264274Smav beio->bio_cmd = BIO_DELETE; 1405264274Smav beio->ds_trans_type = DEVSTAT_FREE; 1406267515Smav DPRINTF("UNMAP\n"); 1407264274Smav be_lun->unmap(be_lun, beio); 1408264274Smav} 1409264274Smav 1410264274Smavstatic void 1411275474Smavctl_be_block_cr_done(struct ctl_be_block_io *beio) 1412275474Smav{ 1413275474Smav union ctl_io *io; 1414275474Smav 1415275474Smav io = beio->io; 1416275474Smav ctl_free_beio(beio); 1417275474Smav ctl_config_read_done(io); 1418275474Smav} 1419275474Smav 1420275474Smavstatic void 1421275474Smavctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 1422275474Smav union ctl_io *io) 1423275474Smav{ 1424275474Smav struct ctl_be_block_io *beio; 1425275474Smav struct ctl_be_block_softc *softc; 1426275474Smav 1427275474Smav DPRINTF("entered\n"); 1428275474Smav 1429275474Smav softc = be_lun->softc; 1430275474Smav beio = ctl_alloc_beio(softc); 1431275474Smav beio->io = io; 1432275474Smav beio->lun = be_lun; 1433275474Smav beio->beio_cont = ctl_be_block_cr_done; 1434275474Smav PRIV(io)->ptr = (void *)beio; 1435275474Smav 1436275474Smav switch (io->scsiio.cdb[0]) { 1437275474Smav case SERVICE_ACTION_IN: /* GET LBA STATUS */ 1438275474Smav beio->bio_cmd = -1; 1439275474Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1440275474Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1441275474Smav beio->io_len = 0; 1442275474Smav if (be_lun->get_lba_status) 1443275474Smav be_lun->get_lba_status(be_lun, beio); 1444275474Smav else 1445275474Smav ctl_be_block_cr_done(beio); 1446275474Smav break; 1447275474Smav default: 1448275474Smav panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1449275474Smav break; 1450275474Smav } 1451275474Smav} 1452275474Smav 1453275474Smavstatic void 1454264274Smavctl_be_block_cw_done(struct ctl_be_block_io *beio) 1455264274Smav{ 1456264274Smav union ctl_io *io; 1457264274Smav 1458264274Smav io = beio->io; 1459264274Smav ctl_free_beio(beio); 1460264274Smav ctl_config_write_done(io); 1461264274Smav} 1462264274Smav 1463264274Smavstatic void 1464229997Skenctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 1465229997Sken union ctl_io *io) 1466229997Sken{ 1467229997Sken struct ctl_be_block_io *beio; 1468229997Sken struct ctl_be_block_softc *softc; 1469229997Sken 1470229997Sken DPRINTF("entered\n"); 1471229997Sken 1472229997Sken softc = be_lun->softc; 1473229997Sken beio = ctl_alloc_beio(softc); 1474229997Sken beio->io = io; 1475229997Sken beio->lun = be_lun; 1476264274Smav beio->beio_cont = ctl_be_block_cw_done; 1477286353Smav switch (io->scsiio.tag_type) { 1478286353Smav case CTL_TAG_ORDERED: 1479286353Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1480286353Smav break; 1481286353Smav case CTL_TAG_HEAD_OF_QUEUE: 1482286353Smav beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1483286353Smav break; 1484286353Smav case CTL_TAG_UNTAGGED: 1485286353Smav case CTL_TAG_SIMPLE: 1486286353Smav case CTL_TAG_ACA: 1487286353Smav default: 1488286353Smav beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1489286353Smav break; 1490286353Smav } 1491267519Smav PRIV(io)->ptr = (void *)beio; 1492229997Sken 1493229997Sken switch (io->scsiio.cdb[0]) { 1494229997Sken case SYNCHRONIZE_CACHE: 1495229997Sken case SYNCHRONIZE_CACHE_16: 1496286353Smav ctl_be_block_cw_dispatch_sync(be_lun, io); 1497229997Sken break; 1498264274Smav case WRITE_SAME_10: 1499264274Smav case WRITE_SAME_16: 1500264274Smav ctl_be_block_cw_dispatch_ws(be_lun, io); 1501264274Smav break; 1502264274Smav case UNMAP: 1503264274Smav ctl_be_block_cw_dispatch_unmap(be_lun, io); 1504264274Smav break; 1505229997Sken default: 1506229997Sken panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1507229997Sken break; 1508229997Sken } 1509229997Sken} 1510229997Sken 1511258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, start, "uint64_t"); 1512258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, start, "uint64_t"); 1513258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, alloc_done, "uint64_t"); 1514258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, alloc_done, "uint64_t"); 1515229997Sken 1516229997Skenstatic void 1517264886Smavctl_be_block_next(struct ctl_be_block_io *beio) 1518264886Smav{ 1519264886Smav struct ctl_be_block_lun *be_lun; 1520264886Smav union ctl_io *io; 1521264886Smav 1522264886Smav io = beio->io; 1523264886Smav be_lun = beio->lun; 1524264886Smav ctl_free_beio(beio); 1525267641Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1526267641Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1527267641Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1528267537Smav ctl_data_submit_done(io); 1529264886Smav return; 1530264886Smav } 1531264886Smav 1532264886Smav io->io_hdr.status &= ~CTL_STATUS_MASK; 1533264886Smav io->io_hdr.status |= CTL_STATUS_NONE; 1534264886Smav 1535267877Smav mtx_lock(&be_lun->queue_lock); 1536264886Smav /* 1537264886Smav * XXX KDM make sure that links is okay to use at this point. 1538264886Smav * Otherwise, we either need to add another field to ctl_io_hdr, 1539264886Smav * or deal with resource allocation here. 1540264886Smav */ 1541264886Smav STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1542267877Smav mtx_unlock(&be_lun->queue_lock); 1543264886Smav 1544264886Smav taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1545264886Smav} 1546264886Smav 1547264886Smavstatic void 1548229997Skenctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 1549229997Sken union ctl_io *io) 1550229997Sken{ 1551287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1552229997Sken struct ctl_be_block_io *beio; 1553229997Sken struct ctl_be_block_softc *softc; 1554267537Smav struct ctl_lba_len_flags *lbalen; 1555267519Smav struct ctl_ptr_len_flags *bptrlen; 1556267519Smav uint64_t len_left, lbas; 1557229997Sken int i; 1558229997Sken 1559229997Sken softc = be_lun->softc; 1560229997Sken 1561229997Sken DPRINTF("entered\n"); 1562229997Sken 1563267537Smav lbalen = ARGS(io); 1564267537Smav if (lbalen->flags & CTL_LLF_WRITE) { 1565267537Smav SDT_PROBE(cbb, kernel, write, start, 0, 0, 0, 0, 0); 1566267537Smav } else { 1567229997Sken SDT_PROBE(cbb, kernel, read, start, 0, 0, 0, 0, 0); 1568229997Sken } 1569229997Sken 1570229997Sken beio = ctl_alloc_beio(softc); 1571229997Sken beio->io = io; 1572229997Sken beio->lun = be_lun; 1573267519Smav bptrlen = PRIV(io); 1574267519Smav bptrlen->ptr = (void *)beio; 1575229997Sken 1576229997Sken switch (io->scsiio.tag_type) { 1577229997Sken case CTL_TAG_ORDERED: 1578229997Sken beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1579229997Sken break; 1580229997Sken case CTL_TAG_HEAD_OF_QUEUE: 1581229997Sken beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1582229997Sken break; 1583229997Sken case CTL_TAG_UNTAGGED: 1584229997Sken case CTL_TAG_SIMPLE: 1585229997Sken case CTL_TAG_ACA: 1586229997Sken default: 1587229997Sken beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1588229997Sken break; 1589229997Sken } 1590229997Sken 1591267537Smav if (lbalen->flags & CTL_LLF_WRITE) { 1592267537Smav beio->bio_cmd = BIO_WRITE; 1593267537Smav beio->ds_trans_type = DEVSTAT_WRITE; 1594267537Smav } else { 1595229997Sken beio->bio_cmd = BIO_READ; 1596229997Sken beio->ds_trans_type = DEVSTAT_READ; 1597229997Sken } 1598229997Sken 1599264886Smav DPRINTF("%s at LBA %jx len %u @%ju\n", 1600229997Sken (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", 1601267519Smav (uintmax_t)lbalen->lba, lbalen->len, bptrlen->len); 1602267537Smav if (lbalen->flags & CTL_LLF_COMPARE) 1603267537Smav lbas = CTLBLK_HALF_IO_SIZE; 1604267537Smav else 1605267537Smav lbas = CTLBLK_MAX_IO_SIZE; 1606287499Smav lbas = MIN(lbalen->len - bptrlen->len, lbas / cbe_lun->blocksize); 1607287499Smav beio->io_offset = (lbalen->lba + bptrlen->len) * cbe_lun->blocksize; 1608287499Smav beio->io_len = lbas * cbe_lun->blocksize; 1609267519Smav bptrlen->len += lbas; 1610229997Sken 1611264886Smav for (i = 0, len_left = beio->io_len; len_left > 0; i++) { 1612264886Smav KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", 1613264886Smav i, CTLBLK_MAX_SEGS)); 1614229997Sken 1615229997Sken /* 1616229997Sken * Setup the S/G entry for this chunk. 1617229997Sken */ 1618264886Smav beio->sg_segs[i].len = min(CTLBLK_MAX_SEG, len_left); 1619229997Sken beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1620229997Sken 1621229997Sken DPRINTF("segment %d addr %p len %zd\n", i, 1622229997Sken beio->sg_segs[i].addr, beio->sg_segs[i].len); 1623229997Sken 1624267537Smav /* Set up second segment for compare operation. */ 1625267537Smav if (lbalen->flags & CTL_LLF_COMPARE) { 1626267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].len = 1627267537Smav beio->sg_segs[i].len; 1628267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = 1629267537Smav uma_zalloc(be_lun->lun_zone, M_WAITOK); 1630267537Smav } 1631267537Smav 1632229997Sken beio->num_segs++; 1633229997Sken len_left -= beio->sg_segs[i].len; 1634229997Sken } 1635267519Smav if (bptrlen->len < lbalen->len) 1636264886Smav beio->beio_cont = ctl_be_block_next; 1637264886Smav io->scsiio.be_move_done = ctl_be_block_move_done; 1638267537Smav /* For compare we have separate S/G lists for read and datamove. */ 1639267537Smav if (lbalen->flags & CTL_LLF_COMPARE) 1640267537Smav io->scsiio.kern_data_ptr = (uint8_t *)&beio->sg_segs[CTLBLK_HALF_SEGS]; 1641267537Smav else 1642267537Smav io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; 1643264886Smav io->scsiio.kern_data_len = beio->io_len; 1644264886Smav io->scsiio.kern_data_resid = 0; 1645264886Smav io->scsiio.kern_sg_entries = beio->num_segs; 1646264886Smav io->io_hdr.flags |= CTL_FLAG_ALLOCATED | CTL_FLAG_KDPTR_SGLIST; 1647229997Sken 1648229997Sken /* 1649229997Sken * For the read case, we need to read the data into our buffers and 1650229997Sken * then we can send it back to the user. For the write case, we 1651229997Sken * need to get the data from the user first. 1652229997Sken */ 1653229997Sken if (beio->bio_cmd == BIO_READ) { 1654229997Sken SDT_PROBE(cbb, kernel, read, alloc_done, 0, 0, 0, 0, 0); 1655229997Sken be_lun->dispatch(be_lun, beio); 1656229997Sken } else { 1657229997Sken SDT_PROBE(cbb, kernel, write, alloc_done, 0, 0, 0, 0, 0); 1658229997Sken#ifdef CTL_TIME_IO 1659229997Sken getbintime(&io->io_hdr.dma_start_bt); 1660229997Sken#endif 1661229997Sken ctl_datamove(io); 1662229997Sken } 1663229997Sken} 1664229997Sken 1665229997Skenstatic void 1666229997Skenctl_be_block_worker(void *context, int pending) 1667229997Sken{ 1668287670Smav struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)context; 1669287670Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1670229997Sken union ctl_io *io; 1671287670Smav struct ctl_be_block_io *beio; 1672229997Sken 1673229997Sken DPRINTF("entered\n"); 1674287670Smav /* 1675287670Smav * Fetch and process I/Os from all queues. If we detect LUN 1676287670Smav * CTL_LUN_FLAG_OFFLINE status here -- it is result of a race, 1677287670Smav * so make response maximally opaque to not confuse initiator. 1678287670Smav */ 1679229997Sken for (;;) { 1680287670Smav mtx_lock(&be_lun->queue_lock); 1681229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue); 1682229997Sken if (io != NULL) { 1683229997Sken DPRINTF("datamove queue\n"); 1684229997Sken STAILQ_REMOVE(&be_lun->datamove_queue, &io->io_hdr, 1685229997Sken ctl_io_hdr, links); 1686267877Smav mtx_unlock(&be_lun->queue_lock); 1687267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1688287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1689287670Smav ctl_set_busy(&io->scsiio); 1690287670Smav ctl_complete_beio(beio); 1691287670Smav return; 1692287670Smav } 1693229997Sken be_lun->dispatch(be_lun, beio); 1694229997Sken continue; 1695229997Sken } 1696229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue); 1697229997Sken if (io != NULL) { 1698229997Sken DPRINTF("config write queue\n"); 1699229997Sken STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr, 1700229997Sken ctl_io_hdr, links); 1701267877Smav mtx_unlock(&be_lun->queue_lock); 1702287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1703287670Smav ctl_set_busy(&io->scsiio); 1704287670Smav ctl_config_write_done(io); 1705287670Smav return; 1706287670Smav } 1707229997Sken ctl_be_block_cw_dispatch(be_lun, io); 1708229997Sken continue; 1709229997Sken } 1710275474Smav io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue); 1711275474Smav if (io != NULL) { 1712275474Smav DPRINTF("config read queue\n"); 1713275474Smav STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr, 1714275474Smav ctl_io_hdr, links); 1715275474Smav mtx_unlock(&be_lun->queue_lock); 1716287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1717287670Smav ctl_set_busy(&io->scsiio); 1718287670Smav ctl_config_read_done(io); 1719287670Smav return; 1720287670Smav } 1721275474Smav ctl_be_block_cr_dispatch(be_lun, io); 1722275474Smav continue; 1723275474Smav } 1724229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue); 1725229997Sken if (io != NULL) { 1726229997Sken DPRINTF("input queue\n"); 1727229997Sken STAILQ_REMOVE(&be_lun->input_queue, &io->io_hdr, 1728229997Sken ctl_io_hdr, links); 1729267877Smav mtx_unlock(&be_lun->queue_lock); 1730287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1731287670Smav ctl_set_busy(&io->scsiio); 1732287670Smav ctl_data_submit_done(io); 1733287670Smav return; 1734287670Smav } 1735229997Sken ctl_be_block_dispatch(be_lun, io); 1736229997Sken continue; 1737229997Sken } 1738229997Sken 1739229997Sken /* 1740229997Sken * If we get here, there is no work left in the queues, so 1741229997Sken * just break out and let the task queue go to sleep. 1742229997Sken */ 1743287670Smav mtx_unlock(&be_lun->queue_lock); 1744229997Sken break; 1745229997Sken } 1746229997Sken} 1747229997Sken 1748229997Sken/* 1749229997Sken * Entry point from CTL to the backend for I/O. We queue everything to a 1750229997Sken * work thread, so this just puts the I/O on a queue and wakes up the 1751229997Sken * thread. 1752229997Sken */ 1753229997Skenstatic int 1754229997Skenctl_be_block_submit(union ctl_io *io) 1755229997Sken{ 1756229997Sken struct ctl_be_block_lun *be_lun; 1757287499Smav struct ctl_be_lun *cbe_lun; 1758229997Sken 1759229997Sken DPRINTF("entered\n"); 1760229997Sken 1761287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 1762229997Sken CTL_PRIV_BACKEND_LUN].ptr; 1763287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 1764229997Sken 1765229997Sken /* 1766229997Sken * Make sure we only get SCSI I/O. 1767229997Sken */ 1768229997Sken KASSERT(io->io_hdr.io_type == CTL_IO_SCSI, ("Non-SCSI I/O (type " 1769229997Sken "%#x) encountered", io->io_hdr.io_type)); 1770229997Sken 1771267519Smav PRIV(io)->len = 0; 1772267519Smav 1773267877Smav mtx_lock(&be_lun->queue_lock); 1774229997Sken /* 1775229997Sken * XXX KDM make sure that links is okay to use at this point. 1776229997Sken * Otherwise, we either need to add another field to ctl_io_hdr, 1777229997Sken * or deal with resource allocation here. 1778229997Sken */ 1779229997Sken STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1780267877Smav mtx_unlock(&be_lun->queue_lock); 1781229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1782229997Sken 1783267514Smav return (CTL_RETVAL_COMPLETE); 1784229997Sken} 1785229997Sken 1786229997Skenstatic int 1787229997Skenctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 1788229997Sken int flag, struct thread *td) 1789229997Sken{ 1790229997Sken struct ctl_be_block_softc *softc; 1791229997Sken int error; 1792229997Sken 1793229997Sken softc = &backend_block_softc; 1794229997Sken 1795229997Sken error = 0; 1796229997Sken 1797229997Sken switch (cmd) { 1798229997Sken case CTL_LUN_REQ: { 1799229997Sken struct ctl_lun_req *lun_req; 1800229997Sken 1801229997Sken lun_req = (struct ctl_lun_req *)addr; 1802229997Sken 1803229997Sken switch (lun_req->reqtype) { 1804229997Sken case CTL_LUNREQ_CREATE: 1805229997Sken error = ctl_be_block_create(softc, lun_req); 1806229997Sken break; 1807229997Sken case CTL_LUNREQ_RM: 1808229997Sken error = ctl_be_block_rm(softc, lun_req); 1809229997Sken break; 1810232604Strasz case CTL_LUNREQ_MODIFY: 1811232604Strasz error = ctl_be_block_modify(softc, lun_req); 1812232604Strasz break; 1813229997Sken default: 1814229997Sken lun_req->status = CTL_LUN_ERROR; 1815229997Sken snprintf(lun_req->error_str, sizeof(lun_req->error_str), 1816272911Smav "invalid LUN request type %d", 1817229997Sken lun_req->reqtype); 1818229997Sken break; 1819229997Sken } 1820229997Sken break; 1821229997Sken } 1822229997Sken default: 1823229997Sken error = ENOTTY; 1824229997Sken break; 1825229997Sken } 1826229997Sken 1827229997Sken return (error); 1828229997Sken} 1829229997Sken 1830229997Skenstatic int 1831229997Skenctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1832229997Sken{ 1833287499Smav struct ctl_be_lun *cbe_lun; 1834229997Sken struct ctl_be_block_filedata *file_data; 1835229997Sken struct ctl_lun_create_params *params; 1836275865Smav char *value; 1837229997Sken struct vattr vattr; 1838275865Smav off_t ps, pss, po, pos, us, uss, uo, uos; 1839229997Sken int error; 1840229997Sken 1841229997Sken error = 0; 1842287499Smav cbe_lun = &be_lun->cbe_lun; 1843229997Sken file_data = &be_lun->backend.file; 1844272911Smav params = &be_lun->params; 1845229997Sken 1846229997Sken be_lun->dev_type = CTL_BE_BLOCK_FILE; 1847229997Sken be_lun->dispatch = ctl_be_block_dispatch_file; 1848229997Sken be_lun->lun_flush = ctl_be_block_flush_file; 1849275474Smav be_lun->get_lba_status = ctl_be_block_gls_file; 1850275481Smav be_lun->getattr = ctl_be_block_getattr_file; 1851287499Smav be_lun->unmap = NULL; 1852287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 1853229997Sken 1854229997Sken error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 1855229997Sken if (error != 0) { 1856229997Sken snprintf(req->error_str, sizeof(req->error_str), 1857229997Sken "error calling VOP_GETATTR() for file %s", 1858229997Sken be_lun->dev_path); 1859229997Sken return (error); 1860229997Sken } 1861229997Sken 1862229997Sken /* 1863229997Sken * Verify that we have the ability to upgrade to exclusive 1864229997Sken * access on this file so we can trap errors at open instead 1865229997Sken * of reporting them during first access. 1866229997Sken */ 1867229997Sken if (VOP_ISLOCKED(be_lun->vn) != LK_EXCLUSIVE) { 1868229997Sken vn_lock(be_lun->vn, LK_UPGRADE | LK_RETRY); 1869229997Sken if (be_lun->vn->v_iflag & VI_DOOMED) { 1870229997Sken error = EBADF; 1871229997Sken snprintf(req->error_str, sizeof(req->error_str), 1872229997Sken "error locking file %s", be_lun->dev_path); 1873229997Sken return (error); 1874229997Sken } 1875229997Sken } 1876229997Sken 1877229997Sken file_data->cred = crhold(curthread->td_ucred); 1878232604Strasz if (params->lun_size_bytes != 0) 1879232604Strasz be_lun->size_bytes = params->lun_size_bytes; 1880232604Strasz else 1881232604Strasz be_lun->size_bytes = vattr.va_size; 1882229997Sken 1883229997Sken /* 1884273029Smav * For files we can use any logical block size. Prefer 512 bytes 1885273029Smav * for compatibility reasons. If file's vattr.va_blocksize 1886273029Smav * (preferred I/O block size) is bigger and multiple to chosen 1887273029Smav * logical block size -- report it as physical block size. 1888229997Sken */ 1889229997Sken if (params->blocksize_bytes != 0) 1890287499Smav cbe_lun->blocksize = params->blocksize_bytes; 1891229997Sken else 1892287499Smav cbe_lun->blocksize = 512; 1893287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 1894287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 1895287499Smav 0 : (be_lun->size_blocks - 1); 1896275865Smav 1897275865Smav us = ps = vattr.va_blocksize; 1898275865Smav uo = po = 0; 1899275865Smav 1900287499Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 1901275865Smav if (value != NULL) 1902275865Smav ctl_expand_number(value, &ps); 1903287499Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 1904275865Smav if (value != NULL) 1905275865Smav ctl_expand_number(value, &po); 1906287499Smav pss = ps / cbe_lun->blocksize; 1907287499Smav pos = po / cbe_lun->blocksize; 1908287499Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 1909287499Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 1910287499Smav cbe_lun->pblockexp = fls(pss) - 1; 1911287499Smav cbe_lun->pblockoff = (pss - pos) % pss; 1912273029Smav } 1913229997Sken 1914287499Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 1915275865Smav if (value != NULL) 1916275865Smav ctl_expand_number(value, &us); 1917287499Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 1918275865Smav if (value != NULL) 1919275865Smav ctl_expand_number(value, &uo); 1920287499Smav uss = us / cbe_lun->blocksize; 1921287499Smav uos = uo / cbe_lun->blocksize; 1922287499Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 1923287499Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 1924287499Smav cbe_lun->ublockexp = fls(uss) - 1; 1925287499Smav cbe_lun->ublockoff = (uss - uos) % uss; 1926275865Smav } 1927275865Smav 1928229997Sken /* 1929229997Sken * Sanity check. The media size has to be at least one 1930229997Sken * sector long. 1931229997Sken */ 1932287499Smav if (be_lun->size_bytes < cbe_lun->blocksize) { 1933229997Sken error = EINVAL; 1934229997Sken snprintf(req->error_str, sizeof(req->error_str), 1935229997Sken "file %s size %ju < block size %u", be_lun->dev_path, 1936287499Smav (uintmax_t)be_lun->size_bytes, cbe_lun->blocksize); 1937229997Sken } 1938275920Smav 1939287499Smav cbe_lun->opttxferlen = CTLBLK_MAX_IO_SIZE / cbe_lun->blocksize; 1940229997Sken return (error); 1941229997Sken} 1942229997Sken 1943229997Skenstatic int 1944229997Skenctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1945229997Sken{ 1946287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1947229997Sken struct ctl_lun_create_params *params; 1948287664Smav struct cdevsw *csw; 1949229997Sken struct cdev *dev; 1950275865Smav char *value; 1951287664Smav int error, atomic, maxio, ref, unmap, tmp; 1952287221Smav off_t ps, pss, po, pos, us, uss, uo, uos, otmp; 1953229997Sken 1954272911Smav params = &be_lun->params; 1955229997Sken 1956229997Sken be_lun->dev_type = CTL_BE_BLOCK_DEV; 1957287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1958287664Smav if (csw == NULL) 1959287664Smav return (ENXIO); 1960287664Smav if (strcmp(csw->d_name, "zvol") == 0) { 1961269123Smav be_lun->dispatch = ctl_be_block_dispatch_zvol; 1962275474Smav be_lun->get_lba_status = ctl_be_block_gls_zvol; 1963275920Smav atomic = maxio = CTLBLK_MAX_IO_SIZE; 1964275920Smav } else { 1965269123Smav be_lun->dispatch = ctl_be_block_dispatch_dev; 1966287499Smav be_lun->get_lba_status = NULL; 1967275920Smav atomic = 0; 1968287664Smav maxio = dev->si_iosize_max; 1969275920Smav if (maxio <= 0) 1970275920Smav maxio = DFLTPHYS; 1971275920Smav if (maxio > CTLBLK_MAX_IO_SIZE) 1972275920Smav maxio = CTLBLK_MAX_IO_SIZE; 1973275920Smav } 1974269123Smav be_lun->lun_flush = ctl_be_block_flush_dev; 1975274154Smav be_lun->getattr = ctl_be_block_getattr_dev; 1976287499Smav be_lun->unmap = ctl_be_block_unmap_dev; 1977229997Sken 1978287664Smav if (!csw->d_ioctl) { 1979287664Smav dev_relthread(dev, ref); 1980229997Sken snprintf(req->error_str, sizeof(req->error_str), 1981287664Smav "no d_ioctl for device %s!", be_lun->dev_path); 1982229997Sken return (ENODEV); 1983229997Sken } 1984229997Sken 1985287664Smav error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD, 1986229997Sken curthread); 1987229997Sken if (error) { 1988287664Smav dev_relthread(dev, ref); 1989229997Sken snprintf(req->error_str, sizeof(req->error_str), 1990272911Smav "error %d returned for DIOCGSECTORSIZE ioctl " 1991272911Smav "on %s!", error, be_lun->dev_path); 1992229997Sken return (error); 1993229997Sken } 1994229997Sken 1995229997Sken /* 1996229997Sken * If the user has asked for a blocksize that is greater than the 1997229997Sken * backing device's blocksize, we can do it only if the blocksize 1998229997Sken * the user is asking for is an even multiple of the underlying 1999229997Sken * device's blocksize. 2000229997Sken */ 2001286811Smav if ((params->blocksize_bytes != 0) && 2002286811Smav (params->blocksize_bytes >= tmp)) { 2003286811Smav if (params->blocksize_bytes % tmp == 0) { 2004287499Smav cbe_lun->blocksize = params->blocksize_bytes; 2005229997Sken } else { 2006287664Smav dev_relthread(dev, ref); 2007229997Sken snprintf(req->error_str, sizeof(req->error_str), 2008272911Smav "requested blocksize %u is not an even " 2009229997Sken "multiple of backing device blocksize %u", 2010287221Smav params->blocksize_bytes, tmp); 2011229997Sken return (EINVAL); 2012229997Sken } 2013286811Smav } else if (params->blocksize_bytes != 0) { 2014287664Smav dev_relthread(dev, ref); 2015229997Sken snprintf(req->error_str, sizeof(req->error_str), 2016272911Smav "requested blocksize %u < backing device " 2017287221Smav "blocksize %u", params->blocksize_bytes, tmp); 2018229997Sken return (EINVAL); 2019286811Smav } else 2020287499Smav cbe_lun->blocksize = tmp; 2021229997Sken 2022287664Smav error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD, 2023287664Smav curthread); 2024229997Sken if (error) { 2025287664Smav dev_relthread(dev, ref); 2026229997Sken snprintf(req->error_str, sizeof(req->error_str), 2027272911Smav "error %d returned for DIOCGMEDIASIZE " 2028272911Smav " ioctl on %s!", error, 2029232604Strasz be_lun->dev_path); 2030229997Sken return (error); 2031229997Sken } 2032229997Sken 2033232604Strasz if (params->lun_size_bytes != 0) { 2034287221Smav if (params->lun_size_bytes > otmp) { 2035287664Smav dev_relthread(dev, ref); 2036232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2037272911Smav "requested LUN size %ju > backing device " 2038272911Smav "size %ju", 2039232604Strasz (uintmax_t)params->lun_size_bytes, 2040287221Smav (uintmax_t)otmp); 2041232604Strasz return (EINVAL); 2042232604Strasz } 2043232604Strasz 2044232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2045286811Smav } else 2046287221Smav be_lun->size_bytes = otmp; 2047287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2048287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2049287499Smav 0 : (be_lun->size_blocks - 1); 2050232604Strasz 2051287664Smav error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD, 2052287664Smav curthread); 2053264191Smav if (error) 2054264191Smav ps = po = 0; 2055264191Smav else { 2056287664Smav error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po, 2057287664Smav FREAD, curthread); 2058264191Smav if (error) 2059264191Smav po = 0; 2060264191Smav } 2061275865Smav us = ps; 2062275865Smav uo = po; 2063275865Smav 2064287499Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 2065275865Smav if (value != NULL) 2066275865Smav ctl_expand_number(value, &ps); 2067287499Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 2068275865Smav if (value != NULL) 2069275865Smav ctl_expand_number(value, &po); 2070287499Smav pss = ps / cbe_lun->blocksize; 2071287499Smav pos = po / cbe_lun->blocksize; 2072287499Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 2073287499Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 2074287499Smav cbe_lun->pblockexp = fls(pss) - 1; 2075287499Smav cbe_lun->pblockoff = (pss - pos) % pss; 2076264191Smav } 2077264191Smav 2078287499Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 2079275865Smav if (value != NULL) 2080275865Smav ctl_expand_number(value, &us); 2081287499Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 2082275865Smav if (value != NULL) 2083275865Smav ctl_expand_number(value, &uo); 2084287499Smav uss = us / cbe_lun->blocksize; 2085287499Smav uos = uo / cbe_lun->blocksize; 2086287499Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 2087287499Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 2088287499Smav cbe_lun->ublockexp = fls(uss) - 1; 2089287499Smav cbe_lun->ublockoff = (uss - uos) % uss; 2090275865Smav } 2091275865Smav 2092287499Smav cbe_lun->atomicblock = atomic / cbe_lun->blocksize; 2093287499Smav cbe_lun->opttxferlen = maxio / cbe_lun->blocksize; 2094278672Smav 2095278672Smav if (be_lun->dispatch == ctl_be_block_dispatch_zvol) { 2096278672Smav unmap = 1; 2097278672Smav } else { 2098278672Smav struct diocgattr_arg arg; 2099278672Smav 2100278672Smav strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name)); 2101278672Smav arg.len = sizeof(arg.value.i); 2102287664Smav error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 2103287664Smav curthread); 2104278672Smav unmap = (error == 0) ? arg.value.i : 0; 2105278672Smav } 2106287499Smav value = ctl_get_opt(&cbe_lun->options, "unmap"); 2107278672Smav if (value != NULL) 2108278672Smav unmap = (strcmp(value, "on") == 0); 2109278672Smav if (unmap) 2110287499Smav cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 2111287499Smav else 2112287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 2113278672Smav 2114287664Smav dev_relthread(dev, ref); 2115229997Sken return (0); 2116229997Sken} 2117229997Sken 2118229997Skenstatic int 2119229997Skenctl_be_block_close(struct ctl_be_block_lun *be_lun) 2120229997Sken{ 2121287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2122287499Smav int flags; 2123287499Smav 2124229997Sken if (be_lun->vn) { 2125287499Smav flags = FREAD; 2126287499Smav if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0) 2127287499Smav flags |= FWRITE; 2128229997Sken (void)vn_close(be_lun->vn, flags, NOCRED, curthread); 2129229997Sken be_lun->vn = NULL; 2130229997Sken 2131229997Sken switch (be_lun->dev_type) { 2132229997Sken case CTL_BE_BLOCK_DEV: 2133229997Sken break; 2134229997Sken case CTL_BE_BLOCK_FILE: 2135229997Sken if (be_lun->backend.file.cred != NULL) { 2136229997Sken crfree(be_lun->backend.file.cred); 2137229997Sken be_lun->backend.file.cred = NULL; 2138229997Sken } 2139229997Sken break; 2140229997Sken case CTL_BE_BLOCK_NONE: 2141258871Strasz break; 2142229997Sken default: 2143229997Sken panic("Unexpected backend type."); 2144229997Sken break; 2145229997Sken } 2146272911Smav be_lun->dev_type = CTL_BE_BLOCK_NONE; 2147229997Sken } 2148229997Sken return (0); 2149229997Sken} 2150229997Sken 2151229997Skenstatic int 2152229997Skenctl_be_block_open(struct ctl_be_block_softc *softc, 2153287499Smav struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 2154229997Sken{ 2155287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2156229997Sken struct nameidata nd; 2157287499Smav char *value; 2158287499Smav int error, flags; 2159229997Sken 2160229997Sken error = 0; 2161229997Sken if (rootvnode == NULL) { 2162229997Sken snprintf(req->error_str, sizeof(req->error_str), 2163272911Smav "Root filesystem is not mounted"); 2164229997Sken return (1); 2165229997Sken } 2166285391Smjg pwd_ensure_dirs(); 2167229997Sken 2168287499Smav value = ctl_get_opt(&cbe_lun->options, "file"); 2169287499Smav if (value == NULL) { 2170287499Smav snprintf(req->error_str, sizeof(req->error_str), 2171287499Smav "no file argument specified"); 2172287499Smav return (1); 2173287499Smav } 2174287499Smav free(be_lun->dev_path, M_CTLBLK); 2175287499Smav be_lun->dev_path = strdup(value, M_CTLBLK); 2176287499Smav 2177287499Smav flags = FREAD; 2178287499Smav value = ctl_get_opt(&cbe_lun->options, "readonly"); 2179287499Smav if (value == NULL || strcmp(value, "on") != 0) 2180287499Smav flags |= FWRITE; 2181287499Smav 2182287499Smavagain: 2183229997Sken NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, be_lun->dev_path, curthread); 2184229997Sken error = vn_open(&nd, &flags, 0, NULL); 2185287499Smav if ((error == EROFS || error == EACCES) && (flags & FWRITE)) { 2186287499Smav flags &= ~FWRITE; 2187287499Smav goto again; 2188287499Smav } 2189229997Sken if (error) { 2190229997Sken /* 2191229997Sken * This is the only reasonable guess we can make as far as 2192229997Sken * path if the user doesn't give us a fully qualified path. 2193229997Sken * If they want to specify a file, they need to specify the 2194229997Sken * full path. 2195229997Sken */ 2196229997Sken if (be_lun->dev_path[0] != '/') { 2197229997Sken char *dev_name; 2198229997Sken 2199287499Smav asprintf(&dev_name, M_CTLBLK, "/dev/%s", 2200287499Smav be_lun->dev_path); 2201287499Smav free(be_lun->dev_path, M_CTLBLK); 2202287499Smav be_lun->dev_path = dev_name; 2203287499Smav goto again; 2204229997Sken } 2205229997Sken snprintf(req->error_str, sizeof(req->error_str), 2206272911Smav "error opening %s: %d", be_lun->dev_path, error); 2207229997Sken return (error); 2208229997Sken } 2209287499Smav if (flags & FWRITE) 2210287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_READONLY; 2211287499Smav else 2212287499Smav cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 2213229997Sken 2214229997Sken NDFREE(&nd, NDF_ONLY_PNBUF); 2215229997Sken be_lun->vn = nd.ni_vp; 2216229997Sken 2217229997Sken /* We only support disks and files. */ 2218229997Sken if (vn_isdisk(be_lun->vn, &error)) { 2219229997Sken error = ctl_be_block_open_dev(be_lun, req); 2220229997Sken } else if (be_lun->vn->v_type == VREG) { 2221229997Sken error = ctl_be_block_open_file(be_lun, req); 2222229997Sken } else { 2223229997Sken error = EINVAL; 2224229997Sken snprintf(req->error_str, sizeof(req->error_str), 2225258871Strasz "%s is not a disk or plain file", be_lun->dev_path); 2226229997Sken } 2227229997Sken VOP_UNLOCK(be_lun->vn, 0); 2228229997Sken 2229286811Smav if (error != 0) 2230229997Sken ctl_be_block_close(be_lun); 2231287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2232287499Smav if (be_lun->dispatch != ctl_be_block_dispatch_dev) 2233287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2234287499Smav value = ctl_get_opt(&cbe_lun->options, "serseq"); 2235287499Smav if (value != NULL && strcmp(value, "on") == 0) 2236287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 2237287499Smav else if (value != NULL && strcmp(value, "read") == 0) 2238287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2239287499Smav else if (value != NULL && strcmp(value, "off") == 0) 2240287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2241229997Sken return (0); 2242229997Sken} 2243229997Sken 2244229997Skenstatic int 2245229997Skenctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2246229997Sken{ 2247287499Smav struct ctl_be_lun *cbe_lun; 2248229997Sken struct ctl_be_block_lun *be_lun; 2249229997Sken struct ctl_lun_create_params *params; 2250267481Smav char num_thread_str[16]; 2251229997Sken char tmpstr[32]; 2252267481Smav char *value; 2253278672Smav int retval, num_threads; 2254267481Smav int tmp_num_threads; 2255229997Sken 2256229997Sken params = &req->reqdata.create; 2257229997Sken retval = 0; 2258272911Smav req->status = CTL_LUN_OK; 2259229997Sken 2260229997Sken be_lun = malloc(sizeof(*be_lun), M_CTLBLK, M_ZERO | M_WAITOK); 2261287499Smav cbe_lun = &be_lun->cbe_lun; 2262287499Smav cbe_lun->be_lun = be_lun; 2263272911Smav be_lun->params = req->reqdata.create; 2264229997Sken be_lun->softc = softc; 2265229997Sken STAILQ_INIT(&be_lun->input_queue); 2266275474Smav STAILQ_INIT(&be_lun->config_read_queue); 2267229997Sken STAILQ_INIT(&be_lun->config_write_queue); 2268229997Sken STAILQ_INIT(&be_lun->datamove_queue); 2269229997Sken sprintf(be_lun->lunname, "cblk%d", softc->num_luns); 2270267877Smav mtx_init(&be_lun->io_lock, "cblk io lock", NULL, MTX_DEF); 2271267877Smav mtx_init(&be_lun->queue_lock, "cblk queue lock", NULL, MTX_DEF); 2272287499Smav ctl_init_opts(&cbe_lun->options, 2273268280Smav req->num_be_args, req->kern_be_args); 2274264886Smav be_lun->lun_zone = uma_zcreate(be_lun->lunname, CTLBLK_MAX_SEG, 2275256995Smav NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); 2276229997Sken if (be_lun->lun_zone == NULL) { 2277229997Sken snprintf(req->error_str, sizeof(req->error_str), 2278272911Smav "error allocating UMA zone"); 2279229997Sken goto bailout_error; 2280229997Sken } 2281229997Sken 2282229997Sken if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 2283287499Smav cbe_lun->lun_type = params->device_type; 2284229997Sken else 2285287499Smav cbe_lun->lun_type = T_DIRECT; 2286287499Smav be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED; 2287287621Smav cbe_lun->flags = 0; 2288287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2289287621Smav if (value != NULL) { 2290287621Smav if (strcmp(value, "primary") == 0) 2291287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2292287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2293287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2294229997Sken 2295287499Smav if (cbe_lun->lun_type == T_DIRECT) { 2296286811Smav be_lun->size_bytes = params->lun_size_bytes; 2297286811Smav if (params->blocksize_bytes != 0) 2298287499Smav cbe_lun->blocksize = params->blocksize_bytes; 2299286811Smav else 2300287499Smav cbe_lun->blocksize = 512; 2301287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2302287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2303287499Smav 0 : (be_lun->size_blocks - 1); 2304229997Sken 2305287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2306287621Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2307287621Smav retval = ctl_be_block_open(softc, be_lun, req); 2308287621Smav if (retval != 0) { 2309287621Smav retval = 0; 2310287621Smav req->status = CTL_LUN_WARNING; 2311287621Smav } 2312229997Sken } 2313287499Smav num_threads = cbb_num_threads; 2314229997Sken } else { 2315229997Sken num_threads = 1; 2316229997Sken } 2317229997Sken 2318229997Sken /* 2319229997Sken * XXX This searching loop might be refactored to be combined with 2320229997Sken * the loop above, 2321229997Sken */ 2322287499Smav value = ctl_get_opt(&cbe_lun->options, "num_threads"); 2323267481Smav if (value != NULL) { 2324267481Smav tmp_num_threads = strtol(value, NULL, 0); 2325229997Sken 2326267481Smav /* 2327267481Smav * We don't let the user specify less than one 2328267481Smav * thread, but hope he's clueful enough not to 2329267481Smav * specify 1000 threads. 2330267481Smav */ 2331267481Smav if (tmp_num_threads < 1) { 2332267481Smav snprintf(req->error_str, sizeof(req->error_str), 2333272911Smav "invalid number of threads %s", 2334272911Smav num_thread_str); 2335267481Smav goto bailout_error; 2336229997Sken } 2337267481Smav num_threads = tmp_num_threads; 2338229997Sken } 2339229997Sken 2340272911Smav if (be_lun->vn == NULL) 2341287499Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2342229997Sken /* Tell the user the blocksize we ended up using */ 2343272911Smav params->lun_size_bytes = be_lun->size_bytes; 2344287499Smav params->blocksize_bytes = cbe_lun->blocksize; 2345229997Sken if (params->flags & CTL_LUN_FLAG_ID_REQ) { 2346287499Smav cbe_lun->req_lun_id = params->req_lun_id; 2347287499Smav cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 2348229997Sken } else 2349287499Smav cbe_lun->req_lun_id = 0; 2350229997Sken 2351287499Smav cbe_lun->lun_shutdown = ctl_be_block_lun_shutdown; 2352287499Smav cbe_lun->lun_config_status = ctl_be_block_lun_config_status; 2353287499Smav cbe_lun->be = &ctl_be_block_driver; 2354229997Sken 2355229997Sken if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 2356229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 2357229997Sken softc->num_luns); 2358287499Smav strncpy((char *)cbe_lun->serial_num, tmpstr, 2359287499Smav MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 2360229997Sken 2361229997Sken /* Tell the user what we used for a serial number */ 2362229997Sken strncpy((char *)params->serial_num, tmpstr, 2363275953Smav MIN(sizeof(params->serial_num), sizeof(tmpstr))); 2364229997Sken } else { 2365287499Smav strncpy((char *)cbe_lun->serial_num, params->serial_num, 2366287499Smav MIN(sizeof(cbe_lun->serial_num), 2367229997Sken sizeof(params->serial_num))); 2368229997Sken } 2369229997Sken if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 2370229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 2371287499Smav strncpy((char *)cbe_lun->device_id, tmpstr, 2372287499Smav MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 2373229997Sken 2374229997Sken /* Tell the user what we used for a device ID */ 2375229997Sken strncpy((char *)params->device_id, tmpstr, 2376275953Smav MIN(sizeof(params->device_id), sizeof(tmpstr))); 2377229997Sken } else { 2378287499Smav strncpy((char *)cbe_lun->device_id, params->device_id, 2379287499Smav MIN(sizeof(cbe_lun->device_id), 2380275953Smav sizeof(params->device_id))); 2381229997Sken } 2382229997Sken 2383229997Sken TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_be_block_worker, be_lun); 2384229997Sken 2385229997Sken be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 2386229997Sken taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 2387229997Sken 2388229997Sken if (be_lun->io_taskqueue == NULL) { 2389229997Sken snprintf(req->error_str, sizeof(req->error_str), 2390272911Smav "unable to create taskqueue"); 2391229997Sken goto bailout_error; 2392229997Sken } 2393229997Sken 2394229997Sken /* 2395229997Sken * Note that we start the same number of threads by default for 2396229997Sken * both the file case and the block device case. For the file 2397229997Sken * case, we need multiple threads to allow concurrency, because the 2398229997Sken * vnode interface is designed to be a blocking interface. For the 2399229997Sken * block device case, ZFS zvols at least will block the caller's 2400229997Sken * context in many instances, and so we need multiple threads to 2401229997Sken * overcome that problem. Other block devices don't need as many 2402229997Sken * threads, but they shouldn't cause too many problems. 2403229997Sken * 2404229997Sken * If the user wants to just have a single thread for a block 2405229997Sken * device, he can specify that when the LUN is created, or change 2406229997Sken * the tunable/sysctl to alter the default number of threads. 2407229997Sken */ 2408229997Sken retval = taskqueue_start_threads(&be_lun->io_taskqueue, 2409229997Sken /*num threads*/num_threads, 2410229997Sken /*priority*/PWAIT, 2411229997Sken /*thread name*/ 2412229997Sken "%s taskq", be_lun->lunname); 2413229997Sken 2414229997Sken if (retval != 0) 2415229997Sken goto bailout_error; 2416229997Sken 2417229997Sken be_lun->num_threads = num_threads; 2418229997Sken 2419229997Sken mtx_lock(&softc->lock); 2420229997Sken softc->num_luns++; 2421229997Sken STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 2422229997Sken 2423229997Sken mtx_unlock(&softc->lock); 2424229997Sken 2425287499Smav retval = ctl_add_lun(&be_lun->cbe_lun); 2426229997Sken if (retval != 0) { 2427229997Sken mtx_lock(&softc->lock); 2428229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2429229997Sken links); 2430229997Sken softc->num_luns--; 2431229997Sken mtx_unlock(&softc->lock); 2432229997Sken snprintf(req->error_str, sizeof(req->error_str), 2433272911Smav "ctl_add_lun() returned error %d, see dmesg for " 2434272911Smav "details", retval); 2435229997Sken retval = 0; 2436229997Sken goto bailout_error; 2437229997Sken } 2438229997Sken 2439229997Sken mtx_lock(&softc->lock); 2440229997Sken 2441229997Sken /* 2442229997Sken * Tell the config_status routine that we're waiting so it won't 2443229997Sken * clean up the LUN in the event of an error. 2444229997Sken */ 2445229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2446229997Sken 2447229997Sken while (be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) { 2448229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2449229997Sken if (retval == EINTR) 2450229997Sken break; 2451229997Sken } 2452229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2453229997Sken 2454229997Sken if (be_lun->flags & CTL_BE_BLOCK_LUN_CONFIG_ERR) { 2455229997Sken snprintf(req->error_str, sizeof(req->error_str), 2456272911Smav "LUN configuration error, see dmesg for details"); 2457229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2458229997Sken links); 2459229997Sken softc->num_luns--; 2460229997Sken mtx_unlock(&softc->lock); 2461229997Sken goto bailout_error; 2462229997Sken } else { 2463287499Smav params->req_lun_id = cbe_lun->lun_id; 2464229997Sken } 2465229997Sken 2466229997Sken mtx_unlock(&softc->lock); 2467229997Sken 2468229997Sken be_lun->disk_stats = devstat_new_entry("cbb", params->req_lun_id, 2469287499Smav cbe_lun->blocksize, 2470229997Sken DEVSTAT_ALL_SUPPORTED, 2471287499Smav cbe_lun->lun_type 2472229997Sken | DEVSTAT_TYPE_IF_OTHER, 2473229997Sken DEVSTAT_PRIORITY_OTHER); 2474229997Sken 2475229997Sken return (retval); 2476229997Sken 2477229997Skenbailout_error: 2478229997Sken req->status = CTL_LUN_ERROR; 2479229997Sken 2480267429Smav if (be_lun->io_taskqueue != NULL) 2481267429Smav taskqueue_free(be_lun->io_taskqueue); 2482229997Sken ctl_be_block_close(be_lun); 2483267429Smav if (be_lun->dev_path != NULL) 2484267429Smav free(be_lun->dev_path, M_CTLBLK); 2485267429Smav if (be_lun->lun_zone != NULL) 2486267429Smav uma_zdestroy(be_lun->lun_zone); 2487287499Smav ctl_free_opts(&cbe_lun->options); 2488267877Smav mtx_destroy(&be_lun->queue_lock); 2489267877Smav mtx_destroy(&be_lun->io_lock); 2490229997Sken free(be_lun, M_CTLBLK); 2491229997Sken 2492229997Sken return (retval); 2493229997Sken} 2494229997Sken 2495229997Skenstatic int 2496229997Skenctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2497229997Sken{ 2498229997Sken struct ctl_lun_rm_params *params; 2499229997Sken struct ctl_be_block_lun *be_lun; 2500287670Smav struct ctl_be_lun *cbe_lun; 2501229997Sken int retval; 2502229997Sken 2503229997Sken params = &req->reqdata.rm; 2504229997Sken 2505229997Sken mtx_lock(&softc->lock); 2506229997Sken STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2507287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2508229997Sken break; 2509229997Sken } 2510229997Sken mtx_unlock(&softc->lock); 2511229997Sken 2512229997Sken if (be_lun == NULL) { 2513229997Sken snprintf(req->error_str, sizeof(req->error_str), 2514272911Smav "LUN %u is not managed by the block backend", 2515272911Smav params->lun_id); 2516229997Sken goto bailout_error; 2517229997Sken } 2518287670Smav cbe_lun = &be_lun->cbe_lun; 2519229997Sken 2520287670Smav retval = ctl_disable_lun(cbe_lun); 2521229997Sken if (retval != 0) { 2522229997Sken snprintf(req->error_str, sizeof(req->error_str), 2523272911Smav "error %d returned from ctl_disable_lun() for " 2524272911Smav "LUN %d", retval, params->lun_id); 2525229997Sken goto bailout_error; 2526287670Smav } 2527229997Sken 2528287670Smav if (be_lun->vn != NULL) { 2529287670Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2530287670Smav ctl_lun_offline(cbe_lun); 2531287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2532287670Smav ctl_be_block_close(be_lun); 2533229997Sken } 2534229997Sken 2535287670Smav retval = ctl_invalidate_lun(cbe_lun); 2536229997Sken if (retval != 0) { 2537229997Sken snprintf(req->error_str, sizeof(req->error_str), 2538272911Smav "error %d returned from ctl_invalidate_lun() for " 2539272911Smav "LUN %d", retval, params->lun_id); 2540229997Sken goto bailout_error; 2541229997Sken } 2542229997Sken 2543229997Sken mtx_lock(&softc->lock); 2544229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2545229997Sken while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2546229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2547229997Sken if (retval == EINTR) 2548229997Sken break; 2549229997Sken } 2550229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2551229997Sken 2552229997Sken if ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2553229997Sken snprintf(req->error_str, sizeof(req->error_str), 2554272911Smav "interrupted waiting for LUN to be freed"); 2555229997Sken mtx_unlock(&softc->lock); 2556229997Sken goto bailout_error; 2557229997Sken } 2558229997Sken 2559229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, links); 2560229997Sken 2561229997Sken softc->num_luns--; 2562229997Sken mtx_unlock(&softc->lock); 2563229997Sken 2564287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2565229997Sken taskqueue_free(be_lun->io_taskqueue); 2566229997Sken 2567229997Sken if (be_lun->disk_stats != NULL) 2568229997Sken devstat_remove_entry(be_lun->disk_stats); 2569229997Sken 2570229997Sken uma_zdestroy(be_lun->lun_zone); 2571229997Sken 2572287670Smav ctl_free_opts(&cbe_lun->options); 2573229997Sken free(be_lun->dev_path, M_CTLBLK); 2574267877Smav mtx_destroy(&be_lun->queue_lock); 2575267877Smav mtx_destroy(&be_lun->io_lock); 2576229997Sken free(be_lun, M_CTLBLK); 2577229997Sken 2578229997Sken req->status = CTL_LUN_OK; 2579229997Sken 2580229997Sken return (0); 2581229997Sken 2582229997Skenbailout_error: 2583229997Sken 2584229997Sken req->status = CTL_LUN_ERROR; 2585229997Sken 2586229997Sken return (0); 2587229997Sken} 2588229997Sken 2589232604Straszstatic int 2590232604Straszctl_be_block_modify_file(struct ctl_be_block_lun *be_lun, 2591232604Strasz struct ctl_lun_req *req) 2592232604Strasz{ 2593287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2594232604Strasz struct vattr vattr; 2595232604Strasz int error; 2596272911Smav struct ctl_lun_create_params *params = &be_lun->params; 2597232604Strasz 2598232604Strasz if (params->lun_size_bytes != 0) { 2599232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2600232604Strasz } else { 2601271794Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 2602232604Strasz error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 2603271794Smav VOP_UNLOCK(be_lun->vn, 0); 2604232604Strasz if (error != 0) { 2605232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2606232604Strasz "error calling VOP_GETATTR() for file %s", 2607232604Strasz be_lun->dev_path); 2608232604Strasz return (error); 2609232604Strasz } 2610232604Strasz be_lun->size_bytes = vattr.va_size; 2611232604Strasz } 2612287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2613287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2614287499Smav 0 : (be_lun->size_blocks - 1); 2615232604Strasz return (0); 2616232604Strasz} 2617232604Strasz 2618232604Straszstatic int 2619232604Straszctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun, 2620232604Strasz struct ctl_lun_req *req) 2621232604Strasz{ 2622287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2623272911Smav struct ctl_lun_create_params *params = &be_lun->params; 2624287664Smav struct cdevsw *csw; 2625287664Smav struct cdev *dev; 2626232604Strasz uint64_t size_bytes; 2627287664Smav int error, ref; 2628232604Strasz 2629287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 2630287664Smav if (csw == NULL) 2631287664Smav return (ENXIO); 2632287664Smav if (csw->d_ioctl == NULL) { 2633287664Smav dev_relthread(dev, ref); 2634232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2635272911Smav "no d_ioctl for device %s!", be_lun->dev_path); 2636232604Strasz return (ENODEV); 2637232604Strasz } 2638232604Strasz 2639287664Smav error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&size_bytes, FREAD, 2640287664Smav curthread); 2641287664Smav dev_relthread(dev, ref); 2642232604Strasz if (error) { 2643232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2644272911Smav "error %d returned for DIOCGMEDIASIZE ioctl " 2645272911Smav "on %s!", error, be_lun->dev_path); 2646232604Strasz return (error); 2647232604Strasz } 2648232604Strasz 2649232604Strasz if (params->lun_size_bytes != 0) { 2650232604Strasz if (params->lun_size_bytes > size_bytes) { 2651232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2652272911Smav "requested LUN size %ju > backing device " 2653272911Smav "size %ju", 2654232604Strasz (uintmax_t)params->lun_size_bytes, 2655232604Strasz (uintmax_t)size_bytes); 2656232604Strasz return (EINVAL); 2657232604Strasz } 2658232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2659232604Strasz } else { 2660232604Strasz be_lun->size_bytes = size_bytes; 2661232604Strasz } 2662287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2663287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2664287499Smav 0 : (be_lun->size_blocks - 1); 2665232604Strasz return (0); 2666232604Strasz} 2667232604Strasz 2668232604Straszstatic int 2669232604Straszctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2670232604Strasz{ 2671232604Strasz struct ctl_lun_modify_params *params; 2672232604Strasz struct ctl_be_block_lun *be_lun; 2673287500Smav struct ctl_be_lun *cbe_lun; 2674287621Smav char *value; 2675271794Smav uint64_t oldsize; 2676287621Smav int error, wasprim; 2677232604Strasz 2678232604Strasz params = &req->reqdata.modify; 2679232604Strasz 2680232604Strasz mtx_lock(&softc->lock); 2681232604Strasz STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2682287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2683232604Strasz break; 2684232604Strasz } 2685232604Strasz mtx_unlock(&softc->lock); 2686232604Strasz 2687232604Strasz if (be_lun == NULL) { 2688232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2689272911Smav "LUN %u is not managed by the block backend", 2690272911Smav params->lun_id); 2691232604Strasz goto bailout_error; 2692232604Strasz } 2693287500Smav cbe_lun = &be_lun->cbe_lun; 2694232604Strasz 2695287500Smav if (params->lun_size_bytes != 0) 2696287500Smav be_lun->params.lun_size_bytes = params->lun_size_bytes; 2697287500Smav ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 2698232604Strasz 2699287621Smav wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 2700287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2701287621Smav if (value != NULL) { 2702287621Smav if (strcmp(value, "primary") == 0) 2703287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2704287621Smav else 2705287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2706287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2707287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2708232604Strasz else 2709287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2710287621Smav if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 2711287621Smav if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 2712287621Smav ctl_lun_primary(cbe_lun); 2713287621Smav else 2714287621Smav ctl_lun_secondary(cbe_lun); 2715287621Smav } 2716232604Strasz 2717287621Smav oldsize = be_lun->size_blocks; 2718287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2719287621Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2720287621Smav if (be_lun->vn == NULL) 2721287621Smav error = ctl_be_block_open(softc, be_lun, req); 2722287621Smav else if (vn_isdisk(be_lun->vn, &error)) 2723287621Smav error = ctl_be_block_modify_dev(be_lun, req); 2724287621Smav else if (be_lun->vn->v_type == VREG) 2725287621Smav error = ctl_be_block_modify_file(be_lun, req); 2726287621Smav else 2727287621Smav error = EINVAL; 2728287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) && 2729287621Smav be_lun->vn != NULL) { 2730287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE; 2731287621Smav ctl_lun_online(cbe_lun); 2732287621Smav } 2733287621Smav } else { 2734287621Smav if (be_lun->vn != NULL) { 2735287621Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2736287621Smav ctl_lun_offline(cbe_lun); 2737287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2738287621Smav error = ctl_be_block_close(be_lun); 2739287621Smav } else 2740287621Smav error = 0; 2741287621Smav } 2742287499Smav if (be_lun->size_blocks != oldsize) 2743287500Smav ctl_lun_capacity_changed(cbe_lun); 2744232604Strasz 2745232604Strasz /* Tell the user the exact size we ended up using */ 2746232604Strasz params->lun_size_bytes = be_lun->size_bytes; 2747232604Strasz 2748272911Smav req->status = error ? CTL_LUN_WARNING : CTL_LUN_OK; 2749232604Strasz return (0); 2750232604Strasz 2751232604Straszbailout_error: 2752232604Strasz req->status = CTL_LUN_ERROR; 2753232604Strasz return (0); 2754232604Strasz} 2755232604Strasz 2756229997Skenstatic void 2757229997Skenctl_be_block_lun_shutdown(void *be_lun) 2758229997Sken{ 2759229997Sken struct ctl_be_block_lun *lun; 2760229997Sken struct ctl_be_block_softc *softc; 2761229997Sken 2762229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2763229997Sken 2764229997Sken softc = lun->softc; 2765229997Sken 2766229997Sken mtx_lock(&softc->lock); 2767229997Sken lun->flags |= CTL_BE_BLOCK_LUN_UNCONFIGURED; 2768229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2769229997Sken wakeup(lun); 2770229997Sken mtx_unlock(&softc->lock); 2771229997Sken 2772229997Sken} 2773229997Sken 2774229997Skenstatic void 2775229997Skenctl_be_block_lun_config_status(void *be_lun, ctl_lun_config_status status) 2776229997Sken{ 2777229997Sken struct ctl_be_block_lun *lun; 2778229997Sken struct ctl_be_block_softc *softc; 2779229997Sken 2780229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2781229997Sken softc = lun->softc; 2782229997Sken 2783229997Sken if (status == CTL_LUN_CONFIG_OK) { 2784229997Sken mtx_lock(&softc->lock); 2785229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2786229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2787229997Sken wakeup(lun); 2788229997Sken mtx_unlock(&softc->lock); 2789229997Sken 2790229997Sken /* 2791229997Sken * We successfully added the LUN, attempt to enable it. 2792229997Sken */ 2793287499Smav if (ctl_enable_lun(&lun->cbe_lun) != 0) { 2794229997Sken printf("%s: ctl_enable_lun() failed!\n", __func__); 2795287499Smav if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 2796229997Sken printf("%s: ctl_invalidate_lun() failed!\n", 2797229997Sken __func__); 2798229997Sken } 2799229997Sken } 2800229997Sken 2801229997Sken return; 2802229997Sken } 2803229997Sken 2804229997Sken 2805229997Sken mtx_lock(&softc->lock); 2806229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2807229997Sken lun->flags |= CTL_BE_BLOCK_LUN_CONFIG_ERR; 2808229997Sken wakeup(lun); 2809229997Sken mtx_unlock(&softc->lock); 2810229997Sken} 2811229997Sken 2812229997Sken 2813229997Skenstatic int 2814229997Skenctl_be_block_config_write(union ctl_io *io) 2815229997Sken{ 2816229997Sken struct ctl_be_block_lun *be_lun; 2817287499Smav struct ctl_be_lun *cbe_lun; 2818229997Sken int retval; 2819229997Sken 2820229997Sken retval = 0; 2821229997Sken 2822229997Sken DPRINTF("entered\n"); 2823229997Sken 2824287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2825229997Sken CTL_PRIV_BACKEND_LUN].ptr; 2826287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2827229997Sken 2828229997Sken switch (io->scsiio.cdb[0]) { 2829229997Sken case SYNCHRONIZE_CACHE: 2830229997Sken case SYNCHRONIZE_CACHE_16: 2831264274Smav case WRITE_SAME_10: 2832264274Smav case WRITE_SAME_16: 2833264274Smav case UNMAP: 2834229997Sken /* 2835229997Sken * The upper level CTL code will filter out any CDBs with 2836229997Sken * the immediate bit set and return the proper error. 2837229997Sken * 2838229997Sken * We don't really need to worry about what LBA range the 2839229997Sken * user asked to be synced out. When they issue a sync 2840229997Sken * cache command, we'll sync out the whole thing. 2841229997Sken */ 2842267877Smav mtx_lock(&be_lun->queue_lock); 2843229997Sken STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->io_hdr, 2844229997Sken links); 2845267877Smav mtx_unlock(&be_lun->queue_lock); 2846229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 2847229997Sken break; 2848229997Sken case START_STOP_UNIT: { 2849229997Sken struct scsi_start_stop_unit *cdb; 2850229997Sken 2851229997Sken cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 2852229997Sken 2853229997Sken if (cdb->how & SSS_START) 2854287499Smav retval = ctl_start_lun(cbe_lun); 2855229997Sken else { 2856287499Smav retval = ctl_stop_lun(cbe_lun); 2857229997Sken /* 2858229997Sken * XXX KDM Copan-specific offline behavior. 2859229997Sken * Figure out a reasonable way to port this? 2860229997Sken */ 2861229997Sken#ifdef NEEDTOPORT 2862229997Sken if ((retval == 0) 2863229997Sken && (cdb->byte2 & SSS_ONOFFLINE)) 2864287499Smav retval = ctl_lun_offline(cbe_lun); 2865229997Sken#endif 2866229997Sken } 2867229997Sken 2868229997Sken /* 2869229997Sken * In general, the above routines should not fail. They 2870229997Sken * just set state for the LUN. So we've got something 2871229997Sken * pretty wrong here if we can't start or stop the LUN. 2872229997Sken */ 2873229997Sken if (retval != 0) { 2874229997Sken ctl_set_internal_failure(&io->scsiio, 2875229997Sken /*sks_valid*/ 1, 2876229997Sken /*retry_count*/ 0xf051); 2877229997Sken retval = CTL_RETVAL_COMPLETE; 2878229997Sken } else { 2879229997Sken ctl_set_success(&io->scsiio); 2880229997Sken } 2881229997Sken ctl_config_write_done(io); 2882229997Sken break; 2883229997Sken } 2884229997Sken default: 2885229997Sken ctl_set_invalid_opcode(&io->scsiio); 2886229997Sken ctl_config_write_done(io); 2887229997Sken retval = CTL_RETVAL_COMPLETE; 2888229997Sken break; 2889229997Sken } 2890229997Sken 2891229997Sken return (retval); 2892229997Sken} 2893229997Sken 2894229997Skenstatic int 2895229997Skenctl_be_block_config_read(union ctl_io *io) 2896229997Sken{ 2897275474Smav struct ctl_be_block_lun *be_lun; 2898287499Smav struct ctl_be_lun *cbe_lun; 2899275474Smav int retval = 0; 2900275474Smav 2901275474Smav DPRINTF("entered\n"); 2902275474Smav 2903287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2904275474Smav CTL_PRIV_BACKEND_LUN].ptr; 2905287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2906275474Smav 2907275474Smav switch (io->scsiio.cdb[0]) { 2908275474Smav case SERVICE_ACTION_IN: 2909275474Smav if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 2910275474Smav mtx_lock(&be_lun->queue_lock); 2911275474Smav STAILQ_INSERT_TAIL(&be_lun->config_read_queue, 2912275474Smav &io->io_hdr, links); 2913275474Smav mtx_unlock(&be_lun->queue_lock); 2914275474Smav taskqueue_enqueue(be_lun->io_taskqueue, 2915275474Smav &be_lun->io_task); 2916275474Smav retval = CTL_RETVAL_QUEUED; 2917275474Smav break; 2918275474Smav } 2919275474Smav ctl_set_invalid_field(&io->scsiio, 2920275474Smav /*sks_valid*/ 1, 2921275474Smav /*command*/ 1, 2922275474Smav /*field*/ 1, 2923275474Smav /*bit_valid*/ 1, 2924275474Smav /*bit*/ 4); 2925275474Smav ctl_config_read_done(io); 2926275474Smav retval = CTL_RETVAL_COMPLETE; 2927275474Smav break; 2928275474Smav default: 2929275474Smav ctl_set_invalid_opcode(&io->scsiio); 2930275474Smav ctl_config_read_done(io); 2931275474Smav retval = CTL_RETVAL_COMPLETE; 2932275474Smav break; 2933275474Smav } 2934275474Smav 2935275474Smav return (retval); 2936229997Sken} 2937229997Sken 2938229997Skenstatic int 2939229997Skenctl_be_block_lun_info(void *be_lun, struct sbuf *sb) 2940229997Sken{ 2941229997Sken struct ctl_be_block_lun *lun; 2942229997Sken int retval; 2943229997Sken 2944229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2945229997Sken retval = 0; 2946229997Sken 2947268283Smav retval = sbuf_printf(sb, "\t<num_threads>"); 2948229997Sken 2949229997Sken if (retval != 0) 2950229997Sken goto bailout; 2951229997Sken 2952229997Sken retval = sbuf_printf(sb, "%d", lun->num_threads); 2953229997Sken 2954229997Sken if (retval != 0) 2955229997Sken goto bailout; 2956229997Sken 2957268283Smav retval = sbuf_printf(sb, "</num_threads>\n"); 2958229997Sken 2959229997Skenbailout: 2960229997Sken 2961229997Sken return (retval); 2962229997Sken} 2963229997Sken 2964274154Smavstatic uint64_t 2965274154Smavctl_be_block_lun_attr(void *be_lun, const char *attrname) 2966274154Smav{ 2967274154Smav struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)be_lun; 2968274154Smav 2969274154Smav if (lun->getattr == NULL) 2970274154Smav return (UINT64_MAX); 2971274154Smav return (lun->getattr(lun, attrname)); 2972274154Smav} 2973274154Smav 2974229997Skenint 2975229997Skenctl_be_block_init(void) 2976229997Sken{ 2977229997Sken struct ctl_be_block_softc *softc; 2978229997Sken int retval; 2979229997Sken 2980229997Sken softc = &backend_block_softc; 2981229997Sken retval = 0; 2982229997Sken 2983267877Smav mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF); 2984264020Strasz beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io), 2985264020Strasz NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 2986229997Sken STAILQ_INIT(&softc->lun_list); 2987229997Sken 2988229997Sken return (retval); 2989229997Sken} 2990