ctl_backend_block.c revision 287621
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 287621 2015-09-10 12:40:31Z 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_devdata { 130229997Sken struct cdev *cdev; 131229997Sken struct cdevsw *csw; 132229997Sken int dev_ref; 133229997Sken}; 134229997Sken 135229997Skenstruct ctl_be_block_filedata { 136229997Sken struct ucred *cred; 137229997Sken}; 138229997Sken 139229997Skenunion ctl_be_block_bedata { 140229997Sken struct ctl_be_block_devdata dev; 141229997Sken struct ctl_be_block_filedata file; 142229997Sken}; 143229997Sken 144229997Skenstruct ctl_be_block_io; 145229997Skenstruct ctl_be_block_lun; 146229997Sken 147229997Skentypedef void (*cbb_dispatch_t)(struct ctl_be_block_lun *be_lun, 148229997Sken struct ctl_be_block_io *beio); 149274154Smavtypedef uint64_t (*cbb_getattr_t)(struct ctl_be_block_lun *be_lun, 150274154Smav const char *attrname); 151229997Sken 152229997Sken/* 153229997Sken * Backend LUN structure. There is a 1:1 mapping between a block device 154229997Sken * and a backend block LUN, and between a backend block LUN and a CTL LUN. 155229997Sken */ 156229997Skenstruct ctl_be_block_lun { 157272911Smav struct ctl_lun_create_params params; 158229997Sken char lunname[32]; 159229997Sken char *dev_path; 160229997Sken ctl_be_block_type dev_type; 161229997Sken struct vnode *vn; 162229997Sken union ctl_be_block_bedata backend; 163229997Sken cbb_dispatch_t dispatch; 164229997Sken cbb_dispatch_t lun_flush; 165264274Smav cbb_dispatch_t unmap; 166275474Smav cbb_dispatch_t get_lba_status; 167274154Smav cbb_getattr_t getattr; 168229997Sken uma_zone_t lun_zone; 169229997Sken uint64_t size_blocks; 170229997Sken uint64_t size_bytes; 171229997Sken struct ctl_be_block_softc *softc; 172229997Sken struct devstat *disk_stats; 173229997Sken ctl_be_block_lun_flags flags; 174229997Sken STAILQ_ENTRY(ctl_be_block_lun) links; 175287499Smav struct ctl_be_lun cbe_lun; 176229997Sken struct taskqueue *io_taskqueue; 177229997Sken struct task io_task; 178229997Sken int num_threads; 179229997Sken STAILQ_HEAD(, ctl_io_hdr) input_queue; 180275474Smav STAILQ_HEAD(, ctl_io_hdr) config_read_queue; 181229997Sken STAILQ_HEAD(, ctl_io_hdr) config_write_queue; 182229997Sken STAILQ_HEAD(, ctl_io_hdr) datamove_queue; 183267877Smav struct mtx_padalign io_lock; 184267877Smav struct mtx_padalign queue_lock; 185229997Sken}; 186229997Sken 187229997Sken/* 188229997Sken * Overall softc structure for the block backend module. 189229997Sken */ 190229997Skenstruct ctl_be_block_softc { 191229997Sken struct mtx lock; 192229997Sken int num_luns; 193229997Sken STAILQ_HEAD(, ctl_be_block_lun) lun_list; 194229997Sken}; 195229997Sken 196229997Skenstatic struct ctl_be_block_softc backend_block_softc; 197229997Sken 198229997Sken/* 199229997Sken * Per-I/O information. 200229997Sken */ 201229997Skenstruct ctl_be_block_io { 202229997Sken union ctl_io *io; 203229997Sken struct ctl_sg_entry sg_segs[CTLBLK_MAX_SEGS]; 204229997Sken struct iovec xiovecs[CTLBLK_MAX_SEGS]; 205229997Sken int bio_cmd; 206229997Sken int num_segs; 207229997Sken int num_bios_sent; 208229997Sken int num_bios_done; 209229997Sken int send_complete; 210229997Sken int num_errors; 211229997Sken struct bintime ds_t0; 212229997Sken devstat_tag_type ds_tag_type; 213229997Sken devstat_trans_flags ds_trans_type; 214229997Sken uint64_t io_len; 215229997Sken uint64_t io_offset; 216286353Smav int io_arg; 217229997Sken struct ctl_be_block_softc *softc; 218229997Sken struct ctl_be_block_lun *lun; 219264274Smav void (*beio_cont)(struct ctl_be_block_io *beio); /* to continue processing */ 220229997Sken}; 221229997Sken 222287621Smavextern struct ctl_softc *control_softc; 223287621Smav 224229997Skenstatic int cbb_num_threads = 14; 225229997SkenSYSCTL_NODE(_kern_cam_ctl, OID_AUTO, block, CTLFLAG_RD, 0, 226229997Sken "CAM Target Layer Block Backend"); 227267992ShselaskySYSCTL_INT(_kern_cam_ctl_block, OID_AUTO, num_threads, CTLFLAG_RWTUN, 228229997Sken &cbb_num_threads, 0, "Number of threads per backing file"); 229229997Sken 230229997Skenstatic struct ctl_be_block_io *ctl_alloc_beio(struct ctl_be_block_softc *softc); 231229997Skenstatic void ctl_free_beio(struct ctl_be_block_io *beio); 232229997Skenstatic void ctl_complete_beio(struct ctl_be_block_io *beio); 233229997Skenstatic int ctl_be_block_move_done(union ctl_io *io); 234229997Skenstatic void ctl_be_block_biodone(struct bio *bio); 235229997Skenstatic void ctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 236229997Sken struct ctl_be_block_io *beio); 237229997Skenstatic void ctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 238229997Sken struct ctl_be_block_io *beio); 239275474Smavstatic void ctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 240275474Smav struct ctl_be_block_io *beio); 241275481Smavstatic uint64_t ctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, 242275481Smav const char *attrname); 243229997Skenstatic void ctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 244229997Sken struct ctl_be_block_io *beio); 245264274Smavstatic void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 246264274Smav struct ctl_be_block_io *beio); 247229997Skenstatic void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 248229997Sken struct ctl_be_block_io *beio); 249274154Smavstatic uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, 250274154Smav const char *attrname); 251275474Smavstatic void ctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 252275474Smav union ctl_io *io); 253229997Skenstatic void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 254229997Sken union ctl_io *io); 255229997Skenstatic void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 256229997Sken union ctl_io *io); 257229997Skenstatic void ctl_be_block_worker(void *context, int pending); 258229997Skenstatic int ctl_be_block_submit(union ctl_io *io); 259229997Skenstatic int ctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 260229997Sken int flag, struct thread *td); 261229997Skenstatic int ctl_be_block_open_file(struct ctl_be_block_lun *be_lun, 262229997Sken struct ctl_lun_req *req); 263229997Skenstatic int ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, 264229997Sken struct ctl_lun_req *req); 265229997Skenstatic int ctl_be_block_close(struct ctl_be_block_lun *be_lun); 266229997Skenstatic int ctl_be_block_open(struct ctl_be_block_softc *softc, 267229997Sken struct ctl_be_block_lun *be_lun, 268229997Sken struct ctl_lun_req *req); 269229997Skenstatic int ctl_be_block_create(struct ctl_be_block_softc *softc, 270229997Sken struct ctl_lun_req *req); 271229997Skenstatic int ctl_be_block_rm(struct ctl_be_block_softc *softc, 272229997Sken struct ctl_lun_req *req); 273232604Straszstatic int ctl_be_block_modify_file(struct ctl_be_block_lun *be_lun, 274232604Strasz struct ctl_lun_req *req); 275232604Straszstatic int ctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun, 276232604Strasz struct ctl_lun_req *req); 277232604Straszstatic int ctl_be_block_modify(struct ctl_be_block_softc *softc, 278232604Strasz struct ctl_lun_req *req); 279229997Skenstatic void ctl_be_block_lun_shutdown(void *be_lun); 280229997Skenstatic void ctl_be_block_lun_config_status(void *be_lun, 281229997Sken ctl_lun_config_status status); 282229997Skenstatic int ctl_be_block_config_write(union ctl_io *io); 283229997Skenstatic int ctl_be_block_config_read(union ctl_io *io); 284229997Skenstatic int ctl_be_block_lun_info(void *be_lun, struct sbuf *sb); 285274154Smavstatic uint64_t ctl_be_block_lun_attr(void *be_lun, const char *attrname); 286229997Skenint ctl_be_block_init(void); 287229997Sken 288229997Skenstatic struct ctl_backend_driver ctl_be_block_driver = 289229997Sken{ 290230334Sken .name = "block", 291230334Sken .flags = CTL_BE_FLAG_HAS_CONFIG, 292230334Sken .init = ctl_be_block_init, 293230334Sken .data_submit = ctl_be_block_submit, 294230334Sken .data_move_done = ctl_be_block_move_done, 295230334Sken .config_read = ctl_be_block_config_read, 296230334Sken .config_write = ctl_be_block_config_write, 297230334Sken .ioctl = ctl_be_block_ioctl, 298274154Smav .lun_info = ctl_be_block_lun_info, 299274154Smav .lun_attr = ctl_be_block_lun_attr 300229997Sken}; 301229997Sken 302229997SkenMALLOC_DEFINE(M_CTLBLK, "ctlblk", "Memory used for CTL block backend"); 303229997SkenCTL_BACKEND_DECLARE(cbb, ctl_be_block_driver); 304229997Sken 305264020Straszstatic uma_zone_t beio_zone; 306264020Strasz 307229997Skenstatic struct ctl_be_block_io * 308229997Skenctl_alloc_beio(struct ctl_be_block_softc *softc) 309229997Sken{ 310229997Sken struct ctl_be_block_io *beio; 311229997Sken 312264020Strasz beio = uma_zalloc(beio_zone, M_WAITOK | M_ZERO); 313264020Strasz beio->softc = softc; 314229997Sken return (beio); 315229997Sken} 316229997Sken 317229997Skenstatic void 318229997Skenctl_free_beio(struct ctl_be_block_io *beio) 319229997Sken{ 320229997Sken int duplicate_free; 321229997Sken int i; 322229997Sken 323229997Sken duplicate_free = 0; 324229997Sken 325229997Sken for (i = 0; i < beio->num_segs; i++) { 326229997Sken if (beio->sg_segs[i].addr == NULL) 327229997Sken duplicate_free++; 328229997Sken 329229997Sken uma_zfree(beio->lun->lun_zone, beio->sg_segs[i].addr); 330229997Sken beio->sg_segs[i].addr = NULL; 331267537Smav 332267537Smav /* For compare we had two equal S/G lists. */ 333267537Smav if (ARGS(beio->io)->flags & CTL_LLF_COMPARE) { 334267537Smav uma_zfree(beio->lun->lun_zone, 335267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr); 336267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = NULL; 337267537Smav } 338229997Sken } 339229997Sken 340229997Sken if (duplicate_free > 0) { 341229997Sken printf("%s: %d duplicate frees out of %d segments\n", __func__, 342229997Sken duplicate_free, beio->num_segs); 343229997Sken } 344229997Sken 345264020Strasz uma_zfree(beio_zone, beio); 346229997Sken} 347229997Sken 348229997Skenstatic void 349229997Skenctl_complete_beio(struct ctl_be_block_io *beio) 350229997Sken{ 351267877Smav union ctl_io *io = beio->io; 352229997Sken 353264274Smav if (beio->beio_cont != NULL) { 354264274Smav beio->beio_cont(beio); 355264274Smav } else { 356264274Smav ctl_free_beio(beio); 357267537Smav ctl_data_submit_done(io); 358264274Smav } 359229997Sken} 360229997Sken 361229997Skenstatic int 362229997Skenctl_be_block_move_done(union ctl_io *io) 363229997Sken{ 364229997Sken struct ctl_be_block_io *beio; 365229997Sken struct ctl_be_block_lun *be_lun; 366267537Smav struct ctl_lba_len_flags *lbalen; 367229997Sken#ifdef CTL_TIME_IO 368229997Sken struct bintime cur_bt; 369267537Smav#endif 370267537Smav int i; 371229997Sken 372267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 373229997Sken be_lun = beio->lun; 374229997Sken 375229997Sken DPRINTF("entered\n"); 376229997Sken 377229997Sken#ifdef CTL_TIME_IO 378229997Sken getbintime(&cur_bt); 379229997Sken bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 380229997Sken bintime_add(&io->io_hdr.dma_bt, &cur_bt); 381229997Sken io->io_hdr.num_dmas++; 382229997Sken#endif 383267537Smav io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 384229997Sken 385229997Sken /* 386229997Sken * We set status at this point for read commands, and write 387229997Sken * commands with errors. 388229997Sken */ 389275058Smav if (io->io_hdr.flags & CTL_FLAG_ABORT) { 390275058Smav ; 391275058Smav } else if ((io->io_hdr.port_status == 0) && 392267537Smav ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 393267537Smav lbalen = ARGS(beio->io); 394267537Smav if (lbalen->flags & CTL_LLF_READ) { 395267537Smav ctl_set_success(&io->scsiio); 396267537Smav } else if (lbalen->flags & CTL_LLF_COMPARE) { 397267537Smav /* We have two data blocks ready for comparison. */ 398267537Smav for (i = 0; i < beio->num_segs; i++) { 399267537Smav if (memcmp(beio->sg_segs[i].addr, 400267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr, 401267537Smav beio->sg_segs[i].len) != 0) 402267537Smav break; 403267537Smav } 404267537Smav if (i < beio->num_segs) 405267537Smav ctl_set_sense(&io->scsiio, 406267537Smav /*current_error*/ 1, 407267537Smav /*sense_key*/ SSD_KEY_MISCOMPARE, 408267537Smav /*asc*/ 0x1D, 409267537Smav /*ascq*/ 0x00, 410267537Smav SSD_ELEM_NONE); 411267537Smav else 412267537Smav ctl_set_success(&io->scsiio); 413267537Smav } 414275058Smav } else if ((io->io_hdr.port_status != 0) && 415275058Smav ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 416275058Smav (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 417229997Sken /* 418229997Sken * For hardware error sense keys, the sense key 419229997Sken * specific value is defined to be a retry count, 420229997Sken * but we use it to pass back an internal FETD 421229997Sken * error code. XXX KDM Hopefully the FETD is only 422229997Sken * using 16 bits for an error code, since that's 423229997Sken * all the space we have in the sks field. 424229997Sken */ 425229997Sken ctl_set_internal_failure(&io->scsiio, 426229997Sken /*sks_valid*/ 1, 427229997Sken /*retry_count*/ 428229997Sken io->io_hdr.port_status); 429229997Sken } 430229997Sken 431229997Sken /* 432229997Sken * If this is a read, or a write with errors, it is done. 433229997Sken */ 434229997Sken if ((beio->bio_cmd == BIO_READ) 435229997Sken || ((io->io_hdr.flags & CTL_FLAG_ABORT) != 0) 436229997Sken || ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE)) { 437229997Sken ctl_complete_beio(beio); 438229997Sken return (0); 439229997Sken } 440229997Sken 441229997Sken /* 442229997Sken * At this point, we have a write and the DMA completed 443229997Sken * successfully. We now have to queue it to the task queue to 444229997Sken * execute the backend I/O. That is because we do blocking 445229997Sken * memory allocations, and in the file backing case, blocking I/O. 446229997Sken * This move done routine is generally called in the SIM's 447229997Sken * interrupt context, and therefore we cannot block. 448229997Sken */ 449267877Smav mtx_lock(&be_lun->queue_lock); 450229997Sken /* 451229997Sken * XXX KDM make sure that links is okay to use at this point. 452229997Sken * Otherwise, we either need to add another field to ctl_io_hdr, 453229997Sken * or deal with resource allocation here. 454229997Sken */ 455229997Sken STAILQ_INSERT_TAIL(&be_lun->datamove_queue, &io->io_hdr, links); 456267877Smav mtx_unlock(&be_lun->queue_lock); 457229997Sken 458229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 459229997Sken 460229997Sken return (0); 461229997Sken} 462229997Sken 463229997Skenstatic void 464229997Skenctl_be_block_biodone(struct bio *bio) 465229997Sken{ 466229997Sken struct ctl_be_block_io *beio; 467229997Sken struct ctl_be_block_lun *be_lun; 468229997Sken union ctl_io *io; 469261538Smav int error; 470229997Sken 471229997Sken beio = bio->bio_caller1; 472229997Sken be_lun = beio->lun; 473229997Sken io = beio->io; 474229997Sken 475229997Sken DPRINTF("entered\n"); 476229997Sken 477261538Smav error = bio->bio_error; 478267877Smav mtx_lock(&be_lun->io_lock); 479261538Smav if (error != 0) 480229997Sken beio->num_errors++; 481229997Sken 482229997Sken beio->num_bios_done++; 483229997Sken 484229997Sken /* 485229997Sken * XXX KDM will this cause WITNESS to complain? Holding a lock 486229997Sken * during the free might cause it to complain. 487229997Sken */ 488229997Sken g_destroy_bio(bio); 489229997Sken 490229997Sken /* 491229997Sken * If the send complete bit isn't set, or we aren't the last I/O to 492229997Sken * complete, then we're done. 493229997Sken */ 494229997Sken if ((beio->send_complete == 0) 495229997Sken || (beio->num_bios_done < beio->num_bios_sent)) { 496267877Smav mtx_unlock(&be_lun->io_lock); 497229997Sken return; 498229997Sken } 499229997Sken 500229997Sken /* 501229997Sken * At this point, we've verified that we are the last I/O to 502229997Sken * complete, so it's safe to drop the lock. 503229997Sken */ 504267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 505267877Smav beio->ds_tag_type, beio->ds_trans_type, 506267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 507267877Smav mtx_unlock(&be_lun->io_lock); 508229997Sken 509229997Sken /* 510229997Sken * If there are any errors from the backing device, we fail the 511229997Sken * entire I/O with a medium error. 512229997Sken */ 513229997Sken if (beio->num_errors > 0) { 514261538Smav if (error == EOPNOTSUPP) { 515261538Smav ctl_set_invalid_opcode(&io->scsiio); 516282565Smav } else if (error == ENOSPC || error == EDQUOT) { 517273809Smav ctl_set_space_alloc_fail(&io->scsiio); 518261538Smav } else if (beio->bio_cmd == BIO_FLUSH) { 519229997Sken /* XXX KDM is there is a better error here? */ 520229997Sken ctl_set_internal_failure(&io->scsiio, 521229997Sken /*sks_valid*/ 1, 522229997Sken /*retry_count*/ 0xbad2); 523229997Sken } else 524229997Sken ctl_set_medium_error(&io->scsiio); 525229997Sken ctl_complete_beio(beio); 526229997Sken return; 527229997Sken } 528229997Sken 529229997Sken /* 530267537Smav * If this is a write, a flush, a delete or verify, we're all done. 531229997Sken * If this is a read, we can now send the data to the user. 532229997Sken */ 533229997Sken if ((beio->bio_cmd == BIO_WRITE) 534264274Smav || (beio->bio_cmd == BIO_FLUSH) 535267537Smav || (beio->bio_cmd == BIO_DELETE) 536267537Smav || (ARGS(io)->flags & CTL_LLF_VERIFY)) { 537229997Sken ctl_set_success(&io->scsiio); 538229997Sken ctl_complete_beio(beio); 539229997Sken } else { 540275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 541275058Smav beio->beio_cont == NULL) 542275058Smav ctl_set_success(&io->scsiio); 543229997Sken#ifdef CTL_TIME_IO 544229997Sken getbintime(&io->io_hdr.dma_start_bt); 545229997Sken#endif 546229997Sken ctl_datamove(io); 547229997Sken } 548229997Sken} 549229997Sken 550229997Skenstatic void 551229997Skenctl_be_block_flush_file(struct ctl_be_block_lun *be_lun, 552229997Sken struct ctl_be_block_io *beio) 553229997Sken{ 554267877Smav union ctl_io *io = beio->io; 555229997Sken struct mount *mountpoint; 556241896Skib int error, lock_flags; 557229997Sken 558229997Sken DPRINTF("entered\n"); 559229997Sken 560267877Smav binuptime(&beio->ds_t0); 561267877Smav mtx_lock(&be_lun->io_lock); 562267877Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 563267877Smav mtx_unlock(&be_lun->io_lock); 564229997Sken 565267877Smav (void) vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 566229997Sken 567229997Sken if (MNT_SHARED_WRITES(mountpoint) 568229997Sken || ((mountpoint == NULL) 569229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 570229997Sken lock_flags = LK_SHARED; 571229997Sken else 572229997Sken lock_flags = LK_EXCLUSIVE; 573229997Sken 574229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 575229997Sken 576286353Smav error = VOP_FSYNC(be_lun->vn, beio->io_arg ? MNT_NOWAIT : MNT_WAIT, 577286353Smav curthread); 578229997Sken VOP_UNLOCK(be_lun->vn, 0); 579229997Sken 580229997Sken vn_finished_write(mountpoint); 581229997Sken 582267877Smav mtx_lock(&be_lun->io_lock); 583267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 584267877Smav beio->ds_tag_type, beio->ds_trans_type, 585267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 586267877Smav mtx_unlock(&be_lun->io_lock); 587267877Smav 588229997Sken if (error == 0) 589229997Sken ctl_set_success(&io->scsiio); 590229997Sken else { 591229997Sken /* XXX KDM is there is a better error here? */ 592229997Sken ctl_set_internal_failure(&io->scsiio, 593229997Sken /*sks_valid*/ 1, 594229997Sken /*retry_count*/ 0xbad1); 595229997Sken } 596229997Sken 597229997Sken ctl_complete_beio(beio); 598229997Sken} 599229997Sken 600258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_start, "uint64_t"); 601258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_start, "uint64_t"); 602258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, file_done,"uint64_t"); 603258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, file_done, "uint64_t"); 604229997Sken 605229997Skenstatic void 606229997Skenctl_be_block_dispatch_file(struct ctl_be_block_lun *be_lun, 607229997Sken struct ctl_be_block_io *beio) 608229997Sken{ 609229997Sken struct ctl_be_block_filedata *file_data; 610229997Sken union ctl_io *io; 611229997Sken struct uio xuio; 612229997Sken struct iovec *xiovec; 613241896Skib int flags; 614229997Sken int error, i; 615229997Sken 616229997Sken DPRINTF("entered\n"); 617229997Sken 618229997Sken file_data = &be_lun->backend.file; 619229997Sken io = beio->io; 620271309Smav flags = 0; 621271309Smav if (ARGS(io)->flags & CTL_LLF_DPO) 622271309Smav flags |= IO_DIRECT; 623271309Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 624271309Smav flags |= IO_SYNC; 625229997Sken 626267537Smav bzero(&xuio, sizeof(xuio)); 627229997Sken if (beio->bio_cmd == BIO_READ) { 628229997Sken SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 629267537Smav xuio.uio_rw = UIO_READ; 630229997Sken } else { 631229997Sken SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 632267537Smav xuio.uio_rw = UIO_WRITE; 633229997Sken } 634229997Sken xuio.uio_offset = beio->io_offset; 635229997Sken xuio.uio_resid = beio->io_len; 636229997Sken xuio.uio_segflg = UIO_SYSSPACE; 637229997Sken xuio.uio_iov = beio->xiovecs; 638229997Sken xuio.uio_iovcnt = beio->num_segs; 639229997Sken xuio.uio_td = curthread; 640229997Sken 641229997Sken for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 642229997Sken xiovec->iov_base = beio->sg_segs[i].addr; 643229997Sken xiovec->iov_len = beio->sg_segs[i].len; 644229997Sken } 645229997Sken 646267877Smav binuptime(&beio->ds_t0); 647267877Smav mtx_lock(&be_lun->io_lock); 648267877Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 649267877Smav mtx_unlock(&be_lun->io_lock); 650267877Smav 651229997Sken if (beio->bio_cmd == BIO_READ) { 652229997Sken vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 653229997Sken 654229997Sken /* 655229997Sken * UFS pays attention to IO_DIRECT for reads. If the 656229997Sken * DIRECTIO option is configured into the kernel, it calls 657229997Sken * ffs_rawread(). But that only works for single-segment 658229997Sken * uios with user space addresses. In our case, with a 659229997Sken * kernel uio, it still reads into the buffer cache, but it 660229997Sken * will just try to release the buffer from the cache later 661229997Sken * on in ffs_read(). 662229997Sken * 663229997Sken * ZFS does not pay attention to IO_DIRECT for reads. 664229997Sken * 665229997Sken * UFS does not pay attention to IO_SYNC for reads. 666229997Sken * 667229997Sken * ZFS pays attention to IO_SYNC (which translates into the 668229997Sken * Solaris define FRSYNC for zfs_read()) for reads. It 669229997Sken * attempts to sync the file before reading. 670229997Sken */ 671271309Smav error = VOP_READ(be_lun->vn, &xuio, flags, file_data->cred); 672229997Sken 673229997Sken VOP_UNLOCK(be_lun->vn, 0); 674267537Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 675229997Sken } else { 676229997Sken struct mount *mountpoint; 677229997Sken int lock_flags; 678229997Sken 679229997Sken (void)vn_start_write(be_lun->vn, &mountpoint, V_WAIT); 680229997Sken 681229997Sken if (MNT_SHARED_WRITES(mountpoint) 682229997Sken || ((mountpoint == NULL) 683229997Sken && MNT_SHARED_WRITES(be_lun->vn->v_mount))) 684229997Sken lock_flags = LK_SHARED; 685229997Sken else 686229997Sken lock_flags = LK_EXCLUSIVE; 687229997Sken 688229997Sken vn_lock(be_lun->vn, lock_flags | LK_RETRY); 689229997Sken 690229997Sken /* 691229997Sken * UFS pays attention to IO_DIRECT for writes. The write 692229997Sken * is done asynchronously. (Normally the write would just 693229997Sken * get put into cache. 694229997Sken * 695229997Sken * UFS pays attention to IO_SYNC for writes. It will 696229997Sken * attempt to write the buffer out synchronously if that 697229997Sken * flag is set. 698229997Sken * 699229997Sken * ZFS does not pay attention to IO_DIRECT for writes. 700229997Sken * 701229997Sken * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC) 702229997Sken * for writes. It will flush the transaction from the 703229997Sken * cache before returning. 704229997Sken */ 705271309Smav error = VOP_WRITE(be_lun->vn, &xuio, flags, file_data->cred); 706229997Sken VOP_UNLOCK(be_lun->vn, 0); 707229997Sken 708229997Sken vn_finished_write(mountpoint); 709267537Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 710229997Sken } 711229997Sken 712267877Smav mtx_lock(&be_lun->io_lock); 713267877Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 714267877Smav beio->ds_tag_type, beio->ds_trans_type, 715267877Smav /*now*/ NULL, /*then*/&beio->ds_t0); 716267877Smav mtx_unlock(&be_lun->io_lock); 717267877Smav 718229997Sken /* 719229997Sken * If we got an error, set the sense data to "MEDIUM ERROR" and 720229997Sken * return the I/O to the user. 721229997Sken */ 722229997Sken if (error != 0) { 723229997Sken char path_str[32]; 724229997Sken 725229997Sken ctl_scsi_path_string(io, path_str, sizeof(path_str)); 726229997Sken printf("%s%s command returned errno %d\n", path_str, 727229997Sken (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", error); 728282565Smav if (error == ENOSPC || error == EDQUOT) { 729273809Smav ctl_set_space_alloc_fail(&io->scsiio); 730273809Smav } else 731273809Smav ctl_set_medium_error(&io->scsiio); 732229997Sken ctl_complete_beio(beio); 733229997Sken return; 734229997Sken } 735229997Sken 736229997Sken /* 737269122Smav * If this is a write or a verify, we're all done. 738229997Sken * If this is a read, we can now send the data to the user. 739229997Sken */ 740269122Smav if ((beio->bio_cmd == BIO_WRITE) || 741269122Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 742229997Sken ctl_set_success(&io->scsiio); 743229997Sken ctl_complete_beio(beio); 744229997Sken } else { 745275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 746275058Smav beio->beio_cont == NULL) 747275058Smav ctl_set_success(&io->scsiio); 748229997Sken#ifdef CTL_TIME_IO 749229997Sken getbintime(&io->io_hdr.dma_start_bt); 750229997Sken#endif 751229997Sken ctl_datamove(io); 752229997Sken } 753229997Sken} 754229997Sken 755229997Skenstatic void 756275474Smavctl_be_block_gls_file(struct ctl_be_block_lun *be_lun, 757275474Smav struct ctl_be_block_io *beio) 758275474Smav{ 759275474Smav union ctl_io *io = beio->io; 760275474Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 761275474Smav struct scsi_get_lba_status_data *data; 762275474Smav off_t roff, off; 763275474Smav int error, status; 764275474Smav 765275474Smav DPRINTF("entered\n"); 766275474Smav 767287499Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 768275474Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 769275474Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKHOLE, &off, 770275474Smav 0, curthread->td_ucred, curthread); 771275474Smav if (error == 0 && off > roff) 772275474Smav status = 0; /* mapped up to off */ 773275474Smav else { 774275474Smav error = VOP_IOCTL(be_lun->vn, FIOSEEKDATA, &off, 775275474Smav 0, curthread->td_ucred, curthread); 776275474Smav if (error == 0 && off > roff) 777275474Smav status = 1; /* deallocated up to off */ 778275474Smav else { 779275474Smav status = 0; /* unknown up to the end */ 780275474Smav off = be_lun->size_bytes; 781275474Smav } 782275474Smav } 783275474Smav VOP_UNLOCK(be_lun->vn, 0); 784275474Smav 785275474Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 786275474Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 787287499Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 788287499Smav lbalen->lba), data->descr[0].length); 789275474Smav data->descr[0].status = status; 790275474Smav 791275474Smav ctl_complete_beio(beio); 792275474Smav} 793275474Smav 794275481Smavstatic uint64_t 795275481Smavctl_be_block_getattr_file(struct ctl_be_block_lun *be_lun, const char *attrname) 796275481Smav{ 797275481Smav struct vattr vattr; 798275481Smav struct statfs statfs; 799285030Smav uint64_t val; 800275481Smav int error; 801275481Smav 802285030Smav val = UINT64_MAX; 803275481Smav if (be_lun->vn == NULL) 804285030Smav return (val); 805285030Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 806275481Smav if (strcmp(attrname, "blocksused") == 0) { 807275481Smav error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 808285030Smav if (error == 0) 809287499Smav val = vattr.va_bytes / be_lun->cbe_lun.blocksize; 810275481Smav } 811285030Smav if (strcmp(attrname, "blocksavail") == 0 && 812285030Smav (be_lun->vn->v_iflag & VI_DOOMED) == 0) { 813275481Smav error = VFS_STATFS(be_lun->vn->v_mount, &statfs); 814285030Smav if (error == 0) 815286811Smav val = statfs.f_bavail * statfs.f_bsize / 816287499Smav be_lun->cbe_lun.blocksize; 817275481Smav } 818285030Smav VOP_UNLOCK(be_lun->vn, 0); 819285030Smav return (val); 820275481Smav} 821275481Smav 822275474Smavstatic void 823269123Smavctl_be_block_dispatch_zvol(struct ctl_be_block_lun *be_lun, 824269123Smav struct ctl_be_block_io *beio) 825269123Smav{ 826269123Smav struct ctl_be_block_devdata *dev_data; 827269123Smav union ctl_io *io; 828269123Smav struct uio xuio; 829269123Smav struct iovec *xiovec; 830269123Smav int flags; 831269123Smav int error, i; 832269123Smav 833269123Smav DPRINTF("entered\n"); 834269123Smav 835269123Smav dev_data = &be_lun->backend.dev; 836269123Smav io = beio->io; 837271309Smav flags = 0; 838271309Smav if (ARGS(io)->flags & CTL_LLF_DPO) 839271309Smav flags |= IO_DIRECT; 840271309Smav if (beio->bio_cmd == BIO_WRITE && ARGS(io)->flags & CTL_LLF_FUA) 841271309Smav flags |= IO_SYNC; 842269123Smav 843269123Smav bzero(&xuio, sizeof(xuio)); 844269123Smav if (beio->bio_cmd == BIO_READ) { 845269123Smav SDT_PROBE(cbb, kernel, read, file_start, 0, 0, 0, 0, 0); 846269123Smav xuio.uio_rw = UIO_READ; 847269123Smav } else { 848269123Smav SDT_PROBE(cbb, kernel, write, file_start, 0, 0, 0, 0, 0); 849269123Smav xuio.uio_rw = UIO_WRITE; 850269123Smav } 851269123Smav xuio.uio_offset = beio->io_offset; 852269123Smav xuio.uio_resid = beio->io_len; 853269123Smav xuio.uio_segflg = UIO_SYSSPACE; 854269123Smav xuio.uio_iov = beio->xiovecs; 855269123Smav xuio.uio_iovcnt = beio->num_segs; 856269123Smav xuio.uio_td = curthread; 857269123Smav 858269123Smav for (i = 0, xiovec = xuio.uio_iov; i < xuio.uio_iovcnt; i++, xiovec++) { 859269123Smav xiovec->iov_base = beio->sg_segs[i].addr; 860269123Smav xiovec->iov_len = beio->sg_segs[i].len; 861269123Smav } 862269123Smav 863269123Smav binuptime(&beio->ds_t0); 864269123Smav mtx_lock(&be_lun->io_lock); 865269123Smav devstat_start_transaction(beio->lun->disk_stats, &beio->ds_t0); 866269123Smav mtx_unlock(&be_lun->io_lock); 867269123Smav 868269123Smav if (beio->bio_cmd == BIO_READ) { 869271309Smav error = (*dev_data->csw->d_read)(dev_data->cdev, &xuio, flags); 870269123Smav SDT_PROBE(cbb, kernel, read, file_done, 0, 0, 0, 0, 0); 871269123Smav } else { 872271309Smav error = (*dev_data->csw->d_write)(dev_data->cdev, &xuio, flags); 873269123Smav SDT_PROBE(cbb, kernel, write, file_done, 0, 0, 0, 0, 0); 874269123Smav } 875269123Smav 876269123Smav mtx_lock(&be_lun->io_lock); 877269123Smav devstat_end_transaction(beio->lun->disk_stats, beio->io_len, 878269123Smav beio->ds_tag_type, beio->ds_trans_type, 879269123Smav /*now*/ NULL, /*then*/&beio->ds_t0); 880269123Smav mtx_unlock(&be_lun->io_lock); 881269123Smav 882269123Smav /* 883269123Smav * If we got an error, set the sense data to "MEDIUM ERROR" and 884269123Smav * return the I/O to the user. 885269123Smav */ 886269123Smav if (error != 0) { 887282565Smav if (error == ENOSPC || error == EDQUOT) { 888273809Smav ctl_set_space_alloc_fail(&io->scsiio); 889273809Smav } else 890273809Smav ctl_set_medium_error(&io->scsiio); 891269123Smav ctl_complete_beio(beio); 892269123Smav return; 893269123Smav } 894269123Smav 895269123Smav /* 896269123Smav * If this is a write or a verify, we're all done. 897269123Smav * If this is a read, we can now send the data to the user. 898269123Smav */ 899269123Smav if ((beio->bio_cmd == BIO_WRITE) || 900269123Smav (ARGS(io)->flags & CTL_LLF_VERIFY)) { 901269123Smav ctl_set_success(&io->scsiio); 902269123Smav ctl_complete_beio(beio); 903269123Smav } else { 904275058Smav if ((ARGS(io)->flags & CTL_LLF_READ) && 905275058Smav beio->beio_cont == NULL) 906275058Smav ctl_set_success(&io->scsiio); 907269123Smav#ifdef CTL_TIME_IO 908269123Smav getbintime(&io->io_hdr.dma_start_bt); 909269123Smav#endif 910269123Smav ctl_datamove(io); 911269123Smav } 912269123Smav} 913269123Smav 914269123Smavstatic void 915275474Smavctl_be_block_gls_zvol(struct ctl_be_block_lun *be_lun, 916275474Smav struct ctl_be_block_io *beio) 917275474Smav{ 918275474Smav struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev; 919275474Smav union ctl_io *io = beio->io; 920275474Smav struct ctl_lba_len_flags *lbalen = ARGS(io); 921275474Smav struct scsi_get_lba_status_data *data; 922275474Smav off_t roff, off; 923275474Smav int error, status; 924275474Smav 925275474Smav DPRINTF("entered\n"); 926275474Smav 927287499Smav off = roff = ((off_t)lbalen->lba) * be_lun->cbe_lun.blocksize; 928275474Smav error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKHOLE, 929275474Smav (caddr_t)&off, FREAD, curthread); 930275474Smav if (error == 0 && off > roff) 931275474Smav status = 0; /* mapped up to off */ 932275474Smav else { 933275474Smav error = (*dev_data->csw->d_ioctl)(dev_data->cdev, FIOSEEKDATA, 934275474Smav (caddr_t)&off, FREAD, curthread); 935275474Smav if (error == 0 && off > roff) 936275474Smav status = 1; /* deallocated up to off */ 937275474Smav else { 938275474Smav status = 0; /* unknown up to the end */ 939275474Smav off = be_lun->size_bytes; 940275474Smav } 941275474Smav } 942275474Smav 943275474Smav data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 944275474Smav scsi_u64to8b(lbalen->lba, data->descr[0].addr); 945287499Smav scsi_ulto4b(MIN(UINT32_MAX, off / be_lun->cbe_lun.blocksize - 946287499Smav lbalen->lba), data->descr[0].length); 947275474Smav data->descr[0].status = status; 948275474Smav 949275474Smav ctl_complete_beio(beio); 950275474Smav} 951275474Smav 952275474Smavstatic void 953229997Skenctl_be_block_flush_dev(struct ctl_be_block_lun *be_lun, 954229997Sken struct ctl_be_block_io *beio) 955229997Sken{ 956229997Sken struct bio *bio; 957229997Sken union ctl_io *io; 958229997Sken struct ctl_be_block_devdata *dev_data; 959229997Sken 960229997Sken dev_data = &be_lun->backend.dev; 961229997Sken io = beio->io; 962229997Sken 963229997Sken DPRINTF("entered\n"); 964229997Sken 965229997Sken /* This can't fail, it's a blocking allocation. */ 966229997Sken bio = g_alloc_bio(); 967229997Sken 968229997Sken bio->bio_cmd = BIO_FLUSH; 969229997Sken bio->bio_dev = dev_data->cdev; 970229997Sken bio->bio_offset = 0; 971229997Sken bio->bio_data = 0; 972229997Sken bio->bio_done = ctl_be_block_biodone; 973229997Sken bio->bio_caller1 = beio; 974229997Sken bio->bio_pblkno = 0; 975229997Sken 976229997Sken /* 977229997Sken * We don't need to acquire the LUN lock here, because we are only 978229997Sken * sending one bio, and so there is no other context to synchronize 979229997Sken * with. 980229997Sken */ 981229997Sken beio->num_bios_sent = 1; 982229997Sken beio->send_complete = 1; 983229997Sken 984229997Sken binuptime(&beio->ds_t0); 985267877Smav mtx_lock(&be_lun->io_lock); 986229997Sken devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 987267877Smav mtx_unlock(&be_lun->io_lock); 988229997Sken 989229997Sken (*dev_data->csw->d_strategy)(bio); 990229997Sken} 991229997Sken 992229997Skenstatic void 993264274Smavctl_be_block_unmap_dev_range(struct ctl_be_block_lun *be_lun, 994264274Smav struct ctl_be_block_io *beio, 995264274Smav uint64_t off, uint64_t len, int last) 996264274Smav{ 997264274Smav struct bio *bio; 998264274Smav struct ctl_be_block_devdata *dev_data; 999264296Smav uint64_t maxlen; 1000264274Smav 1001264274Smav dev_data = &be_lun->backend.dev; 1002287499Smav maxlen = LONG_MAX - (LONG_MAX % be_lun->cbe_lun.blocksize); 1003264274Smav while (len > 0) { 1004264274Smav bio = g_alloc_bio(); 1005264274Smav bio->bio_cmd = BIO_DELETE; 1006264274Smav bio->bio_dev = dev_data->cdev; 1007264274Smav bio->bio_offset = off; 1008264296Smav bio->bio_length = MIN(len, maxlen); 1009264274Smav bio->bio_data = 0; 1010264274Smav bio->bio_done = ctl_be_block_biodone; 1011264274Smav bio->bio_caller1 = beio; 1012287499Smav bio->bio_pblkno = off / be_lun->cbe_lun.blocksize; 1013264274Smav 1014264274Smav off += bio->bio_length; 1015264274Smav len -= bio->bio_length; 1016264274Smav 1017267877Smav mtx_lock(&be_lun->io_lock); 1018264274Smav beio->num_bios_sent++; 1019264274Smav if (last && len == 0) 1020264274Smav beio->send_complete = 1; 1021267877Smav mtx_unlock(&be_lun->io_lock); 1022264274Smav 1023264274Smav (*dev_data->csw->d_strategy)(bio); 1024264274Smav } 1025264274Smav} 1026264274Smav 1027264274Smavstatic void 1028264274Smavctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun, 1029264274Smav struct ctl_be_block_io *beio) 1030264274Smav{ 1031264274Smav union ctl_io *io; 1032264274Smav struct ctl_be_block_devdata *dev_data; 1033267515Smav struct ctl_ptr_len_flags *ptrlen; 1034264274Smav struct scsi_unmap_desc *buf, *end; 1035264274Smav uint64_t len; 1036264274Smav 1037264274Smav dev_data = &be_lun->backend.dev; 1038264274Smav io = beio->io; 1039264274Smav 1040264274Smav DPRINTF("entered\n"); 1041264274Smav 1042264274Smav binuptime(&beio->ds_t0); 1043267877Smav mtx_lock(&be_lun->io_lock); 1044264274Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1045267877Smav mtx_unlock(&be_lun->io_lock); 1046264274Smav 1047264274Smav if (beio->io_offset == -1) { 1048264274Smav beio->io_len = 0; 1049267515Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1050267515Smav buf = (struct scsi_unmap_desc *)ptrlen->ptr; 1051267515Smav end = buf + ptrlen->len / sizeof(*buf); 1052264274Smav for (; buf < end; buf++) { 1053264274Smav len = (uint64_t)scsi_4btoul(buf->length) * 1054287499Smav be_lun->cbe_lun.blocksize; 1055264274Smav beio->io_len += len; 1056264274Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1057287499Smav scsi_8btou64(buf->lba) * be_lun->cbe_lun.blocksize, 1058287499Smav len, (end - buf < 2) ? TRUE : FALSE); 1059264274Smav } 1060264274Smav } else 1061264274Smav ctl_be_block_unmap_dev_range(be_lun, beio, 1062264274Smav beio->io_offset, beio->io_len, TRUE); 1063264274Smav} 1064264274Smav 1065264274Smavstatic void 1066229997Skenctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun, 1067229997Sken struct ctl_be_block_io *beio) 1068229997Sken{ 1069267877Smav TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 1070229997Sken int i; 1071229997Sken struct bio *bio; 1072229997Sken struct ctl_be_block_devdata *dev_data; 1073229997Sken off_t cur_offset; 1074229997Sken int max_iosize; 1075229997Sken 1076229997Sken DPRINTF("entered\n"); 1077229997Sken 1078229997Sken dev_data = &be_lun->backend.dev; 1079229997Sken 1080229997Sken /* 1081229997Sken * We have to limit our I/O size to the maximum supported by the 1082229997Sken * backend device. Hopefully it is MAXPHYS. If the driver doesn't 1083229997Sken * set it properly, use DFLTPHYS. 1084229997Sken */ 1085229997Sken max_iosize = dev_data->cdev->si_iosize_max; 1086229997Sken if (max_iosize < PAGE_SIZE) 1087229997Sken max_iosize = DFLTPHYS; 1088229997Sken 1089229997Sken cur_offset = beio->io_offset; 1090229997Sken for (i = 0; i < beio->num_segs; i++) { 1091229997Sken size_t cur_size; 1092229997Sken uint8_t *cur_ptr; 1093229997Sken 1094229997Sken cur_size = beio->sg_segs[i].len; 1095229997Sken cur_ptr = beio->sg_segs[i].addr; 1096229997Sken 1097229997Sken while (cur_size > 0) { 1098229997Sken /* This can't fail, it's a blocking allocation. */ 1099229997Sken bio = g_alloc_bio(); 1100229997Sken 1101229997Sken KASSERT(bio != NULL, ("g_alloc_bio() failed!\n")); 1102229997Sken 1103229997Sken bio->bio_cmd = beio->bio_cmd; 1104229997Sken bio->bio_dev = dev_data->cdev; 1105229997Sken bio->bio_caller1 = beio; 1106229997Sken bio->bio_length = min(cur_size, max_iosize); 1107229997Sken bio->bio_offset = cur_offset; 1108229997Sken bio->bio_data = cur_ptr; 1109229997Sken bio->bio_done = ctl_be_block_biodone; 1110287499Smav bio->bio_pblkno = cur_offset / be_lun->cbe_lun.blocksize; 1111229997Sken 1112229997Sken cur_offset += bio->bio_length; 1113229997Sken cur_ptr += bio->bio_length; 1114229997Sken cur_size -= bio->bio_length; 1115229997Sken 1116267877Smav TAILQ_INSERT_TAIL(&queue, bio, bio_queue); 1117229997Sken beio->num_bios_sent++; 1118229997Sken } 1119229997Sken } 1120267877Smav binuptime(&beio->ds_t0); 1121267877Smav mtx_lock(&be_lun->io_lock); 1122267877Smav devstat_start_transaction(be_lun->disk_stats, &beio->ds_t0); 1123267877Smav beio->send_complete = 1; 1124267877Smav mtx_unlock(&be_lun->io_lock); 1125267877Smav 1126267877Smav /* 1127267877Smav * Fire off all allocated requests! 1128267877Smav */ 1129267877Smav while ((bio = TAILQ_FIRST(&queue)) != NULL) { 1130267877Smav TAILQ_REMOVE(&queue, bio, bio_queue); 1131267877Smav (*dev_data->csw->d_strategy)(bio); 1132267877Smav } 1133229997Sken} 1134229997Sken 1135274154Smavstatic uint64_t 1136274154Smavctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname) 1137274154Smav{ 1138274154Smav struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev; 1139274154Smav struct diocgattr_arg arg; 1140274154Smav int error; 1141274154Smav 1142274154Smav if (dev_data->csw == NULL || dev_data->csw->d_ioctl == NULL) 1143274154Smav return (UINT64_MAX); 1144274154Smav strlcpy(arg.name, attrname, sizeof(arg.name)); 1145274154Smav arg.len = sizeof(arg.value.off); 1146274154Smav error = dev_data->csw->d_ioctl(dev_data->cdev, 1147274154Smav DIOCGATTR, (caddr_t)&arg, FREAD, curthread); 1148274154Smav if (error != 0) 1149274154Smav return (UINT64_MAX); 1150274154Smav return (arg.value.off); 1151274154Smav} 1152274154Smav 1153229997Skenstatic void 1154286353Smavctl_be_block_cw_dispatch_sync(struct ctl_be_block_lun *be_lun, 1155286353Smav union ctl_io *io) 1156286353Smav{ 1157287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1158286353Smav struct ctl_be_block_io *beio; 1159286353Smav struct ctl_lba_len_flags *lbalen; 1160286353Smav 1161286353Smav DPRINTF("entered\n"); 1162286353Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1163286353Smav lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1164286353Smav 1165287499Smav beio->io_len = lbalen->len * cbe_lun->blocksize; 1166287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1167286353Smav beio->io_arg = (lbalen->flags & SSC_IMMED) != 0; 1168286353Smav beio->bio_cmd = BIO_FLUSH; 1169286353Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1170286353Smav DPRINTF("SYNC\n"); 1171286353Smav be_lun->lun_flush(be_lun, beio); 1172286353Smav} 1173286353Smav 1174286353Smavstatic void 1175264274Smavctl_be_block_cw_done_ws(struct ctl_be_block_io *beio) 1176264274Smav{ 1177264274Smav union ctl_io *io; 1178264274Smav 1179264274Smav io = beio->io; 1180264274Smav ctl_free_beio(beio); 1181267641Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1182267641Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1183267641Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1184264274Smav ctl_config_write_done(io); 1185264274Smav return; 1186264274Smav } 1187264274Smav 1188264274Smav ctl_be_block_config_write(io); 1189264274Smav} 1190264274Smav 1191264274Smavstatic void 1192264274Smavctl_be_block_cw_dispatch_ws(struct ctl_be_block_lun *be_lun, 1193264274Smav union ctl_io *io) 1194264274Smav{ 1195287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1196264274Smav struct ctl_be_block_io *beio; 1197267515Smav struct ctl_lba_len_flags *lbalen; 1198278625Smav uint64_t len_left, lba; 1199278625Smav uint32_t pb, pbo, adj; 1200264274Smav int i, seglen; 1201264274Smav uint8_t *buf, *end; 1202264274Smav 1203264274Smav DPRINTF("entered\n"); 1204264274Smav 1205267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1206267537Smav lbalen = ARGS(beio->io); 1207264274Smav 1208271839Smav if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB) || 1209269622Smav (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR) && be_lun->unmap == NULL)) { 1210264274Smav ctl_free_beio(beio); 1211264274Smav ctl_set_invalid_field(&io->scsiio, 1212264274Smav /*sks_valid*/ 1, 1213264274Smav /*command*/ 1, 1214264274Smav /*field*/ 1, 1215264274Smav /*bit_valid*/ 0, 1216264274Smav /*bit*/ 0); 1217264274Smav ctl_config_write_done(io); 1218264274Smav return; 1219264274Smav } 1220264274Smav 1221269622Smav if (lbalen->flags & (SWS_UNMAP | SWS_ANCHOR)) { 1222287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1223287499Smav beio->io_len = (uint64_t)lbalen->len * cbe_lun->blocksize; 1224264274Smav beio->bio_cmd = BIO_DELETE; 1225264274Smav beio->ds_trans_type = DEVSTAT_FREE; 1226264274Smav 1227264274Smav be_lun->unmap(be_lun, beio); 1228264274Smav return; 1229264274Smav } 1230264274Smav 1231264274Smav beio->bio_cmd = BIO_WRITE; 1232264274Smav beio->ds_trans_type = DEVSTAT_WRITE; 1233264274Smav 1234264274Smav DPRINTF("WRITE SAME at LBA %jx len %u\n", 1235267515Smav (uintmax_t)lbalen->lba, lbalen->len); 1236264274Smav 1237287499Smav pb = cbe_lun->blocksize << be_lun->cbe_lun.pblockexp; 1238287499Smav if (be_lun->cbe_lun.pblockoff > 0) 1239287499Smav pbo = pb - cbe_lun->blocksize * be_lun->cbe_lun.pblockoff; 1240278625Smav else 1241278625Smav pbo = 0; 1242287499Smav len_left = (uint64_t)lbalen->len * cbe_lun->blocksize; 1243264274Smav for (i = 0, lba = 0; i < CTLBLK_MAX_SEGS && len_left > 0; i++) { 1244264274Smav 1245264274Smav /* 1246264274Smav * Setup the S/G entry for this chunk. 1247264274Smav */ 1248264886Smav seglen = MIN(CTLBLK_MAX_SEG, len_left); 1249287499Smav if (pb > cbe_lun->blocksize) { 1250287499Smav adj = ((lbalen->lba + lba) * cbe_lun->blocksize + 1251278619Smav seglen - pbo) % pb; 1252278619Smav if (seglen > adj) 1253278619Smav seglen -= adj; 1254278619Smav else 1255287499Smav seglen -= seglen % cbe_lun->blocksize; 1256278619Smav } else 1257287499Smav seglen -= seglen % cbe_lun->blocksize; 1258264274Smav beio->sg_segs[i].len = seglen; 1259264274Smav beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1260264274Smav 1261264274Smav DPRINTF("segment %d addr %p len %zd\n", i, 1262264274Smav beio->sg_segs[i].addr, beio->sg_segs[i].len); 1263264274Smav 1264264274Smav beio->num_segs++; 1265264274Smav len_left -= seglen; 1266264274Smav 1267264274Smav buf = beio->sg_segs[i].addr; 1268264274Smav end = buf + seglen; 1269287499Smav for (; buf < end; buf += cbe_lun->blocksize) { 1270287499Smav memcpy(buf, io->scsiio.kern_data_ptr, cbe_lun->blocksize); 1271267515Smav if (lbalen->flags & SWS_LBDATA) 1272267515Smav scsi_ulto4b(lbalen->lba + lba, buf); 1273264274Smav lba++; 1274264274Smav } 1275264274Smav } 1276264274Smav 1277287499Smav beio->io_offset = lbalen->lba * cbe_lun->blocksize; 1278287499Smav beio->io_len = lba * cbe_lun->blocksize; 1279264274Smav 1280264274Smav /* We can not do all in one run. Correct and schedule rerun. */ 1281264274Smav if (len_left > 0) { 1282267515Smav lbalen->lba += lba; 1283267515Smav lbalen->len -= lba; 1284264274Smav beio->beio_cont = ctl_be_block_cw_done_ws; 1285264274Smav } 1286264274Smav 1287264274Smav be_lun->dispatch(be_lun, beio); 1288264274Smav} 1289264274Smav 1290264274Smavstatic void 1291264274Smavctl_be_block_cw_dispatch_unmap(struct ctl_be_block_lun *be_lun, 1292264274Smav union ctl_io *io) 1293264274Smav{ 1294264274Smav struct ctl_be_block_io *beio; 1295267515Smav struct ctl_ptr_len_flags *ptrlen; 1296264274Smav 1297264274Smav DPRINTF("entered\n"); 1298264274Smav 1299267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1300267515Smav ptrlen = (struct ctl_ptr_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 1301264274Smav 1302269622Smav if ((ptrlen->flags & ~SU_ANCHOR) != 0 || be_lun->unmap == NULL) { 1303264274Smav ctl_free_beio(beio); 1304264274Smav ctl_set_invalid_field(&io->scsiio, 1305264274Smav /*sks_valid*/ 0, 1306264274Smav /*command*/ 1, 1307264274Smav /*field*/ 0, 1308264274Smav /*bit_valid*/ 0, 1309264274Smav /*bit*/ 0); 1310264274Smav ctl_config_write_done(io); 1311264274Smav return; 1312264274Smav } 1313264274Smav 1314264274Smav beio->io_len = 0; 1315264274Smav beio->io_offset = -1; 1316264274Smav beio->bio_cmd = BIO_DELETE; 1317264274Smav beio->ds_trans_type = DEVSTAT_FREE; 1318267515Smav DPRINTF("UNMAP\n"); 1319264274Smav be_lun->unmap(be_lun, beio); 1320264274Smav} 1321264274Smav 1322264274Smavstatic void 1323275474Smavctl_be_block_cr_done(struct ctl_be_block_io *beio) 1324275474Smav{ 1325275474Smav union ctl_io *io; 1326275474Smav 1327275474Smav io = beio->io; 1328275474Smav ctl_free_beio(beio); 1329275474Smav ctl_config_read_done(io); 1330275474Smav} 1331275474Smav 1332275474Smavstatic void 1333275474Smavctl_be_block_cr_dispatch(struct ctl_be_block_lun *be_lun, 1334275474Smav union ctl_io *io) 1335275474Smav{ 1336275474Smav struct ctl_be_block_io *beio; 1337275474Smav struct ctl_be_block_softc *softc; 1338275474Smav 1339275474Smav DPRINTF("entered\n"); 1340275474Smav 1341275474Smav softc = be_lun->softc; 1342275474Smav beio = ctl_alloc_beio(softc); 1343275474Smav beio->io = io; 1344275474Smav beio->lun = be_lun; 1345275474Smav beio->beio_cont = ctl_be_block_cr_done; 1346275474Smav PRIV(io)->ptr = (void *)beio; 1347275474Smav 1348275474Smav switch (io->scsiio.cdb[0]) { 1349275474Smav case SERVICE_ACTION_IN: /* GET LBA STATUS */ 1350275474Smav beio->bio_cmd = -1; 1351275474Smav beio->ds_trans_type = DEVSTAT_NO_DATA; 1352275474Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1353275474Smav beio->io_len = 0; 1354275474Smav if (be_lun->get_lba_status) 1355275474Smav be_lun->get_lba_status(be_lun, beio); 1356275474Smav else 1357275474Smav ctl_be_block_cr_done(beio); 1358275474Smav break; 1359275474Smav default: 1360275474Smav panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1361275474Smav break; 1362275474Smav } 1363275474Smav} 1364275474Smav 1365275474Smavstatic void 1366264274Smavctl_be_block_cw_done(struct ctl_be_block_io *beio) 1367264274Smav{ 1368264274Smav union ctl_io *io; 1369264274Smav 1370264274Smav io = beio->io; 1371264274Smav ctl_free_beio(beio); 1372264274Smav ctl_config_write_done(io); 1373264274Smav} 1374264274Smav 1375264274Smavstatic void 1376229997Skenctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun, 1377229997Sken union ctl_io *io) 1378229997Sken{ 1379229997Sken struct ctl_be_block_io *beio; 1380229997Sken struct ctl_be_block_softc *softc; 1381229997Sken 1382229997Sken DPRINTF("entered\n"); 1383229997Sken 1384229997Sken softc = be_lun->softc; 1385229997Sken beio = ctl_alloc_beio(softc); 1386229997Sken beio->io = io; 1387229997Sken beio->lun = be_lun; 1388264274Smav beio->beio_cont = ctl_be_block_cw_done; 1389286353Smav switch (io->scsiio.tag_type) { 1390286353Smav case CTL_TAG_ORDERED: 1391286353Smav beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1392286353Smav break; 1393286353Smav case CTL_TAG_HEAD_OF_QUEUE: 1394286353Smav beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1395286353Smav break; 1396286353Smav case CTL_TAG_UNTAGGED: 1397286353Smav case CTL_TAG_SIMPLE: 1398286353Smav case CTL_TAG_ACA: 1399286353Smav default: 1400286353Smav beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1401286353Smav break; 1402286353Smav } 1403267519Smav PRIV(io)->ptr = (void *)beio; 1404229997Sken 1405229997Sken switch (io->scsiio.cdb[0]) { 1406229997Sken case SYNCHRONIZE_CACHE: 1407229997Sken case SYNCHRONIZE_CACHE_16: 1408286353Smav ctl_be_block_cw_dispatch_sync(be_lun, io); 1409229997Sken break; 1410264274Smav case WRITE_SAME_10: 1411264274Smav case WRITE_SAME_16: 1412264274Smav ctl_be_block_cw_dispatch_ws(be_lun, io); 1413264274Smav break; 1414264274Smav case UNMAP: 1415264274Smav ctl_be_block_cw_dispatch_unmap(be_lun, io); 1416264274Smav break; 1417229997Sken default: 1418229997Sken panic("Unhandled CDB type %#x", io->scsiio.cdb[0]); 1419229997Sken break; 1420229997Sken } 1421229997Sken} 1422229997Sken 1423258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, start, "uint64_t"); 1424258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, start, "uint64_t"); 1425258622SavgSDT_PROBE_DEFINE1(cbb, kernel, read, alloc_done, "uint64_t"); 1426258622SavgSDT_PROBE_DEFINE1(cbb, kernel, write, alloc_done, "uint64_t"); 1427229997Sken 1428229997Skenstatic void 1429264886Smavctl_be_block_next(struct ctl_be_block_io *beio) 1430264886Smav{ 1431264886Smav struct ctl_be_block_lun *be_lun; 1432264886Smav union ctl_io *io; 1433264886Smav 1434264886Smav io = beio->io; 1435264886Smav be_lun = beio->lun; 1436264886Smav ctl_free_beio(beio); 1437267641Smav if ((io->io_hdr.flags & CTL_FLAG_ABORT) || 1438267641Smav ((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE && 1439267641Smav (io->io_hdr.status & CTL_STATUS_MASK) != CTL_SUCCESS)) { 1440267537Smav ctl_data_submit_done(io); 1441264886Smav return; 1442264886Smav } 1443264886Smav 1444264886Smav io->io_hdr.status &= ~CTL_STATUS_MASK; 1445264886Smav io->io_hdr.status |= CTL_STATUS_NONE; 1446264886Smav 1447267877Smav mtx_lock(&be_lun->queue_lock); 1448264886Smav /* 1449264886Smav * XXX KDM make sure that links is okay to use at this point. 1450264886Smav * Otherwise, we either need to add another field to ctl_io_hdr, 1451264886Smav * or deal with resource allocation here. 1452264886Smav */ 1453264886Smav STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1454267877Smav mtx_unlock(&be_lun->queue_lock); 1455264886Smav 1456264886Smav taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1457264886Smav} 1458264886Smav 1459264886Smavstatic void 1460229997Skenctl_be_block_dispatch(struct ctl_be_block_lun *be_lun, 1461229997Sken union ctl_io *io) 1462229997Sken{ 1463287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1464229997Sken struct ctl_be_block_io *beio; 1465229997Sken struct ctl_be_block_softc *softc; 1466267537Smav struct ctl_lba_len_flags *lbalen; 1467267519Smav struct ctl_ptr_len_flags *bptrlen; 1468267519Smav uint64_t len_left, lbas; 1469229997Sken int i; 1470229997Sken 1471229997Sken softc = be_lun->softc; 1472229997Sken 1473229997Sken DPRINTF("entered\n"); 1474229997Sken 1475267537Smav lbalen = ARGS(io); 1476267537Smav if (lbalen->flags & CTL_LLF_WRITE) { 1477267537Smav SDT_PROBE(cbb, kernel, write, start, 0, 0, 0, 0, 0); 1478267537Smav } else { 1479229997Sken SDT_PROBE(cbb, kernel, read, start, 0, 0, 0, 0, 0); 1480229997Sken } 1481229997Sken 1482229997Sken beio = ctl_alloc_beio(softc); 1483229997Sken beio->io = io; 1484229997Sken beio->lun = be_lun; 1485267519Smav bptrlen = PRIV(io); 1486267519Smav bptrlen->ptr = (void *)beio; 1487229997Sken 1488229997Sken switch (io->scsiio.tag_type) { 1489229997Sken case CTL_TAG_ORDERED: 1490229997Sken beio->ds_tag_type = DEVSTAT_TAG_ORDERED; 1491229997Sken break; 1492229997Sken case CTL_TAG_HEAD_OF_QUEUE: 1493229997Sken beio->ds_tag_type = DEVSTAT_TAG_HEAD; 1494229997Sken break; 1495229997Sken case CTL_TAG_UNTAGGED: 1496229997Sken case CTL_TAG_SIMPLE: 1497229997Sken case CTL_TAG_ACA: 1498229997Sken default: 1499229997Sken beio->ds_tag_type = DEVSTAT_TAG_SIMPLE; 1500229997Sken break; 1501229997Sken } 1502229997Sken 1503267537Smav if (lbalen->flags & CTL_LLF_WRITE) { 1504267537Smav beio->bio_cmd = BIO_WRITE; 1505267537Smav beio->ds_trans_type = DEVSTAT_WRITE; 1506267537Smav } else { 1507229997Sken beio->bio_cmd = BIO_READ; 1508229997Sken beio->ds_trans_type = DEVSTAT_READ; 1509229997Sken } 1510229997Sken 1511264886Smav DPRINTF("%s at LBA %jx len %u @%ju\n", 1512229997Sken (beio->bio_cmd == BIO_READ) ? "READ" : "WRITE", 1513267519Smav (uintmax_t)lbalen->lba, lbalen->len, bptrlen->len); 1514267537Smav if (lbalen->flags & CTL_LLF_COMPARE) 1515267537Smav lbas = CTLBLK_HALF_IO_SIZE; 1516267537Smav else 1517267537Smav lbas = CTLBLK_MAX_IO_SIZE; 1518287499Smav lbas = MIN(lbalen->len - bptrlen->len, lbas / cbe_lun->blocksize); 1519287499Smav beio->io_offset = (lbalen->lba + bptrlen->len) * cbe_lun->blocksize; 1520287499Smav beio->io_len = lbas * cbe_lun->blocksize; 1521267519Smav bptrlen->len += lbas; 1522229997Sken 1523264886Smav for (i = 0, len_left = beio->io_len; len_left > 0; i++) { 1524264886Smav KASSERT(i < CTLBLK_MAX_SEGS, ("Too many segs (%d >= %d)", 1525264886Smav i, CTLBLK_MAX_SEGS)); 1526229997Sken 1527229997Sken /* 1528229997Sken * Setup the S/G entry for this chunk. 1529229997Sken */ 1530264886Smav beio->sg_segs[i].len = min(CTLBLK_MAX_SEG, len_left); 1531229997Sken beio->sg_segs[i].addr = uma_zalloc(be_lun->lun_zone, M_WAITOK); 1532229997Sken 1533229997Sken DPRINTF("segment %d addr %p len %zd\n", i, 1534229997Sken beio->sg_segs[i].addr, beio->sg_segs[i].len); 1535229997Sken 1536267537Smav /* Set up second segment for compare operation. */ 1537267537Smav if (lbalen->flags & CTL_LLF_COMPARE) { 1538267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].len = 1539267537Smav beio->sg_segs[i].len; 1540267537Smav beio->sg_segs[i + CTLBLK_HALF_SEGS].addr = 1541267537Smav uma_zalloc(be_lun->lun_zone, M_WAITOK); 1542267537Smav } 1543267537Smav 1544229997Sken beio->num_segs++; 1545229997Sken len_left -= beio->sg_segs[i].len; 1546229997Sken } 1547267519Smav if (bptrlen->len < lbalen->len) 1548264886Smav beio->beio_cont = ctl_be_block_next; 1549264886Smav io->scsiio.be_move_done = ctl_be_block_move_done; 1550267537Smav /* For compare we have separate S/G lists for read and datamove. */ 1551267537Smav if (lbalen->flags & CTL_LLF_COMPARE) 1552267537Smav io->scsiio.kern_data_ptr = (uint8_t *)&beio->sg_segs[CTLBLK_HALF_SEGS]; 1553267537Smav else 1554267537Smav io->scsiio.kern_data_ptr = (uint8_t *)beio->sg_segs; 1555264886Smav io->scsiio.kern_data_len = beio->io_len; 1556264886Smav io->scsiio.kern_data_resid = 0; 1557264886Smav io->scsiio.kern_sg_entries = beio->num_segs; 1558264886Smav io->io_hdr.flags |= CTL_FLAG_ALLOCATED | CTL_FLAG_KDPTR_SGLIST; 1559229997Sken 1560229997Sken /* 1561229997Sken * For the read case, we need to read the data into our buffers and 1562229997Sken * then we can send it back to the user. For the write case, we 1563229997Sken * need to get the data from the user first. 1564229997Sken */ 1565229997Sken if (beio->bio_cmd == BIO_READ) { 1566229997Sken SDT_PROBE(cbb, kernel, read, alloc_done, 0, 0, 0, 0, 0); 1567229997Sken be_lun->dispatch(be_lun, beio); 1568229997Sken } else { 1569229997Sken SDT_PROBE(cbb, kernel, write, alloc_done, 0, 0, 0, 0, 0); 1570229997Sken#ifdef CTL_TIME_IO 1571229997Sken getbintime(&io->io_hdr.dma_start_bt); 1572229997Sken#endif 1573229997Sken ctl_datamove(io); 1574229997Sken } 1575229997Sken} 1576229997Sken 1577229997Skenstatic void 1578229997Skenctl_be_block_worker(void *context, int pending) 1579229997Sken{ 1580229997Sken struct ctl_be_block_lun *be_lun; 1581229997Sken struct ctl_be_block_softc *softc; 1582229997Sken union ctl_io *io; 1583229997Sken 1584229997Sken be_lun = (struct ctl_be_block_lun *)context; 1585229997Sken softc = be_lun->softc; 1586229997Sken 1587229997Sken DPRINTF("entered\n"); 1588229997Sken 1589267877Smav mtx_lock(&be_lun->queue_lock); 1590229997Sken for (;;) { 1591229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->datamove_queue); 1592229997Sken if (io != NULL) { 1593229997Sken struct ctl_be_block_io *beio; 1594229997Sken 1595229997Sken DPRINTF("datamove queue\n"); 1596229997Sken 1597229997Sken STAILQ_REMOVE(&be_lun->datamove_queue, &io->io_hdr, 1598229997Sken ctl_io_hdr, links); 1599229997Sken 1600267877Smav mtx_unlock(&be_lun->queue_lock); 1601229997Sken 1602267519Smav beio = (struct ctl_be_block_io *)PRIV(io)->ptr; 1603229997Sken 1604229997Sken be_lun->dispatch(be_lun, beio); 1605229997Sken 1606267877Smav mtx_lock(&be_lun->queue_lock); 1607229997Sken continue; 1608229997Sken } 1609229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_write_queue); 1610229997Sken if (io != NULL) { 1611229997Sken DPRINTF("config write queue\n"); 1612229997Sken STAILQ_REMOVE(&be_lun->config_write_queue, &io->io_hdr, 1613229997Sken ctl_io_hdr, links); 1614267877Smav mtx_unlock(&be_lun->queue_lock); 1615229997Sken ctl_be_block_cw_dispatch(be_lun, io); 1616267877Smav mtx_lock(&be_lun->queue_lock); 1617229997Sken continue; 1618229997Sken } 1619275474Smav io = (union ctl_io *)STAILQ_FIRST(&be_lun->config_read_queue); 1620275474Smav if (io != NULL) { 1621275474Smav DPRINTF("config read queue\n"); 1622275474Smav STAILQ_REMOVE(&be_lun->config_read_queue, &io->io_hdr, 1623275474Smav ctl_io_hdr, links); 1624275474Smav mtx_unlock(&be_lun->queue_lock); 1625275474Smav ctl_be_block_cr_dispatch(be_lun, io); 1626275474Smav mtx_lock(&be_lun->queue_lock); 1627275474Smav continue; 1628275474Smav } 1629229997Sken io = (union ctl_io *)STAILQ_FIRST(&be_lun->input_queue); 1630229997Sken if (io != NULL) { 1631229997Sken DPRINTF("input queue\n"); 1632229997Sken 1633229997Sken STAILQ_REMOVE(&be_lun->input_queue, &io->io_hdr, 1634229997Sken ctl_io_hdr, links); 1635267877Smav mtx_unlock(&be_lun->queue_lock); 1636229997Sken 1637229997Sken /* 1638229997Sken * We must drop the lock, since this routine and 1639229997Sken * its children may sleep. 1640229997Sken */ 1641229997Sken ctl_be_block_dispatch(be_lun, io); 1642229997Sken 1643267877Smav mtx_lock(&be_lun->queue_lock); 1644229997Sken continue; 1645229997Sken } 1646229997Sken 1647229997Sken /* 1648229997Sken * If we get here, there is no work left in the queues, so 1649229997Sken * just break out and let the task queue go to sleep. 1650229997Sken */ 1651229997Sken break; 1652229997Sken } 1653267877Smav mtx_unlock(&be_lun->queue_lock); 1654229997Sken} 1655229997Sken 1656229997Sken/* 1657229997Sken * Entry point from CTL to the backend for I/O. We queue everything to a 1658229997Sken * work thread, so this just puts the I/O on a queue and wakes up the 1659229997Sken * thread. 1660229997Sken */ 1661229997Skenstatic int 1662229997Skenctl_be_block_submit(union ctl_io *io) 1663229997Sken{ 1664229997Sken struct ctl_be_block_lun *be_lun; 1665287499Smav struct ctl_be_lun *cbe_lun; 1666229997Sken 1667229997Sken DPRINTF("entered\n"); 1668229997Sken 1669287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 1670229997Sken CTL_PRIV_BACKEND_LUN].ptr; 1671287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 1672229997Sken 1673229997Sken /* 1674229997Sken * Make sure we only get SCSI I/O. 1675229997Sken */ 1676229997Sken KASSERT(io->io_hdr.io_type == CTL_IO_SCSI, ("Non-SCSI I/O (type " 1677229997Sken "%#x) encountered", io->io_hdr.io_type)); 1678229997Sken 1679267519Smav PRIV(io)->len = 0; 1680267519Smav 1681267877Smav mtx_lock(&be_lun->queue_lock); 1682229997Sken /* 1683229997Sken * XXX KDM make sure that links is okay to use at this point. 1684229997Sken * Otherwise, we either need to add another field to ctl_io_hdr, 1685229997Sken * or deal with resource allocation here. 1686229997Sken */ 1687229997Sken STAILQ_INSERT_TAIL(&be_lun->input_queue, &io->io_hdr, links); 1688267877Smav mtx_unlock(&be_lun->queue_lock); 1689229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 1690229997Sken 1691267514Smav return (CTL_RETVAL_COMPLETE); 1692229997Sken} 1693229997Sken 1694229997Skenstatic int 1695229997Skenctl_be_block_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 1696229997Sken int flag, struct thread *td) 1697229997Sken{ 1698229997Sken struct ctl_be_block_softc *softc; 1699229997Sken int error; 1700229997Sken 1701229997Sken softc = &backend_block_softc; 1702229997Sken 1703229997Sken error = 0; 1704229997Sken 1705229997Sken switch (cmd) { 1706229997Sken case CTL_LUN_REQ: { 1707229997Sken struct ctl_lun_req *lun_req; 1708229997Sken 1709229997Sken lun_req = (struct ctl_lun_req *)addr; 1710229997Sken 1711229997Sken switch (lun_req->reqtype) { 1712229997Sken case CTL_LUNREQ_CREATE: 1713229997Sken error = ctl_be_block_create(softc, lun_req); 1714229997Sken break; 1715229997Sken case CTL_LUNREQ_RM: 1716229997Sken error = ctl_be_block_rm(softc, lun_req); 1717229997Sken break; 1718232604Strasz case CTL_LUNREQ_MODIFY: 1719232604Strasz error = ctl_be_block_modify(softc, lun_req); 1720232604Strasz break; 1721229997Sken default: 1722229997Sken lun_req->status = CTL_LUN_ERROR; 1723229997Sken snprintf(lun_req->error_str, sizeof(lun_req->error_str), 1724272911Smav "invalid LUN request type %d", 1725229997Sken lun_req->reqtype); 1726229997Sken break; 1727229997Sken } 1728229997Sken break; 1729229997Sken } 1730229997Sken default: 1731229997Sken error = ENOTTY; 1732229997Sken break; 1733229997Sken } 1734229997Sken 1735229997Sken return (error); 1736229997Sken} 1737229997Sken 1738229997Skenstatic int 1739229997Skenctl_be_block_open_file(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1740229997Sken{ 1741287499Smav struct ctl_be_lun *cbe_lun; 1742229997Sken struct ctl_be_block_filedata *file_data; 1743229997Sken struct ctl_lun_create_params *params; 1744275865Smav char *value; 1745229997Sken struct vattr vattr; 1746275865Smav off_t ps, pss, po, pos, us, uss, uo, uos; 1747229997Sken int error; 1748229997Sken 1749229997Sken error = 0; 1750287499Smav cbe_lun = &be_lun->cbe_lun; 1751229997Sken file_data = &be_lun->backend.file; 1752272911Smav params = &be_lun->params; 1753229997Sken 1754229997Sken be_lun->dev_type = CTL_BE_BLOCK_FILE; 1755229997Sken be_lun->dispatch = ctl_be_block_dispatch_file; 1756229997Sken be_lun->lun_flush = ctl_be_block_flush_file; 1757275474Smav be_lun->get_lba_status = ctl_be_block_gls_file; 1758275481Smav be_lun->getattr = ctl_be_block_getattr_file; 1759287499Smav be_lun->unmap = NULL; 1760287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 1761229997Sken 1762229997Sken error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 1763229997Sken if (error != 0) { 1764229997Sken snprintf(req->error_str, sizeof(req->error_str), 1765229997Sken "error calling VOP_GETATTR() for file %s", 1766229997Sken be_lun->dev_path); 1767229997Sken return (error); 1768229997Sken } 1769229997Sken 1770229997Sken /* 1771229997Sken * Verify that we have the ability to upgrade to exclusive 1772229997Sken * access on this file so we can trap errors at open instead 1773229997Sken * of reporting them during first access. 1774229997Sken */ 1775229997Sken if (VOP_ISLOCKED(be_lun->vn) != LK_EXCLUSIVE) { 1776229997Sken vn_lock(be_lun->vn, LK_UPGRADE | LK_RETRY); 1777229997Sken if (be_lun->vn->v_iflag & VI_DOOMED) { 1778229997Sken error = EBADF; 1779229997Sken snprintf(req->error_str, sizeof(req->error_str), 1780229997Sken "error locking file %s", be_lun->dev_path); 1781229997Sken return (error); 1782229997Sken } 1783229997Sken } 1784229997Sken 1785229997Sken file_data->cred = crhold(curthread->td_ucred); 1786232604Strasz if (params->lun_size_bytes != 0) 1787232604Strasz be_lun->size_bytes = params->lun_size_bytes; 1788232604Strasz else 1789232604Strasz be_lun->size_bytes = vattr.va_size; 1790229997Sken 1791229997Sken /* 1792273029Smav * For files we can use any logical block size. Prefer 512 bytes 1793273029Smav * for compatibility reasons. If file's vattr.va_blocksize 1794273029Smav * (preferred I/O block size) is bigger and multiple to chosen 1795273029Smav * logical block size -- report it as physical block size. 1796229997Sken */ 1797229997Sken if (params->blocksize_bytes != 0) 1798287499Smav cbe_lun->blocksize = params->blocksize_bytes; 1799229997Sken else 1800287499Smav cbe_lun->blocksize = 512; 1801287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 1802287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 1803287499Smav 0 : (be_lun->size_blocks - 1); 1804275865Smav 1805275865Smav us = ps = vattr.va_blocksize; 1806275865Smav uo = po = 0; 1807275865Smav 1808287499Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 1809275865Smav if (value != NULL) 1810275865Smav ctl_expand_number(value, &ps); 1811287499Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 1812275865Smav if (value != NULL) 1813275865Smav ctl_expand_number(value, &po); 1814287499Smav pss = ps / cbe_lun->blocksize; 1815287499Smav pos = po / cbe_lun->blocksize; 1816287499Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 1817287499Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 1818287499Smav cbe_lun->pblockexp = fls(pss) - 1; 1819287499Smav cbe_lun->pblockoff = (pss - pos) % pss; 1820273029Smav } 1821229997Sken 1822287499Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 1823275865Smav if (value != NULL) 1824275865Smav ctl_expand_number(value, &us); 1825287499Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 1826275865Smav if (value != NULL) 1827275865Smav ctl_expand_number(value, &uo); 1828287499Smav uss = us / cbe_lun->blocksize; 1829287499Smav uos = uo / cbe_lun->blocksize; 1830287499Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 1831287499Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 1832287499Smav cbe_lun->ublockexp = fls(uss) - 1; 1833287499Smav cbe_lun->ublockoff = (uss - uos) % uss; 1834275865Smav } 1835275865Smav 1836229997Sken /* 1837229997Sken * Sanity check. The media size has to be at least one 1838229997Sken * sector long. 1839229997Sken */ 1840287499Smav if (be_lun->size_bytes < cbe_lun->blocksize) { 1841229997Sken error = EINVAL; 1842229997Sken snprintf(req->error_str, sizeof(req->error_str), 1843229997Sken "file %s size %ju < block size %u", be_lun->dev_path, 1844287499Smav (uintmax_t)be_lun->size_bytes, cbe_lun->blocksize); 1845229997Sken } 1846275920Smav 1847287499Smav cbe_lun->opttxferlen = CTLBLK_MAX_IO_SIZE / cbe_lun->blocksize; 1848229997Sken return (error); 1849229997Sken} 1850229997Sken 1851229997Skenstatic int 1852229997Skenctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 1853229997Sken{ 1854287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 1855229997Sken struct ctl_lun_create_params *params; 1856229997Sken struct vattr vattr; 1857229997Sken struct cdev *dev; 1858229997Sken struct cdevsw *devsw; 1859275865Smav char *value; 1860287221Smav int error, atomic, maxio, unmap, tmp; 1861287221Smav off_t ps, pss, po, pos, us, uss, uo, uos, otmp; 1862229997Sken 1863272911Smav params = &be_lun->params; 1864229997Sken 1865229997Sken be_lun->dev_type = CTL_BE_BLOCK_DEV; 1866229997Sken be_lun->backend.dev.cdev = be_lun->vn->v_rdev; 1867229997Sken be_lun->backend.dev.csw = dev_refthread(be_lun->backend.dev.cdev, 1868229997Sken &be_lun->backend.dev.dev_ref); 1869229997Sken if (be_lun->backend.dev.csw == NULL) 1870229997Sken panic("Unable to retrieve device switch"); 1871275474Smav if (strcmp(be_lun->backend.dev.csw->d_name, "zvol") == 0) { 1872269123Smav be_lun->dispatch = ctl_be_block_dispatch_zvol; 1873275474Smav be_lun->get_lba_status = ctl_be_block_gls_zvol; 1874275920Smav atomic = maxio = CTLBLK_MAX_IO_SIZE; 1875275920Smav } else { 1876269123Smav be_lun->dispatch = ctl_be_block_dispatch_dev; 1877287499Smav be_lun->get_lba_status = NULL; 1878275920Smav atomic = 0; 1879275920Smav maxio = be_lun->backend.dev.cdev->si_iosize_max; 1880275920Smav if (maxio <= 0) 1881275920Smav maxio = DFLTPHYS; 1882275920Smav if (maxio > CTLBLK_MAX_IO_SIZE) 1883275920Smav maxio = CTLBLK_MAX_IO_SIZE; 1884275920Smav } 1885269123Smav be_lun->lun_flush = ctl_be_block_flush_dev; 1886274154Smav be_lun->getattr = ctl_be_block_getattr_dev; 1887287499Smav be_lun->unmap = ctl_be_block_unmap_dev; 1888229997Sken 1889229997Sken error = VOP_GETATTR(be_lun->vn, &vattr, NOCRED); 1890229997Sken if (error) { 1891229997Sken snprintf(req->error_str, sizeof(req->error_str), 1892272911Smav "error getting vnode attributes for device %s", 1893272911Smav be_lun->dev_path); 1894229997Sken return (error); 1895229997Sken } 1896229997Sken 1897229997Sken dev = be_lun->vn->v_rdev; 1898229997Sken devsw = dev->si_devsw; 1899229997Sken if (!devsw->d_ioctl) { 1900229997Sken snprintf(req->error_str, sizeof(req->error_str), 1901272911Smav "no d_ioctl for device %s!", 1902229997Sken be_lun->dev_path); 1903229997Sken return (ENODEV); 1904229997Sken } 1905229997Sken 1906286811Smav error = devsw->d_ioctl(dev, DIOCGSECTORSIZE, (caddr_t)&tmp, FREAD, 1907229997Sken curthread); 1908229997Sken if (error) { 1909229997Sken snprintf(req->error_str, sizeof(req->error_str), 1910272911Smav "error %d returned for DIOCGSECTORSIZE ioctl " 1911272911Smav "on %s!", error, be_lun->dev_path); 1912229997Sken return (error); 1913229997Sken } 1914229997Sken 1915229997Sken /* 1916229997Sken * If the user has asked for a blocksize that is greater than the 1917229997Sken * backing device's blocksize, we can do it only if the blocksize 1918229997Sken * the user is asking for is an even multiple of the underlying 1919229997Sken * device's blocksize. 1920229997Sken */ 1921286811Smav if ((params->blocksize_bytes != 0) && 1922286811Smav (params->blocksize_bytes >= tmp)) { 1923286811Smav if (params->blocksize_bytes % tmp == 0) { 1924287499Smav cbe_lun->blocksize = params->blocksize_bytes; 1925229997Sken } else { 1926229997Sken snprintf(req->error_str, sizeof(req->error_str), 1927272911Smav "requested blocksize %u is not an even " 1928229997Sken "multiple of backing device blocksize %u", 1929287221Smav params->blocksize_bytes, tmp); 1930229997Sken return (EINVAL); 1931229997Sken 1932229997Sken } 1933286811Smav } else if (params->blocksize_bytes != 0) { 1934229997Sken snprintf(req->error_str, sizeof(req->error_str), 1935272911Smav "requested blocksize %u < backing device " 1936287221Smav "blocksize %u", params->blocksize_bytes, tmp); 1937229997Sken return (EINVAL); 1938286811Smav } else 1939287499Smav cbe_lun->blocksize = tmp; 1940229997Sken 1941287221Smav error = devsw->d_ioctl(dev, DIOCGMEDIASIZE, (caddr_t)&otmp, FREAD, 1942229997Sken curthread); 1943229997Sken if (error) { 1944229997Sken snprintf(req->error_str, sizeof(req->error_str), 1945272911Smav "error %d returned for DIOCGMEDIASIZE " 1946272911Smav " ioctl on %s!", error, 1947232604Strasz be_lun->dev_path); 1948229997Sken return (error); 1949229997Sken } 1950229997Sken 1951232604Strasz if (params->lun_size_bytes != 0) { 1952287221Smav if (params->lun_size_bytes > otmp) { 1953232604Strasz snprintf(req->error_str, sizeof(req->error_str), 1954272911Smav "requested LUN size %ju > backing device " 1955272911Smav "size %ju", 1956232604Strasz (uintmax_t)params->lun_size_bytes, 1957287221Smav (uintmax_t)otmp); 1958232604Strasz return (EINVAL); 1959232604Strasz } 1960232604Strasz 1961232604Strasz be_lun->size_bytes = params->lun_size_bytes; 1962286811Smav } else 1963287221Smav be_lun->size_bytes = otmp; 1964287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 1965287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 1966287499Smav 0 : (be_lun->size_blocks - 1); 1967232604Strasz 1968264191Smav error = devsw->d_ioctl(dev, DIOCGSTRIPESIZE, 1969264191Smav (caddr_t)&ps, FREAD, curthread); 1970264191Smav if (error) 1971264191Smav ps = po = 0; 1972264191Smav else { 1973264191Smav error = devsw->d_ioctl(dev, DIOCGSTRIPEOFFSET, 1974264191Smav (caddr_t)&po, FREAD, curthread); 1975264191Smav if (error) 1976264191Smav po = 0; 1977264191Smav } 1978275865Smav us = ps; 1979275865Smav uo = po; 1980275865Smav 1981287499Smav value = ctl_get_opt(&cbe_lun->options, "pblocksize"); 1982275865Smav if (value != NULL) 1983275865Smav ctl_expand_number(value, &ps); 1984287499Smav value = ctl_get_opt(&cbe_lun->options, "pblockoffset"); 1985275865Smav if (value != NULL) 1986275865Smav ctl_expand_number(value, &po); 1987287499Smav pss = ps / cbe_lun->blocksize; 1988287499Smav pos = po / cbe_lun->blocksize; 1989287499Smav if ((pss > 0) && (pss * cbe_lun->blocksize == ps) && (pss >= pos) && 1990287499Smav ((pss & (pss - 1)) == 0) && (pos * cbe_lun->blocksize == po)) { 1991287499Smav cbe_lun->pblockexp = fls(pss) - 1; 1992287499Smav cbe_lun->pblockoff = (pss - pos) % pss; 1993264191Smav } 1994264191Smav 1995287499Smav value = ctl_get_opt(&cbe_lun->options, "ublocksize"); 1996275865Smav if (value != NULL) 1997275865Smav ctl_expand_number(value, &us); 1998287499Smav value = ctl_get_opt(&cbe_lun->options, "ublockoffset"); 1999275865Smav if (value != NULL) 2000275865Smav ctl_expand_number(value, &uo); 2001287499Smav uss = us / cbe_lun->blocksize; 2002287499Smav uos = uo / cbe_lun->blocksize; 2003287499Smav if ((uss > 0) && (uss * cbe_lun->blocksize == us) && (uss >= uos) && 2004287499Smav ((uss & (uss - 1)) == 0) && (uos * cbe_lun->blocksize == uo)) { 2005287499Smav cbe_lun->ublockexp = fls(uss) - 1; 2006287499Smav cbe_lun->ublockoff = (uss - uos) % uss; 2007275865Smav } 2008275865Smav 2009287499Smav cbe_lun->atomicblock = atomic / cbe_lun->blocksize; 2010287499Smav cbe_lun->opttxferlen = maxio / cbe_lun->blocksize; 2011278672Smav 2012278672Smav if (be_lun->dispatch == ctl_be_block_dispatch_zvol) { 2013278672Smav unmap = 1; 2014278672Smav } else { 2015278672Smav struct diocgattr_arg arg; 2016278672Smav 2017278672Smav strlcpy(arg.name, "GEOM::candelete", sizeof(arg.name)); 2018278672Smav arg.len = sizeof(arg.value.i); 2019278672Smav error = devsw->d_ioctl(dev, DIOCGATTR, 2020278672Smav (caddr_t)&arg, FREAD, curthread); 2021278672Smav unmap = (error == 0) ? arg.value.i : 0; 2022278672Smav } 2023287499Smav value = ctl_get_opt(&cbe_lun->options, "unmap"); 2024278672Smav if (value != NULL) 2025278672Smav unmap = (strcmp(value, "on") == 0); 2026278672Smav if (unmap) 2027287499Smav cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 2028287499Smav else 2029287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_UNMAP; 2030278672Smav 2031229997Sken return (0); 2032229997Sken} 2033229997Sken 2034229997Skenstatic int 2035229997Skenctl_be_block_close(struct ctl_be_block_lun *be_lun) 2036229997Sken{ 2037287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2038287499Smav int flags; 2039287499Smav 2040229997Sken if (be_lun->vn) { 2041229997Sken switch (be_lun->dev_type) { 2042229997Sken case CTL_BE_BLOCK_DEV: 2043229997Sken if (be_lun->backend.dev.csw) { 2044229997Sken dev_relthread(be_lun->backend.dev.cdev, 2045229997Sken be_lun->backend.dev.dev_ref); 2046229997Sken be_lun->backend.dev.csw = NULL; 2047229997Sken be_lun->backend.dev.cdev = NULL; 2048229997Sken } 2049229997Sken break; 2050229997Sken case CTL_BE_BLOCK_FILE: 2051229997Sken break; 2052229997Sken case CTL_BE_BLOCK_NONE: 2053258871Strasz break; 2054229997Sken default: 2055229997Sken panic("Unexpected backend type."); 2056229997Sken break; 2057229997Sken } 2058229997Sken 2059287499Smav flags = FREAD; 2060287499Smav if ((cbe_lun->flags & CTL_LUN_FLAG_READONLY) == 0) 2061287499Smav flags |= FWRITE; 2062229997Sken (void)vn_close(be_lun->vn, flags, NOCRED, curthread); 2063229997Sken be_lun->vn = NULL; 2064229997Sken 2065229997Sken switch (be_lun->dev_type) { 2066229997Sken case CTL_BE_BLOCK_DEV: 2067229997Sken break; 2068229997Sken case CTL_BE_BLOCK_FILE: 2069229997Sken if (be_lun->backend.file.cred != NULL) { 2070229997Sken crfree(be_lun->backend.file.cred); 2071229997Sken be_lun->backend.file.cred = NULL; 2072229997Sken } 2073229997Sken break; 2074229997Sken case CTL_BE_BLOCK_NONE: 2075258871Strasz break; 2076229997Sken default: 2077229997Sken panic("Unexpected backend type."); 2078229997Sken break; 2079229997Sken } 2080272911Smav be_lun->dev_type = CTL_BE_BLOCK_NONE; 2081229997Sken } 2082229997Sken return (0); 2083229997Sken} 2084229997Sken 2085229997Skenstatic int 2086229997Skenctl_be_block_open(struct ctl_be_block_softc *softc, 2087287499Smav struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req) 2088229997Sken{ 2089287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2090229997Sken struct nameidata nd; 2091287499Smav char *value; 2092287499Smav int error, flags; 2093229997Sken 2094229997Sken error = 0; 2095229997Sken if (rootvnode == NULL) { 2096229997Sken snprintf(req->error_str, sizeof(req->error_str), 2097272911Smav "Root filesystem is not mounted"); 2098229997Sken return (1); 2099229997Sken } 2100285391Smjg pwd_ensure_dirs(); 2101229997Sken 2102287499Smav value = ctl_get_opt(&cbe_lun->options, "file"); 2103287499Smav if (value == NULL) { 2104287499Smav snprintf(req->error_str, sizeof(req->error_str), 2105287499Smav "no file argument specified"); 2106287499Smav return (1); 2107287499Smav } 2108287499Smav free(be_lun->dev_path, M_CTLBLK); 2109287499Smav be_lun->dev_path = strdup(value, M_CTLBLK); 2110287499Smav 2111287499Smav flags = FREAD; 2112287499Smav value = ctl_get_opt(&cbe_lun->options, "readonly"); 2113287499Smav if (value == NULL || strcmp(value, "on") != 0) 2114287499Smav flags |= FWRITE; 2115287499Smav 2116287499Smavagain: 2117229997Sken NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, be_lun->dev_path, curthread); 2118229997Sken error = vn_open(&nd, &flags, 0, NULL); 2119287499Smav if ((error == EROFS || error == EACCES) && (flags & FWRITE)) { 2120287499Smav flags &= ~FWRITE; 2121287499Smav goto again; 2122287499Smav } 2123229997Sken if (error) { 2124229997Sken /* 2125229997Sken * This is the only reasonable guess we can make as far as 2126229997Sken * path if the user doesn't give us a fully qualified path. 2127229997Sken * If they want to specify a file, they need to specify the 2128229997Sken * full path. 2129229997Sken */ 2130229997Sken if (be_lun->dev_path[0] != '/') { 2131229997Sken char *dev_name; 2132229997Sken 2133287499Smav asprintf(&dev_name, M_CTLBLK, "/dev/%s", 2134287499Smav be_lun->dev_path); 2135287499Smav free(be_lun->dev_path, M_CTLBLK); 2136287499Smav be_lun->dev_path = dev_name; 2137287499Smav goto again; 2138229997Sken } 2139229997Sken snprintf(req->error_str, sizeof(req->error_str), 2140272911Smav "error opening %s: %d", be_lun->dev_path, error); 2141229997Sken return (error); 2142229997Sken } 2143287499Smav if (flags & FWRITE) 2144287499Smav cbe_lun->flags &= ~CTL_LUN_FLAG_READONLY; 2145287499Smav else 2146287499Smav cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 2147229997Sken 2148229997Sken NDFREE(&nd, NDF_ONLY_PNBUF); 2149229997Sken be_lun->vn = nd.ni_vp; 2150229997Sken 2151229997Sken /* We only support disks and files. */ 2152229997Sken if (vn_isdisk(be_lun->vn, &error)) { 2153229997Sken error = ctl_be_block_open_dev(be_lun, req); 2154229997Sken } else if (be_lun->vn->v_type == VREG) { 2155229997Sken error = ctl_be_block_open_file(be_lun, req); 2156229997Sken } else { 2157229997Sken error = EINVAL; 2158229997Sken snprintf(req->error_str, sizeof(req->error_str), 2159258871Strasz "%s is not a disk or plain file", be_lun->dev_path); 2160229997Sken } 2161229997Sken VOP_UNLOCK(be_lun->vn, 0); 2162229997Sken 2163286811Smav if (error != 0) 2164229997Sken ctl_be_block_close(be_lun); 2165287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2166287499Smav if (be_lun->dispatch != ctl_be_block_dispatch_dev) 2167287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2168287499Smav value = ctl_get_opt(&cbe_lun->options, "serseq"); 2169287499Smav if (value != NULL && strcmp(value, "on") == 0) 2170287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 2171287499Smav else if (value != NULL && strcmp(value, "read") == 0) 2172287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 2173287499Smav else if (value != NULL && strcmp(value, "off") == 0) 2174287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 2175229997Sken return (0); 2176229997Sken} 2177229997Sken 2178229997Skenstatic int 2179229997Skenctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2180229997Sken{ 2181287499Smav struct ctl_be_lun *cbe_lun; 2182229997Sken struct ctl_be_block_lun *be_lun; 2183229997Sken struct ctl_lun_create_params *params; 2184267481Smav char num_thread_str[16]; 2185229997Sken char tmpstr[32]; 2186267481Smav char *value; 2187278672Smav int retval, num_threads; 2188267481Smav int tmp_num_threads; 2189229997Sken 2190229997Sken params = &req->reqdata.create; 2191229997Sken retval = 0; 2192272911Smav req->status = CTL_LUN_OK; 2193229997Sken 2194229997Sken be_lun = malloc(sizeof(*be_lun), M_CTLBLK, M_ZERO | M_WAITOK); 2195287499Smav cbe_lun = &be_lun->cbe_lun; 2196287499Smav cbe_lun->be_lun = be_lun; 2197272911Smav be_lun->params = req->reqdata.create; 2198229997Sken be_lun->softc = softc; 2199229997Sken STAILQ_INIT(&be_lun->input_queue); 2200275474Smav STAILQ_INIT(&be_lun->config_read_queue); 2201229997Sken STAILQ_INIT(&be_lun->config_write_queue); 2202229997Sken STAILQ_INIT(&be_lun->datamove_queue); 2203229997Sken sprintf(be_lun->lunname, "cblk%d", softc->num_luns); 2204267877Smav mtx_init(&be_lun->io_lock, "cblk io lock", NULL, MTX_DEF); 2205267877Smav mtx_init(&be_lun->queue_lock, "cblk queue lock", NULL, MTX_DEF); 2206287499Smav ctl_init_opts(&cbe_lun->options, 2207268280Smav req->num_be_args, req->kern_be_args); 2208264886Smav be_lun->lun_zone = uma_zcreate(be_lun->lunname, CTLBLK_MAX_SEG, 2209256995Smav NULL, NULL, NULL, NULL, /*align*/ 0, /*flags*/0); 2210229997Sken if (be_lun->lun_zone == NULL) { 2211229997Sken snprintf(req->error_str, sizeof(req->error_str), 2212272911Smav "error allocating UMA zone"); 2213229997Sken goto bailout_error; 2214229997Sken } 2215229997Sken 2216229997Sken if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 2217287499Smav cbe_lun->lun_type = params->device_type; 2218229997Sken else 2219287499Smav cbe_lun->lun_type = T_DIRECT; 2220287499Smav be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED; 2221287621Smav cbe_lun->flags = 0; 2222287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2223287621Smav if (value != NULL) { 2224287621Smav if (strcmp(value, "primary") == 0) 2225287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2226287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2227287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2228229997Sken 2229287499Smav if (cbe_lun->lun_type == T_DIRECT) { 2230286811Smav be_lun->size_bytes = params->lun_size_bytes; 2231286811Smav if (params->blocksize_bytes != 0) 2232287499Smav cbe_lun->blocksize = params->blocksize_bytes; 2233286811Smav else 2234287499Smav cbe_lun->blocksize = 512; 2235287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2236287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2237287499Smav 0 : (be_lun->size_blocks - 1); 2238229997Sken 2239287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2240287621Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2241287621Smav retval = ctl_be_block_open(softc, be_lun, req); 2242287621Smav if (retval != 0) { 2243287621Smav retval = 0; 2244287621Smav req->status = CTL_LUN_WARNING; 2245287621Smav } 2246229997Sken } 2247287499Smav num_threads = cbb_num_threads; 2248229997Sken } else { 2249229997Sken num_threads = 1; 2250229997Sken } 2251229997Sken 2252229997Sken /* 2253229997Sken * XXX This searching loop might be refactored to be combined with 2254229997Sken * the loop above, 2255229997Sken */ 2256287499Smav value = ctl_get_opt(&cbe_lun->options, "num_threads"); 2257267481Smav if (value != NULL) { 2258267481Smav tmp_num_threads = strtol(value, NULL, 0); 2259229997Sken 2260267481Smav /* 2261267481Smav * We don't let the user specify less than one 2262267481Smav * thread, but hope he's clueful enough not to 2263267481Smav * specify 1000 threads. 2264267481Smav */ 2265267481Smav if (tmp_num_threads < 1) { 2266267481Smav snprintf(req->error_str, sizeof(req->error_str), 2267272911Smav "invalid number of threads %s", 2268272911Smav num_thread_str); 2269267481Smav goto bailout_error; 2270229997Sken } 2271267481Smav num_threads = tmp_num_threads; 2272229997Sken } 2273229997Sken 2274272911Smav if (be_lun->vn == NULL) 2275287499Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2276229997Sken /* Tell the user the blocksize we ended up using */ 2277272911Smav params->lun_size_bytes = be_lun->size_bytes; 2278287499Smav params->blocksize_bytes = cbe_lun->blocksize; 2279229997Sken if (params->flags & CTL_LUN_FLAG_ID_REQ) { 2280287499Smav cbe_lun->req_lun_id = params->req_lun_id; 2281287499Smav cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 2282229997Sken } else 2283287499Smav cbe_lun->req_lun_id = 0; 2284229997Sken 2285287499Smav cbe_lun->lun_shutdown = ctl_be_block_lun_shutdown; 2286287499Smav cbe_lun->lun_config_status = ctl_be_block_lun_config_status; 2287287499Smav cbe_lun->be = &ctl_be_block_driver; 2288229997Sken 2289229997Sken if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 2290229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 2291229997Sken softc->num_luns); 2292287499Smav strncpy((char *)cbe_lun->serial_num, tmpstr, 2293287499Smav MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 2294229997Sken 2295229997Sken /* Tell the user what we used for a serial number */ 2296229997Sken strncpy((char *)params->serial_num, tmpstr, 2297275953Smav MIN(sizeof(params->serial_num), sizeof(tmpstr))); 2298229997Sken } else { 2299287499Smav strncpy((char *)cbe_lun->serial_num, params->serial_num, 2300287499Smav MIN(sizeof(cbe_lun->serial_num), 2301229997Sken sizeof(params->serial_num))); 2302229997Sken } 2303229997Sken if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 2304229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 2305287499Smav strncpy((char *)cbe_lun->device_id, tmpstr, 2306287499Smav MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 2307229997Sken 2308229997Sken /* Tell the user what we used for a device ID */ 2309229997Sken strncpy((char *)params->device_id, tmpstr, 2310275953Smav MIN(sizeof(params->device_id), sizeof(tmpstr))); 2311229997Sken } else { 2312287499Smav strncpy((char *)cbe_lun->device_id, params->device_id, 2313287499Smav MIN(sizeof(cbe_lun->device_id), 2314275953Smav sizeof(params->device_id))); 2315229997Sken } 2316229997Sken 2317229997Sken TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_be_block_worker, be_lun); 2318229997Sken 2319229997Sken be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 2320229997Sken taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 2321229997Sken 2322229997Sken if (be_lun->io_taskqueue == NULL) { 2323229997Sken snprintf(req->error_str, sizeof(req->error_str), 2324272911Smav "unable to create taskqueue"); 2325229997Sken goto bailout_error; 2326229997Sken } 2327229997Sken 2328229997Sken /* 2329229997Sken * Note that we start the same number of threads by default for 2330229997Sken * both the file case and the block device case. For the file 2331229997Sken * case, we need multiple threads to allow concurrency, because the 2332229997Sken * vnode interface is designed to be a blocking interface. For the 2333229997Sken * block device case, ZFS zvols at least will block the caller's 2334229997Sken * context in many instances, and so we need multiple threads to 2335229997Sken * overcome that problem. Other block devices don't need as many 2336229997Sken * threads, but they shouldn't cause too many problems. 2337229997Sken * 2338229997Sken * If the user wants to just have a single thread for a block 2339229997Sken * device, he can specify that when the LUN is created, or change 2340229997Sken * the tunable/sysctl to alter the default number of threads. 2341229997Sken */ 2342229997Sken retval = taskqueue_start_threads(&be_lun->io_taskqueue, 2343229997Sken /*num threads*/num_threads, 2344229997Sken /*priority*/PWAIT, 2345229997Sken /*thread name*/ 2346229997Sken "%s taskq", be_lun->lunname); 2347229997Sken 2348229997Sken if (retval != 0) 2349229997Sken goto bailout_error; 2350229997Sken 2351229997Sken be_lun->num_threads = num_threads; 2352229997Sken 2353229997Sken mtx_lock(&softc->lock); 2354229997Sken softc->num_luns++; 2355229997Sken STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 2356229997Sken 2357229997Sken mtx_unlock(&softc->lock); 2358229997Sken 2359287499Smav retval = ctl_add_lun(&be_lun->cbe_lun); 2360229997Sken if (retval != 0) { 2361229997Sken mtx_lock(&softc->lock); 2362229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2363229997Sken links); 2364229997Sken softc->num_luns--; 2365229997Sken mtx_unlock(&softc->lock); 2366229997Sken snprintf(req->error_str, sizeof(req->error_str), 2367272911Smav "ctl_add_lun() returned error %d, see dmesg for " 2368272911Smav "details", retval); 2369229997Sken retval = 0; 2370229997Sken goto bailout_error; 2371229997Sken } 2372229997Sken 2373229997Sken mtx_lock(&softc->lock); 2374229997Sken 2375229997Sken /* 2376229997Sken * Tell the config_status routine that we're waiting so it won't 2377229997Sken * clean up the LUN in the event of an error. 2378229997Sken */ 2379229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2380229997Sken 2381229997Sken while (be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) { 2382229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2383229997Sken if (retval == EINTR) 2384229997Sken break; 2385229997Sken } 2386229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2387229997Sken 2388229997Sken if (be_lun->flags & CTL_BE_BLOCK_LUN_CONFIG_ERR) { 2389229997Sken snprintf(req->error_str, sizeof(req->error_str), 2390272911Smav "LUN configuration error, see dmesg for details"); 2391229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, 2392229997Sken links); 2393229997Sken softc->num_luns--; 2394229997Sken mtx_unlock(&softc->lock); 2395229997Sken goto bailout_error; 2396229997Sken } else { 2397287499Smav params->req_lun_id = cbe_lun->lun_id; 2398229997Sken } 2399229997Sken 2400229997Sken mtx_unlock(&softc->lock); 2401229997Sken 2402229997Sken be_lun->disk_stats = devstat_new_entry("cbb", params->req_lun_id, 2403287499Smav cbe_lun->blocksize, 2404229997Sken DEVSTAT_ALL_SUPPORTED, 2405287499Smav cbe_lun->lun_type 2406229997Sken | DEVSTAT_TYPE_IF_OTHER, 2407229997Sken DEVSTAT_PRIORITY_OTHER); 2408229997Sken 2409229997Sken return (retval); 2410229997Sken 2411229997Skenbailout_error: 2412229997Sken req->status = CTL_LUN_ERROR; 2413229997Sken 2414267429Smav if (be_lun->io_taskqueue != NULL) 2415267429Smav taskqueue_free(be_lun->io_taskqueue); 2416229997Sken ctl_be_block_close(be_lun); 2417267429Smav if (be_lun->dev_path != NULL) 2418267429Smav free(be_lun->dev_path, M_CTLBLK); 2419267429Smav if (be_lun->lun_zone != NULL) 2420267429Smav uma_zdestroy(be_lun->lun_zone); 2421287499Smav ctl_free_opts(&cbe_lun->options); 2422267877Smav mtx_destroy(&be_lun->queue_lock); 2423267877Smav mtx_destroy(&be_lun->io_lock); 2424229997Sken free(be_lun, M_CTLBLK); 2425229997Sken 2426229997Sken return (retval); 2427229997Sken} 2428229997Sken 2429229997Skenstatic int 2430229997Skenctl_be_block_rm(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2431229997Sken{ 2432229997Sken struct ctl_lun_rm_params *params; 2433229997Sken struct ctl_be_block_lun *be_lun; 2434229997Sken int retval; 2435229997Sken 2436229997Sken params = &req->reqdata.rm; 2437229997Sken 2438229997Sken mtx_lock(&softc->lock); 2439229997Sken STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2440287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2441229997Sken break; 2442229997Sken } 2443229997Sken mtx_unlock(&softc->lock); 2444229997Sken 2445229997Sken if (be_lun == NULL) { 2446229997Sken snprintf(req->error_str, sizeof(req->error_str), 2447272911Smav "LUN %u is not managed by the block backend", 2448272911Smav params->lun_id); 2449229997Sken goto bailout_error; 2450229997Sken } 2451229997Sken 2452287499Smav retval = ctl_disable_lun(&be_lun->cbe_lun); 2453229997Sken 2454229997Sken if (retval != 0) { 2455229997Sken snprintf(req->error_str, sizeof(req->error_str), 2456272911Smav "error %d returned from ctl_disable_lun() for " 2457272911Smav "LUN %d", retval, params->lun_id); 2458229997Sken goto bailout_error; 2459229997Sken 2460229997Sken } 2461229997Sken 2462287499Smav retval = ctl_invalidate_lun(&be_lun->cbe_lun); 2463229997Sken if (retval != 0) { 2464229997Sken snprintf(req->error_str, sizeof(req->error_str), 2465272911Smav "error %d returned from ctl_invalidate_lun() for " 2466272911Smav "LUN %d", retval, params->lun_id); 2467229997Sken goto bailout_error; 2468229997Sken } 2469229997Sken 2470229997Sken mtx_lock(&softc->lock); 2471229997Sken 2472229997Sken be_lun->flags |= CTL_BE_BLOCK_LUN_WAITING; 2473229997Sken 2474229997Sken while ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2475229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlblk", 0); 2476229997Sken if (retval == EINTR) 2477229997Sken break; 2478229997Sken } 2479229997Sken 2480229997Sken be_lun->flags &= ~CTL_BE_BLOCK_LUN_WAITING; 2481229997Sken 2482229997Sken if ((be_lun->flags & CTL_BE_BLOCK_LUN_UNCONFIGURED) == 0) { 2483229997Sken snprintf(req->error_str, sizeof(req->error_str), 2484272911Smav "interrupted waiting for LUN to be freed"); 2485229997Sken mtx_unlock(&softc->lock); 2486229997Sken goto bailout_error; 2487229997Sken } 2488229997Sken 2489229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_block_lun, links); 2490229997Sken 2491229997Sken softc->num_luns--; 2492229997Sken mtx_unlock(&softc->lock); 2493229997Sken 2494229997Sken taskqueue_drain(be_lun->io_taskqueue, &be_lun->io_task); 2495229997Sken 2496229997Sken taskqueue_free(be_lun->io_taskqueue); 2497229997Sken 2498229997Sken ctl_be_block_close(be_lun); 2499229997Sken 2500229997Sken if (be_lun->disk_stats != NULL) 2501229997Sken devstat_remove_entry(be_lun->disk_stats); 2502229997Sken 2503229997Sken uma_zdestroy(be_lun->lun_zone); 2504229997Sken 2505287499Smav ctl_free_opts(&be_lun->cbe_lun.options); 2506229997Sken free(be_lun->dev_path, M_CTLBLK); 2507267877Smav mtx_destroy(&be_lun->queue_lock); 2508267877Smav mtx_destroy(&be_lun->io_lock); 2509229997Sken free(be_lun, M_CTLBLK); 2510229997Sken 2511229997Sken req->status = CTL_LUN_OK; 2512229997Sken 2513229997Sken return (0); 2514229997Sken 2515229997Skenbailout_error: 2516229997Sken 2517229997Sken req->status = CTL_LUN_ERROR; 2518229997Sken 2519229997Sken return (0); 2520229997Sken} 2521229997Sken 2522232604Straszstatic int 2523232604Straszctl_be_block_modify_file(struct ctl_be_block_lun *be_lun, 2524232604Strasz struct ctl_lun_req *req) 2525232604Strasz{ 2526287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2527232604Strasz struct vattr vattr; 2528232604Strasz int error; 2529272911Smav struct ctl_lun_create_params *params = &be_lun->params; 2530232604Strasz 2531232604Strasz if (params->lun_size_bytes != 0) { 2532232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2533232604Strasz } else { 2534271794Smav vn_lock(be_lun->vn, LK_SHARED | LK_RETRY); 2535232604Strasz error = VOP_GETATTR(be_lun->vn, &vattr, curthread->td_ucred); 2536271794Smav VOP_UNLOCK(be_lun->vn, 0); 2537232604Strasz if (error != 0) { 2538232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2539232604Strasz "error calling VOP_GETATTR() for file %s", 2540232604Strasz be_lun->dev_path); 2541232604Strasz return (error); 2542232604Strasz } 2543232604Strasz be_lun->size_bytes = vattr.va_size; 2544232604Strasz } 2545287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2546287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2547287499Smav 0 : (be_lun->size_blocks - 1); 2548232604Strasz return (0); 2549232604Strasz} 2550232604Strasz 2551232604Straszstatic int 2552232604Straszctl_be_block_modify_dev(struct ctl_be_block_lun *be_lun, 2553232604Strasz struct ctl_lun_req *req) 2554232604Strasz{ 2555287499Smav struct ctl_be_lun *cbe_lun = &be_lun->cbe_lun; 2556271794Smav struct ctl_be_block_devdata *dev_data; 2557232604Strasz int error; 2558272911Smav struct ctl_lun_create_params *params = &be_lun->params; 2559232604Strasz uint64_t size_bytes; 2560232604Strasz 2561271794Smav dev_data = &be_lun->backend.dev; 2562271794Smav if (!dev_data->csw->d_ioctl) { 2563232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2564272911Smav "no d_ioctl for device %s!", be_lun->dev_path); 2565232604Strasz return (ENODEV); 2566232604Strasz } 2567232604Strasz 2568271794Smav error = dev_data->csw->d_ioctl(dev_data->cdev, DIOCGMEDIASIZE, 2569232604Strasz (caddr_t)&size_bytes, FREAD, 2570232604Strasz curthread); 2571232604Strasz if (error) { 2572232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2573272911Smav "error %d returned for DIOCGMEDIASIZE ioctl " 2574272911Smav "on %s!", error, be_lun->dev_path); 2575232604Strasz return (error); 2576232604Strasz } 2577232604Strasz 2578232604Strasz if (params->lun_size_bytes != 0) { 2579232604Strasz if (params->lun_size_bytes > size_bytes) { 2580232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2581272911Smav "requested LUN size %ju > backing device " 2582272911Smav "size %ju", 2583232604Strasz (uintmax_t)params->lun_size_bytes, 2584232604Strasz (uintmax_t)size_bytes); 2585232604Strasz return (EINVAL); 2586232604Strasz } 2587232604Strasz be_lun->size_bytes = params->lun_size_bytes; 2588232604Strasz } else { 2589232604Strasz be_lun->size_bytes = size_bytes; 2590232604Strasz } 2591287499Smav be_lun->size_blocks = be_lun->size_bytes / cbe_lun->blocksize; 2592287499Smav cbe_lun->maxlba = (be_lun->size_blocks == 0) ? 2593287499Smav 0 : (be_lun->size_blocks - 1); 2594232604Strasz return (0); 2595232604Strasz} 2596232604Strasz 2597232604Straszstatic int 2598232604Straszctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req) 2599232604Strasz{ 2600232604Strasz struct ctl_lun_modify_params *params; 2601232604Strasz struct ctl_be_block_lun *be_lun; 2602287500Smav struct ctl_be_lun *cbe_lun; 2603287621Smav char *value; 2604271794Smav uint64_t oldsize; 2605287621Smav int error, wasprim; 2606232604Strasz 2607232604Strasz params = &req->reqdata.modify; 2608232604Strasz 2609232604Strasz mtx_lock(&softc->lock); 2610232604Strasz STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 2611287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 2612232604Strasz break; 2613232604Strasz } 2614232604Strasz mtx_unlock(&softc->lock); 2615232604Strasz 2616232604Strasz if (be_lun == NULL) { 2617232604Strasz snprintf(req->error_str, sizeof(req->error_str), 2618272911Smav "LUN %u is not managed by the block backend", 2619272911Smav params->lun_id); 2620232604Strasz goto bailout_error; 2621232604Strasz } 2622287500Smav cbe_lun = &be_lun->cbe_lun; 2623232604Strasz 2624287500Smav if (params->lun_size_bytes != 0) 2625287500Smav be_lun->params.lun_size_bytes = params->lun_size_bytes; 2626287500Smav ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 2627232604Strasz 2628287621Smav wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 2629287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 2630287621Smav if (value != NULL) { 2631287621Smav if (strcmp(value, "primary") == 0) 2632287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2633287621Smav else 2634287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2635287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 2636287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 2637232604Strasz else 2638287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 2639287621Smav if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 2640287621Smav if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 2641287621Smav ctl_lun_primary(cbe_lun); 2642287621Smav else 2643287621Smav ctl_lun_secondary(cbe_lun); 2644287621Smav } 2645232604Strasz 2646287621Smav oldsize = be_lun->size_blocks; 2647287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) || 2648287621Smav control_softc->ha_mode == CTL_HA_MODE_SER_ONLY) { 2649287621Smav if (be_lun->vn == NULL) 2650287621Smav error = ctl_be_block_open(softc, be_lun, req); 2651287621Smav else if (vn_isdisk(be_lun->vn, &error)) 2652287621Smav error = ctl_be_block_modify_dev(be_lun, req); 2653287621Smav else if (be_lun->vn->v_type == VREG) 2654287621Smav error = ctl_be_block_modify_file(be_lun, req); 2655287621Smav else 2656287621Smav error = EINVAL; 2657287621Smav if ((cbe_lun->flags & CTL_LUN_FLAG_OFFLINE) && 2658287621Smav be_lun->vn != NULL) { 2659287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_OFFLINE; 2660287621Smav ctl_lun_online(cbe_lun); 2661287621Smav } 2662287621Smav } else { 2663287621Smav if (be_lun->vn != NULL) { 2664287621Smav cbe_lun->flags |= CTL_LUN_FLAG_OFFLINE; 2665287621Smav ctl_lun_offline(cbe_lun); 2666287621Smav pause("CTL LUN offline", hz / 8); // XXX 2667287621Smav error = ctl_be_block_close(be_lun); 2668287621Smav } else 2669287621Smav error = 0; 2670287621Smav } 2671287499Smav if (be_lun->size_blocks != oldsize) 2672287500Smav ctl_lun_capacity_changed(cbe_lun); 2673232604Strasz 2674232604Strasz /* Tell the user the exact size we ended up using */ 2675232604Strasz params->lun_size_bytes = be_lun->size_bytes; 2676232604Strasz 2677272911Smav req->status = error ? CTL_LUN_WARNING : CTL_LUN_OK; 2678232604Strasz return (0); 2679232604Strasz 2680232604Straszbailout_error: 2681232604Strasz req->status = CTL_LUN_ERROR; 2682232604Strasz return (0); 2683232604Strasz} 2684232604Strasz 2685229997Skenstatic void 2686229997Skenctl_be_block_lun_shutdown(void *be_lun) 2687229997Sken{ 2688229997Sken struct ctl_be_block_lun *lun; 2689229997Sken struct ctl_be_block_softc *softc; 2690229997Sken 2691229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2692229997Sken 2693229997Sken softc = lun->softc; 2694229997Sken 2695229997Sken mtx_lock(&softc->lock); 2696229997Sken lun->flags |= CTL_BE_BLOCK_LUN_UNCONFIGURED; 2697229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2698229997Sken wakeup(lun); 2699229997Sken mtx_unlock(&softc->lock); 2700229997Sken 2701229997Sken} 2702229997Sken 2703229997Skenstatic void 2704229997Skenctl_be_block_lun_config_status(void *be_lun, ctl_lun_config_status status) 2705229997Sken{ 2706229997Sken struct ctl_be_block_lun *lun; 2707229997Sken struct ctl_be_block_softc *softc; 2708229997Sken 2709229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2710229997Sken softc = lun->softc; 2711229997Sken 2712229997Sken if (status == CTL_LUN_CONFIG_OK) { 2713229997Sken mtx_lock(&softc->lock); 2714229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2715229997Sken if (lun->flags & CTL_BE_BLOCK_LUN_WAITING) 2716229997Sken wakeup(lun); 2717229997Sken mtx_unlock(&softc->lock); 2718229997Sken 2719229997Sken /* 2720229997Sken * We successfully added the LUN, attempt to enable it. 2721229997Sken */ 2722287499Smav if (ctl_enable_lun(&lun->cbe_lun) != 0) { 2723229997Sken printf("%s: ctl_enable_lun() failed!\n", __func__); 2724287499Smav if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 2725229997Sken printf("%s: ctl_invalidate_lun() failed!\n", 2726229997Sken __func__); 2727229997Sken } 2728229997Sken } 2729229997Sken 2730229997Sken return; 2731229997Sken } 2732229997Sken 2733229997Sken 2734229997Sken mtx_lock(&softc->lock); 2735229997Sken lun->flags &= ~CTL_BE_BLOCK_LUN_UNCONFIGURED; 2736229997Sken lun->flags |= CTL_BE_BLOCK_LUN_CONFIG_ERR; 2737229997Sken wakeup(lun); 2738229997Sken mtx_unlock(&softc->lock); 2739229997Sken} 2740229997Sken 2741229997Sken 2742229997Skenstatic int 2743229997Skenctl_be_block_config_write(union ctl_io *io) 2744229997Sken{ 2745229997Sken struct ctl_be_block_lun *be_lun; 2746287499Smav struct ctl_be_lun *cbe_lun; 2747229997Sken int retval; 2748229997Sken 2749229997Sken retval = 0; 2750229997Sken 2751229997Sken DPRINTF("entered\n"); 2752229997Sken 2753287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2754229997Sken CTL_PRIV_BACKEND_LUN].ptr; 2755287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2756229997Sken 2757229997Sken switch (io->scsiio.cdb[0]) { 2758229997Sken case SYNCHRONIZE_CACHE: 2759229997Sken case SYNCHRONIZE_CACHE_16: 2760264274Smav case WRITE_SAME_10: 2761264274Smav case WRITE_SAME_16: 2762264274Smav case UNMAP: 2763229997Sken /* 2764229997Sken * The upper level CTL code will filter out any CDBs with 2765229997Sken * the immediate bit set and return the proper error. 2766229997Sken * 2767229997Sken * We don't really need to worry about what LBA range the 2768229997Sken * user asked to be synced out. When they issue a sync 2769229997Sken * cache command, we'll sync out the whole thing. 2770229997Sken */ 2771267877Smav mtx_lock(&be_lun->queue_lock); 2772229997Sken STAILQ_INSERT_TAIL(&be_lun->config_write_queue, &io->io_hdr, 2773229997Sken links); 2774267877Smav mtx_unlock(&be_lun->queue_lock); 2775229997Sken taskqueue_enqueue(be_lun->io_taskqueue, &be_lun->io_task); 2776229997Sken break; 2777229997Sken case START_STOP_UNIT: { 2778229997Sken struct scsi_start_stop_unit *cdb; 2779229997Sken 2780229997Sken cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 2781229997Sken 2782229997Sken if (cdb->how & SSS_START) 2783287499Smav retval = ctl_start_lun(cbe_lun); 2784229997Sken else { 2785287499Smav retval = ctl_stop_lun(cbe_lun); 2786229997Sken /* 2787229997Sken * XXX KDM Copan-specific offline behavior. 2788229997Sken * Figure out a reasonable way to port this? 2789229997Sken */ 2790229997Sken#ifdef NEEDTOPORT 2791229997Sken if ((retval == 0) 2792229997Sken && (cdb->byte2 & SSS_ONOFFLINE)) 2793287499Smav retval = ctl_lun_offline(cbe_lun); 2794229997Sken#endif 2795229997Sken } 2796229997Sken 2797229997Sken /* 2798229997Sken * In general, the above routines should not fail. They 2799229997Sken * just set state for the LUN. So we've got something 2800229997Sken * pretty wrong here if we can't start or stop the LUN. 2801229997Sken */ 2802229997Sken if (retval != 0) { 2803229997Sken ctl_set_internal_failure(&io->scsiio, 2804229997Sken /*sks_valid*/ 1, 2805229997Sken /*retry_count*/ 0xf051); 2806229997Sken retval = CTL_RETVAL_COMPLETE; 2807229997Sken } else { 2808229997Sken ctl_set_success(&io->scsiio); 2809229997Sken } 2810229997Sken ctl_config_write_done(io); 2811229997Sken break; 2812229997Sken } 2813229997Sken default: 2814229997Sken ctl_set_invalid_opcode(&io->scsiio); 2815229997Sken ctl_config_write_done(io); 2816229997Sken retval = CTL_RETVAL_COMPLETE; 2817229997Sken break; 2818229997Sken } 2819229997Sken 2820229997Sken return (retval); 2821229997Sken} 2822229997Sken 2823229997Skenstatic int 2824229997Skenctl_be_block_config_read(union ctl_io *io) 2825229997Sken{ 2826275474Smav struct ctl_be_block_lun *be_lun; 2827287499Smav struct ctl_be_lun *cbe_lun; 2828275474Smav int retval = 0; 2829275474Smav 2830275474Smav DPRINTF("entered\n"); 2831275474Smav 2832287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 2833275474Smav CTL_PRIV_BACKEND_LUN].ptr; 2834287499Smav be_lun = (struct ctl_be_block_lun *)cbe_lun->be_lun; 2835275474Smav 2836275474Smav switch (io->scsiio.cdb[0]) { 2837275474Smav case SERVICE_ACTION_IN: 2838275474Smav if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 2839275474Smav mtx_lock(&be_lun->queue_lock); 2840275474Smav STAILQ_INSERT_TAIL(&be_lun->config_read_queue, 2841275474Smav &io->io_hdr, links); 2842275474Smav mtx_unlock(&be_lun->queue_lock); 2843275474Smav taskqueue_enqueue(be_lun->io_taskqueue, 2844275474Smav &be_lun->io_task); 2845275474Smav retval = CTL_RETVAL_QUEUED; 2846275474Smav break; 2847275474Smav } 2848275474Smav ctl_set_invalid_field(&io->scsiio, 2849275474Smav /*sks_valid*/ 1, 2850275474Smav /*command*/ 1, 2851275474Smav /*field*/ 1, 2852275474Smav /*bit_valid*/ 1, 2853275474Smav /*bit*/ 4); 2854275474Smav ctl_config_read_done(io); 2855275474Smav retval = CTL_RETVAL_COMPLETE; 2856275474Smav break; 2857275474Smav default: 2858275474Smav ctl_set_invalid_opcode(&io->scsiio); 2859275474Smav ctl_config_read_done(io); 2860275474Smav retval = CTL_RETVAL_COMPLETE; 2861275474Smav break; 2862275474Smav } 2863275474Smav 2864275474Smav return (retval); 2865229997Sken} 2866229997Sken 2867229997Skenstatic int 2868229997Skenctl_be_block_lun_info(void *be_lun, struct sbuf *sb) 2869229997Sken{ 2870229997Sken struct ctl_be_block_lun *lun; 2871229997Sken int retval; 2872229997Sken 2873229997Sken lun = (struct ctl_be_block_lun *)be_lun; 2874229997Sken retval = 0; 2875229997Sken 2876268283Smav retval = sbuf_printf(sb, "\t<num_threads>"); 2877229997Sken 2878229997Sken if (retval != 0) 2879229997Sken goto bailout; 2880229997Sken 2881229997Sken retval = sbuf_printf(sb, "%d", lun->num_threads); 2882229997Sken 2883229997Sken if (retval != 0) 2884229997Sken goto bailout; 2885229997Sken 2886268283Smav retval = sbuf_printf(sb, "</num_threads>\n"); 2887229997Sken 2888229997Skenbailout: 2889229997Sken 2890229997Sken return (retval); 2891229997Sken} 2892229997Sken 2893274154Smavstatic uint64_t 2894274154Smavctl_be_block_lun_attr(void *be_lun, const char *attrname) 2895274154Smav{ 2896274154Smav struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)be_lun; 2897274154Smav 2898274154Smav if (lun->getattr == NULL) 2899274154Smav return (UINT64_MAX); 2900274154Smav return (lun->getattr(lun, attrname)); 2901274154Smav} 2902274154Smav 2903229997Skenint 2904229997Skenctl_be_block_init(void) 2905229997Sken{ 2906229997Sken struct ctl_be_block_softc *softc; 2907229997Sken int retval; 2908229997Sken 2909229997Sken softc = &backend_block_softc; 2910229997Sken retval = 0; 2911229997Sken 2912267877Smav mtx_init(&softc->lock, "ctlblock", NULL, MTX_DEF); 2913264020Strasz beio_zone = uma_zcreate("beio", sizeof(struct ctl_be_block_io), 2914264020Strasz NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 2915229997Sken STAILQ_INIT(&softc->lun_list); 2916229997Sken 2917229997Sken return (retval); 2918229997Sken} 2919