1 /* $NetBSD: disk.c,v 1.9 2014/09/30 15:25:18 mlelstv Exp $ */
2
3 /*-
4 * Copyright (c) 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Alistair Crooks (agc@netbsd.org)
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 /*
32 * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
33 * By downloading, copying, installing or using the software you agree
34 * to this license. If you do not agree to this license, do not
35 * download, install, copy or use the software.
36 *
37 * Intel License Agreement
38 *
39 * Copyright (c) 2000, Intel Corporation
40 * All rights reserved.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 *
46 * -Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 *
49 * -Redistributions in binary form must reproduce the above copyright
50 * notice, this list of conditions and the following disclaimer in the
51 * documentation and/or other materials provided with the
52 * distribution.
53 *
54 * -The name of Intel Corporation may not be used to endorse or
55 * promote products derived from this software without specific prior
56 * written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
59 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
60 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
61 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL
62 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
63 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
64 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
65 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
66 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
67 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
68 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 */
71 #include "config.h"
72
73 #ifdef HAVE_INTTYPES_H
74 #include <inttypes.h>
75 #endif
76
77 #include <sys/types.h>
78
79 #ifdef HAVE_SYS_PARAM_H
80 #include <sys/param.h>
81 #endif
82
83 #ifdef HAVE_SYS_STAT_H
84 #include <sys/stat.h>
85 #endif
86
87 #ifdef HAVE_SYS_UIO_H
88 #include <sys/uio.h>
89 #endif
90
91 #ifdef HAVE_SYS_TIME_H
92 #include <sys/time.h>
93 #endif
94
95 #ifdef HAVE_SYS_MMAN_H
96 #include <sys/mman.h>
97 #endif
98
99 #ifdef HAVE_NETINET_IN_H
100 #include <netinet/in.h>
101 #endif
102
103 #include <assert.h>
104
105 #ifdef HAVE_ERRNO_H
106 #include <errno.h>
107 #endif
108
109 #ifdef HAVE_FCNTL_H
110 #include <fcntl.h>
111 #endif
112
113 #include <ctype.h>
114 #include <stdio.h>
115 #include <stdlib.h>
116
117 #ifdef HAVE_STRING_H
118 #include <string.h>
119 #endif
120
121 #include <unistd.h>
122
123 #include "scsi_cmd_codes.h"
124
125 #include "iscsiprotocol.h"
126 #include "compat.h"
127 #include "iscsiutil.h"
128 #include "device.h"
129 #include "target.h"
130 #include "defs.h"
131 #include "storage.h"
132
133 #define iSCSI_DEFAULT_LUNS 1
134 #define iSCSI_DEFAULT_BLOCKLEN 512
135
136 /* End disk configuration */
137
138 /*
139 * Globals
140 */
141 enum {
142 MAX_RESERVATIONS = 32,
143
144 ISCSI_FS = 0x03,
145 ISCSI_CONTROL = 0x04
146 };
147
148 #define MB(x) ((x) * 1024 * 1024)
149
150 /* this struct describes an iscsi LUN */
151 typedef struct iscsi_disk_t {
152 int type; /* type of disk - fs/mmap and fs */
153 char filename[MAXPATHLEN]; /* filename for the disk */
154 uint64_t blockc; /* # of blocks */
155 uint64_t blocklen; /* block size */
156 uint64_t luns; /* # of luns */
157 uint64_t size; /* size of complete disk */
158 nbuuid_t uuid; /* disk's uuid */
159 char *uuid_string; /* uuid string */
160 targv_t *lunv; /* the component devices and extents */
161 uint32_t resc; /* # of reservation keys */
162 uint64_t reskeys[MAX_RESERVATIONS]; /* reservation keys */
163 } iscsi_disk_t;
164
165 DEFINE_ARRAY(disks_t, iscsi_disk_t);
166
167 static disks_t disks;
168 static iscsi_disk_t defaults;
169
170 #ifndef FDATASYNC
171 /*
172 this means that we probably don't have the fsync_range(2) system call,
173 but no matter - define this here to preserve the abstraction for the
174 disk/extent code
175 */
176 #define FDATASYNC 0x0010
177 #endif
178
179 /*
180 * Private Interface
181 */
182 static int disk_read(target_session_t *, iscsi_scsi_cmd_args_t *,
183 uint32_t, uint16_t, uint8_t);
184 static int disk_write(target_session_t *, iscsi_scsi_cmd_args_t *,
185 uint8_t, uint32_t, uint32_t);
186
187 /* return the de index and offset within the device for RAID0 */
188 static int
raid0_getoff(disc_device_t * dp,uint64_t off,uint32_t * d,uint64_t * de_off)189 raid0_getoff(disc_device_t *dp, uint64_t off, uint32_t *d, uint64_t *de_off)
190 {
191 uint64_t o;
192
193 for (o = 0, *d = 0 ; *d < dp->c ; o += dp->xv[*d].size, (*d)++) {
194 if (off >= o && off < o + dp->xv[*d].size) {
195 break;
196 }
197 }
198 *de_off = off - o;
199 return (*d < dp->c);
200 }
201
202 /* open the extent's device */
203 static int
extent_open(disc_extent_t * xp,int mode,int flags)204 extent_open(disc_extent_t *xp, int mode, int flags)
205 {
206 return xp->fd = open(xp->dev, mode, flags);
207 }
208
209 /* (recursively) open the device's devices */
210 static int
device_open(disc_device_t * dp,int flags,int mode)211 device_open(disc_device_t *dp, int flags, int mode)
212 {
213 int fd;
214 uint32_t i;
215
216 for (fd = -1, i = 0 ; i < dp->c ; i++) {
217 switch (dp->xv[i].type) {
218 case DE_DEVICE:
219 fd = device_open(dp->xv[i].u.dp, flags, mode);
220 if (fd < 0) {
221 return -1;
222 }
223 break;
224 case DE_EXTENT:
225 fd = extent_open(dp->xv[i].u.xp, flags, mode);
226 if (fd < 0) {
227 return -1;
228 }
229 break;
230 default:
231 break;
232 }
233 }
234 return fd;
235 }
236
237 /* and for the undecided... */
238 static int
de_open(disc_de_t * dp,int flags,int mode)239 de_open(disc_de_t *dp, int flags, int mode)
240 {
241 switch(dp->type) {
242 case DE_DEVICE:
243 return device_open(dp->u.dp, flags, mode);
244 case DE_EXTENT:
245 return extent_open(dp->u.xp, flags, mode);
246 default:
247 return -1;
248 }
249 }
250
251 /* lseek on the extent */
252 static off_t
extent_lseek(disc_extent_t * xp,off_t off,int whence)253 extent_lseek(disc_extent_t *xp, off_t off, int whence)
254 {
255 return lseek(xp->fd, (long long)(xp->sacred + off), whence);
256 }
257
258 /* (recursively) lseek on the device's devices */
259 static off_t
device_lseek(disc_device_t * dp,off_t off,int whence)260 device_lseek(disc_device_t *dp, off_t off, int whence)
261 {
262 uint64_t suboff;
263 off_t ret;
264 uint32_t d;
265
266 ret = -1;
267 switch(dp->raid) {
268 case 0:
269 if (raid0_getoff(dp, (uint64_t) off, &d, &suboff)) {
270 switch (dp->xv[d].type) {
271 case DE_DEVICE:
272 ret = device_lseek(dp->xv[d].u.dp,
273 (off_t) suboff, whence);
274 if (ret < 0) {
275 return -1;
276 }
277 break;
278 case DE_EXTENT:
279 ret = extent_lseek(dp->xv[d].u.xp,
280 (off_t) suboff, whence);
281 if (ret < 0) {
282 return -1;
283 }
284 break;
285 default:
286 break;
287 }
288 }
289 break;
290 case 1:
291 for (d = 0 ; d < dp->c ; d++) {
292 switch (dp->xv[d].type) {
293 case DE_DEVICE:
294 ret = device_lseek(dp->xv[d].u.dp, (off_t)off,
295 whence);
296 if (ret < 0) {
297 return -1;
298 }
299 break;
300 case DE_EXTENT:
301 ret = extent_lseek(dp->xv[d].u.xp, (off_t)off,
302 whence);
303 if (ret < 0) {
304 return -1;
305 }
306 break;
307 default:
308 break;
309 }
310 }
311 break;
312 default:
313 break;
314 }
315 return dp->off = ret;
316 }
317
318 /* and for the undecided... */
319 static off_t
de_lseek(disc_de_t * dp,off_t off,int whence)320 de_lseek(disc_de_t *dp, off_t off, int whence)
321 {
322 switch(dp->type) {
323 case DE_DEVICE:
324 return device_lseek(dp->u.dp, off, whence);
325 case DE_EXTENT:
326 return extent_lseek(dp->u.xp, off, whence);
327 default:
328 return -1;
329 }
330 }
331
332 /* fsync_range on the extent */
333 static int
extent_fsync_range(disc_extent_t * xp,int how,off_t from,off_t len)334 extent_fsync_range(disc_extent_t *xp, int how, off_t from, off_t len)
335 {
336 #ifdef HAVE_FSYNC_RANGE
337 return fsync_range(xp->fd, how, (off_t)(xp->sacred + from), len);
338 #else
339 return fsync(xp->fd);
340 #endif
341 }
342
343 /* (recursively) fsync_range on the device's devices */
344 static int
device_fsync_range(disc_device_t * dp,int how,off_t from,off_t len)345 device_fsync_range(disc_device_t *dp, int how, off_t from, off_t len)
346 {
347 uint64_t suboff;
348 int ret;
349 uint32_t d;
350
351 ret = -1;
352 switch(dp->raid) {
353 case 0:
354 if (raid0_getoff(dp, (uint64_t) from, &d, &suboff)) {
355 switch (dp->xv[d].type) {
356 case DE_DEVICE:
357 ret = device_fsync_range(dp->xv[d].u.dp, how,
358 (off_t)suboff, len);
359 if (ret < 0) {
360 return -1;
361 }
362 break;
363 case DE_EXTENT:
364 ret = extent_fsync_range(dp->xv[d].u.xp, how,
365 (off_t)suboff, len);
366 if (ret < 0) {
367 return -1;
368 }
369 break;
370 default:
371 break;
372 }
373 }
374 break;
375 case 1:
376 for (d = 0 ; d < dp->c ; d++) {
377 switch (dp->xv[d].type) {
378 case DE_DEVICE:
379 ret = device_fsync_range(dp->xv[d].u.dp, how,
380 from, len);
381 if (ret < 0) {
382 return -1;
383 }
384 break;
385 case DE_EXTENT:
386 ret = extent_fsync_range(dp->xv[d].u.xp, how,
387 from, len);
388 if (ret < 0) {
389 return -1;
390 }
391 break;
392 default:
393 break;
394 }
395 }
396 break;
397 default:
398 break;
399 }
400 dp->off = (uint64_t) ret;
401 return ret;
402 }
403
404 /* and for the undecided... */
405 static int
de_fsync_range(disc_de_t * dp,int how,off_t from,off_t len)406 de_fsync_range(disc_de_t *dp, int how, off_t from, off_t len)
407 {
408 switch(dp->type) {
409 case DE_DEVICE:
410 return device_fsync_range(dp->u.dp, how, from, len);
411 case DE_EXTENT:
412 return extent_fsync_range(dp->u.xp, how, from, len);
413 default:
414 return -1;
415 }
416 }
417
418 /* read from the extent */
419 static ssize_t
extent_read(disc_extent_t * xp,void * buf,size_t cc)420 extent_read(disc_extent_t *xp, void *buf, size_t cc)
421 {
422 return read(xp->fd, buf, cc);
423 }
424
425 /* (recursively) read from the device's devices */
426 static ssize_t
device_read(disc_device_t * dp,void * buf,size_t cc)427 device_read(disc_device_t *dp, void *buf, size_t cc)
428 {
429 uint64_t suboff;
430 uint64_t got;
431 uint32_t d;
432 ssize_t ret;
433 size_t subcc;
434 char *cbuf;
435
436 ret = -1;
437 switch(dp->raid) {
438 case 0:
439 for (cbuf = (char *) buf, got = 0 ; got < cc ; got += ret) {
440 if (!raid0_getoff(dp, dp->off, &d, &suboff)) {
441 return -1;
442 }
443 if (device_lseek(dp, (off_t)dp->off, SEEK_SET) < 0) {
444 return -1;
445 }
446 subcc = MIN(cc - (size_t)got,
447 (size_t)(dp->len - (size_t)dp->off));
448 switch (dp->xv[d].type) {
449 case DE_DEVICE:
450 ret = device_read(dp->xv[d].u.dp,
451 &cbuf[(int)got], subcc);
452 if (ret < 0) {
453 return -1;
454 }
455 break;
456 case DE_EXTENT:
457 ret = extent_read(dp->xv[d].u.xp,
458 &cbuf[(int)got], subcc);
459 if (ret < 0) {
460 return -1;
461 }
462 break;
463 default:
464 break;
465 }
466 dp->off += ret;
467 }
468 ret = (ssize_t)got;
469 break;
470 case 1:
471 for (d = 0 ; d < dp->c ; d++) {
472 switch (dp->xv[d].type) {
473 case DE_DEVICE:
474 ret = device_read(dp->xv[d].u.dp, buf, cc);
475 if (ret < 0) {
476 return -1;
477 }
478 break;
479 case DE_EXTENT:
480 ret = extent_read(dp->xv[d].u.xp, buf, cc);
481 if (ret < 0) {
482 return -1;
483 }
484 break;
485 default:
486 break;
487 }
488 }
489 dp->off += ret;
490 break;
491 default:
492 break;
493 }
494 return ret;
495 }
496
497 /* and for the undecided... */
498 static ssize_t
de_read(disc_de_t * dp,void * buf,size_t cc)499 de_read(disc_de_t *dp, void *buf, size_t cc)
500 {
501 switch(dp->type) {
502 case DE_DEVICE:
503 return device_read(dp->u.dp, buf, cc);
504 case DE_EXTENT:
505 return extent_read(dp->u.xp, buf, cc);
506 default:
507 return -1;
508 }
509 }
510
511 /* write to the extent */
512 static ssize_t
extent_write(disc_extent_t * xp,void * buf,size_t cc)513 extent_write(disc_extent_t *xp, void *buf, size_t cc)
514 {
515 return write(xp->fd, buf, cc);
516 }
517
518 /* (recursively) write to the device's devices */
519 static ssize_t
device_write(disc_device_t * dp,void * buf,size_t cc)520 device_write(disc_device_t *dp, void *buf, size_t cc)
521 {
522 uint64_t suboff;
523 uint64_t done;
524 uint32_t d;
525 ssize_t ret;
526 size_t subcc;
527 char *cbuf;
528
529 ret = -1;
530 switch(dp->raid) {
531 case 0:
532 for (cbuf = (char *) buf, done = 0 ; done < cc ; done += ret) {
533 if (!raid0_getoff(dp, dp->off, &d, &suboff)) {
534 return -1;
535 }
536 subcc = (size_t)MIN(cc - (size_t)done,
537 (size_t)(dp->len - dp->off));
538 if (device_lseek(dp, (off_t)dp->off, SEEK_SET) < 0) {
539 return -1;
540 }
541 switch (dp->xv[d].type) {
542 case DE_DEVICE:
543 ret = device_write(dp->xv[d].u.dp,
544 &cbuf[(int)done], subcc);
545 if (ret < 0) {
546 return -1;
547 }
548 break;
549 case DE_EXTENT:
550 ret = extent_write(dp->xv[d].u.xp,
551 &cbuf[(int)done], subcc);
552 if (ret < 0) {
553 return -1;
554 }
555 break;
556 default:
557 break;
558 }
559 dp->off += ret;
560 }
561 ret = (ssize_t) done;
562 break;
563 case 1:
564 for (d = 0 ; d < dp->c ; d++) {
565 switch (dp->xv[d].type) {
566 case DE_DEVICE:
567 ret = device_write(dp->xv[d].u.dp, buf, cc);
568 if (ret < 0) {
569 iscsi_err(__FILE__, __LINE__,
570 "device_write RAID1 device "
571 "write failure\n");
572 return -1;
573 }
574 break;
575 case DE_EXTENT:
576 ret = extent_write(dp->xv[d].u.xp, buf, cc);
577 if (ret < 0) {
578 iscsi_err(__FILE__, __LINE__,
579 "device_write RAID1 extent "
580 "write failure\n");
581 return -1;
582 }
583 break;
584 default:
585 break;
586 }
587 }
588 dp->off += ret;
589 break;
590 default:
591 break;
592 }
593 return ret;
594 }
595
596 /* and for the undecided... */
597 static ssize_t
de_write(disc_de_t * dp,void * buf,size_t cc)598 de_write(disc_de_t *dp, void *buf, size_t cc)
599 {
600 switch(dp->type) {
601 case DE_DEVICE:
602 return device_write(dp->u.dp, buf, cc);
603 case DE_EXTENT:
604 return extent_write(dp->u.xp, buf, cc);
605 default:
606 return -1;
607 }
608 }
609
610 /* return non-zero if the target is writable */
611 static int
target_writable(disc_target_t * tp)612 target_writable(disc_target_t *tp)
613 {
614 return !(tp->flags & TARGET_READONLY);
615 }
616
617 /* return size of the extent */
618 static uint64_t
extent_getsize(disc_extent_t * xp)619 extent_getsize(disc_extent_t *xp)
620 {
621 return xp->len;
622 }
623
624 /* (recursively) return the size of the device's devices */
625 static uint64_t
device_getsize(disc_device_t * dp)626 device_getsize(disc_device_t *dp)
627 {
628 uint64_t size;
629 uint32_t d;
630
631 size = 0;
632 switch(dp->raid) {
633 case 0:
634 for (d = 0 ; d < dp->c ; d++) {
635 switch (dp->xv[d].type) {
636 case DE_DEVICE:
637 size += device_getsize(dp->xv[d].u.dp);
638 break;
639 case DE_EXTENT:
640 size += extent_getsize(dp->xv[d].u.xp);
641 break;
642 default:
643 break;
644 }
645 }
646 break;
647 case 1:
648 size = dp->len;
649 break;
650 default:
651 break;
652 }
653 return size;
654 }
655
656 /* and for the undecided... */
657 static int64_t
de_getsize(disc_de_t * dp)658 de_getsize(disc_de_t *dp)
659 {
660 switch(dp->type) {
661 case DE_DEVICE:
662 return device_getsize(dp->u.dp);
663 case DE_EXTENT:
664 return extent_getsize(dp->u.xp);
665 default:
666 return -1;
667 }
668 }
669
670 /* return a filename for the device or extent */
671 static char *
disc_get_filename(disc_de_t * de)672 disc_get_filename(disc_de_t *de)
673 {
674 switch (de->type) {
675 case DE_EXTENT:
676 return de->u.xp->dev;
677 case DE_DEVICE:
678 return disc_get_filename(&de->u.dp->xv[0]);
679 default:
680 return NULL;
681 }
682 }
683
684 /*
685 * Public Interface (called by utarget and ktarket)
686 */
687
688 /* set various global variables */
689 void
device_set_var(const char * var,const char * arg)690 device_set_var(const char *var, const char *arg)
691 {
692 if (strcmp(var, "blocklen") == 0) {
693 defaults.blocklen = strtoll(arg, (char **)NULL, 10);
694 } else if (strcmp(var, "blocks") == 0) {
695 defaults.blockc = strtoll(arg, (char **)NULL, 10);
696 } else if (strcmp(var, "luns") == 0) {
697 defaults.luns = strtoll(arg, (char **)NULL, 10);
698 } else {
699 (void) fprintf(stderr, "Unrecognised variable: `%s'\n", var);
700 }
701 }
702
703 /* allocate some space for a disk/extent, using an lseek, read and
704 * write combination */
705 static int
de_allocate(disc_de_t * de,char * filename,uint64_t blocklen)706 de_allocate(disc_de_t *de, char *filename, uint64_t blocklen)
707 {
708 off_t size;
709 char *block;
710
711 block = malloc(blocklen);
712 size = de_getsize(de);
713 if (de_lseek(de, size - blocklen, SEEK_SET) == -1) {
714 iscsi_err(__FILE__, __LINE__,
715 "error seeking \"%s\"\n", filename);
716 free(block);
717 return 0;
718 }
719 if (de_read(de, block, blocklen) == -1) {
720 iscsi_err(__FILE__, __LINE__,
721 "error reading \"%s\"\n", filename);
722 free(block);
723 return 0;
724 }
725 if (de_write(de, block, blocklen) == -1) {
726 iscsi_err(__FILE__, __LINE__,
727 "error writing \"%s\"\n", filename);
728 free(block);
729 return 0;
730 }
731 free(block);
732 return 1;
733 }
734
735 /* allocate space as desired */
736 static int
allocate_space(disc_target_t * tp,uint64_t blocklen)737 allocate_space(disc_target_t *tp, uint64_t blocklen)
738 {
739 uint32_t i;
740
741 /* Don't perform check for writability in the target here, as the
742 following write() in de_allocate is non-destructive */
743 switch(tp->de.type) {
744 case DE_EXTENT:
745 return de_allocate(&tp->de, tp->target, blocklen);
746 case DE_DEVICE:
747 for (i = 0 ; i < tp->de.u.dp->c ; i++) {
748 if (!de_allocate(&tp->de.u.dp->xv[i], tp->target, blocklen)) {
749 return 0;
750 }
751 }
752 return 1;
753 default:
754 break;
755 }
756 return 0;
757 }
758
759 /* copy src to dst, of size `n' bytes, padding any extra with `pad' */
760 static void
strpadcpy(uint8_t * dst,size_t dstlen,const char * src,const size_t srclen,char pad)761 strpadcpy(uint8_t *dst, size_t dstlen, const char *src, const size_t srclen,
762 char pad)
763 {
764 if (srclen < dstlen) {
765 (void) memcpy(dst, src, srclen);
766 (void) memset(&dst[srclen], pad, dstlen - srclen);
767 } else {
768 (void) memcpy(dst, src, dstlen);
769 }
770 }
771
772 /* handle REPORT LUNs SCSI command */
773 static int
report_luns(uint8_t * data,uint64_t luns)774 report_luns(uint8_t *data, uint64_t luns)
775 {
776 uint64_t i;
777 uint32_t len;
778
779 len = 8;
780 for (i = 0; i < luns; i++) {
781 uint8_t *p = &data[len];
782
783 if (i < 256) {
784 memset(p, 0, 8);
785 p[1] = (uint8_t)(i & 0xff);
786 len += 8;
787 } else if (i < 16384) {
788 memset(p, 0, 8);
789 p[0] = (uint8_t)(0x40 | ((i >> 8) & 0x3f));
790 p[1] = (uint8_t)(i & 0xff);
791 len += 8;
792 } else {
793 /* XXX */
794 }
795 }
796 *((uint32_t *)(void *)data) = ISCSI_HTONL(len - 8);
797 memset(&data[4], 0, 4);
798 return len;
799 }
800
801 /* handle persistent reserve in command */
802 static int
persistent_reserve_in(uint8_t action,uint8_t * data)803 persistent_reserve_in(uint8_t action, uint8_t *data)
804 {
805 uint64_t key;
806
807 switch(action) {
808 case PERSISTENT_RESERVE_IN_READ_KEYS:
809 key = 0; /* simulate "just powered on" */
810 *((uint32_t *)(void *)data) =
811 (uint32_t)ISCSI_HTONL((uint32_t) 0);
812 *((uint32_t *) (void *)data + 4) =
813 (uint32_t) ISCSI_HTONL((uint32_t) sizeof(key));
814 /* length in bytes of list of keys */
815 *((uint64_t *) (void *)data + 8) = (uint64_t) ISCSI_HTONLL(key);
816 return 8 + sizeof(key);
817 case PERSISTENT_RESERVE_IN_REPORT_CAPABILITIES:
818 (void) memset(data, 0x0, 8);
819 /* length is fixed at 8 bytes */
820 *((uint16_t *)(void *)data) =
821 (uint16_t)ISCSI_HTONS((uint16_t)8);
822 data[2] = PERSISTENT_RESERVE_IN_CRH;
823 /* also SIP_C, ATP_C and PTPL_C here */
824 data[3] = 0; /* also TMV and PTPL_A here */
825 data[4] = 0;
826 /* also WR_EX_AR, EX_AC_RD, WR_EX_RD, EX_AC, WR_EX */
827 data[5] = 0; /* also EX_AC_AR here */
828 return 8;
829 default:
830 iscsi_err(__FILE__, __LINE__,
831 "persistent_reserve_in: action %x unrecognised\n",
832 action);
833 return 0;
834 }
835 }
836
837 /* initialise the device */
838 int
device_init(iscsi_target_t * tgt,targv_t * tvp,disc_target_t * tp)839 device_init(iscsi_target_t *tgt, targv_t *tvp, disc_target_t *tp)
840 {
841 iscsi_disk_t *idisk;
842 int mode;
843
844 ALLOC(iscsi_disk_t, disks.v, disks.size, disks.c, 10, 10,
845 "device_init", ;);
846 idisk = &disks.v[disks.c];
847 idisk->lunv = tvp;
848 if ((idisk->luns = defaults.luns) == 0) {
849 idisk->luns = iSCSI_DEFAULT_LUNS;
850 }
851 idisk->blocklen = atoi(iscsi_target_getvar(tgt, "blocklen"));
852 switch(idisk->blocklen) {
853 case 512:
854 case 1024:
855 case 2048:
856 case 4096:
857 case 8192:
858 break;
859 default:
860 iscsi_err(__FILE__, __LINE__,
861 "Invalid block len %" PRIu64
862 ". Choose one of 512, 1024, 2048, 4096, or 8192.\n",
863 idisk->blocklen);
864 return -1;
865 }
866 idisk->size = de_getsize(&tp->de);
867 idisk->blockc = idisk->size / idisk->blocklen;
868 idisk->type = ISCSI_FS;
869 printf("DISK: %" PRIu64 " logical unit%s (%" PRIu64 " blocks, %"
870 PRIu64 " bytes/block), type %s\n",
871 idisk->luns,
872 (idisk->luns == 1) ? "" : "s",
873 idisk->blockc, idisk->blocklen,
874 (idisk->type == ISCSI_FS) ? "iscsi fs" :
875 "iscsi fs mmap");
876 printf("DISK: LUN 0: ");
877 (void) strlcpy(idisk->filename, disc_get_filename(&tp->de),
878 sizeof(idisk->filename));
879 mode = (tp->flags & TARGET_READONLY) ? O_RDONLY : (O_CREAT | O_RDWR);
880 if (de_open(&tp->de, mode, 0666) == -1) {
881 iscsi_err(__FILE__, __LINE__,
882 "error opening \"%s\"\n", idisk->filename);
883 return -1;
884 }
885 if (!(tp->flags & TARGET_READONLY) && !allocate_space(tp, idisk->blocklen)) {
886 iscsi_err(__FILE__, __LINE__,
887 "error allocating space for \"%s\"\n", tp->target);
888 return -1;
889 }
890 printf("%" PRIu64 " MB %sdisk storage for \"%s\"\n",
891 (de_getsize(&tp->de) / MB(1)),
892 (tp->flags & TARGET_READONLY) ? "readonly " : "",
893 tp->target);
894 return disks.c++;
895 }
896
897 static void
cdb2lba(uint32_t * lba,uint16_t * len,uint8_t * cdb)898 cdb2lba(uint32_t *lba, uint16_t *len, uint8_t *cdb)
899 {
900 /* Some platforms (like strongarm) aligns on */
901 /* word boundaries. So HTONL and NTOHL won't */
902 /* work here. */
903 int little_endian = 1;
904
905 if (*(char *) (void *) &little_endian) {
906 /* little endian */
907 ((uint8_t *) (void *) lba)[0] = cdb[5];
908 ((uint8_t *) (void *) lba)[1] = cdb[4];
909 ((uint8_t *) (void *) lba)[2] = cdb[3];
910 ((uint8_t *) (void *) lba)[3] = cdb[2];
911 ((uint8_t *) (void *) len)[0] = cdb[8];
912 ((uint8_t *) (void *) len)[1] = cdb[7];
913 } else {
914 ((uint8_t *) (void *) lba)[0] = cdb[2];
915 ((uint8_t *) (void *) lba)[1] = cdb[3];
916 ((uint8_t *) (void *) lba)[2] = cdb[4];
917 ((uint8_t *) (void *) lba)[3] = cdb[5];
918 ((uint8_t *) (void *) len)[0] = cdb[7];
919 ((uint8_t *) (void *) len)[1] = cdb[8];
920 }
921 }
922
923 /* handle MODE_SENSE_6 and MODE_SENSE_10 commands */
924 static int
mode_sense(const int bytes,target_cmd_t * cmd)925 mode_sense(const int bytes, target_cmd_t *cmd)
926 {
927 iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd;
928 uint16_t len;
929 uint8_t *cp;
930 uint8_t *cdb = args->cdb;
931 size_t mode_data_len;
932
933 switch(bytes) {
934 case 6:
935 cp = args->send_data;
936 len = ISCSI_MODE_SENSE_LEN;
937 mode_data_len = len + 3;
938
939 iscsi_trace(TRACE_SCSI_CMD, "MODE_SENSE_6\n");
940 (void) memset(cp, 0x0, mode_data_len);
941
942 cp[0] = mode_data_len;
943 cp[1] = 0;
944 cp[2] = 0;
945 cp[3] = 8; /* block descriptor length */
946 cp[10] = 2; /* density code and block length */
947
948 args->input = 1;
949 args->length = (unsigned)len;
950 args->status = SCSI_SUCCESS;
951 return 1;
952 case 10:
953 cp = args->send_data;
954 len = ISCSI_MODE_SENSE_LEN;
955 mode_data_len = len + 3;
956
957 iscsi_trace(TRACE_SCSI_CMD, "MODE_SENSE_10\n");
958 (void) memset(cp, 0x0, mode_data_len);
959 if (cdb[4] == 0) {
960 /* zero length cdb means just return success */
961 args->input = 1;
962 args->length = (unsigned)(mode_data_len);
963 args->status = SCSI_SUCCESS;
964 return 1;
965 }
966 if ((cdb[2] & PAGE_CONTROL_MASK) ==
967 PAGE_CONTROL_CHANGEABLE_VALUES) {
968 /* just send back a CHECK CONDITION */
969 args->input = 1;
970 args->length = (unsigned)(len);
971 args->status = SCSI_CHECK_CONDITION;
972 cp[2] = SCSI_SKEY_ILLEGAL_REQUEST;
973 cp[12] = ASC_LUN_UNSUPPORTED;
974 cp[13] = ASCQ_LUN_UNSUPPORTED;
975 return 1;
976 }
977 iscsi_trace(TRACE_SCSI_CMD, "PC %02x\n", cdb[2]);
978
979 cp[0] = mode_data_len;
980 cp[1] = 0;
981 cp[2] = 0;
982 cp[3] = 8; /* block descriptor length */
983 cp[10] = 2; /* density code and block length */
984
985 args->input = 1;
986 args->length = (unsigned)(len);
987 args->status = SCSI_SUCCESS;
988 return 1;
989 }
990 return 0;
991 }
992
993 /* fill in the device serial number vital product data */
994 static uint8_t
serial_vpd(uint8_t * data)995 serial_vpd(uint8_t *data)
996 {
997 uint8_t len;
998
999 data[0] = DISK_PERIPHERAL_DEVICE;
1000 data[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
1001 len = 16;
1002 /* add target device's Unit Serial Number */
1003 /* section 7.6.10 of SPC-3 says that if there is no serial number,
1004 * use spaces */
1005 strpadcpy(&data[4], (size_t)len, " ", strlen(" "), ' ');
1006 return len;
1007 }
1008
1009 /* fill in the device identification vital product data */
1010 static void
device_vpd(iscsi_target_t * tgt,uint8_t * data,uint8_t * rspc,uint8_t * cdbsize,uint8_t lun,char * uuid)1011 device_vpd(iscsi_target_t *tgt, uint8_t *data, uint8_t *rspc,
1012 uint8_t *cdbsize, uint8_t lun, char *uuid)
1013 {
1014 uint16_t len;
1015 uint8_t *cp;
1016
1017 data[0] = DISK_PERIPHERAL_DEVICE;
1018 data[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
1019 *rspc = 0;
1020 cp = &data[4];
1021 /* add target device's IQN */
1022 cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
1023 INQUIRY_DEVICE_CODESET_UTF8;
1024 cp[1] = (INQUIRY_DEVICE_PIV << 7) |
1025 (INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE << 4) |
1026 INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
1027 len = (uint8_t) snprintf((char *)&cp[4],
1028 (unsigned)(*cdbsize - (int)(cp - &data[4])), "%s",
1029 iscsi_target_getvar(tgt, "iqn"));
1030 cp[3] = len;
1031 *rspc += len + 4;
1032 cp += len + 4;
1033 /* add target port's IQN + LUN */
1034 cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
1035 INQUIRY_DEVICE_CODESET_UTF8;
1036 cp[1] = (INQUIRY_DEVICE_PIV << 7) |
1037 (INQUIRY_DEVICE_ASSOCIATION_TARGET_PORT << 4) |
1038 INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
1039 len = (uint8_t) snprintf((char *)&cp[4],
1040 (unsigned)(*cdbsize - (int)(cp - &data[4])),
1041 "%s,t,%#x",
1042 iscsi_target_getvar(tgt, "iqn"),
1043 lun);
1044 cp[3] = len;
1045 *rspc += len + 4;
1046 cp += len + 4;
1047 /* add target port's IQN + LUN extension */
1048 cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
1049 INQUIRY_DEVICE_CODESET_UTF8;
1050 cp[1] = (INQUIRY_DEVICE_PIV << 7) |
1051 (INQUIRY_DEVICE_ASSOCIATION_LOGICAL_UNIT << 4) |
1052 INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
1053 len = (uint8_t) snprintf((char *)&cp[4],
1054 (unsigned) (*cdbsize - (int)(cp - &data[4])),
1055 "%s,L,0x%8.8s%4.4s%4.4s",
1056 iscsi_target_getvar(tgt, "iqn"),
1057 uuid, &uuid[9], &uuid[14]);
1058 cp[3] = len;
1059 *rspc += len + 4;
1060 cp += len + 4;
1061 /* add target's uuid as a T10 identifier */
1062 cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
1063 INQUIRY_DEVICE_CODESET_UTF8;
1064 cp[1] = (INQUIRY_DEVICE_PIV << 7) |
1065 (INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE << 4) |
1066 INQUIRY_IDENTIFIER_TYPE_T10;
1067 strpadcpy(&cp[4], 8, ISCSI_VENDOR, strlen(ISCSI_VENDOR), ' ');
1068 len = 8;
1069 len += (uint8_t) snprintf((char *)&cp[8 + 4],
1070 (unsigned)(*cdbsize - (int)(cp - &data[4])),
1071 "0x%8.8s%4.4s%4.4s",
1072 uuid, &uuid[9], &uuid[14]);
1073 cp[3] = len;
1074 *rspc += len + 4;
1075 }
1076
1077 static void
version_inquiry(uint8_t * data,uint8_t * cdbsize)1078 version_inquiry(uint8_t *data, uint8_t *cdbsize)
1079 {
1080 char versionstr[8];
1081
1082 data[0] = DISK_PERIPHERAL_DEVICE;
1083 data[2] = SCSI_VERSION_SPC;
1084 data[4] = *cdbsize - 4; /* Additional length */
1085 data[7] |= (WIDE_BUS_32 | WIDE_BUS_16);
1086 strpadcpy(&data[8], 8, ISCSI_VENDOR, strlen(ISCSI_VENDOR), ' ');
1087 strpadcpy(&data[16], 16, ISCSI_PRODUCT, strlen(ISCSI_PRODUCT), ' ');
1088 (void) snprintf(versionstr, sizeof(versionstr), "%d", ISCSI_VERSION);
1089 strpadcpy(&data[32], 4, versionstr, strlen(versionstr), ' ');
1090 }
1091
1092 int
device_command(target_session_t * sess,target_cmd_t * cmd)1093 device_command(target_session_t *sess, target_cmd_t *cmd)
1094 {
1095 iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd;
1096 uint32_t status;
1097 uint32_t lba;
1098 uint16_t len;
1099 uint8_t *cdbsize;
1100 uint8_t *rspc;
1101 uint8_t *data;
1102 uint8_t *cdb;
1103 uint8_t lun;
1104
1105 cdb = args->cdb;
1106 lun = (uint8_t) (args->lun >> 48);
1107 cdbsize = &cdb[4];
1108
1109 /*
1110 * added section to return no device equivalent for lun request
1111 * beyond available lun
1112 */
1113 if (lun >= disks.v[sess->d].luns) {
1114 data = args->send_data;
1115 (void) memset(data, 0x0, (size_t) *cdbsize);
1116 /*
1117 * data[0] = 0x7F; means no device
1118 */
1119 data[0] = 0x1F; /* device type */
1120 data[0] |= 0x60;/* peripheral qualifier */
1121 args->input = 1;
1122 args->length = cdb[4] + 1;
1123 args->status = SCSI_SUCCESS;
1124 return 0;
1125 }
1126
1127 lun = (uint8_t) sess->d;
1128 iscsi_trace(TRACE_SCSI_CMD, "SCSI op %#x (lun %d): \n", cdb[0], lun);
1129
1130 switch (cdb[0]) {
1131 case TEST_UNIT_READY:
1132 iscsi_trace(TRACE_SCSI_CMD, "TEST_UNIT_READY\n");
1133 args->status = SCSI_SUCCESS;
1134 args->length = 0;
1135 break;
1136
1137 case INQUIRY:
1138 iscsi_trace(TRACE_SCSI_CMD, "INQUIRY%s\n",
1139 (cdb[1] & INQUIRY_EVPD_BIT) ?
1140 " for Vital Product Data" : "");
1141 data = args->send_data;
1142 args->status = SCSI_SUCCESS;
1143 /* Clear allocated buffer */
1144 (void) memset(data, 0x0, (unsigned) *cdbsize);
1145 if (cdb[1] & INQUIRY_EVPD_BIT) {
1146 rspc = &data[3];
1147 switch(cdb[2]) {
1148 case INQUIRY_UNIT_SERIAL_NUMBER_VPD:
1149 *rspc = serial_vpd(data);
1150 args->length = 16;
1151 break;
1152 case INQUIRY_DEVICE_IDENTIFICATION_VPD:
1153 if (disks.v[sess->d].uuid_string == NULL) {
1154 nbuuid_create(&disks.v[sess->d].uuid,
1155 &status);
1156 nbuuid_to_string(&disks.v[sess->d].uuid,
1157 &disks.v[sess->d].uuid_string,
1158 &status);
1159 }
1160 device_vpd(sess->target, data, rspc, cdbsize,
1161 lun, disks.v[sess->d].uuid_string);
1162 args->length = *rspc + 6;
1163 break;
1164 case INQUIRY_SUPPORTED_VPD_PAGES:
1165 data[0] = DISK_PERIPHERAL_DEVICE;
1166 data[1] = INQUIRY_SUPPORTED_VPD_PAGES;
1167 *rspc = 3; /* # of supported pages */
1168 data[4] = INQUIRY_SUPPORTED_VPD_PAGES;
1169 data[5] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
1170 data[6] = EXTENDED_INQUIRY_DATA_VPD;
1171 args->length = *cdbsize + 1;
1172 break;
1173 case EXTENDED_INQUIRY_DATA_VPD:
1174 data[0] = DISK_PERIPHERAL_DEVICE;
1175 data[1] = EXTENDED_INQUIRY_DATA_VPD;
1176 data[3] = 0x3c; /* length is defined to be 60 */
1177 data[4] = 0;
1178 data[5] = 0;
1179 args->length = 64;
1180 break;
1181 default:
1182 iscsi_err(__FILE__, __LINE__,
1183 "Unsupported INQUIRY VPD page %x\n",
1184 cdb[2]);
1185 args->status = SCSI_CHECK_CONDITION;
1186 break;
1187 }
1188 } else {
1189 version_inquiry(data, cdbsize);
1190 args->length = cdb[4] + 1;
1191 }
1192 if (args->status == SCSI_SUCCESS) {
1193 args->input = 1;
1194 }
1195 break;
1196
1197 case MODE_SELECT_6:
1198 iscsi_trace(TRACE_SCSI_CMD, "MODE_SELECT_6\n");
1199 args->status = SCSI_SUCCESS;
1200 args->length = 0;
1201 break;
1202
1203 case STOP_START_UNIT:
1204 iscsi_trace(TRACE_SCSI_CMD, "STOP_START_UNIT\n");
1205 args->status = SCSI_SUCCESS;
1206 args->length = 0;
1207 break;
1208
1209 case READ_CAPACITY:
1210 iscsi_trace(TRACE_SCSI_CMD, "READ_CAPACITY\n");
1211 data = args->send_data;
1212 *((uint32_t *)(void *)data) = (uint32_t) ISCSI_HTONL(
1213 (uint32_t) disks.v[sess->d].blockc - 1);
1214 /* Max LBA */
1215 *((uint32_t *)(void *)(data + 4)) = (uint32_t) ISCSI_HTONL(
1216 (uint32_t) disks.v[sess->d].blocklen);
1217 /* Block len */
1218 args->input = 8;
1219 args->length = 8;
1220 args->status = SCSI_SUCCESS;
1221 break;
1222
1223 case WRITE_6:
1224 lba = ISCSI_NTOHL(*((uint32_t *) (void *)cdb)) & 0x001fffff;
1225 if ((len = *cdbsize) == 0) {
1226 len = 256;
1227 }
1228 iscsi_trace(TRACE_SCSI_CMD,
1229 "WRITE_6(lba %u, len %u blocks)\n", lba, len);
1230 if (disk_write(sess, args, lun, lba, (unsigned) len) != 0) {
1231 iscsi_err(__FILE__, __LINE__,
1232 "disk_write() failed\n");
1233 args->status = SCSI_CHECK_CONDITION;
1234 }
1235 args->length = 0;
1236 break;
1237
1238
1239 case READ_6:
1240 lba = ISCSI_NTOHL(*((uint32_t *)(void *)cdb)) & 0x001fffff;
1241 if ((len = *cdbsize) == 0) {
1242 len = 256;
1243 }
1244 iscsi_trace(TRACE_SCSI_CMD,
1245 "READ_6(lba %u, len %u blocks)\n", lba, len);
1246 if (disk_read(sess, args, lba, len, lun) != 0) {
1247 iscsi_err(__FILE__, __LINE__,
1248 "disk_read() failed\n");
1249 args->status = SCSI_CHECK_CONDITION;
1250 }
1251 args->input = 1;
1252 break;
1253
1254 case MODE_SENSE_6:
1255 mode_sense(6, cmd);
1256 break;
1257
1258 case WRITE_10:
1259 case WRITE_VERIFY:
1260 cdb2lba(&lba, &len, cdb);
1261
1262 iscsi_trace(TRACE_SCSI_CMD,
1263 "WRITE_10 | WRITE_VERIFY(lba %u, len %u blocks)\n",
1264 lba, len);
1265 if (disk_write(sess, args, lun, lba, (unsigned) len) != 0) {
1266 iscsi_err(__FILE__, __LINE__,
1267 "disk_write() failed\n");
1268 args->status = SCSI_CHECK_CONDITION;
1269 }
1270 args->length = 0;
1271 break;
1272
1273 case READ_10:
1274 cdb2lba(&lba, &len, cdb);
1275 iscsi_trace(TRACE_SCSI_CMD,
1276 "READ_10(lba %u, len %u blocks)\n", lba, len);
1277 if (disk_read(sess, args, lba, len, lun) != 0) {
1278 iscsi_err(__FILE__, __LINE__,
1279 "disk_read() failed\n");
1280 args->status = SCSI_CHECK_CONDITION;
1281 }
1282 args->input = 1;
1283 break;
1284
1285 case VERIFY:
1286 /* For now just set the status to success. */
1287 args->status = SCSI_SUCCESS;
1288 break;
1289
1290 case SYNC_CACHE:
1291 cdb2lba(&lba, &len, cdb);
1292 iscsi_trace(TRACE_SCSI_CMD,
1293 "SYNC_CACHE (lba %u, len %u blocks)\n", lba, len);
1294 if (de_fsync_range(&disks.v[sess->d].lunv->v[lun].de,
1295 FDATASYNC, lba,
1296 (off_t)(len * disks.v[sess->d].blocklen)) < 0) {
1297 iscsi_err(__FILE__, __LINE__,
1298 "disk_read() failed\n");
1299 args->status = SCSI_CHECK_CONDITION;
1300 } else {
1301 args->status = SCSI_SUCCESS;
1302 args->length = 0;
1303 }
1304 break;
1305
1306 case LOG_SENSE:
1307 iscsi_trace(TRACE_SCSI_CMD, "LOG_SENSE\n");
1308 args->status = SCSI_SUCCESS;
1309 args->length = 0;
1310 break;
1311
1312 case MODE_SENSE_10:
1313 mode_sense(10, cmd);
1314 break;
1315
1316 case MODE_SELECT_10:
1317 /* XXX still to do */
1318 iscsi_trace(TRACE_SCSI_CMD, "MODE_SELECT_10\n");
1319 args->status = SCSI_SUCCESS;
1320 args->length = 0;
1321 break;
1322
1323 case PERSISTENT_RESERVE_IN:
1324 iscsi_trace(TRACE_SCSI_CMD, "PERSISTENT_RESERVE_IN\n");
1325 args->length = persistent_reserve_in((cdb[1] &
1326 PERSISTENT_RESERVE_IN_SERVICE_ACTION_MASK),
1327 args->send_data);
1328 args->status = SCSI_SUCCESS;
1329 break;
1330
1331 case REPORT_LUNS:
1332 iscsi_trace(TRACE_SCSI_CMD, "REPORT LUNS\n");
1333 args->length = report_luns(args->send_data,
1334 disks.v[sess->d].luns);
1335 args->input = 8;
1336 args->status = SCSI_SUCCESS;
1337 break;
1338
1339 case RESERVE_6:
1340 iscsi_trace(TRACE_SCSI_CMD, "RESERVE_6\n");
1341 args->status = SCSI_SUCCESS;
1342 args->length = 0;
1343 break;
1344
1345 case RELEASE_6:
1346 iscsi_trace(TRACE_SCSI_CMD, "RELEASE_6\n");
1347 args->status = SCSI_SUCCESS;
1348 args->length = 0;
1349 break;
1350
1351 case RESERVE_10:
1352 iscsi_trace(TRACE_SCSI_CMD, "RESERVE_10\n");
1353 args->status = SCSI_SUCCESS;
1354 args->length = 0;
1355 break;
1356
1357 case RELEASE_10:
1358 iscsi_trace(TRACE_SCSI_CMD, "RELEASE_10\n");
1359 args->status = SCSI_SUCCESS;
1360 args->length = 0;
1361 break;
1362
1363 default:
1364 iscsi_err(__FILE__, __LINE__,
1365 "UNKNOWN OPCODE %#x\n", cdb[0]);
1366 /* to not cause confusion with some initiators */
1367 args->status = SCSI_CHECK_CONDITION;
1368 break;
1369 }
1370 iscsi_trace(TRACE_SCSI_DEBUG,
1371 "SCSI op %#x: done (status %#x)\n", cdb[0], args->status);
1372 return 0;
1373 }
1374
1375 int
device_shutdown(target_session_t * sess)1376 device_shutdown(target_session_t *sess)
1377 {
1378 USE_ARG(sess);
1379 return 1;
1380 }
1381
1382 /*
1383 * Private Interface
1384 */
1385
1386 static int
disk_write(target_session_t * sess,iscsi_scsi_cmd_args_t * args,uint8_t lun,uint32_t lba,uint32_t len)1387 disk_write(target_session_t *sess, iscsi_scsi_cmd_args_t *args, uint8_t lun,
1388 uint32_t lba, uint32_t len)
1389 {
1390 struct iovec sg;
1391 uint64_t byte_offset;
1392 uint64_t bytec;
1393 uint8_t *ptr;
1394 int result;
1395
1396 byte_offset = lba * disks.v[sess->d].blocklen;
1397 bytec = len * disks.v[sess->d].blocklen;
1398 ptr = NULL;
1399 iscsi_trace(TRACE_SCSI_DATA,
1400 "writing %" PRIu64
1401 " bytes from socket into device at byte offset %" PRIu64 "\n",
1402 bytec, byte_offset);
1403
1404 if ((unsigned) bytec > MB(1)) {
1405 iscsi_err(__FILE__, __LINE__, "bytec > %" PRIu64 "m\n", bytec);
1406 NO_CLEANUP;
1407 return -1;
1408 }
1409
1410 /* Assign ptr for write data */
1411 ptr = malloc(MB(1));
1412
1413 /* Have target do data transfer */
1414 sg.iov_base = ptr;
1415 sg.iov_len = (unsigned)bytec;
1416 if (target_transfer_data(sess, args, &sg, 1) != 0) {
1417 iscsi_err(__FILE__, __LINE__,
1418 "target_transfer_data() failed\n");
1419 result = -1;
1420 goto out;
1421 }
1422 /* Finish up write */
1423 if (de_lseek(&disks.v[sess->d].lunv->v[lun].de, (off_t)byte_offset,
1424 SEEK_SET) == -1) {
1425 iscsi_err(__FILE__, __LINE__,
1426 "lseek() to offset %" PRIu64 " failed\n",
1427 byte_offset);
1428 result = -1;
1429 goto out;
1430 }
1431 if (!target_writable(&disks.v[sess->d].lunv->v[lun])) {
1432 iscsi_err(__FILE__, __LINE__,
1433 "write() of %" PRIu64 " bytes failed at offset %"
1434 PRIu64 ", size %" PRIu64 "[READONLY TARGET]\n",
1435 bytec, byte_offset,
1436 de_getsize(&disks.v[sess->d].lunv->v[lun].de));
1437 result = -1;
1438 goto out;
1439 }
1440 if ((uint64_t)de_write(&disks.v[sess->d].lunv->v[lun].de, ptr,
1441 (unsigned) bytec) != bytec) {
1442 iscsi_err(__FILE__, __LINE__,
1443 "write() of %" PRIu64 " bytes failed at offset %"
1444 PRIu64 ", size %" PRIu64 "\n",
1445 bytec, byte_offset,
1446 de_getsize(&disks.v[sess->d].lunv->v[lun].de));
1447 result = -1;
1448 goto out;
1449 }
1450 iscsi_trace(TRACE_SCSI_DATA,
1451 "wrote %" PRIu64 " bytes to device OK\n", bytec);
1452 result = 0;
1453 out:
1454 free(ptr);
1455 return result;
1456 }
1457
1458 static int
disk_read(target_session_t * sess,iscsi_scsi_cmd_args_t * args,uint32_t lba,uint16_t len,uint8_t lun)1459 disk_read(target_session_t *sess, iscsi_scsi_cmd_args_t *args, uint32_t lba,
1460 uint16_t len, uint8_t lun)
1461 {
1462 uint64_t byte_offset;
1463 uint64_t bytec;
1464 uint64_t extra;
1465 uint8_t *ptr;
1466 uint32_t n;
1467 int rc;
1468 int result;
1469
1470 assert(args->send_buffer == NULL);
1471 byte_offset = lba * disks.v[sess->d].blocklen;
1472 bytec = len * disks.v[sess->d].blocklen;
1473 extra = 0;
1474 if (len == 0) {
1475 iscsi_err(__FILE__, __LINE__, "Zero \"len\"\n");
1476 NO_CLEANUP;
1477 return -1;
1478 }
1479 if (lba > disks.v[sess->d].blockc - 1 ||
1480 (lba + len) > disks.v[sess->d].blockc) {
1481 iscsi_err(__FILE__, __LINE__,
1482 "attempt to read beyond end of media\n"
1483 "max_lba = %" PRIu64 ", requested lba = %u, len = %u\n",
1484 disks.v[sess->d].blockc - 1, lba, len);
1485 return -1;
1486 }
1487 if ((unsigned) bytec > MB(1)) {
1488 iscsi_err(__FILE__, __LINE__, "bytec > %" PRIu64 "\n", bytec);
1489 NO_CLEANUP;
1490 return -1;
1491 }
1492 ptr = malloc(MB(1));
1493 n = 0;
1494 do {
1495 if (de_lseek(&disks.v[sess->d].lunv->v[lun].de,
1496 (off_t)(n + byte_offset), SEEK_SET) == -1) {
1497 iscsi_err(__FILE__, __LINE__, "lseek failed\n");
1498 result = -1;
1499 goto out;
1500 }
1501 rc = de_read(&disks.v[sess->d].lunv->v[lun].de, ptr + n,
1502 (size_t)(bytec - n));
1503 if (rc <= 0) {
1504 iscsi_err(__FILE__, __LINE__,
1505 "read failed: rc %d errno %d\n", rc, errno);
1506 result = -1;
1507 goto out;
1508 }
1509 n += rc;
1510 if (n < bytec) {
1511 iscsi_err(__FILE__, __LINE__,
1512 "Got partial file read: %d bytes of %" PRIu64
1513 "\n", rc, bytec - n + rc);
1514 }
1515 } while (n < bytec);
1516 ((struct iovec *)(void *)args->send_data)[0].iov_base =
1517 ptr + (unsigned) extra;
1518 ((struct iovec *)(void *)args->send_data)[0].iov_len =
1519 (unsigned) bytec;
1520 args->length = (unsigned) bytec;
1521 args->send_sg_len = 1;
1522 args->status = SCSI_SUCCESS;
1523 args->send_buffer = ptr;
1524 return 0;
1525 out:
1526 free(ptr);
1527 return result;
1528 }
1529