ctl_backend_block.c revision 287868
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 287868 2015-09-16 18:33:04Z 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); 545229997Sken } else 546229997Sken ctl_set_medium_error(&io->scsiio); 547229997Sken ctl_complete_beio(beio); 548229997Sken return; 549229997Sken } 550229997Sken 551229997Sken /* 552267537Smav * If this is a write, a flush, a delete or verify, we're all done. 553229997Sken * If this is a read, we can now send the data to the user. 554229997Sken */ 555229997Sken if ((beio->bio_cmd == BIO_WRITE) 556264274Smav || (beio->bio_cmd == BIO_FLUSH) 557267537Smav || (beio->bio_cmd == BIO_DELETE) 558267537Smav || (ARGS(io)->flags & CTL_LLF_VERIFY)) { 559229997Sken ctl_set_success(&io->scsiio); 560229997Sken ctl_complete_beio(beio); 561229997Sken } else { 562275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 563275058Smav beio->beio_cont == NULL) 564275058Smav ctl_set_success(&io->scsiio); 565229997Sken#ifdef CTL_TIME_IO 566229997Sken getbintime(&io->io_hdr.dma_start_bt); 567229997Sken#endif 568229997Sken ctl_datamove(io); 569229997Sken } 570229997Sken} 571229997Sken 572229997Skenstatic void 573229997Skenctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 574229997Sken struct ctl_be_block_io *beio) 575229997Sken{ 576267877Smav union ctl_io *io = beio->io; 577229997Sken struct mount *mountpoint; 578241896Skib int error, lock_flags; 579229997Sken 580229997Sken DPRINTF("entered\n"); 581229997Sken 582267877Smav binuptime(&beio->ds_t0); 583267877Smav mtx_lock(&be_lun->io_lock); 584267877Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 585267877Smav mtx_unlock(&be_lun->io_lock); 586229997Sken 587267877Smav (void) vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 588229997Sken 589229997Sken if (MNT_SHARED_WRITES(mountpoint) 590229997Sken || ((mountpoint == NULL) 591229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 592229997Sken lock_flags = LK_SHARED; 593229997Sken else 594229997Sken lock_flags = LK_EXCLUSIVE; 595229997Sken 596229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 597229997Sken 598286353Smav error = VOP_FSYNC(be_lun->vn, beio->io_arg ? MNT_NOWAIT : MNT_WAIT, 599286353Smav curthread); 600229997Sken VOP_UNLOCK(be_lun->vn, 0); 601229997Sken 602229997Sken vn_finished_write(mountpoint); 603229997Sken 604267877Smav mtx_lock(&be_lun->io_lock); 605267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 606267877Smav beio->ds_tag_type, beio->ds_trans_type, 607267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 608267877Smav mtx_unlock(&be_lun->io_lock); 609267877Smav 610229997Sken if (error == 0) 611229997Sken ctl_set_success(&io->scsiio); 612229997Sken else { 613229997Sken /* XXX KDM is there is a better error here? */ 614229997Sken ctl_set_internal_failure(&io->scsiio, 615229997Sken /*sks_valid*/ 1, 616229997Sken /*retry_count*/ 0xbad1); 617229997Sken } 618229997Sken 619229997Sken ctl_complete_beio(beio); 620229997Sken} 621229997Sken 622258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_start, "uint64_t"); 623258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_start, "uint64_t"); 624258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_done,"uint64_t"); 625258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_done, "uint64_t"); 626229997Sken 627229997Skenstatic void 628229997Skenctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 629229997Sken struct ctl_be_block_io *beio) 630229997Sken{ 631229997Sken struct ctl_be_block_filedata *file_data; 632229997Sken union ctl_io *io; 633229997Sken struct uio xuio; 634229997Sken struct iovec *xiovec; 635241896Skib int flags; 636229997Sken int error, i; 637229997Sken 638229997Sken DPRINTF("entered\n"); 639229997Sken 640229997Sken file_data = &be_lun->backend.file; 641229997Sken io = beio->io; 642271309Smav flags = 0; 643271309Smav if (ARGS(io)->flags & CTL_LLF_DPO) 644271309Smav flags |= IO_DIRECT; 645271309Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 646271309Smav flags |= IO_SYNC; 647229997Sken 648267537Smav bzero(&xuio, sizeof(xuio)); 649229997Sken if (beio->bio_cmd == BIO_READ) { 650229997Sken SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 651267537Smav xuio.uio_rw = UIO_READ; 652229997Sken } else { 653229997Sken SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 654267537Smav xuio.uio_rw = UIO_WRITE; 655229997Sken } 656229997Sken xuio.uio_offset = beio->io_offset; 657229997Sken xuio.uio_resid = beio->io_len; 658229997Sken xuio.uio_segflg = UIO_SYSSPACE; 659229997Sken xuio.uio_iov = beio->xiovecs; 660229997Sken xuio.uio_iovcnt = beio->num_segs; 661229997Sken xuio.uio_td = curthread; 662229997Sken 663229997Sken for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 664229997Sken xiovec->iov_base = beio->sg_segs[i].addr; 665229997Sken xiovec->iov_len = beio->sg_segs[i].len; 666229997Sken } 667229997Sken 668267877Smav binuptime(&beio->ds_t0); 669267877Smav mtx_lock(&be_lun->io_lock); 670267877Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 671267877Smav mtx_unlock(&be_lun->io_lock); 672267877Smav 673229997Sken if (beio->bio_cmd == BIO_READ) { 674229997Sken vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 675229997Sken 676229997Sken /* 677229997Sken * UFS pays attention to IO_DIRECT for reads. If the 678229997Sken * DIRECTIO option is configured into the kernel, it calls 679229997Sken * ffs_rawread(). But that only works for single-segment 680229997Sken * uios with user space addresses. In our case, with a 681229997Sken * kernel uio, it still reads into the buffer cache, but it 682229997Sken * will just try to release the buffer from the cache later 683229997Sken * on in ffs_read(). 684229997Sken * 685229997Sken * ZFS does not pay attention to IO_DIRECT for reads. 686229997Sken * 687229997Sken * UFS does not pay attention to IO_SYNC for reads. 688229997Sken * 689229997Sken * ZFS pays attention to IO_SYNC (which translates into the 690229997Sken * Solaris define FRSYNC for zfs_read()) for reads. It 691229997Sken * attempts to sync the file before reading. 692229997Sken */ 693271309Smav error = VOP_READ(be_lun->vn, &xuio, flags, file_data->cred); 694229997Sken 695229997Sken VOP_UNLOCK(be_lun->vn, 0); 696267537Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 697229997Sken } else { 698229997Sken struct mount *mountpoint; 699229997Sken int lock_flags; 700229997Sken 701229997Sken (void)vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 702229997Sken 703229997Sken if (MNT_SHARED_WRITES(mountpoint) 704229997Sken || ((mountpoint == NULL) 705229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 706229997Sken lock_flags = LK_SHARED; 707229997Sken else 708229997Sken lock_flags = LK_EXCLUSIVE; 709229997Sken 710229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 711229997Sken 712229997Sken /* 713229997Sken * UFS pays attention to IO_DIRECT for writes. The write 714229997Sken * is done asynchronously. (Normally the write would just 715229997Sken * get put into cache. 716229997Sken * 717229997Sken * UFS pays attention to IO_SYNC for writes. It will 718229997Sken * attempt to write the buffer out synchronously if that 719229997Sken * flag is set. 720229997Sken * 721229997Sken * ZFS does not pay attention to IO_DIRECT for writes. 722229997Sken * 723229997Sken * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC) 724229997Sken * for writes. It will flush the transaction from the 725229997Sken * cache before returning. 726229997Sken */ 727271309Smav error = VOP_WRITE(be_lun->vn, &xuio, flags, file_data->cred); 728229997Sken VOP_UNLOCK(be_lun->vn, 0); 729229997Sken 730229997Sken vn_finished_write(mountpoint); 731267537Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 732229997Sken } 733229997Sken 734267877Smav mtx_lock(&be_lun->io_lock); 735267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 736267877Smav beio->ds_tag_type, beio->ds_trans_type, 737267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 738267877Smav mtx_unlock(&be_lun->io_lock); 739267877Smav 740229997Sken /* 741229997Sken * If we got an error, set the sense data to "MEDIUM ERROR" and 742229997Sken * return the I/O to the user. 743229997Sken */ 744229997Sken if (error != 0) { 745229997Sken char path_str[32]; 746229997Sken 747229997Sken ctl_scsi_path_string(io, path_str, sizeof(path_str)); 748229997Sken printf("%s%s command returned errno %d\n", path_str, 749229997Sken (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", error); 750282565Smav if (error == ENOSPC || error == EDQUOT) { 751273809Smav ctl_set_space_alloc_fail(&io->scsiio); 752287760Smav } else if (error == EROFS || error == EACCES) { 753287760Smav ctl_set_hw_write_protected(&io->scsiio); 754273809Smav } else 755273809Smav ctl_set_medium_error(&io->scsiio); 756229997Sken ctl_complete_beio(beio); 757229997Sken return; 758229997Sken } 759229997Sken 760229997Sken /* 761269122Smav * If this is a write or a verify, we're all done. 762229997Sken * If this is a read, we can now send the data to the user. 763229997Sken */ 764269122Smav if ((beio->bio_cmd == BIO_WRITE) || 765269122Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 766229997Sken ctl_set_success(&io->scsiio); 767229997Sken ctl_complete_beio(beio); 768229997Sken } else { 769275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 770275058Smav beio->beio_cont == NULL) 771275058Smav ctl_set_success(&io->scsiio); 772229997Sken#ifdef CTL_TIME_IO 773229997Sken getbintime(&io->io_hdr.dma_start_bt); 774229997Sken#endif 775229997Sken ctl_datamove(io); 776229997Sken } 777229997Sken} 778229997Sken 779229997Skenstatic void 780275474Smavctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 781275474Smav struct ctl_be_block_io *beio) 782275474Smav{ 783275474Smav union ctl_io *io = beio->io; 784275474Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 785275474Smav struct scsi_get_lba_status_data *data; 786275474Smav off_t roff, off; 787275474Smav int error, status; 788275474Smav 789275474Smav DPRINTF("entered\n"); 790275474Smav 791287499Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 792275474Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 793275474Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off, 794275474Smav 0, curthread->td_ucred, curthread); 795275474Smav if (error == 0 && off > roff) 796275474Smav status = 0; /* mapped up to off */ 797275474Smav else { 798275474Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off, 799275474Smav 0, curthread->td_ucred, curthread); 800275474Smav if (error == 0 && off > roff) 801275474Smav status = 1; /* deallocated up to off */ 802275474Smav else { 803275474Smav status = 0; /* unknown up to the end */ 804275474Smav off = be_lun->size_bytes; 805275474Smav } 806275474Smav } 807275474Smav VOP_UNLOCK(be_lun->vn, 0); 808275474Smav 809275474Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 810275474Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 811287499Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 812287499Smav lbalen->lba), data->descr[0].length); 813275474Smav data->descr[0].status = status; 814275474Smav 815275474Smav ctl_complete_beio(beio); 816275474Smav} 817275474Smav 818275481Smavstatic uint64_t 819275481Smavctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, const char *attrname) 820275481Smav{ 821275481Smav struct vattr vattr; 822275481Smav struct statfs statfs; 823285030Smav uint64_t val; 824275481Smav int error; 825275481Smav 826285030Smav val = UINT64_MAX; 827275481Smav if (be_lun->vn == NULL) 828285030Smav return (val); 829285030Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 830275481Smav if (strcmp(attrname, "blocksused") == 0) { 831275481Smav error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 832285030Smav if (error == 0) 833287499Smav val = vattr.va_bytes / be_lun->cbe_lun.blocksize; 834275481Smav } 835285030Smav if (strcmp(attrname, "blocksavail") == 0 && 836285030Smav (be_lun->vn->v_iflag & VI_DOOMED) == 0) { 837275481Smav error = VFS_STATFS(be_lun->vn->v_mount, &statfs); 838285030Smav if (error == 0) 839286811Smav val = statfs.f_bavail * statfs.f_bsize / 840287499Smav be_lun->cbe_lun.blocksize; 841275481Smav } 842285030Smav VOP_UNLOCK(be_lun->vn, 0); 843285030Smav return (val); 844275481Smav} 845275481Smav 846275474Smavstatic void 847269123Smavctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, 848269123Smav struct ctl_be_block_io *beio) 849269123Smav{ 850269123Smav union ctl_io *io; 851287664Smav struct cdevsw *csw; 852287664Smav struct cdev *dev; 853269123Smav struct uio xuio; 854269123Smav struct iovec *xiovec; 855287664Smav int error, flags, i, ref; 856269123Smav 857269123Smav DPRINTF("entered\n"); 858269123Smav 859269123Smav io = beio->io; 860271309Smav flags = 0; 861271309Smav if (ARGS(io)->flags & CTL_LLF_DPO) 862271309Smav flags |= IO_DIRECT; 863271309Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 864271309Smav flags |= IO_SYNC; 865269123Smav 866269123Smav bzero(&xuio, sizeof(xuio)); 867269123Smav if (beio->bio_cmd == BIO_READ) { 868269123Smav SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 869269123Smav xuio.uio_rw = UIO_READ; 870269123Smav } else { 871269123Smav SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 872269123Smav xuio.uio_rw = UIO_WRITE; 873269123Smav } 874269123Smav xuio.uio_offset = beio->io_offset; 875269123Smav xuio.uio_resid = beio->io_len; 876269123Smav xuio.uio_segflg = UIO_SYSSPACE; 877269123Smav xuio.uio_iov = beio->xiovecs; 878269123Smav xuio.uio_iovcnt = beio->num_segs; 879269123Smav xuio.uio_td = curthread; 880269123Smav 881269123Smav for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 882269123Smav xiovec->iov_base = beio->sg_segs[i].addr; 883269123Smav xiovec->iov_len = beio->sg_segs[i].len; 884269123Smav } 885269123Smav 886269123Smav binuptime(&beio->ds_t0); 887269123Smav mtx_lock(&be_lun->io_lock); 888269123Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 889269123Smav mtx_unlock(&be_lun->io_lock); 890269123Smav 891287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 892287664Smav if (csw) { 893287664Smav if (beio->bio_cmd == BIO_READ) 894287664Smav error = csw->d_read(dev, &xuio, flags); 895287664Smav else 896287664Smav error = csw->d_write(dev, &xuio, flags); 897287664Smav dev_relthread(dev, ref); 898287664Smav } else 899287664Smav error = ENXIO; 900287664Smav 901287664Smav if (beio->bio_cmd == BIO_READ) 902269123Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 903287664Smav else 904269123Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 905269123Smav 906269123Smav mtx_lock(&be_lun->io_lock); 907269123Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 908269123Smav beio->ds_tag_type, beio->ds_trans_type, 909269123Smav /*now*/ NULL, /*then*/&beio->ds_t0); 910269123Smav mtx_unlock(&be_lun->io_lock); 911269123Smav 912269123Smav /* 913269123Smav * If we got an error, set the sense data to "MEDIUM ERROR" and 914269123Smav * return the I/O to the user. 915269123Smav */ 916269123Smav if (error != 0) { 917282565Smav if (error == ENOSPC || error == EDQUOT) { 918273809Smav ctl_set_space_alloc_fail(&io->scsiio); 919287760Smav } else if (error == EROFS || error == EACCES) { 920287760Smav ctl_set_hw_write_protected(&io->scsiio); 921273809Smav } else 922273809Smav ctl_set_medium_error(&io->scsiio); 923269123Smav ctl_complete_beio(beio); 924269123Smav return; 925269123Smav } 926269123Smav 927269123Smav /* 928269123Smav * If this is a write or a verify, we're all done. 929269123Smav * If this is a read, we can now send the data to the user. 930269123Smav */ 931269123Smav if ((beio->bio_cmd == BIO_WRITE) || 932269123Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 933269123Smav ctl_set_success(&io->scsiio); 934269123Smav ctl_complete_beio(beio); 935269123Smav } else { 936275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 937275058Smav beio->beio_cont == NULL) 938275058Smav ctl_set_success(&io->scsiio); 939269123Smav#ifdef CTL_TIME_IO 940269123Smav getbintime(&io->io_hdr.dma_start_bt); 941269123Smav#endif 942269123Smav ctl_datamove(io); 943269123Smav } 944269123Smav} 945269123Smav 946269123Smavstatic void 947275474Smavctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, 948275474Smav struct ctl_be_block_io *beio) 949275474Smav{ 950275474Smav union ctl_io *io = beio->io; 951287664Smav struct cdevsw *csw; 952287664Smav struct cdev *dev; 953275474Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 954275474Smav struct scsi_get_lba_status_data *data; 955275474Smav off_t roff, off; 956287664Smav int error, ref, status; 957275474Smav 958275474Smav DPRINTF("entered\n"); 959275474Smav 960287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 961287664Smav if (csw == NULL) { 962287664Smav status = 0; /* unknown up to the end */ 963287664Smav off = be_lun->size_bytes; 964287664Smav goto done; 965287664Smav } 966287499Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 967287664Smav error = csw->d_ioctl(dev, FIOSEEKHOLE, (caddr_t)&off, FREAD, 968287664Smav curthread); 969275474Smav if (error == 0 && off > roff) 970275474Smav status = 0; /* mapped up to off */ 971275474Smav else { 972287664Smav error = csw->d_ioctl(dev, FIOSEEKDATA, (caddr_t)&off, FREAD, 973287664Smav curthread); 974275474Smav if (error == 0 && off > roff) 975275474Smav status = 1; /* deallocated up to off */ 976275474Smav else { 977275474Smav status = 0; /* unknown up to the end */ 978275474Smav off = be_lun->size_bytes; 979275474Smav } 980275474Smav } 981287664Smav dev_relthread(dev, ref); 982275474Smav 983287664Smavdone: 984275474Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 985275474Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 986287499Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 987287499Smav lbalen->lba), data->descr[0].length); 988275474Smav data->descr[0].status = status; 989275474Smav 990275474Smav ctl_complete_beio(beio); 991275474Smav} 992275474Smav 993275474Smavstatic void 994229997Skenctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 995229997Sken struct ctl_be_block_io *beio) 996229997Sken{ 997229997Sken struct bio *bio; 998229997Sken union ctl_io *io; 999287664Smav struct cdevsw *csw; 1000287664Smav struct cdev *dev; 1001287664Smav int ref; 1002229997Sken 1003229997Sken io = beio->io; 1004229997Sken 1005229997Sken DPRINTF("entered\n"); 1006229997Sken 1007229997Sken /* This can't fail, it's a blocking allocation. */ 1008229997Sken bio = g_alloc_bio(); 1009229997Sken 1010229997Sken bio->bio_cmd = BIO_FLUSH; 1011229997Sken bio->bio_offset = 0; 1012229997Sken bio->bio_data = 0; 1013229997Sken bio->bio_done = ctl_be_block_biodone; 1014229997Sken bio->bio_caller1 = beio; 1015229997Sken bio->bio_pblkno = 0; 1016229997Sken 1017229997Sken /* 1018229997Sken * We don't need to acquire the LUN lock here, because we are only 1019229997Sken * sending one bio, and so there is no other context to synchronize 1020229997Sken * with. 1021229997Sken */ 1022229997Sken beio->num_bios_sent = 1; 1023229997Sken beio->send_complete = 1; 1024229997Sken 1025229997Sken binuptime(&beio->ds_t0); 1026267877Smav mtx_lock(&be_lun->io_lock); 1027229997Sken devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1028267877Smav mtx_unlock(&be_lun->io_lock); 1029229997Sken 1030287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1031287664Smav if (csw) { 1032287664Smav bio->bio_dev = dev; 1033287664Smav csw->d_strategy(bio); 1034287664Smav dev_relthread(dev, ref); 1035287664Smav } else { 1036287664Smav bio->bio_error = ENXIO; 1037287664Smav ctl_be_block_biodone(bio); 1038287664Smav } 1039229997Sken} 1040229997Sken 1041229997Skenstatic void 1042264274Smavctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, 1043264274Smav struct ctl_be_block_io *beio, 1044264274Smav uint64_t off, uint64_t len, int last) 1045264274Smav{ 1046264274Smav struct bio *bio; 1047264296Smav uint64_t maxlen; 1048287664Smav struct cdevsw *csw; 1049287664Smav struct cdev *dev; 1050287664Smav int ref; 1051264274Smav 1052287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1053287499Smav maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize); 1054264274Smav while (len > 0) { 1055264274Smav bio = g_alloc_bio(); 1056264274Smav bio->bio_cmd = BIO_DELETE; 1057287664Smav bio->bio_dev = dev; 1058264274Smav bio->bio_offset = off; 1059264296Smav bio->bio_length = MIN(len, maxlen); 1060264274Smav bio->bio_data = 0; 1061264274Smav bio->bio_done = ctl_be_block_biodone; 1062264274Smav bio->bio_caller1 = beio; 1063287499Smav bio->bio_pblkno = off / be_lun->cbe_lun.blocksize; 1064264274Smav 1065264274Smav off += bio->bio_length; 1066264274Smav len -= bio->bio_length; 1067264274Smav 1068267877Smav mtx_lock(&be_lun->io_lock); 1069264274Smav beio->num_bios_sent++; 1070264274Smav if (last && len == 0) 1071264274Smav beio->send_complete = 1; 1072267877Smav mtx_unlock(&be_lun->io_lock); 1073264274Smav 1074287664Smav if (csw) { 1075287664Smav csw->d_strategy(bio); 1076287664Smav } else { 1077287664Smav bio->bio_error = ENXIO; 1078287664Smav ctl_be_block_biodone(bio); 1079287664Smav } 1080264274Smav } 1081287664Smav if (csw) 1082287664Smav dev_relthread(dev, ref); 1083264274Smav} 1084264274Smav 1085264274Smavstatic void 1086264274Smavctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 1087264274Smav struct ctl_be_block_io *beio) 1088264274Smav{ 1089264274Smav union ctl_io *io; 1090267515Smav struct ctl_ptr_len_flags *ptrlen; 1091264274Smav struct scsi_unmap_desc *buf, *end; 1092264274Smav uint64_t len; 1093264274Smav 1094264274Smav io = beio->io; 1095264274Smav 1096264274Smav DPRINTF("entered\n"); 1097264274Smav 1098264274Smav binuptime(&beio->ds_t0); 1099267877Smav mtx_lock(&be_lun->io_lock); 1100264274Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1101267877Smav mtx_unlock(&be_lun->io_lock); 1102264274Smav 1103264274Smav if (beio->io_offset == -1) { 1104264274Smav beio->io_len = 0; 1105267515Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1106267515Smav buf = (struct scsi_unmap_desc *)ptrlen->ptr; 1107267515Smav end = buf + ptrlen->len / sizeof(*buf); 1108264274Smav for (; buf < end; buf++) { 1109264274Smav len = (uint64_t)scsi_4btoul(buf->length) * 1110287499Smav be_lun->cbe_lun.blocksize; 1111264274Smav beio->io_len += len; 1112264274Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1113287499Smav scsi_8btou64(buf->lba) * be_lun->cbe_lun.blocksize, 1114287499Smav len, (end - buf < 2) ? TRUE : FALSE); 1115264274Smav } 1116264274Smav } else 1117264274Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1118264274Smav beio->io_offset, beio->io_len, TRUE); 1119264274Smav} 1120264274Smav 1121264274Smavstatic void 1122229997Skenctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 1123229997Sken struct ctl_be_block_io *beio) 1124229997Sken{ 1125267877Smav TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 1126229997Sken struct bio *bio; 1127287664Smav struct cdevsw *csw; 1128287664Smav struct cdev *dev; 1129229997Sken off_t cur_offset; 1130287664Smav int i, max_iosize, ref; 1131229997Sken 1132229997Sken DPRINTF("entered\n"); 1133287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1134229997Sken 1135229997Sken /* 1136229997Sken * We have to limit our I/O size to the maximum supported by the 1137229997Sken * backend device. Hopefully it is MAXPHYS. If the driver doesn't 1138229997Sken * set it properly, use DFLTPHYS. 1139229997Sken */ 1140287664Smav if (csw) { 1141287664Smav max_iosize = dev->si_iosize_max; 1142287664Smav if (max_iosize < PAGE_SIZE) 1143287664Smav max_iosize = DFLTPHYS; 1144287664Smav } else 1145229997Sken max_iosize = DFLTPHYS; 1146229997Sken 1147229997Sken cur_offset = beio->io_offset; 1148229997Sken for (i = 0; i < beio->num_segs; i++) { 1149229997Sken size_t cur_size; 1150229997Sken uint8_t *cur_ptr; 1151229997Sken 1152229997Sken cur_size = beio->sg_segs[i].len; 1153229997Sken cur_ptr = beio->sg_segs[i].addr; 1154229997Sken 1155229997Sken while (cur_size > 0) { 1156229997Sken /* This can't fail, it's a blocking allocation. */ 1157229997Sken bio = g_alloc_bio(); 1158229997Sken 1159229997Sken KASSERT(bio != NULL, ("g_alloc_bio() failed!\n")); 1160229997Sken 1161229997Sken bio->bio_cmd = beio->bio_cmd; 1162287664Smav bio->bio_dev = dev; 1163229997Sken bio->bio_caller1 = beio; 1164229997Sken bio->bio_length = min(cur_size, max_iosize); 1165229997Sken bio->bio_offset = cur_offset; 1166229997Sken bio->bio_data = cur_ptr; 1167229997Sken bio->bio_done = ctl_be_block_biodone; 1168287499Smav bio->bio_pblkno = cur_offset / be_lun->cbe_lun.blocksize; 1169229997Sken 1170229997Sken cur_offset += bio->bio_length; 1171229997Sken cur_ptr += bio->bio_length; 1172229997Sken cur_size -= bio->bio_length; 1173229997Sken 1174267877Smav TAILQ_INSERT_TAIL(&queue, bio, bio_queue); 1175229997Sken beio->num_bios_sent++; 1176229997Sken } 1177229997Sken } 1178267877Smav binuptime(&beio->ds_t0); 1179267877Smav mtx_lock(&be_lun->io_lock); 1180267877Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1181267877Smav beio->send_complete = 1; 1182267877Smav mtx_unlock(&be_lun->io_lock); 1183267877Smav 1184267877Smav /* 1185267877Smav * Fire off all allocated requests! 1186267877Smav */ 1187267877Smav while ((bio = TAILQ_FIRST(&queue)) != NULL) { 1188267877Smav TAILQ_REMOVE(&queue, bio, bio_queue); 1189287664Smav if (csw) 1190287664Smav csw->d_strategy(bio); 1191287664Smav else { 1192287664Smav bio->bio_error = ENXIO; 1193287664Smav ctl_be_block_biodone(bio); 1194287664Smav } 1195267877Smav } 1196287664Smav if (csw) 1197287664Smav dev_relthread(dev, ref); 1198229997Sken} 1199229997Sken 1200274154Smavstatic uint64_t 1201274154Smavctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname) 1202274154Smav{ 1203274154Smav struct diocgattr_arg arg; 1204287664Smav struct cdevsw *csw; 1205287664Smav struct cdev *dev; 1206287664Smav int error, ref; 1207274154Smav 1208287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1209287664Smav if (csw == NULL) 1210274154Smav return (UINT64_MAX); 1211274154Smav strlcpy(arg.name, attrname, sizeof(arg.name)); 1212274154Smav arg.len = sizeof(arg.value.off); 1213287664Smav if (csw->d_ioctl) { 1214287664Smav error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 1215287664Smav curthread); 1216287664Smav } else 1217287664Smav error = ENODEV; 1218287664Smav dev_relthread(dev, ref); 1219274154Smav if (error != 0) 1220274154Smav return (UINT64_MAX); 1221274154Smav return (arg.value.off); 1222274154Smav} 1223274154Smav 1224229997Skenstatic void 1225286353Smavctl_be_block_cw_dispatch_sync(struct ctl_be_block_lun *be_lun, 1226286353Smav union ctl_io *io) 1227286353Smav{ 1228287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1229286353Smav struct ctl_be_block_io *beio; 1230286353Smav struct ctl_lba_len_flags *lbalen; 1231286353Smav 1232286353Smav DPRINTF("entered\n"); 1233286353Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1234286353Smav lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1235286353Smav 1236287499Smav beio->io_len = lbalen->len * cbe_lun->blocksize; 1237287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1238286353Smav beio->io_arg = (lbalen->flags & SSC_IMMED) != 0; 1239286353Smav beio->bio_cmd = BIO_FLUSH; 1240286353Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1241286353Smav DPRINTF("SYNC\n"); 1242286353Smav be_lun->lun_flush(be_lun, beio); 1243286353Smav} 1244286353Smav 1245286353Smavstatic void 1246264274Smavctl_be_block_cw_done_ws(struct ctl_be_block_io *beio) 1247264274Smav{ 1248264274Smav union ctl_io *io; 1249264274Smav 1250264274Smav io = beio->io; 1251264274Smav ctl_free_beio(beio); 1252267641Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1253267641Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1254267641Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1255264274Smav ctl_config_write_done(io); 1256264274Smav return; 1257264274Smav } 1258264274Smav 1259264274Smav ctl_be_block_config_write(io); 1260264274Smav} 1261264274Smav 1262264274Smavstatic void 1263264274Smavctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun, 1264264274Smav union ctl_io *io) 1265264274Smav{ 1266287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1267264274Smav struct ctl_be_block_io *beio; 1268267515Smav struct ctl_lba_len_flags *lbalen; 1269278625Smav uint64_t len_left, lba; 1270278625Smav uint32_t pb, pbo, adj; 1271264274Smav int i, seglen; 1272264274Smav uint8_t *buf, *end; 1273264274Smav 1274264274Smav DPRINTF("entered\n"); 1275264274Smav 1276267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1277267537Smav lbalen = ARGS(beio->io); 1278264274Smav 1279271839Smav if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB) || 1280269622Smav (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR) && be_lun->unmap == NULL)) { 1281264274Smav ctl_free_beio(beio); 1282264274Smav ctl_set_invalid_field(&io->scsiio, 1283264274Smav /*sks_valid*/ 1, 1284264274Smav /*command*/ 1, 1285264274Smav /*field*/ 1, 1286264274Smav /*bit_valid*/ 0, 1287264274Smav /*bit*/ 0); 1288264274Smav ctl_config_write_done(io); 1289264274Smav return; 1290264274Smav } 1291264274Smav 1292269622Smav if (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR)) { 1293287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1294287499Smav beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize; 1295264274Smav beio->bio_cmd = BIO_DELETE; 1296264274Smav beio->ds_trans_type = DEVSTAT_FREE; 1297264274Smav 1298264274Smav be_lun->unmap(be_lun, beio); 1299264274Smav return; 1300264274Smav } 1301264274Smav 1302264274Smav beio->bio_cmd = BIO_WRITE; 1303264274Smav beio->ds_trans_type = DEVSTAT_WRITE; 1304264274Smav 1305264274Smav DPRINTF("WRITE SAME at LBA %jx len %u\n", 1306267515Smav (uintmax_t)lbalen->lba, lbalen->len); 1307264274Smav 1308287499Smav pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp; 1309287499Smav if (be_lun->cbe_lun.pblockoff > 0) 1310287499Smav pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff; 1311278625Smav else 1312278625Smav pbo = 0; 1313287499Smav len_left = (uint64_t)lbalen->len * cbe_lun->blocksize; 1314264274Smav for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) { 1315264274Smav 1316264274Smav /* 1317264274Smav * Setup the S/G entry for this chunk. 1318264274Smav */ 1319264886Smav seglen = MIN(CTLBLK_MAX_SEG, len_left); 1320287499Smav if (pb > cbe_lun->blocksize) { 1321287499Smav adj = ((lbalen->lba + lba) * cbe_lun->blocksize + 1322278619Smav seglen - pbo) % pb; 1323278619Smav if (seglen > adj) 1324278619Smav seglen -= adj; 1325278619Smav else 1326287499Smav seglen -= seglen % cbe_lun->blocksize; 1327278619Smav } else 1328287499Smav seglen -= seglen % cbe_lun->blocksize; 1329264274Smav beio->sg_segs[i].len = seglen; 1330264274Smav beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1331264274Smav 1332264274Smav DPRINTF("segment %d addr %p len %zd\n", i, 1333264274Smav beio->sg_segs[i].addr, beio->sg_segs[i].len); 1334264274Smav 1335264274Smav beio->num_segs++; 1336264274Smav len_left -= seglen; 1337264274Smav 1338264274Smav buf = beio->sg_segs[i].addr; 1339264274Smav end = buf + seglen; 1340287499Smav for (; buf < end; buf += cbe_lun->blocksize) { 1341287499Smav memcpy(buf, io->scsiio.kern_data_ptr, cbe_lun->blocksize); 1342267515Smav if (lbalen->flags & SWS_LBDATA) 1343267515Smav scsi_ulto4b(lbalen->lba + lba, buf); 1344264274Smav lba++; 1345264274Smav } 1346264274Smav } 1347264274Smav 1348287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1349287499Smav beio->io_len = lba * cbe_lun->blocksize; 1350264274Smav 1351264274Smav /* We can not do all in one run. Correct and schedule rerun. */ 1352264274Smav if (len_left > 0) { 1353267515Smav lbalen->lba += lba; 1354267515Smav lbalen->len -= lba; 1355264274Smav beio->beio_cont = ctl_be_block_cw_done_ws; 1356264274Smav } 1357264274Smav 1358264274Smav be_lun->dispatch(be_lun, beio); 1359264274Smav} 1360264274Smav 1361264274Smavstatic void 1362264274Smavctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun, 1363264274Smav union ctl_io *io) 1364264274Smav{ 1365264274Smav struct ctl_be_block_io *beio; 1366267515Smav struct ctl_ptr_len_flags *ptrlen; 1367264274Smav 1368264274Smav DPRINTF("entered\n"); 1369264274Smav 1370267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1371267515Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1372264274Smav 1373269622Smav if ((ptrlen->flags & ~SU_ANCHOR) != 0 || be_lun->unmap == NULL) { 1374264274Smav ctl_free_beio(beio); 1375264274Smav ctl_set_invalid_field(&io->scsiio, 1376264274Smav /*sks_valid*/ 0, 1377264274Smav /*command*/ 1, 1378264274Smav /*field*/ 0, 1379264274Smav /*bit_valid*/ 0, 1380264274Smav /*bit*/ 0); 1381264274Smav ctl_config_write_done(io); 1382264274Smav return; 1383264274Smav } 1384264274Smav 1385264274Smav beio->io_len = 0; 1386264274Smav beio->io_offset = -1; 1387264274Smav beio->bio_cmd = BIO_DELETE; 1388264274Smav beio->ds_trans_type = DEVSTAT_FREE; 1389267515Smav DPRINTF("UNMAP\n"); 1390264274Smav be_lun->unmap(be_lun, beio); 1391264274Smav} 1392264274Smav 1393264274Smavstatic void 1394275474Smavctl_be_block_cr_done(struct ctl_be_block_io *beio) 1395275474Smav{ 1396275474Smav union ctl_io *io; 1397275474Smav 1398275474Smav io = beio->io; 1399275474Smav ctl_free_beio(beio); 1400275474Smav ctl_config_read_done(io); 1401275474Smav} 1402275474Smav 1403275474Smavstatic void 1404275474Smavctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 1405275474Smav union ctl_io *io) 1406275474Smav{ 1407275474Smav struct ctl_be_block_io *beio; 1408275474Smav struct ctl_be_block_softc *softc; 1409275474Smav 1410275474Smav DPRINTF("entered\n"); 1411275474Smav 1412275474Smav softc = be_lun->softc; 1413275474Smav beio = ctl_alloc_beio(softc); 1414275474Smav beio->io = io; 1415275474Smav beio->lun = be_lun; 1416275474Smav beio->beio_cont = ctl_be_block_cr_done; 1417275474Smav PRIV(io)->ptr = (void *)beio; 1418275474Smav 1419275474Smav switch (io->scsiio.cdb[0]) { 1420275474Smav case SERVICE_ACTION_IN: /* GET LBA STATUS */ 1421275474Smav beio->bio_cmd = -1; 1422275474Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1423275474Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1424275474Smav beio->io_len = 0; 1425275474Smav if (be_lun->get_lba_status) 1426275474Smav be_lun->get_lba_status(be_lun, beio); 1427275474Smav else 1428275474Smav ctl_be_block_cr_done(beio); 1429275474Smav break; 1430275474Smav default: 1431275474Smav panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1432275474Smav break; 1433275474Smav } 1434275474Smav} 1435275474Smav 1436275474Smavstatic void 1437264274Smavctl_be_block_cw_done(struct ctl_be_block_io *beio) 1438264274Smav{ 1439264274Smav union ctl_io *io; 1440264274Smav 1441264274Smav io = beio->io; 1442264274Smav ctl_free_beio(beio); 1443264274Smav ctl_config_write_done(io); 1444264274Smav} 1445264274Smav 1446264274Smavstatic void 1447229997Skenctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 1448229997Sken union ctl_io *io) 1449229997Sken{ 1450229997Sken struct ctl_be_block_io *beio; 1451229997Sken struct ctl_be_block_softc *softc; 1452229997Sken 1453229997Sken DPRINTF("entered\n"); 1454229997Sken 1455229997Sken softc = be_lun->softc; 1456229997Sken beio = ctl_alloc_beio(softc); 1457229997Sken beio->io = io; 1458229997Sken beio->lun = be_lun; 1459264274Smav beio->beio_cont = ctl_be_block_cw_done; 1460286353Smav switch (io->scsiio.tag_type) { 1461286353Smav case CTL_TAG_ORDERED: 1462286353Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1463286353Smav break; 1464286353Smav case CTL_TAG_HEAD_OF_QUEUE: 1465286353Smav beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1466286353Smav break; 1467286353Smav case CTL_TAG_UNTAGGED: 1468286353Smav case CTL_TAG_SIMPLE: 1469286353Smav case CTL_TAG_ACA: 1470286353Smav default: 1471286353Smav beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1472286353Smav break; 1473286353Smav } 1474267519Smav PRIV(io)->ptr = (void *)beio; 1475229997Sken 1476229997Sken switch (io->scsiio.cdb[0]) { 1477229997Sken case SYNCHRONIZE_CACHE: 1478229997Sken case SYNCHRONIZE_CACHE_16: 1479286353Smav ctl_be_block_cw_dispatch_sync(be_lun, io); 1480229997Sken break; 1481264274Smav case WRITE_SAME_10: 1482264274Smav case WRITE_SAME_16: 1483264274Smav ctl_be_block_cw_dispatch_ws(be_lun, io); 1484264274Smav break; 1485264274Smav case UNMAP: 1486264274Smav ctl_be_block_cw_dispatch_unmap(be_lun, io); 1487264274Smav break; 1488229997Sken default: 1489229997Sken panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1490229997Sken break; 1491229997Sken } 1492229997Sken} 1493229997Sken 1494258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, start, "uint64_t"); 1495258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, start, "uint64_t"); 1496258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, alloc_done, "uint64_t"); 1497258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, alloc_done, "uint64_t"); 1498229997Sken 1499229997Skenstatic void 1500264886Smavctl_be_block_next(struct ctl_be_block_io *beio) 1501264886Smav{ 1502264886Smav struct ctl_be_block_lun *be_lun; 1503264886Smav union ctl_io *io; 1504264886Smav 1505264886Smav io = beio->io; 1506264886Smav be_lun = beio->lun; 1507264886Smav ctl_free_beio(beio); 1508267641Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1509267641Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1510267641Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1511267537Smav ctl_data_submit_done(io); 1512264886Smav return; 1513264886Smav } 1514264886Smav 1515264886Smav io->io_hdr.status &= ~CTL_STATUS_MASK; 1516264886Smav io->io_hdr.status |= CTL_STATUS_NONE; 1517264886Smav 1518267877Smav mtx_lock(&be_lun->queue_lock); 1519264886Smav /* 1520264886Smav * XXX KDM make sure that links is okay to use at this point. 1521264886Smav * Otherwise, we either need to add another field to ctl_io_hdr, 1522264886Smav * or deal with resource allocation here. 1523264886Smav */ 1524264886Smav STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1525267877Smav mtx_unlock(&be_lun->queue_lock); 1526264886Smav 1527264886Smav taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1528264886Smav} 1529264886Smav 1530264886Smavstatic void 1531229997Skenctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 1532229997Sken union ctl_io *io) 1533229997Sken{ 1534287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1535229997Sken struct ctl_be_block_io *beio; 1536229997Sken struct ctl_be_block_softc *softc; 1537267537Smav struct ctl_lba_len_flags *lbalen; 1538267519Smav struct ctl_ptr_len_flags *bptrlen; 1539267519Smav uint64_t len_left, lbas; 1540229997Sken int i; 1541229997Sken 1542229997Sken softc = be_lun->softc; 1543229997Sken 1544229997Sken DPRINTF("entered\n"); 1545229997Sken 1546267537Smav lbalen = ARGS(io); 1547267537Smav if (lbalen->flags & CTL_LLF_WRITE) { 1548267537Smav SDT_PROBE(cbb, kernel, write, start, 0, 0, 0, 0, 0); 1549267537Smav } else { 1550229997Sken SDT_PROBE(cbb, kernel, read, start, 0, 0, 0, 0, 0); 1551229997Sken } 1552229997Sken 1553229997Sken beio = ctl_alloc_beio(softc); 1554229997Sken beio->io = io; 1555229997Sken beio->lun = be_lun; 1556267519Smav bptrlen = PRIV(io); 1557267519Smav bptrlen->ptr = (void *)beio; 1558229997Sken 1559229997Sken switch (io->scsiio.tag_type) { 1560229997Sken case CTL_TAG_ORDERED: 1561229997Sken beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1562229997Sken break; 1563229997Sken case CTL_TAG_HEAD_OF_QUEUE: 1564229997Sken beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1565229997Sken break; 1566229997Sken case CTL_TAG_UNTAGGED: 1567229997Sken case CTL_TAG_SIMPLE: 1568229997Sken case CTL_TAG_ACA: 1569229997Sken default: 1570229997Sken beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1571229997Sken break; 1572229997Sken } 1573229997Sken 1574267537Smav if (lbalen->flags & CTL_LLF_WRITE) { 1575267537Smav beio->bio_cmd = BIO_WRITE; 1576267537Smav beio->ds_trans_type = DEVSTAT_WRITE; 1577267537Smav } else { 1578229997Sken beio->bio_cmd = BIO_READ; 1579229997Sken beio->ds_trans_type = DEVSTAT_READ; 1580229997Sken } 1581229997Sken 1582264886Smav DPRINTF("%s at LBA %jx len %u @%ju\n", 1583229997Sken (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", 1584267519Smav (uintmax_t)lbalen->lba, lbalen->len, bptrlen->len); 1585267537Smav if (lbalen->flags & CTL_LLF_COMPARE) 1586267537Smav lbas = CTLBLK_HALF_IO_SIZE; 1587267537Smav else 1588267537Smav lbas = CTLBLK_MAX_IO_SIZE; 1589287499Smav lbas = MIN(lbalen->len - bptrlen->len, lbas / cbe_lun->blocksize); 1590287499Smav beio->io_offset = (lbalen->lba + bptrlen->len) * cbe_lun->blocksize; 1591287499Smav beio->io_len = lbas * cbe_lun->blocksize; 1592267519Smav bptrlen->len += lbas; 1593229997Sken 1594264886Smav for (i = 0, len_left = beio->io_len; len_left > 0; i++) { 1595264886Smav KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", 1596264886Smav i, CTLBLK_MAX_SEGS)); 1597229997Sken 1598229997Sken /* 1599229997Sken * Setup the S/G entry for this chunk. 1600229997Sken */ 1601264886Smav beio->sg_segs[i].len = min(CTLBLK_MAX_SEG, len_left); 1602229997Sken beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1603229997Sken 1604229997Sken DPRINTF("segment %d addr %p len %zd\n", i, 1605229997Sken beio->sg_segs[i].addr, beio->sg_segs[i].len); 1606229997Sken 1607267537Smav /* Set up second segment for compare operation. */ 1608267537Smav if (lbalen->flags & CTL_LLF_COMPARE) { 1609267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].len = 1610267537Smav beio->sg_segs[i].len; 1611267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = 1612267537Smav uma_zalloc(be_lun->lun_zone, M_WAITOK); 1613267537Smav } 1614267537Smav 1615229997Sken beio->num_segs++; 1616229997Sken len_left -= beio->sg_segs[i].len; 1617229997Sken } 1618267519Smav if (bptrlen->len < lbalen->len) 1619264886Smav beio->beio_cont = ctl_be_block_next; 1620264886Smav io->scsiio.be_move_done = ctl_be_block_move_done; 1621267537Smav /* For compare we have separate S/G lists for read and datamove. */ 1622267537Smav if (lbalen->flags & CTL_LLF_COMPARE) 1623267537Smav io->scsiio.kern_data_ptr = (uint8_t *)&beio->sg_segs[CTLBLK_HALF_SEGS]; 1624267537Smav else 1625267537Smav io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; 1626264886Smav io->scsiio.kern_data_len = beio->io_len; 1627264886Smav io->scsiio.kern_data_resid = 0; 1628264886Smav io->scsiio.kern_sg_entries = beio->num_segs; 1629264886Smav io->io_hdr.flags |= CTL_FLAG_ALLOCATED | CTL_FLAG_KDPTR_SGLIST; 1630229997Sken 1631229997Sken /* 1632229997Sken * For the read case, we need to read the data into our buffers and 1633229997Sken * then we can send it back to the user. For the write case, we 1634229997Sken * need to get the data from the user first. 1635229997Sken */ 1636229997Sken if (beio->bio_cmd == BIO_READ) { 1637229997Sken SDT_PROBE(cbb, kernel, read, alloc_done, 0, 0, 0, 0, 0); 1638229997Sken be_lun->dispatch(be_lun, beio); 1639229997Sken } else { 1640229997Sken SDT_PROBE(cbb, kernel, write, alloc_done, 0, 0, 0, 0, 0); 1641229997Sken#ifdef CTL_TIME_IO 1642229997Sken getbintime(&io->io_hdr.dma_start_bt); 1643229997Sken#endif 1644229997Sken ctl_datamove(io); 1645229997Sken } 1646229997Sken} 1647229997Sken 1648229997Skenstatic void 1649229997Skenctl_be_block_worker(void *context, int pending) 1650229997Sken{ 1651287670Smav struct ctl_be_block_lun *be_lun = (struct ctl_be_block_lun *)context; 1652287670Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1653229997Sken union ctl_io *io; 1654287670Smav struct ctl_be_block_io *beio; 1655229997Sken 1656229997Sken DPRINTF("entered\n"); 1657287670Smav /* 1658287670Smav * Fetch and process I/Os from all queues. If we detect LUN 1659287670Smav * CTL_LUN_FLAG_OFFLINE status here -- it is result of a race, 1660287670Smav * so make response maximally opaque to not confuse initiator. 1661287670Smav */ 1662229997Sken for (;;) { 1663287670Smav mtx_lock(&be_lun->queue_lock); 1664229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue); 1665229997Sken if (io != NULL) { 1666229997Sken DPRINTF("datamove queue\n"); 1667229997Sken STAILQ_REMOVE(&be_lun->datamove_queue, &io->io_hdr, 1668229997Sken ctl_io_hdr, links); 1669267877Smav mtx_unlock(&be_lun->queue_lock); 1670267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1671287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1672287670Smav ctl_set_busy(&io->scsiio); 1673287670Smav ctl_complete_beio(beio); 1674287670Smav return; 1675287670Smav } 1676229997Sken be_lun->dispatch(be_lun, beio); 1677229997Sken continue; 1678229997Sken } 1679229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue); 1680229997Sken if (io != NULL) { 1681229997Sken DPRINTF("config write queue\n"); 1682229997Sken STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr, 1683229997Sken ctl_io_hdr, links); 1684267877Smav mtx_unlock(&be_lun->queue_lock); 1685287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1686287670Smav ctl_set_busy(&io->scsiio); 1687287670Smav ctl_config_write_done(io); 1688287670Smav return; 1689287670Smav } 1690229997Sken ctl_be_block_cw_dispatch(be_lun, io); 1691229997Sken continue; 1692229997Sken } 1693275474Smav io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue); 1694275474Smav if (io != NULL) { 1695275474Smav DPRINTF("config read queue\n"); 1696275474Smav STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr, 1697275474Smav ctl_io_hdr, links); 1698275474Smav mtx_unlock(&be_lun->queue_lock); 1699287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1700287670Smav ctl_set_busy(&io->scsiio); 1701287670Smav ctl_config_read_done(io); 1702287670Smav return; 1703287670Smav } 1704275474Smav ctl_be_block_cr_dispatch(be_lun, io); 1705275474Smav continue; 1706275474Smav } 1707229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue); 1708229997Sken if (io != NULL) { 1709229997Sken DPRINTF("input queue\n"); 1710229997Sken STAILQ_REMOVE(&be_lun->input_queue, &io->io_hdr, 1711229997Sken ctl_io_hdr, links); 1712267877Smav mtx_unlock(&be_lun->queue_lock); 1713287670Smav if (cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) { 1714287670Smav ctl_set_busy(&io->scsiio); 1715287670Smav ctl_data_submit_done(io); 1716287670Smav return; 1717287670Smav } 1718229997Sken ctl_be_block_dispatch(be_lun, io); 1719229997Sken continue; 1720229997Sken } 1721229997Sken 1722229997Sken /* 1723229997Sken * If we get here, there is no work left in the queues, so 1724229997Sken * just break out and let the task queue go to sleep. 1725229997Sken */ 1726287670Smav mtx_unlock(&be_lun->queue_lock); 1727229997Sken break; 1728229997Sken } 1729229997Sken} 1730229997Sken 1731229997Sken/* 1732229997Sken * Entry point from CTL to the backend for I/O. We queue everything to a 1733229997Sken * work thread, so this just puts the I/O on a queue and wakes up the 1734229997Sken * thread. 1735229997Sken */ 1736229997Skenstatic int 1737229997Skenctl_be_block_submit(union ctl_io *io) 1738229997Sken{ 1739229997Sken struct ctl_be_block_lun *be_lun; 1740287499Smav struct ctl_be_lun *cbe_lun; 1741229997Sken 1742229997Sken DPRINTF("entered\n"); 1743229997Sken 1744287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 1745229997Sken CTL_PRIV_BACKEND_LUN].ptr; 1746287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 1747229997Sken 1748229997Sken /* 1749229997Sken * Make sure we only get SCSI I/O. 1750229997Sken */ 1751229997Sken KASSERT(io->io_hdr.io_type == CTL_IO_SCSI, ("Non-SCSI I/O (type " 1752229997Sken "%#x) encountered", io->io_hdr.io_type)); 1753229997Sken 1754267519Smav PRIV(io)->len = 0; 1755267519Smav 1756267877Smav mtx_lock(&be_lun->queue_lock); 1757229997Sken /* 1758229997Sken * XXX KDM make sure that links is okay to use at this point. 1759229997Sken * Otherwise, we either need to add another field to ctl_io_hdr, 1760229997Sken * or deal with resource allocation here. 1761229997Sken */ 1762229997Sken STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1763267877Smav mtx_unlock(&be_lun->queue_lock); 1764229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1765229997Sken 1766267514Smav return (CTL_RETVAL_COMPLETE); 1767229997Sken} 1768229997Sken 1769229997Skenstatic int 1770229997Skenctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 1771229997Sken int flag, struct thread *td) 1772229997Sken{ 1773229997Sken struct ctl_be_block_softc *softc; 1774229997Sken int error; 1775229997Sken 1776229997Sken softc = &backend_block_softc; 1777229997Sken 1778229997Sken error = 0; 1779229997Sken 1780229997Sken switch (cmd) { 1781229997Sken case CTL_LUN_REQ: { 1782229997Sken struct ctl_lun_req *lun_req; 1783229997Sken 1784229997Sken lun_req = (struct ctl_lun_req *)addr; 1785229997Sken 1786229997Sken switch (lun_req->reqtype) { 1787229997Sken case CTL_LUNREQ_CREATE: 1788229997Sken error = ctl_be_block_create(softc, lun_req); 1789229997Sken break; 1790229997Sken case CTL_LUNREQ_RM: 1791229997Sken error = ctl_be_block_rm(softc, lun_req); 1792229997Sken break; 1793232604Strasz case CTL_LUNREQ_MODIFY: 1794232604Strasz error = ctl_be_block_modify(softc, lun_req); 1795232604Strasz break; 1796229997Sken default: 1797229997Sken lun_req->status = CTL_LUN_ERROR; 1798229997Sken snprintf(lun_req->error_str, sizeof(lun_req->error_str), 1799272911Smav "invalid LUN request type %d", 1800229997Sken lun_req->reqtype); 1801229997Sken break; 1802229997Sken } 1803229997Sken break; 1804229997Sken } 1805229997Sken default: 1806229997Sken error = ENOTTY; 1807229997Sken break; 1808229997Sken } 1809229997Sken 1810229997Sken return (error); 1811229997Sken} 1812229997Sken 1813229997Skenstatic int 1814229997Skenctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1815229997Sken{ 1816287499Smav struct ctl_be_lun *cbe_lun; 1817229997Sken struct ctl_be_block_filedata *file_data; 1818229997Sken struct ctl_lun_create_params *params; 1819275865Smav char *value; 1820229997Sken struct vattr vattr; 1821275865Smav off_t ps, pss, po, pos, us, uss, uo, uos; 1822229997Sken int error; 1823229997Sken 1824229997Sken error = 0; 1825287499Smav cbe_lun = &be_lun->cbe_lun; 1826229997Sken file_data = &be_lun->backend.file; 1827272911Smav params = &be_lun->params; 1828229997Sken 1829229997Sken be_lun->dev_type = CTL_BE_BLOCK_FILE; 1830229997Sken be_lun->dispatch = ctl_be_block_dispatch_file; 1831229997Sken be_lun->lun_flush = ctl_be_block_flush_file; 1832275474Smav be_lun->get_lba_status = ctl_be_block_gls_file; 1833275481Smav be_lun->getattr = ctl_be_block_getattr_file; 1834287499Smav be_lun->unmap = NULL; 1835287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 1836229997Sken 1837229997Sken error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 1838229997Sken if (error != 0) { 1839229997Sken snprintf(req->error_str, sizeof(req->error_str), 1840229997Sken "error calling VOP_GETATTR() for file %s", 1841229997Sken be_lun->dev_path); 1842229997Sken return (error); 1843229997Sken } 1844229997Sken 1845229997Sken /* 1846229997Sken * Verify that we have the ability to upgrade to exclusive 1847229997Sken * access on this file so we can trap errors at open instead 1848229997Sken * of reporting them during first access. 1849229997Sken */ 1850229997Sken if (VOP_ISLOCKED(be_lun->vn) != LK_EXCLUSIVE) { 1851229997Sken vn_lock(be_lun->vn, LK_UPGRADE | LK_RETRY); 1852229997Sken if (be_lun->vn->v_iflag & VI_DOOMED) { 1853229997Sken error = EBADF; 1854229997Sken snprintf(req->error_str, sizeof(req->error_str), 1855229997Sken "error locking file %s", be_lun->dev_path); 1856229997Sken return (error); 1857229997Sken } 1858229997Sken } 1859229997Sken 1860229997Sken file_data->cred = crhold(curthread->td_ucred); 1861232604Strasz if (params->lun_size_bytes != 0) 1862232604Strasz be_lun->size_bytes = params->lun_size_bytes; 1863232604Strasz else 1864232604Strasz be_lun->size_bytes = vattr.va_size; 1865229997Sken 1866229997Sken /* 1867273029Smav * For files we can use any logical block size. Prefer 512 bytes 1868273029Smav * for compatibility reasons. If file's vattr.va_blocksize 1869273029Smav * (preferred I/O block size) is bigger and multiple to chosen 1870273029Smav * logical block size -- report it as physical block size. 1871229997Sken */ 1872229997Sken if (params->blocksize_bytes != 0) 1873287499Smav cbe_lun->blocksize = params->blocksize_bytes; 1874229997Sken else 1875287499Smav cbe_lun->blocksize = 512; 1876287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 1877287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 1878287499Smav 0 : (be_lun->size_blocks - 1); 1879275865Smav 1880275865Smav us = ps = vattr.va_blocksize; 1881275865Smav uo = po = 0; 1882275865Smav 1883287499Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 1884275865Smav if (value != NULL) 1885275865Smav ctl_expand_number(value, &ps); 1886287499Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 1887275865Smav if (value != NULL) 1888275865Smav ctl_expand_number(value, &po); 1889287499Smav pss = ps / cbe_lun->blocksize; 1890287499Smav pos = po / cbe_lun->blocksize; 1891287499Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 1892287499Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 1893287499Smav cbe_lun->pblockexp = fls(pss) - 1; 1894287499Smav cbe_lun->pblockoff = (pss - pos) % pss; 1895273029Smav } 1896229997Sken 1897287499Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 1898275865Smav if (value != NULL) 1899275865Smav ctl_expand_number(value, &us); 1900287499Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 1901275865Smav if (value != NULL) 1902275865Smav ctl_expand_number(value, &uo); 1903287499Smav uss = us / cbe_lun->blocksize; 1904287499Smav uos = uo / cbe_lun->blocksize; 1905287499Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 1906287499Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 1907287499Smav cbe_lun->ublockexp = fls(uss) - 1; 1908287499Smav cbe_lun->ublockoff = (uss - uos) % uss; 1909275865Smav } 1910275865Smav 1911229997Sken /* 1912229997Sken * Sanity check. The media size has to be at least one 1913229997Sken * sector long. 1914229997Sken */ 1915287499Smav if (be_lun->size_bytes < cbe_lun->blocksize) { 1916229997Sken error = EINVAL; 1917229997Sken snprintf(req->error_str, sizeof(req->error_str), 1918229997Sken "file %s size %ju < block size %u", be_lun->dev_path, 1919287499Smav (uintmax_t)be_lun->size_bytes, cbe_lun->blocksize); 1920229997Sken } 1921275920Smav 1922287499Smav cbe_lun->opttxferlen = CTLBLK_MAX_IO_SIZE / cbe_lun->blocksize; 1923229997Sken return (error); 1924229997Sken} 1925229997Sken 1926229997Skenstatic int 1927229997Skenctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1928229997Sken{ 1929287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1930229997Sken struct ctl_lun_create_params *params; 1931287664Smav struct cdevsw *csw; 1932229997Sken struct cdev *dev; 1933275865Smav char *value; 1934287664Smav int error, atomic, maxio, ref, unmap, tmp; 1935287221Smav off_t ps, pss, po, pos, us, uss, uo, uos, otmp; 1936229997Sken 1937272911Smav params = &be_lun->params; 1938229997Sken 1939229997Sken be_lun->dev_type = CTL_BE_BLOCK_DEV; 1940287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 1941287664Smav if (csw == NULL) 1942287664Smav return (ENXIO); 1943287664Smav if (strcmp(csw->d_name, "zvol") == 0) { 1944269123Smav be_lun->dispatch = ctl_be_block_dispatch_zvol; 1945275474Smav be_lun->get_lba_status = ctl_be_block_gls_zvol; 1946275920Smav atomic = maxio = CTLBLK_MAX_IO_SIZE; 1947275920Smav } else { 1948269123Smav be_lun->dispatch = ctl_be_block_dispatch_dev; 1949287499Smav be_lun->get_lba_status = NULL; 1950275920Smav atomic = 0; 1951287664Smav maxio = dev->si_iosize_max; 1952275920Smav if (maxio <= 0) 1953275920Smav maxio = DFLTPHYS; 1954275920Smav if (maxio > CTLBLK_MAX_IO_SIZE) 1955275920Smav maxio = CTLBLK_MAX_IO_SIZE; 1956275920Smav } 1957269123Smav be_lun->lun_flush = ctl_be_block_flush_dev; 1958274154Smav be_lun->getattr = ctl_be_block_getattr_dev; 1959287499Smav be_lun->unmap = ctl_be_block_unmap_dev; 1960229997Sken 1961287664Smav if (!csw->d_ioctl) { 1962287664Smav dev_relthread(dev, ref); 1963229997Sken snprintf(req->error_str, sizeof(req->error_str), 1964287664Smav "no d_ioctl for device %s!", be_lun->dev_path); 1965229997Sken return (ENODEV); 1966229997Sken } 1967229997Sken 1968287664Smav error = csw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD, 1969229997Sken curthread); 1970229997Sken if (error) { 1971287664Smav dev_relthread(dev, ref); 1972229997Sken snprintf(req->error_str, sizeof(req->error_str), 1973272911Smav "error %d returned for DIOCGSECTORSIZE ioctl " 1974272911Smav "on %s!", error, be_lun->dev_path); 1975229997Sken return (error); 1976229997Sken } 1977229997Sken 1978229997Sken /* 1979229997Sken * If the user has asked for a blocksize that is greater than the 1980229997Sken * backing device's blocksize, we can do it only if the blocksize 1981229997Sken * the user is asking for is an even multiple of the underlying 1982229997Sken * device's blocksize. 1983229997Sken */ 1984286811Smav if ((params->blocksize_bytes != 0) && 1985286811Smav (params->blocksize_bytes >= tmp)) { 1986286811Smav if (params->blocksize_bytes % tmp == 0) { 1987287499Smav cbe_lun->blocksize = params->blocksize_bytes; 1988229997Sken } else { 1989287664Smav dev_relthread(dev, ref); 1990229997Sken snprintf(req->error_str, sizeof(req->error_str), 1991272911Smav "requested blocksize %u is not an even " 1992229997Sken "multiple of backing device blocksize %u", 1993287221Smav params->blocksize_bytes, tmp); 1994229997Sken return (EINVAL); 1995229997Sken } 1996286811Smav } else if (params->blocksize_bytes != 0) { 1997287664Smav dev_relthread(dev, ref); 1998229997Sken snprintf(req->error_str, sizeof(req->error_str), 1999272911Smav "requested blocksize %u < backing device " 2000287221Smav "blocksize %u", params->blocksize_bytes, tmp); 2001229997Sken return (EINVAL); 2002286811Smav } else 2003287499Smav cbe_lun->blocksize = tmp; 2004229997Sken 2005287664Smav error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD, 2006287664Smav curthread); 2007229997Sken if (error) { 2008287664Smav dev_relthread(dev, ref); 2009229997Sken snprintf(req->error_str, sizeof(req->error_str), 2010272911Smav "error %d returned for DIOCGMEDIASIZE " 2011272911Smav " ioctl on %s!", error, 2012232604Strasz be_lun->dev_path); 2013229997Sken return (error); 2014229997Sken } 2015229997Sken 2016232604Strasz if (params->lun_size_bytes != 0) { 2017287221Smav if (params->lun_size_bytes > otmp) { 2018287664Smav dev_relthread(dev, ref); 2019232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2020272911Smav "requested LUN size %ju > backing device " 2021272911Smav "size %ju", 2022232604Strasz (uintmax_t)params->lun_size_bytes, 2023287221Smav (uintmax_t)otmp); 2024232604Strasz return (EINVAL); 2025232604Strasz } 2026232604Strasz 2027232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2028286811Smav } else 2029287221Smav be_lun->size_bytes = otmp; 2030287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2031287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2032287499Smav 0 : (be_lun->size_blocks - 1); 2033232604Strasz 2034287664Smav error = csw->d_ioctl(dev, DIOCGSTRIPESIZE, (caddr_t)&ps, FREAD, 2035287664Smav curthread); 2036264191Smav if (error) 2037264191Smav ps = po = 0; 2038264191Smav else { 2039287664Smav error = csw->d_ioctl(dev, DIOCGSTRIPEOFFSET, (caddr_t)&po, 2040287664Smav FREAD, curthread); 2041264191Smav if (error) 2042264191Smav po = 0; 2043264191Smav } 2044275865Smav us = ps; 2045275865Smav uo = po; 2046275865Smav 2047287499Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 2048275865Smav if (value != NULL) 2049275865Smav ctl_expand_number(value, &ps); 2050287499Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 2051275865Smav if (value != NULL) 2052275865Smav ctl_expand_number(value, &po); 2053287499Smav pss = ps / cbe_lun->blocksize; 2054287499Smav pos = po / cbe_lun->blocksize; 2055287499Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 2056287499Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 2057287499Smav cbe_lun->pblockexp = fls(pss) - 1; 2058287499Smav cbe_lun->pblockoff = (pss - pos) % pss; 2059264191Smav } 2060264191Smav 2061287499Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 2062275865Smav if (value != NULL) 2063275865Smav ctl_expand_number(value, &us); 2064287499Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 2065275865Smav if (value != NULL) 2066275865Smav ctl_expand_number(value, &uo); 2067287499Smav uss = us / cbe_lun->blocksize; 2068287499Smav uos = uo / cbe_lun->blocksize; 2069287499Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 2070287499Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 2071287499Smav cbe_lun->ublockexp = fls(uss) - 1; 2072287499Smav cbe_lun->ublockoff = (uss - uos) % uss; 2073275865Smav } 2074275865Smav 2075287499Smav cbe_lun->atomicblock = atomic / cbe_lun->blocksize; 2076287499Smav cbe_lun->opttxferlen = maxio / cbe_lun->blocksize; 2077278672Smav 2078278672Smav if (be_lun->dispatch == ctl_be_block_dispatch_zvol) { 2079278672Smav unmap = 1; 2080278672Smav } else { 2081278672Smav struct diocgattr_arg arg; 2082278672Smav 2083278672Smav strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name)); 2084278672Smav arg.len = sizeof(arg.value.i); 2085287664Smav error = csw->d_ioctl(dev, DIOCGATTR, (caddr_t)&arg, FREAD, 2086287664Smav curthread); 2087278672Smav unmap = (error == 0) ? arg.value.i : 0; 2088278672Smav } 2089287499Smav value = ctl_get_opt(&cbe_lun->options, "unmap"); 2090278672Smav if (value != NULL) 2091278672Smav unmap = (strcmp(value, "on") == 0); 2092278672Smav if (unmap) 2093287499Smav cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 2094287499Smav else 2095287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 2096278672Smav 2097287664Smav dev_relthread(dev, ref); 2098229997Sken return (0); 2099229997Sken} 2100229997Sken 2101229997Skenstatic int 2102229997Skenctl_be_block_close(struct ctl_be_block_lun *be_lun) 2103229997Sken{ 2104287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2105287499Smav int flags; 2106287499Smav 2107229997Sken if (be_lun->vn) { 2108287499Smav flags = FREAD; 2109287499Smav if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0) 2110287499Smav flags |= FWRITE; 2111229997Sken (void)vn_close(be_lun->vn, flags, NOCRED, curthread); 2112229997Sken be_lun->vn = NULL; 2113229997Sken 2114229997Sken switch (be_lun->dev_type) { 2115229997Sken case CTL_BE_BLOCK_DEV: 2116229997Sken break; 2117229997Sken case CTL_BE_BLOCK_FILE: 2118229997Sken if (be_lun->backend.file.cred != NULL) { 2119229997Sken crfree(be_lun->backend.file.cred); 2120229997Sken be_lun->backend.file.cred = NULL; 2121229997Sken } 2122229997Sken break; 2123229997Sken case CTL_BE_BLOCK_NONE: 2124258871Strasz break; 2125229997Sken default: 2126229997Sken panic("Unexpected backend type."); 2127229997Sken break; 2128229997Sken } 2129272911Smav be_lun->dev_type = CTL_BE_BLOCK_NONE; 2130229997Sken } 2131229997Sken return (0); 2132229997Sken} 2133229997Sken 2134229997Skenstatic int 2135229997Skenctl_be_block_open(struct ctl_be_block_softc *softc, 2136287499Smav struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 2137229997Sken{ 2138287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2139229997Sken struct nameidata nd; 2140287499Smav char *value; 2141287499Smav int error, flags; 2142229997Sken 2143229997Sken error = 0; 2144229997Sken if (rootvnode == NULL) { 2145229997Sken snprintf(req->error_str, sizeof(req->error_str), 2146272911Smav "Root filesystem is not mounted"); 2147229997Sken return (1); 2148229997Sken } 2149285391Smjg pwd_ensure_dirs(); 2150229997Sken 2151287499Smav value = ctl_get_opt(&cbe_lun->options, "file"); 2152287499Smav if (value == NULL) { 2153287499Smav snprintf(req->error_str, sizeof(req->error_str), 2154287499Smav "no file argument specified"); 2155287499Smav return (1); 2156287499Smav } 2157287499Smav free(be_lun->dev_path, M_CTLBLK); 2158287499Smav be_lun->dev_path = strdup(value, M_CTLBLK); 2159287499Smav 2160287499Smav flags = FREAD; 2161287499Smav value = ctl_get_opt(&cbe_lun->options, "readonly"); 2162287499Smav if (value == NULL || strcmp(value, "on") != 0) 2163287499Smav flags |= FWRITE; 2164287499Smav 2165287499Smavagain: 2166229997Sken NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, be_lun->dev_path, curthread); 2167229997Sken error = vn_open(&nd, &flags, 0, NULL); 2168287499Smav if ((error == EROFS || error == EACCES) && (flags & FWRITE)) { 2169287499Smav flags &= ~FWRITE; 2170287499Smav goto again; 2171287499Smav } 2172229997Sken if (error) { 2173229997Sken /* 2174229997Sken * This is the only reasonable guess we can make as far as 2175229997Sken * path if the user doesn't give us a fully qualified path. 2176229997Sken * If they want to specify a file, they need to specify the 2177229997Sken * full path. 2178229997Sken */ 2179229997Sken if (be_lun->dev_path[0] != '/') { 2180229997Sken char *dev_name; 2181229997Sken 2182287499Smav asprintf(&dev_name, M_CTLBLK, "/dev/%s", 2183287499Smav be_lun->dev_path); 2184287499Smav free(be_lun->dev_path, M_CTLBLK); 2185287499Smav be_lun->dev_path = dev_name; 2186287499Smav goto again; 2187229997Sken } 2188229997Sken snprintf(req->error_str, sizeof(req->error_str), 2189272911Smav "error opening %s: %d", be_lun->dev_path, error); 2190229997Sken return (error); 2191229997Sken } 2192287499Smav if (flags & FWRITE) 2193287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_READONLY; 2194287499Smav else 2195287499Smav cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 2196229997Sken 2197229997Sken NDFREE(&nd, NDF_ONLY_PNBUF); 2198229997Sken be_lun->vn = nd.ni_vp; 2199229997Sken 2200229997Sken /* We only support disks and files. */ 2201229997Sken if (vn_isdisk(be_lun->vn, &error)) { 2202229997Sken error = ctl_be_block_open_dev(be_lun, req); 2203229997Sken } else if (be_lun->vn->v_type == VREG) { 2204229997Sken error = ctl_be_block_open_file(be_lun, req); 2205229997Sken } else { 2206229997Sken error = EINVAL; 2207229997Sken snprintf(req->error_str, sizeof(req->error_str), 2208258871Strasz "%s is not a disk or plain file", be_lun->dev_path); 2209229997Sken } 2210229997Sken VOP_UNLOCK(be_lun->vn, 0); 2211229997Sken 2212286811Smav if (error != 0) 2213229997Sken ctl_be_block_close(be_lun); 2214287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2215287499Smav if (be_lun->dispatch != ctl_be_block_dispatch_dev) 2216287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2217287499Smav value = ctl_get_opt(&cbe_lun->options, "serseq"); 2218287499Smav if (value != NULL && strcmp(value, "on") == 0) 2219287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 2220287499Smav else if (value != NULL && strcmp(value, "read") == 0) 2221287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2222287499Smav else if (value != NULL && strcmp(value, "off") == 0) 2223287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2224229997Sken return (0); 2225229997Sken} 2226229997Sken 2227229997Skenstatic int 2228229997Skenctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2229229997Sken{ 2230287499Smav struct ctl_be_lun *cbe_lun; 2231229997Sken struct ctl_be_block_lun *be_lun; 2232229997Sken struct ctl_lun_create_params *params; 2233267481Smav char num_thread_str[16]; 2234229997Sken char tmpstr[32]; 2235267481Smav char *value; 2236278672Smav int retval, num_threads; 2237267481Smav int tmp_num_threads; 2238229997Sken 2239229997Sken params = &req->reqdata.create; 2240229997Sken retval = 0; 2241272911Smav req->status = CTL_LUN_OK; 2242229997Sken 2243229997Sken be_lun = malloc(sizeof(*be_lun), M_CTLBLK, M_ZERO | M_WAITOK); 2244287499Smav cbe_lun = &be_lun->cbe_lun; 2245287499Smav cbe_lun->be_lun = be_lun; 2246272911Smav be_lun->params = req->reqdata.create; 2247229997Sken be_lun->softc = softc; 2248229997Sken STAILQ_INIT(&be_lun->input_queue); 2249275474Smav STAILQ_INIT(&be_lun->config_read_queue); 2250229997Sken STAILQ_INIT(&be_lun->config_write_queue); 2251229997Sken STAILQ_INIT(&be_lun->datamove_queue); 2252229997Sken sprintf(be_lun->lunname, "cblk%d", softc->num_luns); 2253267877Smav mtx_init(&be_lun->io_lock, "cblk io lock", NULL, MTX_DEF); 2254267877Smav mtx_init(&be_lun->queue_lock, "cblk queue lock", NULL, MTX_DEF); 2255287499Smav ctl_init_opts(&cbe_lun->options, 2256268280Smav req->num_be_args, req->kern_be_args); 2257264886Smav be_lun->lun_zone = uma_zcreate(be_lun->lunname, CTLBLK_MAX_SEG, 2258256995Smav NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); 2259229997Sken if (be_lun->lun_zone == NULL) { 2260229997Sken snprintf(req->error_str, sizeof(req->error_str), 2261272911Smav "error allocating UMA zone"); 2262229997Sken goto bailout_error; 2263229997Sken } 2264229997Sken 2265229997Sken if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 2266287499Smav cbe_lun->lun_type = params->device_type; 2267229997Sken else 2268287499Smav cbe_lun->lun_type = T_DIRECT; 2269287499Smav be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED; 2270287621Smav cbe_lun->flags = 0; 2271287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2272287621Smav if (value != NULL) { 2273287621Smav if (strcmp(value, "primary") == 0) 2274287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2275287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2276287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2277229997Sken 2278287499Smav if (cbe_lun->lun_type == T_DIRECT) { 2279286811Smav be_lun->size_bytes = params->lun_size_bytes; 2280286811Smav if (params->blocksize_bytes != 0) 2281287499Smav cbe_lun->blocksize = params->blocksize_bytes; 2282286811Smav else 2283287499Smav cbe_lun->blocksize = 512; 2284287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2285287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2286287499Smav 0 : (be_lun->size_blocks - 1); 2287229997Sken 2288287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2289287621Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2290287621Smav retval = ctl_be_block_open(softc, be_lun, req); 2291287621Smav if (retval != 0) { 2292287621Smav retval = 0; 2293287621Smav req->status = CTL_LUN_WARNING; 2294287621Smav } 2295229997Sken } 2296287499Smav num_threads = cbb_num_threads; 2297229997Sken } else { 2298229997Sken num_threads = 1; 2299229997Sken } 2300229997Sken 2301229997Sken /* 2302229997Sken * XXX This searching loop might be refactored to be combined with 2303229997Sken * the loop above, 2304229997Sken */ 2305287499Smav value = ctl_get_opt(&cbe_lun->options, "num_threads"); 2306267481Smav if (value != NULL) { 2307267481Smav tmp_num_threads = strtol(value, NULL, 0); 2308229997Sken 2309267481Smav /* 2310267481Smav * We don't let the user specify less than one 2311267481Smav * thread, but hope he's clueful enough not to 2312267481Smav * specify 1000 threads. 2313267481Smav */ 2314267481Smav if (tmp_num_threads < 1) { 2315267481Smav snprintf(req->error_str, sizeof(req->error_str), 2316272911Smav "invalid number of threads %s", 2317272911Smav num_thread_str); 2318267481Smav goto bailout_error; 2319229997Sken } 2320267481Smav num_threads = tmp_num_threads; 2321229997Sken } 2322229997Sken 2323272911Smav if (be_lun->vn == NULL) 2324287499Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2325229997Sken /* Tell the user the blocksize we ended up using */ 2326272911Smav params->lun_size_bytes = be_lun->size_bytes; 2327287499Smav params->blocksize_bytes = cbe_lun->blocksize; 2328229997Sken if (params->flags & CTL_LUN_FLAG_ID_REQ) { 2329287499Smav cbe_lun->req_lun_id = params->req_lun_id; 2330287499Smav cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 2331229997Sken } else 2332287499Smav cbe_lun->req_lun_id = 0; 2333229997Sken 2334287499Smav cbe_lun->lun_shutdown = ctl_be_block_lun_shutdown; 2335287499Smav cbe_lun->lun_config_status = ctl_be_block_lun_config_status; 2336287499Smav cbe_lun->be = &ctl_be_block_driver; 2337229997Sken 2338229997Sken if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 2339229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 2340229997Sken softc->num_luns); 2341287499Smav strncpy((char *)cbe_lun->serial_num, tmpstr, 2342287499Smav MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 2343229997Sken 2344229997Sken /* Tell the user what we used for a serial number */ 2345229997Sken strncpy((char *)params->serial_num, tmpstr, 2346275953Smav MIN(sizeof(params->serial_num), sizeof(tmpstr))); 2347229997Sken } else { 2348287499Smav strncpy((char *)cbe_lun->serial_num, params->serial_num, 2349287499Smav MIN(sizeof(cbe_lun->serial_num), 2350229997Sken sizeof(params->serial_num))); 2351229997Sken } 2352229997Sken if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 2353229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 2354287499Smav strncpy((char *)cbe_lun->device_id, tmpstr, 2355287499Smav MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 2356229997Sken 2357229997Sken /* Tell the user what we used for a device ID */ 2358229997Sken strncpy((char *)params->device_id, tmpstr, 2359275953Smav MIN(sizeof(params->device_id), sizeof(tmpstr))); 2360229997Sken } else { 2361287499Smav strncpy((char *)cbe_lun->device_id, params->device_id, 2362287499Smav MIN(sizeof(cbe_lun->device_id), 2363275953Smav sizeof(params->device_id))); 2364229997Sken } 2365229997Sken 2366229997Sken TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_be_block_worker, be_lun); 2367229997Sken 2368229997Sken be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 2369229997Sken taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 2370229997Sken 2371229997Sken if (be_lun->io_taskqueue == NULL) { 2372229997Sken snprintf(req->error_str, sizeof(req->error_str), 2373272911Smav "unable to create taskqueue"); 2374229997Sken goto bailout_error; 2375229997Sken } 2376229997Sken 2377229997Sken /* 2378229997Sken * Note that we start the same number of threads by default for 2379229997Sken * both the file case and the block device case. For the file 2380229997Sken * case, we need multiple threads to allow concurrency, because the 2381229997Sken * vnode interface is designed to be a blocking interface. For the 2382229997Sken * block device case, ZFS zvols at least will block the caller's 2383229997Sken * context in many instances, and so we need multiple threads to 2384229997Sken * overcome that problem. Other block devices don't need as many 2385229997Sken * threads, but they shouldn't cause too many problems. 2386229997Sken * 2387229997Sken * If the user wants to just have a single thread for a block 2388229997Sken * device, he can specify that when the LUN is created, or change 2389229997Sken * the tunable/sysctl to alter the default number of threads. 2390229997Sken */ 2391229997Sken retval = taskqueue_start_threads(&be_lun->io_taskqueue, 2392229997Sken /*num threads*/num_threads, 2393229997Sken /*priority*/PWAIT, 2394229997Sken /*thread name*/ 2395229997Sken "%s taskq", be_lun->lunname); 2396229997Sken 2397229997Sken if (retval != 0) 2398229997Sken goto bailout_error; 2399229997Sken 2400229997Sken be_lun->num_threads = num_threads; 2401229997Sken 2402229997Sken mtx_lock(&softc->lock); 2403229997Sken softc->num_luns++; 2404229997Sken STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 2405229997Sken 2406229997Sken mtx_unlock(&softc->lock); 2407229997Sken 2408287499Smav retval = ctl_add_lun(&be_lun->cbe_lun); 2409229997Sken if (retval != 0) { 2410229997Sken mtx_lock(&softc->lock); 2411229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2412229997Sken links); 2413229997Sken softc->num_luns--; 2414229997Sken mtx_unlock(&softc->lock); 2415229997Sken snprintf(req->error_str, sizeof(req->error_str), 2416272911Smav "ctl_add_lun() returned error %d, see dmesg for " 2417272911Smav "details", retval); 2418229997Sken retval = 0; 2419229997Sken goto bailout_error; 2420229997Sken } 2421229997Sken 2422229997Sken mtx_lock(&softc->lock); 2423229997Sken 2424229997Sken /* 2425229997Sken * Tell the config_status routine that we're waiting so it won't 2426229997Sken * clean up the LUN in the event of an error. 2427229997Sken */ 2428229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2429229997Sken 2430229997Sken while (be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) { 2431229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2432229997Sken if (retval == EINTR) 2433229997Sken break; 2434229997Sken } 2435229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2436229997Sken 2437229997Sken if (be_lun->flags & CTL_BE_BLOCK_LUN_CONFIG_ERR) { 2438229997Sken snprintf(req->error_str, sizeof(req->error_str), 2439272911Smav "LUN configuration error, see dmesg for details"); 2440229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2441229997Sken links); 2442229997Sken softc->num_luns--; 2443229997Sken mtx_unlock(&softc->lock); 2444229997Sken goto bailout_error; 2445229997Sken } else { 2446287499Smav params->req_lun_id = cbe_lun->lun_id; 2447229997Sken } 2448229997Sken 2449229997Sken mtx_unlock(&softc->lock); 2450229997Sken 2451229997Sken be_lun->disk_stats = devstat_new_entry("cbb", params->req_lun_id, 2452287499Smav cbe_lun->blocksize, 2453229997Sken DEVSTAT_ALL_SUPPORTED, 2454287499Smav cbe_lun->lun_type 2455229997Sken | DEVSTAT_TYPE_IF_OTHER, 2456229997Sken DEVSTAT_PRIORITY_OTHER); 2457229997Sken 2458229997Sken return (retval); 2459229997Sken 2460229997Skenbailout_error: 2461229997Sken req->status = CTL_LUN_ERROR; 2462229997Sken 2463267429Smav if (be_lun->io_taskqueue != NULL) 2464267429Smav taskqueue_free(be_lun->io_taskqueue); 2465229997Sken ctl_be_block_close(be_lun); 2466267429Smav if (be_lun->dev_path != NULL) 2467267429Smav free(be_lun->dev_path, M_CTLBLK); 2468267429Smav if (be_lun->lun_zone != NULL) 2469267429Smav uma_zdestroy(be_lun->lun_zone); 2470287499Smav ctl_free_opts(&cbe_lun->options); 2471267877Smav mtx_destroy(&be_lun->queue_lock); 2472267877Smav mtx_destroy(&be_lun->io_lock); 2473229997Sken free(be_lun, M_CTLBLK); 2474229997Sken 2475229997Sken return (retval); 2476229997Sken} 2477229997Sken 2478229997Skenstatic int 2479229997Skenctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2480229997Sken{ 2481229997Sken struct ctl_lun_rm_params *params; 2482229997Sken struct ctl_be_block_lun *be_lun; 2483287670Smav struct ctl_be_lun *cbe_lun; 2484229997Sken int retval; 2485229997Sken 2486229997Sken params = &req->reqdata.rm; 2487229997Sken 2488229997Sken mtx_lock(&softc->lock); 2489229997Sken STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2490287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2491229997Sken break; 2492229997Sken } 2493229997Sken mtx_unlock(&softc->lock); 2494229997Sken 2495229997Sken if (be_lun == NULL) { 2496229997Sken snprintf(req->error_str, sizeof(req->error_str), 2497272911Smav "LUN %u is not managed by the block backend", 2498272911Smav params->lun_id); 2499229997Sken goto bailout_error; 2500229997Sken } 2501287670Smav cbe_lun = &be_lun->cbe_lun; 2502229997Sken 2503287670Smav retval = ctl_disable_lun(cbe_lun); 2504229997Sken if (retval != 0) { 2505229997Sken snprintf(req->error_str, sizeof(req->error_str), 2506272911Smav "error %d returned from ctl_disable_lun() for " 2507272911Smav "LUN %d", retval, params->lun_id); 2508229997Sken goto bailout_error; 2509287670Smav } 2510229997Sken 2511287670Smav if (be_lun->vn != NULL) { 2512287670Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2513287670Smav ctl_lun_offline(cbe_lun); 2514287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2515287670Smav ctl_be_block_close(be_lun); 2516229997Sken } 2517229997Sken 2518287670Smav retval = ctl_invalidate_lun(cbe_lun); 2519229997Sken if (retval != 0) { 2520229997Sken snprintf(req->error_str, sizeof(req->error_str), 2521272911Smav "error %d returned from ctl_invalidate_lun() for " 2522272911Smav "LUN %d", retval, params->lun_id); 2523229997Sken goto bailout_error; 2524229997Sken } 2525229997Sken 2526229997Sken mtx_lock(&softc->lock); 2527229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2528229997Sken while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2529229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2530229997Sken if (retval == EINTR) 2531229997Sken break; 2532229997Sken } 2533229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2534229997Sken 2535229997Sken if ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2536229997Sken snprintf(req->error_str, sizeof(req->error_str), 2537272911Smav "interrupted waiting for LUN to be freed"); 2538229997Sken mtx_unlock(&softc->lock); 2539229997Sken goto bailout_error; 2540229997Sken } 2541229997Sken 2542229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, links); 2543229997Sken 2544229997Sken softc->num_luns--; 2545229997Sken mtx_unlock(&softc->lock); 2546229997Sken 2547287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2548229997Sken taskqueue_free(be_lun->io_taskqueue); 2549229997Sken 2550229997Sken if (be_lun->disk_stats != NULL) 2551229997Sken devstat_remove_entry(be_lun->disk_stats); 2552229997Sken 2553229997Sken uma_zdestroy(be_lun->lun_zone); 2554229997Sken 2555287670Smav ctl_free_opts(&cbe_lun->options); 2556229997Sken free(be_lun->dev_path, M_CTLBLK); 2557267877Smav mtx_destroy(&be_lun->queue_lock); 2558267877Smav mtx_destroy(&be_lun->io_lock); 2559229997Sken free(be_lun, M_CTLBLK); 2560229997Sken 2561229997Sken req->status = CTL_LUN_OK; 2562229997Sken 2563229997Sken return (0); 2564229997Sken 2565229997Skenbailout_error: 2566229997Sken 2567229997Sken req->status = CTL_LUN_ERROR; 2568229997Sken 2569229997Sken return (0); 2570229997Sken} 2571229997Sken 2572232604Straszstatic int 2573232604Straszctl_be_block_modify_file(struct ctl_be_block_lun *be_lun, 2574232604Strasz struct ctl_lun_req *req) 2575232604Strasz{ 2576287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2577232604Strasz struct vattr vattr; 2578232604Strasz int error; 2579272911Smav struct ctl_lun_create_params *params = &be_lun->params; 2580232604Strasz 2581232604Strasz if (params->lun_size_bytes != 0) { 2582232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2583232604Strasz } else { 2584271794Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 2585232604Strasz error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 2586271794Smav VOP_UNLOCK(be_lun->vn, 0); 2587232604Strasz if (error != 0) { 2588232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2589232604Strasz "error calling VOP_GETATTR() for file %s", 2590232604Strasz be_lun->dev_path); 2591232604Strasz return (error); 2592232604Strasz } 2593232604Strasz be_lun->size_bytes = vattr.va_size; 2594232604Strasz } 2595287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2596287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2597287499Smav 0 : (be_lun->size_blocks - 1); 2598232604Strasz return (0); 2599232604Strasz} 2600232604Strasz 2601232604Straszstatic int 2602232604Straszctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun, 2603232604Strasz struct ctl_lun_req *req) 2604232604Strasz{ 2605287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2606272911Smav struct ctl_lun_create_params *params = &be_lun->params; 2607287664Smav struct cdevsw *csw; 2608287664Smav struct cdev *dev; 2609232604Strasz uint64_t size_bytes; 2610287664Smav int error, ref; 2611232604Strasz 2612287664Smav csw = devvn_refthread(be_lun->vn, &dev, &ref); 2613287664Smav if (csw == NULL) 2614287664Smav return (ENXIO); 2615287664Smav if (csw->d_ioctl == NULL) { 2616287664Smav dev_relthread(dev, ref); 2617232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2618272911Smav "no d_ioctl for device %s!", be_lun->dev_path); 2619232604Strasz return (ENODEV); 2620232604Strasz } 2621232604Strasz 2622287664Smav error = csw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&size_bytes, FREAD, 2623287664Smav curthread); 2624287664Smav dev_relthread(dev, ref); 2625232604Strasz if (error) { 2626232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2627272911Smav "error %d returned for DIOCGMEDIASIZE ioctl " 2628272911Smav "on %s!", error, be_lun->dev_path); 2629232604Strasz return (error); 2630232604Strasz } 2631232604Strasz 2632232604Strasz if (params->lun_size_bytes != 0) { 2633232604Strasz if (params->lun_size_bytes > size_bytes) { 2634232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2635272911Smav "requested LUN size %ju > backing device " 2636272911Smav "size %ju", 2637232604Strasz (uintmax_t)params->lun_size_bytes, 2638232604Strasz (uintmax_t)size_bytes); 2639232604Strasz return (EINVAL); 2640232604Strasz } 2641232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2642232604Strasz } else { 2643232604Strasz be_lun->size_bytes = size_bytes; 2644232604Strasz } 2645287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2646287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2647287499Smav 0 : (be_lun->size_blocks - 1); 2648232604Strasz return (0); 2649232604Strasz} 2650232604Strasz 2651232604Straszstatic int 2652232604Straszctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2653232604Strasz{ 2654232604Strasz struct ctl_lun_modify_params *params; 2655232604Strasz struct ctl_be_block_lun *be_lun; 2656287500Smav struct ctl_be_lun *cbe_lun; 2657287621Smav char *value; 2658271794Smav uint64_t oldsize; 2659287621Smav int error, wasprim; 2660232604Strasz 2661232604Strasz params = &req->reqdata.modify; 2662232604Strasz 2663232604Strasz mtx_lock(&softc->lock); 2664232604Strasz STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2665287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2666232604Strasz break; 2667232604Strasz } 2668232604Strasz mtx_unlock(&softc->lock); 2669232604Strasz 2670232604Strasz if (be_lun == NULL) { 2671232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2672272911Smav "LUN %u is not managed by the block backend", 2673272911Smav params->lun_id); 2674232604Strasz goto bailout_error; 2675232604Strasz } 2676287500Smav cbe_lun = &be_lun->cbe_lun; 2677232604Strasz 2678287500Smav if (params->lun_size_bytes != 0) 2679287500Smav be_lun->params.lun_size_bytes = params->lun_size_bytes; 2680287500Smav ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 2681232604Strasz 2682287621Smav wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 2683287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2684287621Smav if (value != NULL) { 2685287621Smav if (strcmp(value, "primary") == 0) 2686287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2687287621Smav else 2688287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2689287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2690287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2691232604Strasz else 2692287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2693287621Smav if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 2694287621Smav if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 2695287621Smav ctl_lun_primary(cbe_lun); 2696287621Smav else 2697287621Smav ctl_lun_secondary(cbe_lun); 2698287621Smav } 2699232604Strasz 2700287621Smav oldsize = be_lun->size_blocks; 2701287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2702287621Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2703287621Smav if (be_lun->vn == NULL) 2704287621Smav error = ctl_be_block_open(softc, be_lun, req); 2705287621Smav else if (vn_isdisk(be_lun->vn, &error)) 2706287621Smav error = ctl_be_block_modify_dev(be_lun, req); 2707287621Smav else if (be_lun->vn->v_type == VREG) 2708287621Smav error = ctl_be_block_modify_file(be_lun, req); 2709287621Smav else 2710287621Smav error = EINVAL; 2711287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) && 2712287621Smav be_lun->vn != NULL) { 2713287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE; 2714287621Smav ctl_lun_online(cbe_lun); 2715287621Smav } 2716287621Smav } else { 2717287621Smav if (be_lun->vn != NULL) { 2718287621Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2719287621Smav ctl_lun_offline(cbe_lun); 2720287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 2721287621Smav error = ctl_be_block_close(be_lun); 2722287621Smav } else 2723287621Smav error = 0; 2724287621Smav } 2725287499Smav if (be_lun->size_blocks != oldsize) 2726287500Smav ctl_lun_capacity_changed(cbe_lun); 2727232604Strasz 2728232604Strasz /* Tell the user the exact size we ended up using */ 2729232604Strasz params->lun_size_bytes = be_lun->size_bytes; 2730232604Strasz 2731272911Smav req->status = error ? CTL_LUN_WARNING : CTL_LUN_OK; 2732232604Strasz return (0); 2733232604Strasz 2734232604Straszbailout_error: 2735232604Strasz req->status = CTL_LUN_ERROR; 2736232604Strasz return (0); 2737232604Strasz} 2738232604Strasz 2739229997Skenstatic void 2740229997Skenctl_be_block_lun_shutdown(void *be_lun) 2741229997Sken{ 2742229997Sken struct ctl_be_block_lun *lun; 2743229997Sken struct ctl_be_block_softc *softc; 2744229997Sken 2745229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2746229997Sken 2747229997Sken softc = lun->softc; 2748229997Sken 2749229997Sken mtx_lock(&softc->lock); 2750229997Sken lun->flags |= CTL_BE_BLOCK_LUN_UNCONFIGURED; 2751229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2752229997Sken wakeup(lun); 2753229997Sken mtx_unlock(&softc->lock); 2754229997Sken 2755229997Sken} 2756229997Sken 2757229997Skenstatic void 2758229997Skenctl_be_block_lun_config_status(void *be_lun, ctl_lun_config_status status) 2759229997Sken{ 2760229997Sken struct ctl_be_block_lun *lun; 2761229997Sken struct ctl_be_block_softc *softc; 2762229997Sken 2763229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2764229997Sken softc = lun->softc; 2765229997Sken 2766229997Sken if (status == CTL_LUN_CONFIG_OK) { 2767229997Sken mtx_lock(&softc->lock); 2768229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2769229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2770229997Sken wakeup(lun); 2771229997Sken mtx_unlock(&softc->lock); 2772229997Sken 2773229997Sken /* 2774229997Sken * We successfully added the LUN, attempt to enable it. 2775229997Sken */ 2776287499Smav if (ctl_enable_lun(&lun->cbe_lun) != 0) { 2777229997Sken printf("%s: ctl_enable_lun() failed!\n", __func__); 2778287499Smav if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 2779229997Sken printf("%s: ctl_invalidate_lun() failed!\n", 2780229997Sken __func__); 2781229997Sken } 2782229997Sken } 2783229997Sken 2784229997Sken return; 2785229997Sken } 2786229997Sken 2787229997Sken 2788229997Sken mtx_lock(&softc->lock); 2789229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2790229997Sken lun->flags |= CTL_BE_BLOCK_LUN_CONFIG_ERR; 2791229997Sken wakeup(lun); 2792229997Sken mtx_unlock(&softc->lock); 2793229997Sken} 2794229997Sken 2795229997Sken 2796229997Skenstatic int 2797229997Skenctl_be_block_config_write(union ctl_io *io) 2798229997Sken{ 2799229997Sken struct ctl_be_block_lun *be_lun; 2800287499Smav struct ctl_be_lun *cbe_lun; 2801229997Sken int retval; 2802229997Sken 2803229997Sken retval = 0; 2804229997Sken 2805229997Sken DPRINTF("entered\n"); 2806229997Sken 2807287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2808229997Sken CTL_PRIV_BACKEND_LUN].ptr; 2809287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2810229997Sken 2811229997Sken switch (io->scsiio.cdb[0]) { 2812229997Sken case SYNCHRONIZE_CACHE: 2813229997Sken case SYNCHRONIZE_CACHE_16: 2814264274Smav case WRITE_SAME_10: 2815264274Smav case WRITE_SAME_16: 2816264274Smav case UNMAP: 2817229997Sken /* 2818229997Sken * The upper level CTL code will filter out any CDBs with 2819229997Sken * the immediate bit set and return the proper error. 2820229997Sken * 2821229997Sken * We don't really need to worry about what LBA range the 2822229997Sken * user asked to be synced out. When they issue a sync 2823229997Sken * cache command, we'll sync out the whole thing. 2824229997Sken */ 2825267877Smav mtx_lock(&be_lun->queue_lock); 2826229997Sken STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->io_hdr, 2827229997Sken links); 2828267877Smav mtx_unlock(&be_lun->queue_lock); 2829229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 2830229997Sken break; 2831229997Sken case START_STOP_UNIT: { 2832229997Sken struct scsi_start_stop_unit *cdb; 2833229997Sken 2834229997Sken cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 2835229997Sken 2836229997Sken if (cdb->how & SSS_START) 2837287499Smav retval = ctl_start_lun(cbe_lun); 2838229997Sken else { 2839287499Smav retval = ctl_stop_lun(cbe_lun); 2840229997Sken /* 2841229997Sken * XXX KDM Copan-specific offline behavior. 2842229997Sken * Figure out a reasonable way to port this? 2843229997Sken */ 2844229997Sken#ifdef NEEDTOPORT 2845229997Sken if ((retval == 0) 2846229997Sken && (cdb->byte2 & SSS_ONOFFLINE)) 2847287499Smav retval = ctl_lun_offline(cbe_lun); 2848229997Sken#endif 2849229997Sken } 2850229997Sken 2851229997Sken /* 2852229997Sken * In general, the above routines should not fail. They 2853229997Sken * just set state for the LUN. So we've got something 2854229997Sken * pretty wrong here if we can't start or stop the LUN. 2855229997Sken */ 2856229997Sken if (retval != 0) { 2857229997Sken ctl_set_internal_failure(&io->scsiio, 2858229997Sken /*sks_valid*/ 1, 2859229997Sken /*retry_count*/ 0xf051); 2860229997Sken retval = CTL_RETVAL_COMPLETE; 2861229997Sken } else { 2862229997Sken ctl_set_success(&io->scsiio); 2863229997Sken } 2864229997Sken ctl_config_write_done(io); 2865229997Sken break; 2866229997Sken } 2867229997Sken default: 2868229997Sken ctl_set_invalid_opcode(&io->scsiio); 2869229997Sken ctl_config_write_done(io); 2870229997Sken retval = CTL_RETVAL_COMPLETE; 2871229997Sken break; 2872229997Sken } 2873229997Sken 2874229997Sken return (retval); 2875229997Sken} 2876229997Sken 2877229997Skenstatic int 2878229997Skenctl_be_block_config_read(union ctl_io *io) 2879229997Sken{ 2880275474Smav struct ctl_be_block_lun *be_lun; 2881287499Smav struct ctl_be_lun *cbe_lun; 2882275474Smav int retval = 0; 2883275474Smav 2884275474Smav DPRINTF("entered\n"); 2885275474Smav 2886287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2887275474Smav CTL_PRIV_BACKEND_LUN].ptr; 2888287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2889275474Smav 2890275474Smav switch (io->scsiio.cdb[0]) { 2891275474Smav case SERVICE_ACTION_IN: 2892275474Smav if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 2893275474Smav mtx_lock(&be_lun->queue_lock); 2894275474Smav STAILQ_INSERT_TAIL(&be_lun->config_read_queue, 2895275474Smav &io->io_hdr, links); 2896275474Smav mtx_unlock(&be_lun->queue_lock); 2897275474Smav taskqueue_enqueue(be_lun->io_taskqueue, 2898275474Smav &be_lun->io_task); 2899275474Smav retval = CTL_RETVAL_QUEUED; 2900275474Smav break; 2901275474Smav } 2902275474Smav ctl_set_invalid_field(&io->scsiio, 2903275474Smav /*sks_valid*/ 1, 2904275474Smav /*command*/ 1, 2905275474Smav /*field*/ 1, 2906275474Smav /*bit_valid*/ 1, 2907275474Smav /*bit*/ 4); 2908275474Smav ctl_config_read_done(io); 2909275474Smav retval = CTL_RETVAL_COMPLETE; 2910275474Smav break; 2911275474Smav default: 2912275474Smav ctl_set_invalid_opcode(&io->scsiio); 2913275474Smav ctl_config_read_done(io); 2914275474Smav retval = CTL_RETVAL_COMPLETE; 2915275474Smav break; 2916275474Smav } 2917275474Smav 2918275474Smav return (retval); 2919229997Sken} 2920229997Sken 2921229997Skenstatic int 2922229997Skenctl_be_block_lun_info(void *be_lun, struct sbuf *sb) 2923229997Sken{ 2924229997Sken struct ctl_be_block_lun *lun; 2925229997Sken int retval; 2926229997Sken 2927229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2928229997Sken retval = 0; 2929229997Sken 2930268283Smav retval = sbuf_printf(sb, "\t<num_threads>"); 2931229997Sken 2932229997Sken if (retval != 0) 2933229997Sken goto bailout; 2934229997Sken 2935229997Sken retval = sbuf_printf(sb, "%d", lun->num_threads); 2936229997Sken 2937229997Sken if (retval != 0) 2938229997Sken goto bailout; 2939229997Sken 2940268283Smav retval = sbuf_printf(sb, "</num_threads>\n"); 2941229997Sken 2942229997Skenbailout: 2943229997Sken 2944229997Sken return (retval); 2945229997Sken} 2946229997Sken 2947274154Smavstatic uint64_t 2948274154Smavctl_be_block_lun_attr(void *be_lun, const char *attrname) 2949274154Smav{ 2950274154Smav struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)be_lun; 2951274154Smav 2952274154Smav if (lun->getattr == NULL) 2953274154Smav return (UINT64_MAX); 2954274154Smav return (lun->getattr(lun, attrname)); 2955274154Smav} 2956274154Smav 2957229997Skenint 2958229997Skenctl_be_block_init(void) 2959229997Sken{ 2960229997Sken struct ctl_be_block_softc *softc; 2961229997Sken int retval; 2962229997Sken 2963229997Sken softc = &backend_block_softc; 2964229997Sken retval = 0; 2965229997Sken 2966267877Smav mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF); 2967264020Strasz beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io), 2968264020Strasz NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 2969229997Sken STAILQ_INIT(&softc->lun_list); 2970229997Sken 2971229997Sken return (retval); 2972229997Sken} 2973