ctl_backend_ramdisk.c revision 268148
1/*- 2 * Copyright (c) 2003, 2008 Silicon Graphics International Corp. 3 * Copyright (c) 2012 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by Edward Tomasz Napierala 7 * under sponsorship from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions, and the following disclaimer, 14 * without modification. 15 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16 * substantially similar to the "NO WARRANTY" disclaimer below 17 * ("Disclaimer") and any redistribution must be conditioned upon 18 * including a substantially similar Disclaimer requirement for further 19 * binary redistribution. 20 * 21 * NO WARRANTY 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 30 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 31 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGES. 33 * 34 * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $ 35 */ 36/* 37 * CAM Target Layer backend for a "fake" ramdisk. 38 * 39 * Author: Ken Merry <ken@FreeBSD.org> 40 */ 41 42#include <sys/cdefs.h> 43__FBSDID("$FreeBSD: stable/10/sys/cam/ctl/ctl_backend_ramdisk.c 268148 2014-07-02 10:41:11Z mav $"); 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/kernel.h> 48#include <sys/condvar.h> 49#include <sys/types.h> 50#include <sys/lock.h> 51#include <sys/mutex.h> 52#include <sys/malloc.h> 53#include <sys/taskqueue.h> 54#include <sys/time.h> 55#include <sys/queue.h> 56#include <sys/conf.h> 57#include <sys/ioccom.h> 58#include <sys/module.h> 59 60#include <cam/scsi/scsi_all.h> 61#include <cam/ctl/ctl_io.h> 62#include <cam/ctl/ctl.h> 63#include <cam/ctl/ctl_util.h> 64#include <cam/ctl/ctl_backend.h> 65#include <cam/ctl/ctl_frontend_internal.h> 66#include <cam/ctl/ctl_debug.h> 67#include <cam/ctl/ctl_ioctl.h> 68#include <cam/ctl/ctl_error.h> 69 70typedef enum { 71 CTL_BE_RAMDISK_LUN_UNCONFIGURED = 0x01, 72 CTL_BE_RAMDISK_LUN_CONFIG_ERR = 0x02, 73 CTL_BE_RAMDISK_LUN_WAITING = 0x04 74} ctl_be_ramdisk_lun_flags; 75 76struct ctl_be_ramdisk_lun { 77 char lunname[32]; 78 uint64_t size_bytes; 79 uint64_t size_blocks; 80 struct ctl_be_ramdisk_softc *softc; 81 ctl_be_ramdisk_lun_flags flags; 82 STAILQ_ENTRY(ctl_be_ramdisk_lun) links; 83 struct ctl_be_lun ctl_be_lun; 84 struct taskqueue *io_taskqueue; 85 struct task io_task; 86 STAILQ_HEAD(, ctl_io_hdr) cont_queue; 87 struct mtx lock; 88}; 89 90struct ctl_be_ramdisk_softc { 91 struct mtx lock; 92 int rd_size; 93#ifdef CTL_RAMDISK_PAGES 94 uint8_t **ramdisk_pages; 95 int num_pages; 96#else 97 uint8_t *ramdisk_buffer; 98#endif 99 int num_luns; 100 STAILQ_HEAD(, ctl_be_ramdisk_lun) lun_list; 101}; 102 103static struct ctl_be_ramdisk_softc rd_softc; 104 105int ctl_backend_ramdisk_init(void); 106void ctl_backend_ramdisk_shutdown(void); 107static int ctl_backend_ramdisk_move_done(union ctl_io *io); 108static int ctl_backend_ramdisk_submit(union ctl_io *io); 109static void ctl_backend_ramdisk_continue(union ctl_io *io); 110static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, 111 caddr_t addr, int flag, struct thread *td); 112static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 113 struct ctl_lun_req *req); 114static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 115 struct ctl_lun_req *req, int do_wait); 116static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 117 struct ctl_lun_req *req); 118static void ctl_backend_ramdisk_worker(void *context, int pending); 119static void ctl_backend_ramdisk_lun_shutdown(void *be_lun); 120static void ctl_backend_ramdisk_lun_config_status(void *be_lun, 121 ctl_lun_config_status status); 122static int ctl_backend_ramdisk_config_write(union ctl_io *io); 123static int ctl_backend_ramdisk_config_read(union ctl_io *io); 124 125static struct ctl_backend_driver ctl_be_ramdisk_driver = 126{ 127 .name = "ramdisk", 128 .flags = CTL_BE_FLAG_HAS_CONFIG, 129 .init = ctl_backend_ramdisk_init, 130 .data_submit = ctl_backend_ramdisk_submit, 131 .data_move_done = ctl_backend_ramdisk_move_done, 132 .config_read = ctl_backend_ramdisk_config_read, 133 .config_write = ctl_backend_ramdisk_config_write, 134 .ioctl = ctl_backend_ramdisk_ioctl 135}; 136 137MALLOC_DEFINE(M_RAMDISK, "ramdisk", "Memory used for CTL RAMdisk"); 138CTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver); 139 140int 141ctl_backend_ramdisk_init(void) 142{ 143 struct ctl_be_ramdisk_softc *softc; 144#ifdef CTL_RAMDISK_PAGES 145 int i; 146#endif 147 148 149 softc = &rd_softc; 150 151 memset(softc, 0, sizeof(*softc)); 152 153 mtx_init(&softc->lock, "ramdisk", NULL, MTX_DEF); 154 155 STAILQ_INIT(&softc->lun_list); 156 softc->rd_size = 1024 * 1024; 157#ifdef CTL_RAMDISK_PAGES 158 softc->num_pages = softc->rd_size / PAGE_SIZE; 159 softc->ramdisk_pages = (uint8_t **)malloc(sizeof(uint8_t *) * 160 softc->num_pages, M_RAMDISK, 161 M_WAITOK); 162 for (i = 0; i < softc->num_pages; i++) 163 softc->ramdisk_pages[i] = malloc(PAGE_SIZE, M_RAMDISK,M_WAITOK); 164#else 165 softc->ramdisk_buffer = (uint8_t *)malloc(softc->rd_size, M_RAMDISK, 166 M_WAITOK); 167#endif 168 169 return (0); 170} 171 172void 173ctl_backend_ramdisk_shutdown(void) 174{ 175 struct ctl_be_ramdisk_softc *softc; 176 struct ctl_be_ramdisk_lun *lun, *next_lun; 177#ifdef CTL_RAMDISK_PAGES 178 int i; 179#endif 180 181 softc = &rd_softc; 182 183 mtx_lock(&softc->lock); 184 for (lun = STAILQ_FIRST(&softc->lun_list); lun != NULL; lun = next_lun){ 185 /* 186 * Grab the next LUN. The current LUN may get removed by 187 * ctl_invalidate_lun(), which will call our LUN shutdown 188 * routine, if there is no outstanding I/O for this LUN. 189 */ 190 next_lun = STAILQ_NEXT(lun, links); 191 192 /* 193 * Drop our lock here. Since ctl_invalidate_lun() can call 194 * back into us, this could potentially lead to a recursive 195 * lock of the same mutex, which would cause a hang. 196 */ 197 mtx_unlock(&softc->lock); 198 ctl_disable_lun(&lun->ctl_be_lun); 199 ctl_invalidate_lun(&lun->ctl_be_lun); 200 mtx_lock(&softc->lock); 201 } 202 mtx_unlock(&softc->lock); 203 204#ifdef CTL_RAMDISK_PAGES 205 for (i = 0; i < softc->num_pages; i++) 206 free(softc->ramdisk_pages[i], M_RAMDISK); 207 208 free(softc->ramdisk_pages, M_RAMDISK); 209#else 210 free(softc->ramdisk_buffer, M_RAMDISK); 211#endif 212 213 if (ctl_backend_deregister(&ctl_be_ramdisk_driver) != 0) { 214 printf("ctl_backend_ramdisk_shutdown: " 215 "ctl_backend_deregister() failed!\n"); 216 } 217} 218 219static int 220ctl_backend_ramdisk_move_done(union ctl_io *io) 221{ 222 struct ctl_be_lun *ctl_be_lun; 223 struct ctl_be_ramdisk_lun *be_lun; 224#ifdef CTL_TIME_IO 225 struct bintime cur_bt; 226#endif 227 228 CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); 229 ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 230 CTL_PRIV_BACKEND_LUN].ptr; 231 be_lun = (struct ctl_be_ramdisk_lun *)ctl_be_lun->be_lun; 232#ifdef CTL_TIME_IO 233 getbintime(&cur_bt); 234 bintime_sub(&cur_bt, &io->io_hdr.dma_start_bt); 235 bintime_add(&io->io_hdr.dma_bt, &cur_bt); 236 io->io_hdr.num_dmas++; 237#endif 238 if (io->scsiio.kern_sg_entries > 0) 239 free(io->scsiio.kern_data_ptr, M_RAMDISK); 240 io->scsiio.kern_rel_offset += io->scsiio.kern_data_len; 241 if ((io->io_hdr.port_status == 0) 242 && ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0) 243 && ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)) { 244 if (io->scsiio.kern_rel_offset < io->scsiio.kern_total_len) { 245 mtx_lock(&be_lun->lock); 246 STAILQ_INSERT_TAIL(&be_lun->cont_queue, 247 &io->io_hdr, links); 248 mtx_unlock(&be_lun->lock); 249 taskqueue_enqueue(be_lun->io_taskqueue, 250 &be_lun->io_task); 251 return (0); 252 } 253 io->io_hdr.status = CTL_SUCCESS; 254 } else if ((io->io_hdr.port_status != 0) 255 && ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0) 256 && ((io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE)){ 257 /* 258 * For hardware error sense keys, the sense key 259 * specific value is defined to be a retry count, 260 * but we use it to pass back an internal FETD 261 * error code. XXX KDM Hopefully the FETD is only 262 * using 16 bits for an error code, since that's 263 * all the space we have in the sks field. 264 */ 265 ctl_set_internal_failure(&io->scsiio, 266 /*sks_valid*/ 1, 267 /*retry_count*/ 268 io->io_hdr.port_status); 269 } 270 ctl_done(io); 271 return(0); 272} 273 274static int 275ctl_backend_ramdisk_submit(union ctl_io *io) 276{ 277 278 ctl_backend_ramdisk_continue(io); 279 return (CTL_RETVAL_COMPLETE); 280} 281 282static void 283ctl_backend_ramdisk_continue(union ctl_io *io) 284{ 285 struct ctl_be_ramdisk_softc *softc; 286 int len, len_filled, sg_filled; 287#ifdef CTL_RAMDISK_PAGES 288 struct ctl_sg_entry *sg_entries; 289 int i; 290#endif 291 292 softc = &rd_softc; 293 len = io->scsiio.kern_total_len - io->scsiio.kern_rel_offset; 294#ifdef CTL_RAMDISK_PAGES 295 sg_filled = min(btoc(len), softc->num_pages); 296 if (sg_filled > 1) { 297 io->scsiio.kern_data_ptr = malloc(sizeof(struct ctl_sg_entry) * 298 sg_filled, M_RAMDISK, 299 M_WAITOK); 300 sg_entries = (struct ctl_sg_entry *)io->scsiio.kern_data_ptr; 301 for (i = 0, len_filled = 0; i < sg_filled; i++) { 302 sg_entries[i].addr = softc->ramdisk_pages[i]; 303 sg_entries[i].len = ctl_min(PAGE_SIZE, 304 len - len_filled); 305 len_filled += sg_entries[i].len; 306 } 307 io->io_hdr.flags |= CTL_FLAG_KDPTR_SGLIST; 308 } else { 309 sg_filled = 0; 310 len_filled = len; 311 io->scsiio.kern_data_ptr = softc->ramdisk_pages[0]; 312 } 313#else 314 sg_filled = 0; 315 len_filled = min(len, softc->rd_size); 316 io->scsiio.kern_data_ptr = softc->ramdisk_buffer; 317#endif /* CTL_RAMDISK_PAGES */ 318 319 io->scsiio.be_move_done = ctl_backend_ramdisk_move_done; 320 io->scsiio.kern_data_resid = 0; 321 io->scsiio.kern_data_len = len_filled; 322 io->scsiio.kern_sg_entries = sg_filled; 323 io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 324#ifdef CTL_TIME_IO 325 getbintime(&io->io_hdr.dma_start_bt); 326#endif 327 ctl_datamove(io); 328} 329 330static void 331ctl_backend_ramdisk_worker(void *context, int pending) 332{ 333 struct ctl_be_ramdisk_softc *softc; 334 struct ctl_be_ramdisk_lun *be_lun; 335 union ctl_io *io; 336 337 be_lun = (struct ctl_be_ramdisk_lun *)context; 338 softc = be_lun->softc; 339 340 mtx_lock(&be_lun->lock); 341 for (;;) { 342 io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); 343 if (io != NULL) { 344 STAILQ_REMOVE(&be_lun->cont_queue, &io->io_hdr, 345 ctl_io_hdr, links); 346 347 mtx_unlock(&be_lun->lock); 348 349 ctl_backend_ramdisk_continue(io); 350 351 mtx_lock(&be_lun->lock); 352 continue; 353 } 354 355 /* 356 * If we get here, there is no work left in the queues, so 357 * just break out and let the task queue go to sleep. 358 */ 359 break; 360 } 361 mtx_unlock(&be_lun->lock); 362} 363 364static int 365ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 366 int flag, struct thread *td) 367{ 368 struct ctl_be_ramdisk_softc *softc; 369 int retval; 370 371 retval = 0; 372 softc = &rd_softc; 373 374 switch (cmd) { 375 case CTL_LUN_REQ: { 376 struct ctl_lun_req *lun_req; 377 378 lun_req = (struct ctl_lun_req *)addr; 379 380 switch (lun_req->reqtype) { 381 case CTL_LUNREQ_CREATE: 382 retval = ctl_backend_ramdisk_create(softc, lun_req, 383 /*do_wait*/ 1); 384 break; 385 case CTL_LUNREQ_RM: 386 retval = ctl_backend_ramdisk_rm(softc, lun_req); 387 break; 388 case CTL_LUNREQ_MODIFY: 389 retval = ctl_backend_ramdisk_modify(softc, lun_req); 390 break; 391 default: 392 lun_req->status = CTL_LUN_ERROR; 393 snprintf(lun_req->error_str, sizeof(lun_req->error_str), 394 "%s: invalid LUN request type %d", __func__, 395 lun_req->reqtype); 396 break; 397 } 398 break; 399 } 400 default: 401 retval = ENOTTY; 402 break; 403 } 404 405 return (retval); 406} 407 408static int 409ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 410 struct ctl_lun_req *req) 411{ 412 struct ctl_be_ramdisk_lun *be_lun; 413 struct ctl_lun_rm_params *params; 414 int retval; 415 416 417 retval = 0; 418 params = &req->reqdata.rm; 419 420 be_lun = NULL; 421 422 mtx_lock(&softc->lock); 423 424 STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 425 if (be_lun->ctl_be_lun.lun_id == params->lun_id) 426 break; 427 } 428 mtx_unlock(&softc->lock); 429 430 if (be_lun == NULL) { 431 snprintf(req->error_str, sizeof(req->error_str), 432 "%s: LUN %u is not managed by the ramdisk backend", 433 __func__, params->lun_id); 434 goto bailout_error; 435 } 436 437 retval = ctl_disable_lun(&be_lun->ctl_be_lun); 438 439 if (retval != 0) { 440 snprintf(req->error_str, sizeof(req->error_str), 441 "%s: error %d returned from ctl_disable_lun() for " 442 "LUN %d", __func__, retval, params->lun_id); 443 goto bailout_error; 444 } 445 446 /* 447 * Set the waiting flag before we invalidate the LUN. Our shutdown 448 * routine can be called any time after we invalidate the LUN, 449 * and can be called from our context. 450 * 451 * This tells the shutdown routine that we're waiting, or we're 452 * going to wait for the shutdown to happen. 453 */ 454 mtx_lock(&softc->lock); 455 be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 456 mtx_unlock(&softc->lock); 457 458 retval = ctl_invalidate_lun(&be_lun->ctl_be_lun); 459 if (retval != 0) { 460 snprintf(req->error_str, sizeof(req->error_str), 461 "%s: error %d returned from ctl_invalidate_lun() for " 462 "LUN %d", __func__, retval, params->lun_id); 463 mtx_lock(&softc->lock); 464 be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 465 mtx_unlock(&softc->lock); 466 goto bailout_error; 467 } 468 469 mtx_lock(&softc->lock); 470 471 while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) { 472 retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 473 if (retval == EINTR) 474 break; 475 } 476 be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 477 478 /* 479 * We only remove this LUN from the list and free it (below) if 480 * retval == 0. If the user interrupted the wait, we just bail out 481 * without actually freeing the LUN. We let the shutdown routine 482 * free the LUN if that happens. 483 */ 484 if (retval == 0) { 485 STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 486 links); 487 softc->num_luns--; 488 } 489 490 mtx_unlock(&softc->lock); 491 492 if (retval == 0) { 493 taskqueue_drain(be_lun->io_taskqueue, &be_lun->io_task); 494 taskqueue_free(be_lun->io_taskqueue); 495 ctl_free_opts(&be_lun->ctl_be_lun); 496 mtx_destroy(&be_lun->lock); 497 free(be_lun, M_RAMDISK); 498 } 499 500 req->status = CTL_LUN_OK; 501 502 return (retval); 503 504bailout_error: 505 req->status = CTL_LUN_ERROR; 506 507 return (0); 508} 509 510static int 511ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 512 struct ctl_lun_req *req, int do_wait) 513{ 514 struct ctl_be_ramdisk_lun *be_lun; 515 struct ctl_lun_create_params *params; 516 uint32_t blocksize; 517 char *value; 518 char tmpstr[32]; 519 int retval, unmap; 520 521 retval = 0; 522 params = &req->reqdata.create; 523 if (params->blocksize_bytes != 0) 524 blocksize = params->blocksize_bytes; 525 else 526 blocksize = 512; 527 528 be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | (do_wait ? 529 M_WAITOK : M_NOWAIT)); 530 531 if (be_lun == NULL) { 532 snprintf(req->error_str, sizeof(req->error_str), 533 "%s: error allocating %zd bytes", __func__, 534 sizeof(*be_lun)); 535 goto bailout_error; 536 } 537 sprintf(be_lun->lunname, "cram%d", softc->num_luns); 538 ctl_init_opts(&be_lun->ctl_be_lun, req); 539 540 if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 541 be_lun->ctl_be_lun.lun_type = params->device_type; 542 else 543 be_lun->ctl_be_lun.lun_type = T_DIRECT; 544 545 if (be_lun->ctl_be_lun.lun_type == T_DIRECT) { 546 547 if (params->lun_size_bytes < blocksize) { 548 snprintf(req->error_str, sizeof(req->error_str), 549 "%s: LUN size %ju < blocksize %u", __func__, 550 params->lun_size_bytes, blocksize); 551 goto bailout_error; 552 } 553 554 be_lun->size_blocks = params->lun_size_bytes / blocksize; 555 be_lun->size_bytes = be_lun->size_blocks * blocksize; 556 557 be_lun->ctl_be_lun.maxlba = be_lun->size_blocks - 1; 558 } else { 559 be_lun->ctl_be_lun.maxlba = 0; 560 blocksize = 0; 561 be_lun->size_bytes = 0; 562 be_lun->size_blocks = 0; 563 } 564 565 be_lun->ctl_be_lun.blocksize = blocksize; 566 567 /* Tell the user the blocksize we ended up using */ 568 params->blocksize_bytes = blocksize; 569 570 /* Tell the user the exact size we ended up using */ 571 params->lun_size_bytes = be_lun->size_bytes; 572 573 be_lun->softc = softc; 574 575 unmap = 0; 576 value = ctl_get_opt(&be_lun->ctl_be_lun, "unmap"); 577 if (value != NULL && strcmp(value, "on") == 0) 578 unmap = 1; 579 580 be_lun->flags = CTL_BE_RAMDISK_LUN_UNCONFIGURED; 581 be_lun->ctl_be_lun.flags = CTL_LUN_FLAG_PRIMARY; 582 if (unmap) 583 be_lun->ctl_be_lun.flags |= CTL_LUN_FLAG_UNMAP; 584 be_lun->ctl_be_lun.be_lun = be_lun; 585 586 if (params->flags & CTL_LUN_FLAG_ID_REQ) { 587 be_lun->ctl_be_lun.req_lun_id = params->req_lun_id; 588 be_lun->ctl_be_lun.flags |= CTL_LUN_FLAG_ID_REQ; 589 } else 590 be_lun->ctl_be_lun.req_lun_id = 0; 591 592 be_lun->ctl_be_lun.lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 593 be_lun->ctl_be_lun.lun_config_status = 594 ctl_backend_ramdisk_lun_config_status; 595 be_lun->ctl_be_lun.be = &ctl_be_ramdisk_driver; 596 if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 597 snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%4d", 598 softc->num_luns); 599 strncpy((char *)be_lun->ctl_be_lun.serial_num, tmpstr, 600 ctl_min(sizeof(be_lun->ctl_be_lun.serial_num), 601 sizeof(tmpstr))); 602 603 /* Tell the user what we used for a serial number */ 604 strncpy((char *)params->serial_num, tmpstr, 605 ctl_min(sizeof(params->serial_num), sizeof(tmpstr))); 606 } else { 607 strncpy((char *)be_lun->ctl_be_lun.serial_num, 608 params->serial_num, 609 ctl_min(sizeof(be_lun->ctl_be_lun.serial_num), 610 sizeof(params->serial_num))); 611 } 612 if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 613 snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%4d", softc->num_luns); 614 strncpy((char *)be_lun->ctl_be_lun.device_id, tmpstr, 615 ctl_min(sizeof(be_lun->ctl_be_lun.device_id), 616 sizeof(tmpstr))); 617 618 /* Tell the user what we used for a device ID */ 619 strncpy((char *)params->device_id, tmpstr, 620 ctl_min(sizeof(params->device_id), sizeof(tmpstr))); 621 } else { 622 strncpy((char *)be_lun->ctl_be_lun.device_id, 623 params->device_id, 624 ctl_min(sizeof(be_lun->ctl_be_lun.device_id), 625 sizeof(params->device_id))); 626 } 627 628 STAILQ_INIT(&be_lun->cont_queue); 629 mtx_init(&be_lun->lock, "CTL ramdisk", NULL, MTX_DEF); 630 TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 631 be_lun); 632 633 be_lun->io_taskqueue = taskqueue_create(be_lun->lunname, M_WAITOK, 634 taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 635 if (be_lun->io_taskqueue == NULL) { 636 snprintf(req->error_str, sizeof(req->error_str), 637 "%s: Unable to create taskqueue", __func__); 638 goto bailout_error; 639 } 640 641 retval = taskqueue_start_threads(&be_lun->io_taskqueue, 642 /*num threads*/1, 643 /*priority*/PWAIT, 644 /*thread name*/ 645 "%s taskq", be_lun->lunname); 646 if (retval != 0) 647 goto bailout_error; 648 649 mtx_lock(&softc->lock); 650 softc->num_luns++; 651 STAILQ_INSERT_TAIL(&softc->lun_list, be_lun, links); 652 653 mtx_unlock(&softc->lock); 654 655 retval = ctl_add_lun(&be_lun->ctl_be_lun); 656 if (retval != 0) { 657 mtx_lock(&softc->lock); 658 STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 659 links); 660 softc->num_luns--; 661 mtx_unlock(&softc->lock); 662 snprintf(req->error_str, sizeof(req->error_str), 663 "%s: ctl_add_lun() returned error %d, see dmesg for " 664 "details", __func__, retval); 665 retval = 0; 666 goto bailout_error; 667 } 668 669 if (do_wait == 0) 670 return (retval); 671 672 mtx_lock(&softc->lock); 673 674 /* 675 * Tell the config_status routine that we're waiting so it won't 676 * clean up the LUN in the event of an error. 677 */ 678 be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 679 680 while (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 681 retval = msleep(be_lun, &softc->lock, PCATCH, "ctlram", 0); 682 if (retval == EINTR) 683 break; 684 } 685 be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 686 687 if (be_lun->flags & CTL_BE_RAMDISK_LUN_CONFIG_ERR) { 688 snprintf(req->error_str, sizeof(req->error_str), 689 "%s: LUN configuration error, see dmesg for details", 690 __func__); 691 STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 692 links); 693 softc->num_luns--; 694 mtx_unlock(&softc->lock); 695 goto bailout_error; 696 } else { 697 params->req_lun_id = be_lun->ctl_be_lun.lun_id; 698 } 699 mtx_unlock(&softc->lock); 700 701 req->status = CTL_LUN_OK; 702 703 return (retval); 704 705bailout_error: 706 req->status = CTL_LUN_ERROR; 707 if (be_lun != NULL) { 708 if (be_lun->io_taskqueue != NULL) { 709 taskqueue_free(be_lun->io_taskqueue); 710 } 711 ctl_free_opts(&be_lun->ctl_be_lun); 712 mtx_destroy(&be_lun->lock); 713 free(be_lun, M_RAMDISK); 714 } 715 716 return (retval); 717} 718 719static int 720ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 721 struct ctl_lun_req *req) 722{ 723 struct ctl_be_ramdisk_lun *be_lun; 724 struct ctl_lun_modify_params *params; 725 uint32_t blocksize; 726 727 params = &req->reqdata.modify; 728 729 be_lun = NULL; 730 731 mtx_lock(&softc->lock); 732 STAILQ_FOREACH(be_lun, &softc->lun_list, links) { 733 if (be_lun->ctl_be_lun.lun_id == params->lun_id) 734 break; 735 } 736 mtx_unlock(&softc->lock); 737 738 if (be_lun == NULL) { 739 snprintf(req->error_str, sizeof(req->error_str), 740 "%s: LUN %u is not managed by the ramdisk backend", 741 __func__, params->lun_id); 742 goto bailout_error; 743 } 744 745 if (params->lun_size_bytes == 0) { 746 snprintf(req->error_str, sizeof(req->error_str), 747 "%s: LUN size \"auto\" not supported " 748 "by the ramdisk backend", __func__); 749 goto bailout_error; 750 } 751 752 blocksize = be_lun->ctl_be_lun.blocksize; 753 754 if (params->lun_size_bytes < blocksize) { 755 snprintf(req->error_str, sizeof(req->error_str), 756 "%s: LUN size %ju < blocksize %u", __func__, 757 params->lun_size_bytes, blocksize); 758 goto bailout_error; 759 } 760 761 be_lun->size_blocks = params->lun_size_bytes / blocksize; 762 be_lun->size_bytes = be_lun->size_blocks * blocksize; 763 764 /* 765 * The maximum LBA is the size - 1. 766 * 767 * XXX: Note that this field is being updated without locking, 768 * which might cause problems on 32-bit architectures. 769 */ 770 be_lun->ctl_be_lun.maxlba = be_lun->size_blocks - 1; 771 ctl_lun_capacity_changed(&be_lun->ctl_be_lun); 772 773 /* Tell the user the exact size we ended up using */ 774 params->lun_size_bytes = be_lun->size_bytes; 775 776 req->status = CTL_LUN_OK; 777 778 return (0); 779 780bailout_error: 781 req->status = CTL_LUN_ERROR; 782 783 return (0); 784} 785 786static void 787ctl_backend_ramdisk_lun_shutdown(void *be_lun) 788{ 789 struct ctl_be_ramdisk_lun *lun; 790 struct ctl_be_ramdisk_softc *softc; 791 int do_free; 792 793 lun = (struct ctl_be_ramdisk_lun *)be_lun; 794 softc = lun->softc; 795 do_free = 0; 796 797 mtx_lock(&softc->lock); 798 799 lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 800 801 if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 802 wakeup(lun); 803 } else { 804 STAILQ_REMOVE(&softc->lun_list, be_lun, ctl_be_ramdisk_lun, 805 links); 806 softc->num_luns--; 807 do_free = 1; 808 } 809 810 mtx_unlock(&softc->lock); 811 812 if (do_free != 0) 813 free(be_lun, M_RAMDISK); 814} 815 816static void 817ctl_backend_ramdisk_lun_config_status(void *be_lun, 818 ctl_lun_config_status status) 819{ 820 struct ctl_be_ramdisk_lun *lun; 821 struct ctl_be_ramdisk_softc *softc; 822 823 lun = (struct ctl_be_ramdisk_lun *)be_lun; 824 softc = lun->softc; 825 826 if (status == CTL_LUN_CONFIG_OK) { 827 mtx_lock(&softc->lock); 828 lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 829 if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 830 wakeup(lun); 831 mtx_unlock(&softc->lock); 832 833 /* 834 * We successfully added the LUN, attempt to enable it. 835 */ 836 if (ctl_enable_lun(&lun->ctl_be_lun) != 0) { 837 printf("%s: ctl_enable_lun() failed!\n", __func__); 838 if (ctl_invalidate_lun(&lun->ctl_be_lun) != 0) { 839 printf("%s: ctl_invalidate_lun() failed!\n", 840 __func__); 841 } 842 } 843 844 return; 845 } 846 847 848 mtx_lock(&softc->lock); 849 lun->flags &= ~CTL_BE_RAMDISK_LUN_UNCONFIGURED; 850 851 /* 852 * If we have a user waiting, let him handle the cleanup. If not, 853 * clean things up here. 854 */ 855 if (lun->flags & CTL_BE_RAMDISK_LUN_WAITING) { 856 lun->flags |= CTL_BE_RAMDISK_LUN_CONFIG_ERR; 857 wakeup(lun); 858 } else { 859 STAILQ_REMOVE(&softc->lun_list, lun, ctl_be_ramdisk_lun, 860 links); 861 softc->num_luns--; 862 free(lun, M_RAMDISK); 863 } 864 mtx_unlock(&softc->lock); 865} 866 867static int 868ctl_backend_ramdisk_config_write(union ctl_io *io) 869{ 870 struct ctl_be_ramdisk_softc *softc; 871 int retval; 872 873 retval = 0; 874 softc = &rd_softc; 875 876 switch (io->scsiio.cdb[0]) { 877 case SYNCHRONIZE_CACHE: 878 case SYNCHRONIZE_CACHE_16: 879 /* 880 * The upper level CTL code will filter out any CDBs with 881 * the immediate bit set and return the proper error. It 882 * will also not allow a sync cache command to go to a LUN 883 * that is powered down. 884 * 885 * We don't really need to worry about what LBA range the 886 * user asked to be synced out. When they issue a sync 887 * cache command, we'll sync out the whole thing. 888 * 889 * This is obviously just a stubbed out implementation. 890 * The real implementation will be in the RAIDCore/CTL 891 * interface, and can only really happen when RAIDCore 892 * implements a per-array cache sync. 893 */ 894 ctl_set_success(&io->scsiio); 895 ctl_config_write_done(io); 896 break; 897 case START_STOP_UNIT: { 898 struct scsi_start_stop_unit *cdb; 899 struct ctl_be_lun *ctl_be_lun; 900 struct ctl_be_ramdisk_lun *be_lun; 901 902 cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 903 904 ctl_be_lun = (struct ctl_be_lun *)io->io_hdr.ctl_private[ 905 CTL_PRIV_BACKEND_LUN].ptr; 906 be_lun = (struct ctl_be_ramdisk_lun *)ctl_be_lun->be_lun; 907 908 if (cdb->how & SSS_START) 909 retval = ctl_start_lun(ctl_be_lun); 910 else { 911 retval = ctl_stop_lun(ctl_be_lun); 912#ifdef NEEDTOPORT 913 if ((retval == 0) 914 && (cdb->byte2 & SSS_ONOFFLINE)) 915 retval = ctl_lun_offline(ctl_be_lun); 916#endif 917 } 918 919 /* 920 * In general, the above routines should not fail. They 921 * just set state for the LUN. So we've got something 922 * pretty wrong here if we can't start or stop the LUN. 923 */ 924 if (retval != 0) { 925 ctl_set_internal_failure(&io->scsiio, 926 /*sks_valid*/ 1, 927 /*retry_count*/ 0xf051); 928 retval = CTL_RETVAL_COMPLETE; 929 } else { 930 ctl_set_success(&io->scsiio); 931 } 932 ctl_config_write_done(io); 933 break; 934 } 935 case WRITE_SAME_10: 936 case WRITE_SAME_16: 937 case UNMAP: 938 ctl_set_success(&io->scsiio); 939 ctl_config_write_done(io); 940 break; 941 default: 942 ctl_set_invalid_opcode(&io->scsiio); 943 ctl_config_write_done(io); 944 retval = CTL_RETVAL_COMPLETE; 945 break; 946 } 947 948 return (retval); 949} 950 951static int 952ctl_backend_ramdisk_config_read(union ctl_io *io) 953{ 954 /* 955 * XXX KDM need to implement!! 956 */ 957 return (0); 958} 959