ctl_backend_ramdisk.c revision 288220
1229997Sken/*- 2229997Sken * Copyright (c) 2003, 2008 Silicon Graphics International Corp. 3232604Strasz * Copyright (c) 2012 The FreeBSD Foundation 4229997Sken * All rights reserved. 5229997Sken * 6232604Strasz * Portions of this software were developed by Edward Tomasz Napierala 7232604Strasz * under sponsorship from the FreeBSD Foundation. 8232604Strasz * 9229997Sken * Redistribution and use in source and binary forms, with or without 10229997Sken * modification, are permitted provided that the following conditions 11229997Sken * are met: 12229997Sken * 1. Redistributions of source code must retain the above copyright 13229997Sken * notice, this list of conditions, and the following disclaimer, 14229997Sken * without modification. 15229997Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16229997Sken * substantially similar to the "NO WARRANTY" disclaimer below 17229997Sken * ("Disclaimer") and any redistribution must be conditioned upon 18229997Sken * including a substantially similar Disclaimer requirement for further 19229997Sken * binary redistribution. 20229997Sken * 21229997Sken * NO WARRANTY 22229997Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23229997Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24229997Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 25229997Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26229997Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28229997Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29229997Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30229997Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 31229997Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32229997Sken * POSSIBILITY OF SUCH DAMAGES. 33229997Sken * 34229997Sken * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $ 35229997Sken */ 36229997Sken/* 37229997Sken * CAM Target Layer backend for a "fake" ramdisk. 38229997Sken * 39229997Sken * Author: Ken Merry <ken@FreeBSD.org> 40229997Sken */ 41229997Sken 42229997Sken#include <sys/cdefs.h> 43229997Sken__FBSDID("$FreeBSD: head/sys/cam/ctl/ctl_backend_ramdisk.c 288220 2015-09-25 16:34:59Z mav $"); 44229997Sken 45229997Sken#include <sys/param.h> 46229997Sken#include <sys/systm.h> 47229997Sken#include <sys/kernel.h> 48229997Sken#include <sys/condvar.h> 49229997Sken#include <sys/types.h> 50229997Sken#include <sys/lock.h> 51229997Sken#include <sys/mutex.h> 52229997Sken#include <sys/malloc.h> 53264886Smav#include <sys/taskqueue.h> 54229997Sken#include <sys/time.h> 55229997Sken#include <sys/queue.h> 56229997Sken#include <sys/conf.h> 57229997Sken#include <sys/ioccom.h> 58229997Sken#include <sys/module.h> 59287621Smav#include <sys/sysctl.h> 60229997Sken 61229997Sken#include <cam/scsi/scsi_all.h> 62287621Smav#include <cam/scsi/scsi_da.h> 63229997Sken#include <cam/ctl/ctl_io.h> 64229997Sken#include <cam/ctl/ctl.h> 65229997Sken#include <cam/ctl/ctl_util.h> 66229997Sken#include <cam/ctl/ctl_backend.h> 67229997Sken#include <cam/ctl/ctl_debug.h> 68229997Sken#include <cam/ctl/ctl_ioctl.h> 69287621Smav#include <cam/ctl/ctl_ha.h> 70287621Smav#include <cam/ctl/ctl_private.h> 71229997Sken#include <cam/ctl/ctl_error.h> 72229997Sken 73229997Skentypedef enum { 74229997Sken CTL_BE_RAMDISK_LUN_UNCONFIGURED = 0x01, 75229997Sken CTL_BE_RAMDISK_LUN_CONFIG_ERR = 0x02, 76229997Sken CTL_BE_RAMDISK_LUN_WAITING = 0x04 77229997Sken} ctl_be_ramdisk_lun_flags; 78229997Sken 79229997Skenstruct ctl_be_ramdisk_lun { 80287500Smav struct ctl_lun_create_params params; 81264886Smav char lunname[32]; 82229997Sken uint64_t size_bytes; 83229997Sken uint64_t size_blocks; 84229997Sken struct ctl_be_ramdisk_softc *softc; 85229997Sken ctl_be_ramdisk_lun_flags flags; 86229997Sken STAILQ_ENTRY(ctl_be_ramdisk_lun) links; 87287499Smav struct ctl_be_lun cbe_lun; 88264886Smav struct taskqueue *io_taskqueue; 89264886Smav struct task io_task; 90264886Smav STAILQ_HEAD(, ctl_io_hdr) cont_queue; 91267877Smav struct mtx_padalign queue_lock; 92229997Sken}; 93229997Sken 94229997Skenstruct ctl_be_ramdisk_softc { 95229997Sken struct mtx lock; 96229997Sken int rd_size; 97229997Sken#ifdef CTL_RAMDISK_PAGES 98229997Sken uint8_t **ramdisk_pages; 99229997Sken int num_pages; 100229997Sken#else 101229997Sken uint8_t *ramdisk_buffer; 102229997Sken#endif 103229997Sken int num_luns; 104229997Sken STAILQ_HEAD(, ctl_be_ramdisk_lun) lun_list; 105229997Sken}; 106229997Sken 107229997Skenstatic struct ctl_be_ramdisk_softc rd_softc; 108287621Smavextern struct ctl_softc *control_softc; 109229997Sken 110229997Skenint ctl_backend_ramdisk_init(void); 111229997Skenvoid ctl_backend_ramdisk_shutdown(void); 112229997Skenstatic int ctl_backend_ramdisk_move_done(union ctl_io *io); 113229997Skenstatic int ctl_backend_ramdisk_submit(union ctl_io *io); 114264886Smavstatic void ctl_backend_ramdisk_continue(union ctl_io *io); 115229997Skenstatic int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, 116229997Sken caddr_t addr, int flag, struct thread *td); 117229997Skenstatic int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 118229997Sken struct ctl_lun_req *req); 119229997Skenstatic int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 120287499Smav struct ctl_lun_req *req); 121232604Straszstatic int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 122232604Strasz struct ctl_lun_req *req); 123264886Smavstatic void ctl_backend_ramdisk_worker(void *context, int pending); 124229997Skenstatic void ctl_backend_ramdisk_lun_shutdown(void *be_lun); 125229997Skenstatic void ctl_backend_ramdisk_lun_config_status(void *be_lun, 126229997Sken ctl_lun_config_status status); 127229997Skenstatic int ctl_backend_ramdisk_config_write(union ctl_io *io); 128229997Skenstatic int ctl_backend_ramdisk_config_read(union ctl_io *io); 129229997Sken 130229997Skenstatic struct ctl_backend_driver ctl_be_ramdisk_driver = 131229997Sken{ 132230334Sken .name = "ramdisk", 133230334Sken .flags = CTL_BE_FLAG_HAS_CONFIG, 134230334Sken .init = ctl_backend_ramdisk_init, 135230334Sken .data_submit = ctl_backend_ramdisk_submit, 136230334Sken .data_move_done = ctl_backend_ramdisk_move_done, 137230334Sken .config_read = ctl_backend_ramdisk_config_read, 138230334Sken .config_write = ctl_backend_ramdisk_config_write, 139230334Sken .ioctl = ctl_backend_ramdisk_ioctl 140229997Sken}; 141229997Sken 142229997SkenMALLOC_DEFINE(M_RAMDISK, "ramdisk", "Memory used for CTL RAMdisk"); 143229997SkenCTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver); 144229997Sken 145229997Skenint 146229997Skenctl_backend_ramdisk_init(void) 147229997Sken{ 148288220Smav struct ctl_be_ramdisk_softc *softc = &rd_softc; 149229997Sken#ifdef CTL_RAMDISK_PAGES 150240993Strasz int i; 151229997Sken#endif 152229997Sken 153229997Sken memset(softc, 0, sizeof(*softc)); 154267877Smav mtx_init(&softc->lock, "ctlramdisk", NULL, MTX_DEF); 155229997Sken STAILQ_INIT(&softc->lun_list); 156264886Smav softc->rd_size = 1024 * 1024; 157229997Sken#ifdef CTL_RAMDISK_PAGES 158229997Sken softc->num_pages = softc->rd_size / PAGE_SIZE; 159229997Sken softc->ramdisk_pages = (uint8_t **)malloc(sizeof(uint8_t *) * 160229997Sken softc->num_pages, M_RAMDISK, 161229997Sken M_WAITOK); 162240993Strasz for (i = 0; i < softc->num_pages; i++) 163229997Sken softc->ramdisk_pages[i] = malloc(PAGE_SIZE, M_RAMDISK,M_WAITOK); 164229997Sken#else 165229997Sken softc->ramdisk_buffer = (uint8_t *)malloc(softc->rd_size, M_RAMDISK, 166229997Sken M_WAITOK); 167229997Sken#endif 168229997Sken 169229997Sken return (0); 170229997Sken} 171229997Sken 172229997Skenvoid 173229997Skenctl_backend_ramdisk_shutdown(void) 174229997Sken{ 175288220Smav struct ctl_be_ramdisk_softc *softc = &rd_softc; 176229997Sken struct ctl_be_ramdisk_lun *lun, *next_lun; 177229997Sken#ifdef CTL_RAMDISK_PAGES 178229997Sken int i; 179229997Sken#endif 180229997Sken 181229997Sken mtx_lock(&softc->lock); 182229997Sken for (lun = STAILQ_FIRST(&softc->lun_list); lun != NULL; lun = next_lun){ 183229997Sken /* 184229997Sken * Grab the next LUN. The current LUN may get removed by 185229997Sken * ctl_invalidate_lun(), which will call our LUN shutdown 186229997Sken * routine, if there is no outstanding I/O for this LUN. 187229997Sken */ 188229997Sken next_lun = STAILQ_NEXT(lun, links); 189229997Sken 190229997Sken /* 191229997Sken * Drop our lock here. Since ctl_invalidate_lun() can call 192229997Sken * back into us, this could potentially lead to a recursive 193229997Sken * lock of the same mutex, which would cause a hang. 194229997Sken */ 195229997Sken mtx_unlock(&softc->lock); 196287499Smav ctl_disable_lun(&lun->cbe_lun); 197287499Smav ctl_invalidate_lun(&lun->cbe_lun); 198229997Sken mtx_lock(&softc->lock); 199229997Sken } 200229997Sken mtx_unlock(&softc->lock); 201229997Sken 202229997Sken#ifdef CTL_RAMDISK_PAGES 203229997Sken for (i = 0; i < softc->num_pages; i++) 204229997Sken free(softc->ramdisk_pages[i], M_RAMDISK); 205229997Sken 206229997Sken free(softc->ramdisk_pages, M_RAMDISK); 207229997Sken#else 208229997Sken free(softc->ramdisk_buffer, M_RAMDISK); 209229997Sken#endif 210229997Sken 211229997Sken if (ctl_backend_deregister(&ctl_be_ramdisk_driver) != 0) { 212229997Sken printf("ctl_backend_ramdisk_shutdown: " 213229997Sken "ctl_backend_deregister() failed!\n"); 214229997Sken } 215229997Sken} 216229997Sken 217229997Skenstatic int 218229997Skenctl_backend_ramdisk_move_done(union ctl_io *io) 219229997Sken{ 220287499Smav struct ctl_be_lun *cbe_lun; 221264886Smav struct ctl_be_ramdisk_lun *be_lun; 222229997Sken#ifdef CTL_TIME_IO 223229997Sken struct bintime cur_bt; 224229997Sken#endif 225229997Sken 226229997Sken CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); 227287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 228264886Smav CTL_PRIV_BACKEND_LUN].ptr; 229287499Smav be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun->be_lun; 230264886Smav#ifdef CTL_TIME_IO 231288215Smav getbinuptime(&cur_bt); 232264886Smav bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 233264886Smav bintime_add(&io->io_hdr.dma_bt, &cur_bt); 234288215Smav#endif 235264886Smav io->io_hdr.num_dmas++; 236264886Smav if (io->scsiio.kern_sg_entries > 0) 237264886Smav free(io->scsiio.kern_data_ptr, M_RAMDISK); 238264886Smav io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 239275058Smav if (io->io_hdr.flags & CTL_FLAG_ABORT) { 240275058Smav ; 241275058Smav } else if ((io->io_hdr.port_status == 0) && 242275058Smav ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 243267519Smav if (io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer > 0) { 244267877Smav mtx_lock(&be_lun->queue_lock); 245264886Smav STAILQ_INSERT_TAIL(&be_lun->cont_queue, 246264886Smav &io->io_hdr, links); 247267877Smav mtx_unlock(&be_lun->queue_lock); 248264886Smav taskqueue_enqueue(be_lun->io_taskqueue, 249264886Smav &be_lun->io_task); 250264886Smav return (0); 251264886Smav } 252275009Smav ctl_set_success(&io->scsiio); 253275058Smav } else if ((io->io_hdr.port_status != 0) && 254275058Smav ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE || 255275058Smav (io->io_hdr.status & CTL_STATUS_MASK) == CTL_SUCCESS)) { 256229997Sken /* 257229997Sken * For hardware error sense keys, the sense key 258229997Sken * specific value is defined to be a retry count, 259229997Sken * but we use it to pass back an internal FETD 260229997Sken * error code. XXX KDM Hopefully the FETD is only 261229997Sken * using 16 bits for an error code, since that's 262229997Sken * all the space we have in the sks field. 263229997Sken */ 264229997Sken ctl_set_internal_failure(&io->scsiio, 265229997Sken /*sks_valid*/ 1, 266229997Sken /*retry_count*/ 267229997Sken io->io_hdr.port_status); 268229997Sken } 269267537Smav ctl_data_submit_done(io); 270229997Sken return(0); 271229997Sken} 272229997Sken 273229997Skenstatic int 274229997Skenctl_backend_ramdisk_submit(union ctl_io *io) 275229997Sken{ 276287499Smav struct ctl_be_lun *cbe_lun; 277267537Smav struct ctl_lba_len_flags *lbalen; 278229997Sken 279287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 280267519Smav CTL_PRIV_BACKEND_LUN].ptr; 281267537Smav lbalen = (struct ctl_lba_len_flags *)&io->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]; 282267537Smav if (lbalen->flags & CTL_LLF_VERIFY) { 283267537Smav ctl_set_success(&io->scsiio); 284267537Smav ctl_data_submit_done(io); 285267537Smav return (CTL_RETVAL_COMPLETE); 286267537Smav } 287267519Smav io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer = 288287499Smav lbalen->len * cbe_lun->blocksize; 289264886Smav ctl_backend_ramdisk_continue(io); 290264886Smav return (CTL_RETVAL_COMPLETE); 291264886Smav} 292229997Sken 293264886Smavstatic void 294264886Smavctl_backend_ramdisk_continue(union ctl_io *io) 295264886Smav{ 296264886Smav struct ctl_be_ramdisk_softc *softc; 297264886Smav int len, len_filled, sg_filled; 298264886Smav#ifdef CTL_RAMDISK_PAGES 299264886Smav struct ctl_sg_entry *sg_entries; 300264886Smav int i; 301264886Smav#endif 302229997Sken 303264886Smav softc = &rd_softc; 304267519Smav len = io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer; 305229997Sken#ifdef CTL_RAMDISK_PAGES 306264886Smav sg_filled = min(btoc(len), softc->num_pages); 307264886Smav if (sg_filled > 1) { 308229997Sken io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) * 309264886Smav sg_filled, M_RAMDISK, 310229997Sken M_WAITOK); 311229997Sken sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 312264886Smav for (i = 0, len_filled = 0; i < sg_filled; i++) { 313229997Sken sg_entries[i].addr = softc->ramdisk_pages[i]; 314275953Smav sg_entries[i].len = MIN(PAGE_SIZE, len - len_filled); 315264886Smav len_filled += sg_entries[i].len; 316229997Sken } 317229997Sken } else { 318264886Smav sg_filled = 0; 319264886Smav len_filled = len; 320229997Sken io->scsiio.kern_data_ptr = softc->ramdisk_pages[0]; 321264886Smav } 322229997Sken#else 323264886Smav sg_filled = 0; 324264886Smav len_filled = min(len, softc->rd_size); 325264886Smav io->scsiio.kern_data_ptr = softc->ramdisk_buffer; 326264886Smav#endif /* CTL_RAMDISK_PAGES */ 327229997Sken 328267514Smav io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 329267514Smav io->scsiio.kern_data_resid = 0; 330264886Smav io->scsiio.kern_data_len = len_filled; 331264886Smav io->scsiio.kern_sg_entries = sg_filled; 332264886Smav io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 333267519Smav io->io_hdr.ctl_private[CTL_PRIV_BACKEND].integer -= len_filled; 334229997Sken#ifdef CTL_TIME_IO 335288215Smav getbinuptime(&io->io_hdr.dma_start_bt); 336229997Sken#endif 337229997Sken ctl_datamove(io); 338264886Smav} 339229997Sken 340264886Smavstatic void 341264886Smavctl_backend_ramdisk_worker(void *context, int pending) 342264886Smav{ 343264886Smav struct ctl_be_ramdisk_softc *softc; 344264886Smav struct ctl_be_ramdisk_lun *be_lun; 345264886Smav union ctl_io *io; 346264886Smav 347264886Smav be_lun = (struct ctl_be_ramdisk_lun *)context; 348264886Smav softc = be_lun->softc; 349264886Smav 350267877Smav mtx_lock(&be_lun->queue_lock); 351264886Smav for (;;) { 352264886Smav io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); 353264886Smav if (io != NULL) { 354264886Smav STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr, 355264886Smav ctl_io_hdr, links); 356267877Smav mtx_unlock(&be_lun->queue_lock); 357264886Smav ctl_backend_ramdisk_continue(io); 358267877Smav mtx_lock(&be_lun->queue_lock); 359264886Smav continue; 360264886Smav } 361264886Smav 362264886Smav /* 363264886Smav * If we get here, there is no work left in the queues, so 364264886Smav * just break out and let the task queue go to sleep. 365264886Smav */ 366264886Smav break; 367264886Smav } 368267877Smav mtx_unlock(&be_lun->queue_lock); 369229997Sken} 370229997Sken 371229997Skenstatic int 372229997Skenctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 373229997Sken int flag, struct thread *td) 374229997Sken{ 375288220Smav struct ctl_be_ramdisk_softc *softc = &rd_softc; 376288220Smav struct ctl_lun_req *lun_req; 377229997Sken int retval; 378229997Sken 379229997Sken retval = 0; 380229997Sken switch (cmd) { 381288220Smav case CTL_LUN_REQ: 382229997Sken lun_req = (struct ctl_lun_req *)addr; 383229997Sken switch (lun_req->reqtype) { 384229997Sken case CTL_LUNREQ_CREATE: 385287499Smav retval = ctl_backend_ramdisk_create(softc, lun_req); 386229997Sken break; 387229997Sken case CTL_LUNREQ_RM: 388229997Sken retval = ctl_backend_ramdisk_rm(softc, lun_req); 389229997Sken break; 390232604Strasz case CTL_LUNREQ_MODIFY: 391232604Strasz retval = ctl_backend_ramdisk_modify(softc, lun_req); 392232604Strasz break; 393229997Sken default: 394229997Sken lun_req->status = CTL_LUN_ERROR; 395229997Sken snprintf(lun_req->error_str, sizeof(lun_req->error_str), 396229997Sken "%s: invalid LUN request type %d", __func__, 397229997Sken lun_req->reqtype); 398229997Sken break; 399229997Sken } 400229997Sken break; 401229997Sken default: 402229997Sken retval = ENOTTY; 403229997Sken break; 404229997Sken } 405229997Sken 406229997Sken return (retval); 407229997Sken} 408229997Sken 409229997Skenstatic int 410229997Skenctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 411229997Sken struct ctl_lun_req *req) 412229997Sken{ 413229997Sken struct ctl_be_ramdisk_lun *be_lun; 414229997Sken struct ctl_lun_rm_params *params; 415229997Sken int retval; 416229997Sken 417229997Sken retval = 0; 418229997Sken params = &req->reqdata.rm; 419229997Sken mtx_lock(&softc->lock); 420229997Sken STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 421287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 422229997Sken break; 423229997Sken } 424229997Sken mtx_unlock(&softc->lock); 425229997Sken if (be_lun == NULL) { 426229997Sken snprintf(req->error_str, sizeof(req->error_str), 427229997Sken "%s: LUN %u is not managed by the ramdisk backend", 428229997Sken __func__, params->lun_id); 429229997Sken goto bailout_error; 430229997Sken } 431229997Sken 432287499Smav retval = ctl_disable_lun(&be_lun->cbe_lun); 433229997Sken if (retval != 0) { 434229997Sken snprintf(req->error_str, sizeof(req->error_str), 435229997Sken "%s: error %d returned from ctl_disable_lun() for " 436229997Sken "LUN %d", __func__, retval, params->lun_id); 437229997Sken goto bailout_error; 438229997Sken } 439229997Sken 440229997Sken /* 441229997Sken * Set the waiting flag before we invalidate the LUN. Our shutdown 442229997Sken * routine can be called any time after we invalidate the LUN, 443229997Sken * and can be called from our context. 444229997Sken * 445229997Sken * This tells the shutdown routine that we're waiting, or we're 446229997Sken * going to wait for the shutdown to happen. 447229997Sken */ 448229997Sken mtx_lock(&softc->lock); 449229997Sken be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 450229997Sken mtx_unlock(&softc->lock); 451229997Sken 452287499Smav retval = ctl_invalidate_lun(&be_lun->cbe_lun); 453229997Sken if (retval != 0) { 454229997Sken snprintf(req->error_str, sizeof(req->error_str), 455229997Sken "%s: error %d returned from ctl_invalidate_lun() for " 456229997Sken "LUN %d", __func__, retval, params->lun_id); 457252569Smav mtx_lock(&softc->lock); 458252569Smav be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 459252569Smav mtx_unlock(&softc->lock); 460229997Sken goto bailout_error; 461229997Sken } 462229997Sken 463229997Sken mtx_lock(&softc->lock); 464229997Sken while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) { 465229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 466288220Smav if (retval == EINTR) 467229997Sken break; 468229997Sken } 469229997Sken be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 470229997Sken 471229997Sken /* 472229997Sken * We only remove this LUN from the list and free it (below) if 473229997Sken * retval == 0. If the user interrupted the wait, we just bail out 474229997Sken * without actually freeing the LUN. We let the shutdown routine 475229997Sken * free the LUN if that happens. 476229997Sken */ 477229997Sken if (retval == 0) { 478229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 479229997Sken links); 480229997Sken softc->num_luns--; 481229997Sken } 482229997Sken 483229997Sken mtx_unlock(&softc->lock); 484229997Sken 485264886Smav if (retval == 0) { 486287670Smav taskqueue_drain_all(be_lun->io_taskqueue); 487264886Smav taskqueue_free(be_lun->io_taskqueue); 488287499Smav ctl_free_opts(&be_lun->cbe_lun.options); 489267877Smav mtx_destroy(&be_lun->queue_lock); 490229997Sken free(be_lun, M_RAMDISK); 491264886Smav } 492229997Sken 493229997Sken req->status = CTL_LUN_OK; 494229997Sken return (retval); 495229997Sken 496229997Skenbailout_error: 497229997Sken req->status = CTL_LUN_ERROR; 498229997Sken return (0); 499229997Sken} 500229997Sken 501229997Skenstatic int 502229997Skenctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 503287499Smav struct ctl_lun_req *req) 504229997Sken{ 505229997Sken struct ctl_be_ramdisk_lun *be_lun; 506287499Smav struct ctl_be_lun *cbe_lun; 507229997Sken struct ctl_lun_create_params *params; 508267481Smav char *value; 509229997Sken char tmpstr[32]; 510287499Smav int retval; 511229997Sken 512229997Sken retval = 0; 513229997Sken params = &req->reqdata.create; 514229997Sken 515287499Smav be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK); 516287499Smav cbe_lun = &be_lun->cbe_lun; 517287499Smav cbe_lun->be_lun = be_lun; 518287500Smav be_lun->params = req->reqdata.create; 519287499Smav be_lun->softc = softc; 520264886Smav sprintf(be_lun->lunname, "cram%d", softc->num_luns); 521287499Smav ctl_init_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 522229997Sken 523229997Sken if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 524287499Smav cbe_lun->lun_type = params->device_type; 525229997Sken else 526287499Smav cbe_lun->lun_type = T_DIRECT; 527287499Smav be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED; 528287621Smav cbe_lun->flags = 0; 529287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 530287621Smav if (value != NULL) { 531287621Smav if (strcmp(value, "primary") == 0) 532287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 533287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 534287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 535229997Sken 536287499Smav if (cbe_lun->lun_type == T_DIRECT) { 537287499Smav if (params->blocksize_bytes != 0) 538287499Smav cbe_lun->blocksize = params->blocksize_bytes; 539287499Smav else 540287499Smav cbe_lun->blocksize = 512; 541287499Smav if (params->lun_size_bytes < cbe_lun->blocksize) { 542229997Sken snprintf(req->error_str, sizeof(req->error_str), 543229997Sken "%s: LUN size %ju < blocksize %u", __func__, 544287499Smav params->lun_size_bytes, cbe_lun->blocksize); 545229997Sken goto bailout_error; 546229997Sken } 547287499Smav be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize; 548287499Smav be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize; 549287499Smav cbe_lun->maxlba = be_lun->size_blocks - 1; 550287499Smav cbe_lun->atomicblock = UINT32_MAX; 551287499Smav cbe_lun->opttxferlen = softc->rd_size / cbe_lun->blocksize; 552229997Sken } 553229997Sken 554229997Sken /* Tell the user the blocksize we ended up using */ 555287499Smav params->blocksize_bytes = cbe_lun->blocksize; 556229997Sken params->lun_size_bytes = be_lun->size_bytes; 557229997Sken 558287499Smav value = ctl_get_opt(&cbe_lun->options, "unmap"); 559267481Smav if (value != NULL && strcmp(value, "on") == 0) 560287499Smav cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 561287499Smav value = ctl_get_opt(&cbe_lun->options, "readonly"); 562287499Smav if (value != NULL && strcmp(value, "on") == 0) 563287499Smav cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 564287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 565287499Smav value = ctl_get_opt(&cbe_lun->options, "serseq"); 566287499Smav if (value != NULL && strcmp(value, "on") == 0) 567287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 568287499Smav else if (value != NULL && strcmp(value, "read") == 0) 569287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 570287499Smav else if (value != NULL && strcmp(value, "off") == 0) 571287499Smav cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 572254759Strasz 573229997Sken if (params->flags & CTL_LUN_FLAG_ID_REQ) { 574287499Smav cbe_lun->req_lun_id = params->req_lun_id; 575287499Smav cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 576229997Sken } else 577287499Smav cbe_lun->req_lun_id = 0; 578229997Sken 579287499Smav cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 580287499Smav cbe_lun->lun_config_status = ctl_backend_ramdisk_lun_config_status; 581287499Smav cbe_lun->be = &ctl_be_ramdisk_driver; 582229997Sken if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 583229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 584229997Sken softc->num_luns); 585287499Smav strncpy((char *)cbe_lun->serial_num, tmpstr, 586287499Smav MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 587229997Sken 588229997Sken /* Tell the user what we used for a serial number */ 589229997Sken strncpy((char *)params->serial_num, tmpstr, 590275953Smav MIN(sizeof(params->serial_num), sizeof(tmpstr))); 591229997Sken } else { 592287499Smav strncpy((char *)cbe_lun->serial_num, params->serial_num, 593287499Smav MIN(sizeof(cbe_lun->serial_num), 594275953Smav sizeof(params->serial_num))); 595229997Sken } 596229997Sken if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 597229997Sken snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 598287499Smav strncpy((char *)cbe_lun->device_id, tmpstr, 599287499Smav MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 600229997Sken 601229997Sken /* Tell the user what we used for a device ID */ 602229997Sken strncpy((char *)params->device_id, tmpstr, 603275953Smav MIN(sizeof(params->device_id), sizeof(tmpstr))); 604229997Sken } else { 605287499Smav strncpy((char *)cbe_lun->device_id, params->device_id, 606287499Smav MIN(sizeof(cbe_lun->device_id), 607275953Smav sizeof(params->device_id))); 608229997Sken } 609229997Sken 610264886Smav STAILQ_INIT(&be_lun->cont_queue); 611267877Smav mtx_init(&be_lun->queue_lock, "cram queue lock", NULL, MTX_DEF); 612264886Smav TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 613264886Smav be_lun); 614264886Smav 615264886Smav be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 616264886Smav taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 617264886Smav if (be_lun->io_taskqueue == NULL) { 618264886Smav snprintf(req->error_str, sizeof(req->error_str), 619264886Smav "%s: Unable to create taskqueue", __func__); 620264886Smav goto bailout_error; 621264886Smav } 622264886Smav 623264886Smav retval = taskqueue_start_threads(&be_lun->io_taskqueue, 624264886Smav /*num threads*/1, 625264886Smav /*priority*/PWAIT, 626264886Smav /*thread name*/ 627264886Smav "%s taskq", be_lun->lunname); 628264886Smav if (retval != 0) 629264886Smav goto bailout_error; 630264886Smav 631229997Sken mtx_lock(&softc->lock); 632229997Sken softc->num_luns++; 633229997Sken STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 634229997Sken mtx_unlock(&softc->lock); 635229997Sken 636287499Smav retval = ctl_add_lun(&be_lun->cbe_lun); 637229997Sken if (retval != 0) { 638229997Sken mtx_lock(&softc->lock); 639229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 640229997Sken links); 641229997Sken softc->num_luns--; 642229997Sken mtx_unlock(&softc->lock); 643229997Sken snprintf(req->error_str, sizeof(req->error_str), 644229997Sken "%s: ctl_add_lun() returned error %d, see dmesg for " 645229997Sken "details", __func__, retval); 646229997Sken retval = 0; 647229997Sken goto bailout_error; 648229997Sken } 649229997Sken 650229997Sken mtx_lock(&softc->lock); 651229997Sken 652229997Sken /* 653229997Sken * Tell the config_status routine that we're waiting so it won't 654229997Sken * clean up the LUN in the event of an error. 655229997Sken */ 656229997Sken be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 657229997Sken 658229997Sken while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 659229997Sken retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 660229997Sken if (retval == EINTR) 661229997Sken break; 662229997Sken } 663229997Sken be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 664229997Sken 665229997Sken if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) { 666229997Sken snprintf(req->error_str, sizeof(req->error_str), 667229997Sken "%s: LUN configuration error, see dmesg for details", 668229997Sken __func__); 669229997Sken STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 670229997Sken links); 671229997Sken softc->num_luns--; 672229997Sken mtx_unlock(&softc->lock); 673229997Sken goto bailout_error; 674229997Sken } else { 675287499Smav params->req_lun_id = cbe_lun->lun_id; 676229997Sken } 677229997Sken mtx_unlock(&softc->lock); 678229997Sken 679229997Sken req->status = CTL_LUN_OK; 680229997Sken return (retval); 681229997Sken 682229997Skenbailout_error: 683229997Sken req->status = CTL_LUN_ERROR; 684264886Smav if (be_lun != NULL) { 685264886Smav if (be_lun->io_taskqueue != NULL) { 686264886Smav taskqueue_free(be_lun->io_taskqueue); 687264886Smav } 688287499Smav ctl_free_opts(&cbe_lun->options); 689267877Smav mtx_destroy(&be_lun->queue_lock); 690264886Smav free(be_lun, M_RAMDISK); 691264886Smav } 692229997Sken return (retval); 693229997Sken} 694229997Sken 695232604Straszstatic int 696232604Straszctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 697232604Strasz struct ctl_lun_req *req) 698232604Strasz{ 699232604Strasz struct ctl_be_ramdisk_lun *be_lun; 700287500Smav struct ctl_be_lun *cbe_lun; 701232604Strasz struct ctl_lun_modify_params *params; 702287621Smav char *value; 703232604Strasz uint32_t blocksize; 704287621Smav int wasprim; 705232604Strasz 706232604Strasz params = &req->reqdata.modify; 707232604Strasz 708232604Strasz mtx_lock(&softc->lock); 709232604Strasz STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 710287499Smav if (be_lun->cbe_lun.lun_id == params->lun_id) 711232604Strasz break; 712232604Strasz } 713232604Strasz mtx_unlock(&softc->lock); 714232604Strasz if (be_lun == NULL) { 715232604Strasz snprintf(req->error_str, sizeof(req->error_str), 716232604Strasz "%s: LUN %u is not managed by the ramdisk backend", 717232604Strasz __func__, params->lun_id); 718232604Strasz goto bailout_error; 719232604Strasz } 720287500Smav cbe_lun = &be_lun->cbe_lun; 721232604Strasz 722287500Smav if (params->lun_size_bytes != 0) 723287500Smav be_lun->params.lun_size_bytes = params->lun_size_bytes; 724287500Smav ctl_update_opts(&cbe_lun->options, req->num_be_args, req->kern_be_args); 725287621Smav 726287621Smav wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 727287621Smav value = ctl_get_opt(&cbe_lun->options, "ha_role"); 728287621Smav if (value != NULL) { 729287621Smav if (strcmp(value, "primary") == 0) 730287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 731287621Smav else 732287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 733287621Smav } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 734287621Smav cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 735287621Smav else 736287621Smav cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 737287621Smav if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 738287621Smav if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 739287621Smav ctl_lun_primary(cbe_lun); 740287621Smav else 741287621Smav ctl_lun_secondary(cbe_lun); 742287621Smav } 743287621Smav 744287499Smav blocksize = be_lun->cbe_lun.blocksize; 745287500Smav if (be_lun->params.lun_size_bytes < blocksize) { 746232604Strasz snprintf(req->error_str, sizeof(req->error_str), 747232604Strasz "%s: LUN size %ju < blocksize %u", __func__, 748287500Smav be_lun->params.lun_size_bytes, blocksize); 749232604Strasz goto bailout_error; 750232604Strasz } 751287500Smav be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize; 752232604Strasz be_lun->size_bytes = be_lun->size_blocks * blocksize; 753287499Smav be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1; 754287499Smav ctl_lun_capacity_changed(&be_lun->cbe_lun); 755232604Strasz 756232604Strasz /* Tell the user the exact size we ended up using */ 757232604Strasz params->lun_size_bytes = be_lun->size_bytes; 758232604Strasz 759232604Strasz req->status = CTL_LUN_OK; 760232604Strasz return (0); 761232604Strasz 762232604Straszbailout_error: 763232604Strasz req->status = CTL_LUN_ERROR; 764232604Strasz return (0); 765232604Strasz} 766232604Strasz 767229997Skenstatic void 768229997Skenctl_backend_ramdisk_lun_shutdown(void *be_lun) 769229997Sken{ 770229997Sken struct ctl_be_ramdisk_lun *lun; 771229997Sken struct ctl_be_ramdisk_softc *softc; 772229997Sken int do_free; 773229997Sken 774229997Sken lun = (struct ctl_be_ramdisk_lun *)be_lun; 775229997Sken softc = lun->softc; 776229997Sken do_free = 0; 777229997Sken 778229997Sken mtx_lock(&softc->lock); 779229997Sken lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 780229997Sken if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 781229997Sken wakeup(lun); 782229997Sken } else { 783269058Smav STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 784229997Sken links); 785229997Sken softc->num_luns--; 786229997Sken do_free = 1; 787229997Sken } 788229997Sken mtx_unlock(&softc->lock); 789229997Sken 790229997Sken if (do_free != 0) 791229997Sken free(be_lun, M_RAMDISK); 792229997Sken} 793229997Sken 794229997Skenstatic void 795229997Skenctl_backend_ramdisk_lun_config_status(void *be_lun, 796229997Sken ctl_lun_config_status status) 797229997Sken{ 798229997Sken struct ctl_be_ramdisk_lun *lun; 799229997Sken struct ctl_be_ramdisk_softc *softc; 800229997Sken 801229997Sken lun = (struct ctl_be_ramdisk_lun *)be_lun; 802229997Sken softc = lun->softc; 803229997Sken 804229997Sken if (status == CTL_LUN_CONFIG_OK) { 805229997Sken mtx_lock(&softc->lock); 806229997Sken lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 807229997Sken if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 808229997Sken wakeup(lun); 809229997Sken mtx_unlock(&softc->lock); 810229997Sken 811229997Sken /* 812229997Sken * We successfully added the LUN, attempt to enable it. 813229997Sken */ 814287499Smav if (ctl_enable_lun(&lun->cbe_lun) != 0) { 815229997Sken printf("%s: ctl_enable_lun() failed!\n", __func__); 816287499Smav if (ctl_invalidate_lun(&lun->cbe_lun) != 0) { 817229997Sken printf("%s: ctl_invalidate_lun() failed!\n", 818229997Sken __func__); 819229997Sken } 820229997Sken } 821229997Sken 822229997Sken return; 823229997Sken } 824229997Sken 825229997Sken 826229997Sken mtx_lock(&softc->lock); 827229997Sken lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 828229997Sken 829229997Sken /* 830229997Sken * If we have a user waiting, let him handle the cleanup. If not, 831229997Sken * clean things up here. 832229997Sken */ 833229997Sken if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 834229997Sken lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR; 835229997Sken wakeup(lun); 836229997Sken } else { 837229997Sken STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 838229997Sken links); 839229997Sken softc->num_luns--; 840229997Sken free(lun, M_RAMDISK); 841229997Sken } 842229997Sken mtx_unlock(&softc->lock); 843229997Sken} 844229997Sken 845229997Skenstatic int 846229997Skenctl_backend_ramdisk_config_write(union ctl_io *io) 847229997Sken{ 848229997Sken struct ctl_be_ramdisk_softc *softc; 849229997Sken int retval; 850229997Sken 851229997Sken retval = 0; 852229997Sken softc = &rd_softc; 853229997Sken 854229997Sken switch (io->scsiio.cdb[0]) { 855229997Sken case SYNCHRONIZE_CACHE: 856229997Sken case SYNCHRONIZE_CACHE_16: 857229997Sken /* 858229997Sken * The upper level CTL code will filter out any CDBs with 859229997Sken * the immediate bit set and return the proper error. It 860229997Sken * will also not allow a sync cache command to go to a LUN 861229997Sken * that is powered down. 862229997Sken * 863229997Sken * We don't really need to worry about what LBA range the 864229997Sken * user asked to be synced out. When they issue a sync 865229997Sken * cache command, we'll sync out the whole thing. 866229997Sken * 867229997Sken * This is obviously just a stubbed out implementation. 868229997Sken * The real implementation will be in the RAIDCore/CTL 869229997Sken * interface, and can only really happen when RAIDCore 870229997Sken * implements a per-array cache sync. 871229997Sken */ 872229997Sken ctl_set_success(&io->scsiio); 873229997Sken ctl_config_write_done(io); 874229997Sken break; 875229997Sken case START_STOP_UNIT: { 876229997Sken struct scsi_start_stop_unit *cdb; 877287499Smav struct ctl_be_lun *cbe_lun; 878229997Sken struct ctl_be_ramdisk_lun *be_lun; 879229997Sken 880229997Sken cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 881229997Sken 882287499Smav cbe_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 883229997Sken CTL_PRIV_BACKEND_LUN].ptr; 884287499Smav be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun->be_lun; 885229997Sken 886229997Sken if (cdb->how & SSS_START) 887287499Smav retval = ctl_start_lun(cbe_lun); 888229997Sken else { 889287499Smav retval = ctl_stop_lun(cbe_lun); 890229997Sken#ifdef NEEDTOPORT 891229997Sken if ((retval == 0) 892229997Sken && (cdb->byte2 & SSS_ONOFFLINE)) 893287499Smav retval = ctl_lun_offline(cbe_lun); 894229997Sken#endif 895229997Sken } 896229997Sken 897229997Sken /* 898229997Sken * In general, the above routines should not fail. They 899229997Sken * just set state for the LUN. So we've got something 900229997Sken * pretty wrong here if we can't start or stop the LUN. 901229997Sken */ 902229997Sken if (retval != 0) { 903229997Sken ctl_set_internal_failure(&io->scsiio, 904229997Sken /*sks_valid*/ 1, 905229997Sken /*retry_count*/ 0xf051); 906229997Sken retval = CTL_RETVAL_COMPLETE; 907229997Sken } else { 908229997Sken ctl_set_success(&io->scsiio); 909229997Sken } 910229997Sken ctl_config_write_done(io); 911229997Sken break; 912229997Sken } 913264274Smav case WRITE_SAME_10: 914264274Smav case WRITE_SAME_16: 915264274Smav case UNMAP: 916264274Smav ctl_set_success(&io->scsiio); 917264274Smav ctl_config_write_done(io); 918264274Smav break; 919229997Sken default: 920229997Sken ctl_set_invalid_opcode(&io->scsiio); 921229997Sken ctl_config_write_done(io); 922229997Sken retval = CTL_RETVAL_COMPLETE; 923229997Sken break; 924229997Sken } 925229997Sken 926229997Sken return (retval); 927229997Sken} 928229997Sken 929229997Skenstatic int 930229997Skenctl_backend_ramdisk_config_read(union ctl_io *io) 931229997Sken{ 932275474Smav int retval = 0; 933275474Smav 934275474Smav switch (io->scsiio.cdb[0]) { 935275474Smav case SERVICE_ACTION_IN: 936275474Smav if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 937275474Smav /* We have nothing to tell, leave default data. */ 938275474Smav ctl_config_read_done(io); 939275474Smav retval = CTL_RETVAL_COMPLETE; 940275474Smav break; 941275474Smav } 942275474Smav ctl_set_invalid_field(&io->scsiio, 943275474Smav /*sks_valid*/ 1, 944275474Smav /*command*/ 1, 945275474Smav /*field*/ 1, 946275474Smav /*bit_valid*/ 1, 947275474Smav /*bit*/ 4); 948275474Smav ctl_config_read_done(io); 949275474Smav retval = CTL_RETVAL_COMPLETE; 950275474Smav break; 951275474Smav default: 952275474Smav ctl_set_invalid_opcode(&io->scsiio); 953275474Smav ctl_config_read_done(io); 954275474Smav retval = CTL_RETVAL_COMPLETE; 955275474Smav break; 956275474Smav } 957275474Smav 958275474Smav return (retval); 959229997Sken} 960