1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2003, 2008 Silicon Graphics International Corp. 5 * Copyright (c) 2012 The FreeBSD Foundation 6 * Copyright (c) 2014-2017 Alexander Motin <mav@FreeBSD.org> 7 * All rights reserved. 8 * 9 * Portions of this software were developed by Edward Tomasz Napierala 10 * under sponsorship from the FreeBSD Foundation. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 24 * NO WARRANTY 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGES. 36 * 37 * $Id: //depot/users/kenm/FreeBSD-test2/sys/cam/ctl/ctl_backend_ramdisk.c#3 $ 38 */ 39 /* 40 * CAM Target Layer black hole and RAM disk backend. 41 * 42 * Author: Ken Merry <ken@FreeBSD.org> 43 */ 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/limits.h> 51 #include <sys/lock.h> 52 #include <sys/mutex.h> 53 #include <sys/malloc.h> 54 #include <sys/sx.h> 55 #include <sys/taskqueue.h> 56 #include <sys/time.h> 57 #include <sys/queue.h> 58 #include <sys/conf.h> 59 #include <sys/ioccom.h> 60 #include <sys/module.h> 61 #include <sys/sysctl.h> 62 #include <sys/nv.h> 63 #include <sys/dnv.h> 64 65 #include <cam/scsi/scsi_all.h> 66 #include <cam/scsi/scsi_da.h> 67 #include <cam/ctl/ctl_io.h> 68 #include <cam/ctl/ctl.h> 69 #include <cam/ctl/ctl_util.h> 70 #include <cam/ctl/ctl_backend.h> 71 #include <cam/ctl/ctl_debug.h> 72 #include <cam/ctl/ctl_ioctl.h> 73 #include <cam/ctl/ctl_ha.h> 74 #include <cam/ctl/ctl_private.h> 75 #include <cam/ctl/ctl_error.h> 76 77 #define PRIV(io) \ 78 ((struct ctl_ptr_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_BACKEND]) 79 #define ARGS(io) \ 80 ((struct ctl_lba_len_flags *)&(io)->io_hdr.ctl_private[CTL_PRIV_LBA_LEN]) 81 82 #define PPP (PAGE_SIZE / sizeof(uint8_t **)) 83 #ifdef __LP64__ 84 #define PPPS (PAGE_SHIFT - 3) 85 #else 86 #define PPPS (PAGE_SHIFT - 2) 87 #endif 88 #define SGPP (PAGE_SIZE / sizeof(struct ctl_sg_entry)) 89 90 #define P_UNMAPPED NULL /* Page is unmapped. */ 91 #define P_ANCHORED ((void *)(uintptr_t)1) /* Page is anchored. */ 92 93 typedef enum { 94 GP_READ, /* Return data page or zero page. */ 95 GP_WRITE, /* Return data page, try allocate if none. */ 96 GP_ANCHOR, /* Return data page, try anchor if none. */ 97 GP_OTHER, /* Return what present, do not allocate/anchor. */ 98 } getpage_op_t; 99 100 typedef enum { 101 CTL_BE_RAMDISK_LUN_UNCONFIGURED = 0x01, 102 CTL_BE_RAMDISK_LUN_WAITING = 0x04 103 } ctl_be_ramdisk_lun_flags; 104 105 struct ctl_be_ramdisk_lun { 106 struct ctl_be_lun cbe_lun; /* Must be first element. */ 107 struct ctl_lun_create_params params; 108 int indir; 109 uint8_t **pages; 110 uint8_t *zero_page; 111 struct sx page_lock; 112 u_int pblocksize; 113 u_int pblockmul; 114 uint64_t size_bytes; 115 uint64_t size_blocks; 116 uint64_t cap_bytes; 117 uint64_t cap_used; 118 struct ctl_be_ramdisk_softc *softc; 119 ctl_be_ramdisk_lun_flags flags; 120 SLIST_ENTRY(ctl_be_ramdisk_lun) links; 121 struct taskqueue *io_taskqueue; 122 struct task io_task; 123 STAILQ_HEAD(, ctl_io_hdr) cont_queue; 124 struct mtx_padalign queue_lock; 125 }; 126 127 struct ctl_be_ramdisk_softc { 128 struct sx modify_lock; 129 struct mtx lock; 130 int num_luns; 131 SLIST_HEAD(, ctl_be_ramdisk_lun) lun_list; 132 }; 133 134 static struct ctl_be_ramdisk_softc rd_softc; 135 136 static int ctl_backend_ramdisk_init(void); 137 static int ctl_backend_ramdisk_shutdown(void); 138 static int ctl_backend_ramdisk_move_done(union ctl_io *io, bool samethr); 139 static void ctl_backend_ramdisk_compare(union ctl_io *io); 140 static void ctl_backend_ramdisk_rw(union ctl_io *io); 141 static int ctl_backend_ramdisk_submit(union ctl_io *io); 142 static void ctl_backend_ramdisk_worker(void *context, int pending); 143 static int ctl_backend_ramdisk_config_read(union ctl_io *io); 144 static int ctl_backend_ramdisk_config_write(union ctl_io *io); 145 static uint64_t ctl_backend_ramdisk_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname); 146 static int ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, 147 caddr_t addr, int flag, struct thread *td); 148 static int ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 149 struct ctl_lun_req *req); 150 static int ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 151 struct ctl_lun_req *req); 152 static int ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 153 struct ctl_lun_req *req); 154 static void ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun *cbe_lun); 155 156 static struct ctl_backend_driver ctl_be_ramdisk_driver = 157 { 158 .name = "ramdisk", 159 .flags = CTL_BE_FLAG_HAS_CONFIG, 160 .init = ctl_backend_ramdisk_init, 161 .shutdown = ctl_backend_ramdisk_shutdown, 162 .data_submit = ctl_backend_ramdisk_submit, 163 .config_read = ctl_backend_ramdisk_config_read, 164 .config_write = ctl_backend_ramdisk_config_write, 165 .ioctl = ctl_backend_ramdisk_ioctl, 166 .lun_attr = ctl_backend_ramdisk_lun_attr, 167 }; 168 169 MALLOC_DEFINE(M_RAMDISK, "ctlramdisk", "Memory used for CTL RAMdisk"); 170 CTL_BACKEND_DECLARE(cbr, ctl_be_ramdisk_driver); 171 172 static int 173 ctl_backend_ramdisk_init(void) 174 { 175 struct ctl_be_ramdisk_softc *softc = &rd_softc; 176 177 memset(softc, 0, sizeof(*softc)); 178 sx_init(&softc->modify_lock, "ctlrammod"); 179 mtx_init(&softc->lock, "ctlram", NULL, MTX_DEF); 180 SLIST_INIT(&softc->lun_list); 181 return (0); 182 } 183 184 static int 185 ctl_backend_ramdisk_shutdown(void) 186 { 187 struct ctl_be_ramdisk_softc *softc = &rd_softc; 188 struct ctl_be_ramdisk_lun *lun; 189 190 mtx_lock(&softc->lock); 191 while ((lun = SLIST_FIRST(&softc->lun_list)) != NULL) { 192 SLIST_REMOVE_HEAD(&softc->lun_list, links); 193 softc->num_luns--; 194 /* 195 * Drop our lock here. Since ctl_remove_lun() can call 196 * back into us, this could potentially lead to a recursive 197 * lock of the same mutex, which would cause a hang. 198 */ 199 mtx_unlock(&softc->lock); 200 ctl_remove_lun(&lun->cbe_lun); 201 mtx_lock(&softc->lock); 202 } 203 mtx_unlock(&softc->lock); 204 mtx_destroy(&softc->lock); 205 sx_destroy(&softc->modify_lock); 206 return (0); 207 } 208 209 static uint8_t * 210 ctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn, 211 getpage_op_t op) 212 { 213 uint8_t **p, ***pp; 214 off_t i; 215 int s; 216 217 if (be_lun->cap_bytes == 0) { 218 switch (op) { 219 case GP_READ: 220 return (be_lun->zero_page); 221 case GP_WRITE: 222 return ((uint8_t *)be_lun->pages); 223 case GP_ANCHOR: 224 return (P_ANCHORED); 225 default: 226 return (P_UNMAPPED); 227 } 228 } 229 if (op == GP_WRITE || op == GP_ANCHOR) { 230 sx_xlock(&be_lun->page_lock); 231 pp = &be_lun->pages; 232 for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 233 if (*pp == NULL) { 234 *pp = malloc(PAGE_SIZE, M_RAMDISK, 235 M_WAITOK|M_ZERO); 236 } 237 i = pn >> s; 238 pp = (uint8_t ***)&(*pp)[i]; 239 pn -= i << s; 240 } 241 if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 242 if (op == GP_WRITE) { 243 *pp = malloc(be_lun->pblocksize, M_RAMDISK, 244 M_WAITOK|M_ZERO); 245 } else 246 *pp = P_ANCHORED; 247 be_lun->cap_used += be_lun->pblocksize; 248 } else if (*pp == P_ANCHORED && op == GP_WRITE) { 249 *pp = malloc(be_lun->pblocksize, M_RAMDISK, 250 M_WAITOK|M_ZERO); 251 } 252 sx_xunlock(&be_lun->page_lock); 253 return ((uint8_t *)*pp); 254 } else { 255 sx_slock(&be_lun->page_lock); 256 p = be_lun->pages; 257 for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 258 if (p == NULL) 259 break; 260 i = pn >> s; 261 p = (uint8_t **)p[i]; 262 pn -= i << s; 263 } 264 sx_sunlock(&be_lun->page_lock); 265 if ((p == P_UNMAPPED || p == P_ANCHORED) && op == GP_READ) 266 return (be_lun->zero_page); 267 return ((uint8_t *)p); 268 } 269 }; 270 271 static void 272 ctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 273 { 274 uint8_t ***pp; 275 off_t i; 276 int s; 277 278 if (be_lun->cap_bytes == 0) 279 return; 280 sx_xlock(&be_lun->page_lock); 281 pp = &be_lun->pages; 282 for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 283 if (*pp == NULL) 284 goto noindir; 285 i = pn >> s; 286 pp = (uint8_t ***)&(*pp)[i]; 287 pn -= i << s; 288 } 289 if (*pp == P_ANCHORED) { 290 be_lun->cap_used -= be_lun->pblocksize; 291 *pp = P_UNMAPPED; 292 } else if (*pp != P_UNMAPPED) { 293 free(*pp, M_RAMDISK); 294 be_lun->cap_used -= be_lun->pblocksize; 295 *pp = P_UNMAPPED; 296 } 297 noindir: 298 sx_xunlock(&be_lun->page_lock); 299 }; 300 301 static void 302 ctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun *be_lun, off_t pn) 303 { 304 uint8_t ***pp; 305 off_t i; 306 int s; 307 308 if (be_lun->cap_bytes == 0) 309 return; 310 sx_xlock(&be_lun->page_lock); 311 pp = &be_lun->pages; 312 for (s = (be_lun->indir - 1) * PPPS; s >= 0; s -= PPPS) { 313 if (*pp == NULL) 314 goto noindir; 315 i = pn >> s; 316 pp = (uint8_t ***)&(*pp)[i]; 317 pn -= i << s; 318 } 319 if (*pp == P_UNMAPPED && be_lun->cap_used < be_lun->cap_bytes) { 320 be_lun->cap_used += be_lun->pblocksize; 321 *pp = P_ANCHORED; 322 } else if (*pp != P_ANCHORED) { 323 free(*pp, M_RAMDISK); 324 *pp = P_ANCHORED; 325 } 326 noindir: 327 sx_xunlock(&be_lun->page_lock); 328 }; 329 330 static void 331 ctl_backend_ramdisk_freeallpages(uint8_t **p, int indir) 332 { 333 int i; 334 335 if (p == NULL) 336 return; 337 if (indir == 0) { 338 free(p, M_RAMDISK); 339 return; 340 } 341 for (i = 0; i < PPP; i++) { 342 if (p[i] == NULL) 343 continue; 344 ctl_backend_ramdisk_freeallpages((uint8_t **)p[i], indir - 1); 345 } 346 free(p, M_RAMDISK); 347 }; 348 349 static size_t 350 cmp(uint8_t *a, uint8_t *b, size_t size) 351 { 352 size_t i; 353 354 for (i = 0; i < size; i++) { 355 if (a[i] != b[i]) 356 break; 357 } 358 return (i); 359 } 360 361 static int 362 ctl_backend_ramdisk_cmp(union ctl_io *io) 363 { 364 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 365 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 366 uint8_t *page; 367 uint64_t lba; 368 u_int lbaoff, lbas, res, off; 369 370 lbas = ctl_kern_data_len(io) / cbe_lun->blocksize; 371 lba = ARGS(io)->lba + PRIV(io)->len - lbas; 372 off = 0; 373 for (; lbas > 0; lbas--, lba++) { 374 page = ctl_backend_ramdisk_getpage(be_lun, 375 lba >> cbe_lun->pblockexp, GP_READ); 376 lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 377 page += lbaoff * cbe_lun->blocksize; 378 res = cmp(ctl_kern_data_ptr(io) + off, page, 379 cbe_lun->blocksize); 380 off += res; 381 if (res < cbe_lun->blocksize) 382 break; 383 } 384 free(io->scsiio.kern_data_ptr, M_RAMDISK); 385 if (lbas > 0) { 386 off += ctl_kern_rel_offset(io) - ctl_kern_data_len(io); 387 ctl_io_set_compare_failure(io, off); 388 return (1); 389 } 390 return (0); 391 } 392 393 static int 394 ctl_backend_ramdisk_move_done(union ctl_io *io, bool samethr) 395 { 396 struct ctl_be_ramdisk_lun *be_lun = 397 (struct ctl_be_ramdisk_lun *)CTL_BACKEND_LUN(io); 398 399 CTL_DEBUG_PRINT(("ctl_backend_ramdisk_move_done\n")); 400 if (ctl_kern_sg_entries(io) > 0) 401 free(ctl_kern_data_ptr(io), M_RAMDISK); 402 ctl_add_kern_rel_offset(io, ctl_kern_data_len(io)); 403 if ((io->io_hdr.flags & CTL_FLAG_ABORT) == 0 && 404 (io->io_hdr.status & CTL_STATUS_MASK) == CTL_STATUS_NONE) { 405 if (ARGS(io)->flags & CTL_LLF_COMPARE) { 406 /* We have data block ready for comparison. */ 407 if (ctl_backend_ramdisk_cmp(io)) 408 goto done; 409 } 410 if (ARGS(io)->len > PRIV(io)->len) { 411 mtx_lock(&be_lun->queue_lock); 412 STAILQ_INSERT_TAIL(&be_lun->cont_queue, 413 &io->io_hdr, links); 414 mtx_unlock(&be_lun->queue_lock); 415 taskqueue_enqueue(be_lun->io_taskqueue, 416 &be_lun->io_task); 417 return (0); 418 } 419 ctl_io_set_success(io); 420 } 421 done: 422 ctl_data_submit_done(io); 423 return(0); 424 } 425 426 static void 427 ctl_backend_ramdisk_compare(union ctl_io *io) 428 { 429 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 430 u_int lbas, len; 431 432 lbas = ARGS(io)->len - PRIV(io)->len; 433 lbas = MIN(lbas, 131072 / cbe_lun->blocksize); 434 len = lbas * cbe_lun->blocksize; 435 436 ctl_set_be_move_done(io, ctl_backend_ramdisk_move_done); 437 ctl_set_kern_data_ptr(io, malloc(len, M_RAMDISK, M_WAITOK)); 438 ctl_set_kern_data_len(io, len); 439 ctl_set_kern_sg_entries(io, 0); 440 io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 441 PRIV(io)->len += lbas; 442 ctl_datamove(io); 443 } 444 445 static void 446 ctl_backend_ramdisk_rw(union ctl_io *io) 447 { 448 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 449 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 450 struct ctl_sg_entry *sg_entries; 451 uint8_t *page; 452 uint64_t lba; 453 u_int i, len, lbaoff, lbas, sgs, off; 454 getpage_op_t op; 455 456 lba = ARGS(io)->lba + PRIV(io)->len; 457 lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 458 lbas = ARGS(io)->len - PRIV(io)->len; 459 lbas = MIN(lbas, (SGPP << cbe_lun->pblockexp) - lbaoff); 460 sgs = (lbas + lbaoff + be_lun->pblockmul - 1) >> cbe_lun->pblockexp; 461 off = lbaoff * cbe_lun->blocksize; 462 op = (ARGS(io)->flags & CTL_LLF_WRITE) ? GP_WRITE : GP_READ; 463 if (sgs > 1) { 464 sg_entries = malloc(sizeof(struct ctl_sg_entry) * sgs, 465 M_RAMDISK, M_WAITOK); 466 ctl_set_kern_data_ptr(io, sg_entries); 467 len = lbas * cbe_lun->blocksize; 468 for (i = 0; i < sgs; i++) { 469 page = ctl_backend_ramdisk_getpage(be_lun, 470 (lba >> cbe_lun->pblockexp) + i, op); 471 if (page == P_UNMAPPED || page == P_ANCHORED) { 472 free(sg_entries, M_RAMDISK); 473 nospc: 474 ctl_io_set_space_alloc_fail(io); 475 ctl_data_submit_done(io); 476 return; 477 } 478 sg_entries[i].addr = page + off; 479 sg_entries[i].len = MIN(len, be_lun->pblocksize - off); 480 len -= sg_entries[i].len; 481 off = 0; 482 } 483 } else { 484 page = ctl_backend_ramdisk_getpage(be_lun, 485 lba >> cbe_lun->pblockexp, op); 486 if (page == P_UNMAPPED || page == P_ANCHORED) 487 goto nospc; 488 sgs = 0; 489 ctl_set_kern_data_ptr(io, page + off); 490 } 491 492 ctl_set_be_move_done(io, ctl_backend_ramdisk_move_done); 493 ctl_set_kern_data_len(io, lbas * cbe_lun->blocksize); 494 ctl_set_kern_sg_entries(io, sgs); 495 io->io_hdr.flags |= CTL_FLAG_ALLOCATED; 496 PRIV(io)->len += lbas; 497 if ((ARGS(io)->flags & CTL_LLF_READ) && 498 ARGS(io)->len <= PRIV(io)->len) { 499 ctl_io_set_success(io); 500 if (cbe_lun->serseq >= CTL_LUN_SERSEQ_SOFT) 501 ctl_serseq_done(io); 502 } 503 ctl_datamove(io); 504 } 505 506 static int 507 ctl_backend_ramdisk_submit(union ctl_io *io) 508 { 509 struct ctl_lba_len_flags *lbalen = ARGS(io); 510 511 if (lbalen->flags & CTL_LLF_VERIFY) { 512 ctl_io_set_success(io); 513 ctl_data_submit_done(io); 514 return (CTL_RETVAL_COMPLETE); 515 } 516 PRIV(io)->len = 0; 517 if (lbalen->flags & CTL_LLF_COMPARE) 518 ctl_backend_ramdisk_compare(io); 519 else 520 ctl_backend_ramdisk_rw(io); 521 return (CTL_RETVAL_COMPLETE); 522 } 523 524 static void 525 ctl_backend_ramdisk_worker(void *context, int pending) 526 { 527 struct ctl_be_ramdisk_lun *be_lun; 528 union ctl_io *io; 529 530 be_lun = (struct ctl_be_ramdisk_lun *)context; 531 mtx_lock(&be_lun->queue_lock); 532 for (;;) { 533 io = (union ctl_io *)STAILQ_FIRST(&be_lun->cont_queue); 534 if (io != NULL) { 535 STAILQ_REMOVE_HEAD(&be_lun->cont_queue, links); 536 mtx_unlock(&be_lun->queue_lock); 537 if (ARGS(io)->flags & CTL_LLF_COMPARE) 538 ctl_backend_ramdisk_compare(io); 539 else 540 ctl_backend_ramdisk_rw(io); 541 mtx_lock(&be_lun->queue_lock); 542 continue; 543 } 544 545 /* 546 * If we get here, there is no work left in the queues, so 547 * just break out and let the task queue go to sleep. 548 */ 549 break; 550 } 551 mtx_unlock(&be_lun->queue_lock); 552 } 553 554 static int 555 ctl_backend_ramdisk_gls(union ctl_io *io) 556 { 557 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 558 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 559 struct scsi_get_lba_status_data *data; 560 uint8_t *page; 561 u_int lbaoff; 562 563 data = (struct scsi_get_lba_status_data *)io->scsiio.kern_data_ptr; 564 scsi_u64to8b(ARGS(io)->lba, data->descr[0].addr); 565 lbaoff = ARGS(io)->lba & ~(UINT_MAX << cbe_lun->pblockexp); 566 scsi_ulto4b(be_lun->pblockmul - lbaoff, data->descr[0].length); 567 page = ctl_backend_ramdisk_getpage(be_lun, 568 ARGS(io)->lba >> cbe_lun->pblockexp, GP_OTHER); 569 if (page == P_UNMAPPED) 570 data->descr[0].status = 1; 571 else if (page == P_ANCHORED) 572 data->descr[0].status = 2; 573 else 574 data->descr[0].status = 0; 575 ctl_config_read_done(io); 576 return (CTL_RETVAL_COMPLETE); 577 } 578 579 static int 580 ctl_backend_ramdisk_scsi_config_read(union ctl_io *io) 581 { 582 int retval = 0; 583 584 switch (io->scsiio.cdb[0]) { 585 case SERVICE_ACTION_IN: 586 if (io->scsiio.cdb[1] == SGLS_SERVICE_ACTION) { 587 retval = ctl_backend_ramdisk_gls(io); 588 break; 589 } 590 ctl_set_invalid_field(&io->scsiio, 591 /*sks_valid*/ 1, 592 /*command*/ 1, 593 /*field*/ 1, 594 /*bit_valid*/ 1, 595 /*bit*/ 4); 596 ctl_config_read_done(io); 597 retval = CTL_RETVAL_COMPLETE; 598 break; 599 default: 600 ctl_set_invalid_opcode(&io->scsiio); 601 ctl_config_read_done(io); 602 retval = CTL_RETVAL_COMPLETE; 603 break; 604 } 605 return (retval); 606 } 607 608 static int 609 ramdisk_namespace_data(union ctl_io *io) 610 { 611 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 612 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 613 struct nvme_namespace_data *nsdata; 614 615 if (io->nvmeio.kern_data_len != sizeof(struct nvme_namespace_data) || 616 io->nvmeio.kern_sg_entries != 0) 617 return (CTL_RETVAL_ERROR); 618 619 nsdata = (struct nvme_namespace_data *)io->nvmeio.kern_data_ptr; 620 memset(nsdata, 0, sizeof(*nsdata)); 621 nsdata->nsze = htole64(be_lun->size_blocks); 622 nsdata->ncap = htole64(be_lun->cap_bytes / cbe_lun->blocksize); 623 nsdata->nuse = htole64(be_lun->cap_used / cbe_lun->blocksize); 624 nsdata->nsfeat = NVMEM(NVME_NS_DATA_NSFEAT_THIN_PROV) | 625 NVMEM(NVME_NS_DATA_NSFEAT_DEALLOC); 626 nsdata->nlbaf = 1 - 1; 627 nsdata->dlfeat = NVMEM(NVME_NS_DATA_DLFEAT_DWZ) | 628 NVMEF(NVME_NS_DATA_DLFEAT_READ, NVME_NS_DATA_DLFEAT_READ_00); 629 nsdata->flbas = NVMEF(NVME_NS_DATA_FLBAS_FORMAT, 0); 630 nsdata->lbaf[0] = NVMEF(NVME_NS_DATA_LBAF_LBADS, 631 ffs(cbe_lun->blocksize) - 1); 632 633 ctl_lun_nsdata_ids(cbe_lun, nsdata); 634 ctl_config_read_done(io); 635 return (CTL_RETVAL_COMPLETE); 636 } 637 638 static int 639 ramdisk_nvme_ids(union ctl_io *io) 640 { 641 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 642 643 if (io->nvmeio.kern_data_len != 4096 || io->nvmeio.kern_sg_entries != 0) 644 return (CTL_RETVAL_ERROR); 645 646 ctl_lun_nvme_ids(cbe_lun, io->nvmeio.kern_data_ptr); 647 ctl_config_read_done(io); 648 return (CTL_RETVAL_COMPLETE); 649 } 650 651 static int 652 ctl_backend_ramdisk_nvme_config_read(union ctl_io *io) 653 { 654 switch (io->nvmeio.cmd.opc) { 655 case NVME_OPC_IDENTIFY: 656 { 657 uint8_t cns; 658 659 cns = le32toh(io->nvmeio.cmd.cdw10) & 0xff; 660 switch (cns) { 661 case 0: 662 return (ramdisk_namespace_data(io)); 663 case 3: 664 return (ramdisk_nvme_ids(io)); 665 default: 666 ctl_nvme_set_invalid_field(&io->nvmeio); 667 ctl_config_read_done(io); 668 return (CTL_RETVAL_COMPLETE); 669 } 670 } 671 default: 672 ctl_nvme_set_invalid_opcode(&io->nvmeio); 673 ctl_config_read_done(io); 674 return (CTL_RETVAL_COMPLETE); 675 } 676 } 677 678 static int 679 ctl_backend_ramdisk_config_read(union ctl_io *io) 680 { 681 switch (io->io_hdr.io_type) { 682 case CTL_IO_SCSI: 683 return (ctl_backend_ramdisk_scsi_config_read(io)); 684 case CTL_IO_NVME_ADMIN: 685 return (ctl_backend_ramdisk_nvme_config_read(io)); 686 default: 687 __assert_unreachable(); 688 } 689 } 690 691 static void 692 ctl_backend_ramdisk_delete(struct ctl_be_lun *cbe_lun, off_t lba, off_t len, 693 int anchor) 694 { 695 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 696 uint8_t *page; 697 uint64_t p, lp; 698 u_int lbaoff; 699 getpage_op_t op = anchor ? GP_ANCHOR : GP_OTHER; 700 701 /* Partially zero first partial page. */ 702 p = lba >> cbe_lun->pblockexp; 703 lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 704 if (lbaoff != 0) { 705 page = ctl_backend_ramdisk_getpage(be_lun, p, op); 706 if (page != P_UNMAPPED && page != P_ANCHORED) { 707 memset(page + lbaoff * cbe_lun->blocksize, 0, 708 min(len, be_lun->pblockmul - lbaoff) * 709 cbe_lun->blocksize); 710 } 711 p++; 712 } 713 714 /* Partially zero last partial page. */ 715 lp = (lba + len) >> cbe_lun->pblockexp; 716 lbaoff = (lba + len) & ~(UINT_MAX << cbe_lun->pblockexp); 717 if (p <= lp && lbaoff != 0) { 718 page = ctl_backend_ramdisk_getpage(be_lun, lp, op); 719 if (page != P_UNMAPPED && page != P_ANCHORED) 720 memset(page, 0, lbaoff * cbe_lun->blocksize); 721 } 722 723 /* Delete remaining full pages. */ 724 if (anchor) { 725 for (; p < lp; p++) 726 ctl_backend_ramdisk_anchorpage(be_lun, p); 727 } else { 728 for (; p < lp; p++) 729 ctl_backend_ramdisk_unmappage(be_lun, p); 730 } 731 } 732 733 static void 734 ctl_backend_ramdisk_ws(union ctl_io *io) 735 { 736 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 737 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 738 struct ctl_lba_len_flags *lbalen = ARGS(io); 739 uint8_t *page; 740 uint64_t lba; 741 u_int lbaoff, lbas; 742 743 CTL_IO_ASSERT(io, SCSI); 744 745 if (lbalen->flags & ~(SWS_LBDATA | SWS_UNMAP | SWS_ANCHOR | SWS_NDOB)) { 746 ctl_set_invalid_field(&io->scsiio, 747 /*sks_valid*/ 1, 748 /*command*/ 1, 749 /*field*/ 1, 750 /*bit_valid*/ 0, 751 /*bit*/ 0); 752 ctl_config_write_done(io); 753 return; 754 } 755 if (lbalen->flags & SWS_UNMAP) { 756 ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 757 (lbalen->flags & SWS_ANCHOR) != 0); 758 ctl_set_success(&io->scsiio); 759 ctl_config_write_done(io); 760 return; 761 } 762 763 for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) { 764 page = ctl_backend_ramdisk_getpage(be_lun, 765 lba >> cbe_lun->pblockexp, GP_WRITE); 766 if (page == P_UNMAPPED || page == P_ANCHORED) { 767 ctl_set_space_alloc_fail(&io->scsiio); 768 ctl_data_submit_done(io); 769 return; 770 } 771 lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 772 page += lbaoff * cbe_lun->blocksize; 773 if (lbalen->flags & SWS_NDOB) { 774 memset(page, 0, cbe_lun->blocksize); 775 } else { 776 memcpy(page, io->scsiio.kern_data_ptr, 777 cbe_lun->blocksize); 778 } 779 if (lbalen->flags & SWS_LBDATA) 780 scsi_ulto4b(lba, page); 781 } 782 ctl_set_success(&io->scsiio); 783 ctl_config_write_done(io); 784 } 785 786 static void 787 ctl_backend_ramdisk_unmap(union ctl_io *io) 788 { 789 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 790 struct ctl_ptr_len_flags *ptrlen = (struct ctl_ptr_len_flags *)ARGS(io); 791 struct scsi_unmap_desc *buf, *end; 792 793 CTL_IO_ASSERT(io, SCSI); 794 795 if ((ptrlen->flags & ~SU_ANCHOR) != 0) { 796 ctl_set_invalid_field(&io->scsiio, 797 /*sks_valid*/ 0, 798 /*command*/ 0, 799 /*field*/ 0, 800 /*bit_valid*/ 0, 801 /*bit*/ 0); 802 ctl_config_write_done(io); 803 return; 804 } 805 806 buf = (struct scsi_unmap_desc *)ptrlen->ptr; 807 end = buf + ptrlen->len / sizeof(*buf); 808 for (; buf < end; buf++) { 809 ctl_backend_ramdisk_delete(cbe_lun, 810 scsi_8btou64(buf->lba), scsi_4btoul(buf->length), 811 (ptrlen->flags & SU_ANCHOR) != 0); 812 } 813 814 ctl_set_success(&io->scsiio); 815 ctl_config_write_done(io); 816 } 817 818 static int 819 ctl_backend_ramdisk_scsi_config_write(union ctl_io *io) 820 { 821 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 822 int retval = 0; 823 824 switch (io->scsiio.cdb[0]) { 825 case SYNCHRONIZE_CACHE: 826 case SYNCHRONIZE_CACHE_16: 827 /* We have no cache to flush. */ 828 ctl_set_success(&io->scsiio); 829 ctl_config_write_done(io); 830 break; 831 case START_STOP_UNIT: { 832 struct scsi_start_stop_unit *cdb; 833 834 cdb = (struct scsi_start_stop_unit *)io->scsiio.cdb; 835 if ((cdb->how & SSS_PC_MASK) != 0) { 836 ctl_set_success(&io->scsiio); 837 ctl_config_write_done(io); 838 break; 839 } 840 if (cdb->how & SSS_START) { 841 if (cdb->how & SSS_LOEJ) 842 ctl_lun_has_media(cbe_lun); 843 ctl_start_lun(cbe_lun); 844 } else { 845 ctl_stop_lun(cbe_lun); 846 if (cdb->how & SSS_LOEJ) 847 ctl_lun_ejected(cbe_lun); 848 } 849 ctl_set_success(&io->scsiio); 850 ctl_config_write_done(io); 851 break; 852 } 853 case PREVENT_ALLOW: 854 ctl_set_success(&io->scsiio); 855 ctl_config_write_done(io); 856 break; 857 case WRITE_SAME_10: 858 case WRITE_SAME_16: 859 ctl_backend_ramdisk_ws(io); 860 break; 861 case UNMAP: 862 ctl_backend_ramdisk_unmap(io); 863 break; 864 default: 865 ctl_set_invalid_opcode(&io->scsiio); 866 ctl_config_write_done(io); 867 retval = CTL_RETVAL_COMPLETE; 868 break; 869 } 870 871 return (retval); 872 } 873 874 static void 875 ctl_backend_ramdisk_wu(union ctl_io *io) 876 { 877 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 878 struct ctl_lba_len_flags *lbalen = ARGS(io); 879 880 CTL_IO_ASSERT(io, NVME); 881 882 /* 883 * XXX: Not quite right as reads will return zeroes rather 884 * than failing. 885 */ 886 ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 1); 887 ctl_nvme_set_success(&io->nvmeio); 888 ctl_config_write_done(io); 889 } 890 891 static void 892 ctl_backend_ramdisk_wz(union ctl_io *io) 893 { 894 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 895 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 896 struct ctl_lba_len_flags *lbalen = ARGS(io); 897 uint8_t *page; 898 uint64_t lba; 899 u_int lbaoff, lbas; 900 901 CTL_IO_ASSERT(io, NVME); 902 903 if ((le32toh(io->nvmeio.cmd.cdw12) & (1U << 25)) != 0) { 904 ctl_backend_ramdisk_delete(cbe_lun, lbalen->lba, lbalen->len, 905 0); 906 ctl_nvme_set_success(&io->nvmeio); 907 ctl_config_write_done(io); 908 return; 909 } 910 911 for (lba = lbalen->lba, lbas = lbalen->len; lbas > 0; lba++, lbas--) { 912 page = ctl_backend_ramdisk_getpage(be_lun, 913 lba >> cbe_lun->pblockexp, GP_WRITE); 914 if (page == P_UNMAPPED || page == P_ANCHORED) { 915 ctl_nvme_set_space_alloc_fail(&io->nvmeio); 916 ctl_data_submit_done(io); 917 return; 918 } 919 lbaoff = lba & ~(UINT_MAX << cbe_lun->pblockexp); 920 page += lbaoff * cbe_lun->blocksize; 921 memset(page, 0, cbe_lun->blocksize); 922 } 923 ctl_nvme_set_success(&io->nvmeio); 924 ctl_config_write_done(io); 925 } 926 927 static void 928 ctl_backend_ramdisk_dsm(union ctl_io *io) 929 { 930 struct ctl_be_lun *cbe_lun = CTL_BACKEND_LUN(io); 931 struct nvme_dsm_range *r; 932 uint64_t lba; 933 uint32_t num_blocks; 934 u_int i, ranges; 935 936 CTL_IO_ASSERT(io, NVME); 937 938 ranges = le32toh(io->nvmeio.cmd.cdw10) & 0xff; 939 r = (struct nvme_dsm_range *)io->nvmeio.kern_data_ptr; 940 for (i = 0; i < ranges; i++) { 941 lba = le64toh(r[i].starting_lba); 942 num_blocks = le32toh(r[i].length); 943 if ((le32toh(r[i].attributes) & (1U << 2)) != 0) 944 ctl_backend_ramdisk_delete(cbe_lun, lba, num_blocks, 0); 945 } 946 947 ctl_nvme_set_success(&io->nvmeio); 948 ctl_config_write_done(io); 949 } 950 951 static int 952 ctl_backend_ramdisk_nvme_config_write(union ctl_io *io) 953 { 954 switch (io->nvmeio.cmd.opc) { 955 case NVME_OPC_FLUSH: 956 /* We have no cache to flush. */ 957 ctl_nvme_set_success(&io->nvmeio); 958 ctl_config_write_done(io); 959 break; 960 case NVME_OPC_WRITE_UNCORRECTABLE: 961 ctl_backend_ramdisk_wu(io); 962 break; 963 case NVME_OPC_WRITE_ZEROES: 964 ctl_backend_ramdisk_wz(io); 965 break; 966 case NVME_OPC_DATASET_MANAGEMENT: 967 ctl_backend_ramdisk_dsm(io); 968 break; 969 default: 970 ctl_nvme_set_invalid_opcode(&io->nvmeio); 971 ctl_config_write_done(io); 972 break; 973 } 974 return (CTL_RETVAL_COMPLETE); 975 } 976 977 static int 978 ctl_backend_ramdisk_config_write(union ctl_io *io) 979 { 980 switch (io->io_hdr.io_type) { 981 case CTL_IO_SCSI: 982 return (ctl_backend_ramdisk_scsi_config_write(io)); 983 case CTL_IO_NVME: 984 return (ctl_backend_ramdisk_nvme_config_write(io)); 985 default: 986 __assert_unreachable(); 987 } 988 } 989 990 static uint64_t 991 ctl_backend_ramdisk_lun_attr(struct ctl_be_lun *cbe_lun, const char *attrname) 992 { 993 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 994 uint64_t val; 995 996 val = UINT64_MAX; 997 if (be_lun->cap_bytes == 0) 998 return (val); 999 sx_slock(&be_lun->page_lock); 1000 if (strcmp(attrname, "blocksused") == 0) { 1001 val = be_lun->cap_used / be_lun->cbe_lun.blocksize; 1002 } else if (strcmp(attrname, "blocksavail") == 0) { 1003 val = (be_lun->cap_bytes - be_lun->cap_used) / 1004 be_lun->cbe_lun.blocksize; 1005 } 1006 sx_sunlock(&be_lun->page_lock); 1007 return (val); 1008 } 1009 1010 static int 1011 ctl_backend_ramdisk_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 1012 int flag, struct thread *td) 1013 { 1014 struct ctl_be_ramdisk_softc *softc = &rd_softc; 1015 struct ctl_lun_req *lun_req; 1016 int retval; 1017 1018 retval = 0; 1019 switch (cmd) { 1020 case CTL_LUN_REQ: 1021 lun_req = (struct ctl_lun_req *)addr; 1022 switch (lun_req->reqtype) { 1023 case CTL_LUNREQ_CREATE: 1024 retval = ctl_backend_ramdisk_create(softc, lun_req); 1025 break; 1026 case CTL_LUNREQ_RM: 1027 retval = ctl_backend_ramdisk_rm(softc, lun_req); 1028 break; 1029 case CTL_LUNREQ_MODIFY: 1030 retval = ctl_backend_ramdisk_modify(softc, lun_req); 1031 break; 1032 default: 1033 lun_req->status = CTL_LUN_ERROR; 1034 snprintf(lun_req->error_str, sizeof(lun_req->error_str), 1035 "%s: invalid LUN request type %d", __func__, 1036 lun_req->reqtype); 1037 break; 1038 } 1039 break; 1040 default: 1041 retval = ENOTTY; 1042 break; 1043 } 1044 1045 return (retval); 1046 } 1047 1048 static int 1049 ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc *softc, 1050 struct ctl_lun_req *req) 1051 { 1052 struct ctl_be_ramdisk_lun *be_lun; 1053 struct ctl_lun_rm_params *params; 1054 int retval; 1055 1056 params = &req->reqdata.rm; 1057 sx_xlock(&softc->modify_lock); 1058 mtx_lock(&softc->lock); 1059 SLIST_FOREACH(be_lun, &softc->lun_list, links) { 1060 if (be_lun->cbe_lun.lun_id == params->lun_id) { 1061 SLIST_REMOVE(&softc->lun_list, be_lun, 1062 ctl_be_ramdisk_lun, links); 1063 softc->num_luns--; 1064 break; 1065 } 1066 } 1067 mtx_unlock(&softc->lock); 1068 sx_xunlock(&softc->modify_lock); 1069 if (be_lun == NULL) { 1070 snprintf(req->error_str, sizeof(req->error_str), 1071 "%s: LUN %u is not managed by the ramdisk backend", 1072 __func__, params->lun_id); 1073 goto bailout_error; 1074 } 1075 1076 /* 1077 * Set the waiting flag before we invalidate the LUN. Our shutdown 1078 * routine can be called any time after we invalidate the LUN, 1079 * and can be called from our context. 1080 * 1081 * This tells the shutdown routine that we're waiting, or we're 1082 * going to wait for the shutdown to happen. 1083 */ 1084 mtx_lock(&softc->lock); 1085 be_lun->flags |= CTL_BE_RAMDISK_LUN_WAITING; 1086 mtx_unlock(&softc->lock); 1087 1088 retval = ctl_remove_lun(&be_lun->cbe_lun); 1089 if (retval != 0) { 1090 snprintf(req->error_str, sizeof(req->error_str), 1091 "%s: error %d returned from ctl_remove_lun() for " 1092 "LUN %d", __func__, retval, params->lun_id); 1093 mtx_lock(&softc->lock); 1094 be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 1095 mtx_unlock(&softc->lock); 1096 goto bailout_error; 1097 } 1098 1099 mtx_lock(&softc->lock); 1100 while ((be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) == 0) { 1101 retval = msleep(be_lun, &softc->lock, PCATCH, "ctlramrm", 0); 1102 if (retval == EINTR) 1103 break; 1104 } 1105 be_lun->flags &= ~CTL_BE_RAMDISK_LUN_WAITING; 1106 if (be_lun->flags & CTL_BE_RAMDISK_LUN_UNCONFIGURED) { 1107 mtx_unlock(&softc->lock); 1108 free(be_lun, M_RAMDISK); 1109 } else { 1110 mtx_unlock(&softc->lock); 1111 return (EINTR); 1112 } 1113 1114 req->status = CTL_LUN_OK; 1115 return (retval); 1116 1117 bailout_error: 1118 req->status = CTL_LUN_ERROR; 1119 return (0); 1120 } 1121 1122 static int 1123 ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc *softc, 1124 struct ctl_lun_req *req) 1125 { 1126 struct ctl_be_ramdisk_lun *be_lun; 1127 struct ctl_be_lun *cbe_lun; 1128 struct ctl_lun_create_params *params; 1129 const char *value; 1130 char tmpstr[32]; 1131 uint64_t t; 1132 int retval; 1133 1134 retval = 0; 1135 params = &req->reqdata.create; 1136 1137 be_lun = malloc(sizeof(*be_lun), M_RAMDISK, M_ZERO | M_WAITOK); 1138 cbe_lun = &be_lun->cbe_lun; 1139 cbe_lun->options = nvlist_clone(req->args_nvl); 1140 be_lun->params = req->reqdata.create; 1141 be_lun->softc = softc; 1142 1143 if (params->flags & CTL_LUN_FLAG_DEV_TYPE) 1144 cbe_lun->lun_type = params->device_type; 1145 else 1146 cbe_lun->lun_type = T_DIRECT; 1147 be_lun->flags = 0; 1148 cbe_lun->flags = 0; 1149 value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 1150 if (value != NULL) { 1151 if (strcmp(value, "primary") == 0) 1152 cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 1153 } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 1154 cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 1155 1156 be_lun->pblocksize = PAGE_SIZE; 1157 value = dnvlist_get_string(cbe_lun->options, "pblocksize", NULL); 1158 if (value != NULL) { 1159 ctl_expand_number(value, &t); 1160 be_lun->pblocksize = t; 1161 } 1162 if (be_lun->pblocksize < 512 || be_lun->pblocksize > 131072) { 1163 snprintf(req->error_str, sizeof(req->error_str), 1164 "%s: unsupported pblocksize %u", __func__, 1165 be_lun->pblocksize); 1166 goto bailout_error; 1167 } 1168 1169 if (cbe_lun->lun_type == T_DIRECT || 1170 cbe_lun->lun_type == T_CDROM) { 1171 if (params->blocksize_bytes != 0) 1172 cbe_lun->blocksize = params->blocksize_bytes; 1173 else if (cbe_lun->lun_type == T_CDROM) 1174 cbe_lun->blocksize = 2048; 1175 else 1176 cbe_lun->blocksize = 512; 1177 be_lun->pblockmul = be_lun->pblocksize / cbe_lun->blocksize; 1178 if (be_lun->pblockmul < 1 || !powerof2(be_lun->pblockmul)) { 1179 snprintf(req->error_str, sizeof(req->error_str), 1180 "%s: pblocksize %u not exp2 of blocksize %u", 1181 __func__, 1182 be_lun->pblocksize, cbe_lun->blocksize); 1183 goto bailout_error; 1184 } 1185 if (params->lun_size_bytes < cbe_lun->blocksize) { 1186 snprintf(req->error_str, sizeof(req->error_str), 1187 "%s: LUN size %ju < blocksize %u", __func__, 1188 params->lun_size_bytes, cbe_lun->blocksize); 1189 goto bailout_error; 1190 } 1191 be_lun->size_blocks = params->lun_size_bytes / cbe_lun->blocksize; 1192 be_lun->size_bytes = be_lun->size_blocks * cbe_lun->blocksize; 1193 be_lun->indir = 0; 1194 t = be_lun->size_bytes / be_lun->pblocksize; 1195 while (t > 1) { 1196 t /= PPP; 1197 be_lun->indir++; 1198 } 1199 cbe_lun->maxlba = be_lun->size_blocks - 1; 1200 cbe_lun->pblockexp = fls(be_lun->pblockmul) - 1; 1201 cbe_lun->pblockoff = 0; 1202 cbe_lun->ublockexp = cbe_lun->pblockexp; 1203 cbe_lun->ublockoff = 0; 1204 cbe_lun->atomicblock = be_lun->pblocksize; 1205 cbe_lun->opttxferlen = SGPP * be_lun->pblocksize; 1206 value = dnvlist_get_string(cbe_lun->options, "capacity", NULL); 1207 if (value != NULL) 1208 ctl_expand_number(value, &be_lun->cap_bytes); 1209 } else { 1210 be_lun->pblockmul = 1; 1211 cbe_lun->pblockexp = 0; 1212 } 1213 1214 /* Tell the user the blocksize we ended up using */ 1215 params->blocksize_bytes = cbe_lun->blocksize; 1216 params->lun_size_bytes = be_lun->size_bytes; 1217 1218 value = dnvlist_get_string(cbe_lun->options, "unmap", NULL); 1219 if (value == NULL || strcmp(value, "off") != 0) 1220 cbe_lun->flags |= CTL_LUN_FLAG_UNMAP; 1221 value = dnvlist_get_string(cbe_lun->options, "readonly", NULL); 1222 if (value != NULL) { 1223 if (strcmp(value, "on") == 0) 1224 cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 1225 } else if (cbe_lun->lun_type != T_DIRECT) 1226 cbe_lun->flags |= CTL_LUN_FLAG_READONLY; 1227 cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 1228 value = dnvlist_get_string(cbe_lun->options, "serseq", NULL); 1229 if (value != NULL && strcmp(value, "on") == 0) 1230 cbe_lun->serseq = CTL_LUN_SERSEQ_ON; 1231 else if (value != NULL && strcmp(value, "read") == 0) 1232 cbe_lun->serseq = CTL_LUN_SERSEQ_READ; 1233 else if (value != NULL && strcmp(value, "soft") == 0) 1234 cbe_lun->serseq = CTL_LUN_SERSEQ_SOFT; 1235 else if (value != NULL && strcmp(value, "off") == 0) 1236 cbe_lun->serseq = CTL_LUN_SERSEQ_OFF; 1237 1238 if (params->flags & CTL_LUN_FLAG_ID_REQ) { 1239 cbe_lun->req_lun_id = params->req_lun_id; 1240 cbe_lun->flags |= CTL_LUN_FLAG_ID_REQ; 1241 } else 1242 cbe_lun->req_lun_id = 0; 1243 1244 cbe_lun->lun_shutdown = ctl_backend_ramdisk_lun_shutdown; 1245 cbe_lun->be = &ctl_be_ramdisk_driver; 1246 if ((params->flags & CTL_LUN_FLAG_SERIAL_NUM) == 0) { 1247 snprintf(tmpstr, sizeof(tmpstr), "MYSERIAL%04d", 1248 softc->num_luns); 1249 strncpy((char *)cbe_lun->serial_num, tmpstr, 1250 MIN(sizeof(cbe_lun->serial_num), sizeof(tmpstr))); 1251 1252 /* Tell the user what we used for a serial number */ 1253 strncpy((char *)params->serial_num, tmpstr, 1254 MIN(sizeof(params->serial_num), sizeof(tmpstr))); 1255 } else { 1256 strncpy((char *)cbe_lun->serial_num, params->serial_num, 1257 MIN(sizeof(cbe_lun->serial_num), 1258 sizeof(params->serial_num))); 1259 } 1260 if ((params->flags & CTL_LUN_FLAG_DEVID) == 0) { 1261 snprintf(tmpstr, sizeof(tmpstr), "MYDEVID%04d", softc->num_luns); 1262 strncpy((char *)cbe_lun->device_id, tmpstr, 1263 MIN(sizeof(cbe_lun->device_id), sizeof(tmpstr))); 1264 1265 /* Tell the user what we used for a device ID */ 1266 strncpy((char *)params->device_id, tmpstr, 1267 MIN(sizeof(params->device_id), sizeof(tmpstr))); 1268 } else { 1269 strncpy((char *)cbe_lun->device_id, params->device_id, 1270 MIN(sizeof(cbe_lun->device_id), 1271 sizeof(params->device_id))); 1272 } 1273 1274 STAILQ_INIT(&be_lun->cont_queue); 1275 sx_init(&be_lun->page_lock, "ctlram page"); 1276 if (be_lun->cap_bytes == 0) { 1277 be_lun->indir = 0; 1278 be_lun->pages = malloc(be_lun->pblocksize, M_RAMDISK, M_WAITOK); 1279 } 1280 be_lun->zero_page = malloc(be_lun->pblocksize, M_RAMDISK, 1281 M_WAITOK|M_ZERO); 1282 mtx_init(&be_lun->queue_lock, "ctlram queue", NULL, MTX_DEF); 1283 TASK_INIT(&be_lun->io_task, /*priority*/0, ctl_backend_ramdisk_worker, 1284 be_lun); 1285 1286 be_lun->io_taskqueue = taskqueue_create("ctlramtq", M_WAITOK, 1287 taskqueue_thread_enqueue, /*context*/&be_lun->io_taskqueue); 1288 if (be_lun->io_taskqueue == NULL) { 1289 snprintf(req->error_str, sizeof(req->error_str), 1290 "%s: Unable to create taskqueue", __func__); 1291 goto bailout_error; 1292 } 1293 1294 retval = taskqueue_start_threads_in_proc(&be_lun->io_taskqueue, 1295 /*num threads*/1, 1296 /*priority*/PUSER, 1297 /*proc*/control_softc->ctl_proc, 1298 /*thread name*/"ramdisk"); 1299 if (retval != 0) 1300 goto bailout_error; 1301 1302 retval = ctl_add_lun(&be_lun->cbe_lun); 1303 if (retval != 0) { 1304 snprintf(req->error_str, sizeof(req->error_str), 1305 "%s: ctl_add_lun() returned error %d, see dmesg for " 1306 "details", __func__, retval); 1307 retval = 0; 1308 goto bailout_error; 1309 } 1310 1311 mtx_lock(&softc->lock); 1312 softc->num_luns++; 1313 SLIST_INSERT_HEAD(&softc->lun_list, be_lun, links); 1314 mtx_unlock(&softc->lock); 1315 1316 params->req_lun_id = cbe_lun->lun_id; 1317 1318 req->status = CTL_LUN_OK; 1319 return (retval); 1320 1321 bailout_error: 1322 req->status = CTL_LUN_ERROR; 1323 if (be_lun != NULL) { 1324 if (be_lun->io_taskqueue != NULL) 1325 taskqueue_free(be_lun->io_taskqueue); 1326 nvlist_destroy(cbe_lun->options); 1327 free(be_lun->zero_page, M_RAMDISK); 1328 ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 1329 sx_destroy(&be_lun->page_lock); 1330 mtx_destroy(&be_lun->queue_lock); 1331 free(be_lun, M_RAMDISK); 1332 } 1333 return (retval); 1334 } 1335 1336 static int 1337 ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc *softc, 1338 struct ctl_lun_req *req) 1339 { 1340 struct ctl_be_ramdisk_lun *be_lun; 1341 struct ctl_be_lun *cbe_lun; 1342 struct ctl_lun_modify_params *params; 1343 const char *value; 1344 uint32_t blocksize; 1345 int wasprim; 1346 1347 params = &req->reqdata.modify; 1348 sx_xlock(&softc->modify_lock); 1349 mtx_lock(&softc->lock); 1350 SLIST_FOREACH(be_lun, &softc->lun_list, links) { 1351 if (be_lun->cbe_lun.lun_id == params->lun_id) 1352 break; 1353 } 1354 mtx_unlock(&softc->lock); 1355 if (be_lun == NULL) { 1356 snprintf(req->error_str, sizeof(req->error_str), 1357 "%s: LUN %u is not managed by the ramdisk backend", 1358 __func__, params->lun_id); 1359 goto bailout_error; 1360 } 1361 cbe_lun = &be_lun->cbe_lun; 1362 1363 if (params->lun_size_bytes != 0) 1364 be_lun->params.lun_size_bytes = params->lun_size_bytes; 1365 1366 if (req->args_nvl != NULL) { 1367 nvlist_destroy(cbe_lun->options); 1368 cbe_lun->options = nvlist_clone(req->args_nvl); 1369 } 1370 1371 wasprim = (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY); 1372 value = dnvlist_get_string(cbe_lun->options, "ha_role", NULL); 1373 if (value != NULL) { 1374 if (strcmp(value, "primary") == 0) 1375 cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 1376 else 1377 cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 1378 } else if (control_softc->flags & CTL_FLAG_ACTIVE_SHELF) 1379 cbe_lun->flags |= CTL_LUN_FLAG_PRIMARY; 1380 else 1381 cbe_lun->flags &= ~CTL_LUN_FLAG_PRIMARY; 1382 if (wasprim != (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY)) { 1383 if (cbe_lun->flags & CTL_LUN_FLAG_PRIMARY) 1384 ctl_lun_primary(cbe_lun); 1385 else 1386 ctl_lun_secondary(cbe_lun); 1387 } 1388 1389 blocksize = be_lun->cbe_lun.blocksize; 1390 if (be_lun->params.lun_size_bytes < blocksize) { 1391 snprintf(req->error_str, sizeof(req->error_str), 1392 "%s: LUN size %ju < blocksize %u", __func__, 1393 be_lun->params.lun_size_bytes, blocksize); 1394 goto bailout_error; 1395 } 1396 be_lun->size_blocks = be_lun->params.lun_size_bytes / blocksize; 1397 be_lun->size_bytes = be_lun->size_blocks * blocksize; 1398 be_lun->cbe_lun.maxlba = be_lun->size_blocks - 1; 1399 ctl_lun_capacity_changed(&be_lun->cbe_lun); 1400 1401 /* Tell the user the exact size we ended up using */ 1402 params->lun_size_bytes = be_lun->size_bytes; 1403 1404 sx_xunlock(&softc->modify_lock); 1405 req->status = CTL_LUN_OK; 1406 return (0); 1407 1408 bailout_error: 1409 sx_xunlock(&softc->modify_lock); 1410 req->status = CTL_LUN_ERROR; 1411 return (0); 1412 } 1413 1414 static void 1415 ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun *cbe_lun) 1416 { 1417 struct ctl_be_ramdisk_lun *be_lun = (struct ctl_be_ramdisk_lun *)cbe_lun; 1418 struct ctl_be_ramdisk_softc *softc = be_lun->softc; 1419 1420 taskqueue_drain_all(be_lun->io_taskqueue); 1421 taskqueue_free(be_lun->io_taskqueue); 1422 nvlist_destroy(be_lun->cbe_lun.options); 1423 free(be_lun->zero_page, M_RAMDISK); 1424 ctl_backend_ramdisk_freeallpages(be_lun->pages, be_lun->indir); 1425 sx_destroy(&be_lun->page_lock); 1426 mtx_destroy(&be_lun->queue_lock); 1427 1428 mtx_lock(&softc->lock); 1429 be_lun->flags |= CTL_BE_RAMDISK_LUN_UNCONFIGURED; 1430 if (be_lun->flags & CTL_BE_RAMDISK_LUN_WAITING) 1431 wakeup(be_lun); 1432 else 1433 free(be_lun, M_RAMDISK); 1434 mtx_unlock(&softc->lock); 1435 } 1436