Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cam/ctl/ctl_backend_ramdisk.c
39483 views
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 <[email protected]>
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 <[email protected]>
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
1437