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
ctl_backend_ramdisk_init(void)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
ctl_backend_ramdisk_shutdown(void)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 *
ctl_backend_ramdisk_getpage(struct ctl_be_ramdisk_lun * be_lun,off_t pn,getpage_op_t op)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
ctl_backend_ramdisk_unmappage(struct ctl_be_ramdisk_lun * be_lun,off_t pn)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
ctl_backend_ramdisk_anchorpage(struct ctl_be_ramdisk_lun * be_lun,off_t pn)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
ctl_backend_ramdisk_freeallpages(uint8_t ** p,int indir)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
cmp(uint8_t * a,uint8_t * b,size_t size)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
ctl_backend_ramdisk_cmp(union ctl_io * io)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
ctl_backend_ramdisk_move_done(union ctl_io * io,bool samethr)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
ctl_backend_ramdisk_compare(union ctl_io * io)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
ctl_backend_ramdisk_rw(union ctl_io * io)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
ctl_backend_ramdisk_submit(union ctl_io * io)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
ctl_backend_ramdisk_worker(void * context,int pending)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
ctl_backend_ramdisk_gls(union ctl_io * io)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
ctl_backend_ramdisk_scsi_config_read(union ctl_io * io)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
ramdisk_namespace_data(union ctl_io * io)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
ramdisk_nvme_ids(union ctl_io * io)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
ctl_backend_ramdisk_nvme_config_read(union ctl_io * io)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
ctl_backend_ramdisk_config_read(union ctl_io * io)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
ctl_backend_ramdisk_delete(struct ctl_be_lun * cbe_lun,off_t lba,off_t len,int anchor)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
ctl_backend_ramdisk_ws(union ctl_io * io)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
ctl_backend_ramdisk_unmap(union ctl_io * io)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
ctl_backend_ramdisk_scsi_config_write(union ctl_io * io)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
ctl_backend_ramdisk_wu(union ctl_io * io)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
ctl_backend_ramdisk_wz(union ctl_io * io)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
ctl_backend_ramdisk_dsm(union ctl_io * io)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
ctl_backend_ramdisk_nvme_config_write(union ctl_io * io)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
ctl_backend_ramdisk_config_write(union ctl_io * io)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
ctl_backend_ramdisk_lun_attr(struct ctl_be_lun * cbe_lun,const char * attrname)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
ctl_backend_ramdisk_ioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flag,struct thread * td)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
ctl_backend_ramdisk_rm(struct ctl_be_ramdisk_softc * softc,struct ctl_lun_req * req)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
ctl_backend_ramdisk_create(struct ctl_be_ramdisk_softc * softc,struct ctl_lun_req * req)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
ctl_backend_ramdisk_modify(struct ctl_be_ramdisk_softc * softc,struct ctl_lun_req * req)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
ctl_backend_ramdisk_lun_shutdown(struct ctl_be_lun * cbe_lun)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