Don't use .Xo/.Xc. Fix date format.
[netbsd-mini2440.git] / external / bsd / iscsi / dist / src / lib / disk.c
blobc741609e9cc9c02bc36e29b6c30065f72d9b08ff
1 /* $NetBSD: disk.c,v 1.40 2009/06/23 05:11:47 agc Exp $ */
3 /*-
4 * Copyright (c) 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Alistair Crooks (agc@netbsd.org)
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.
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.
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.
37 * Intel License Agreement
39 * Copyright (c) 2000, Intel Corporation
40 * All rights reserved.
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
46 * -Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
71 #include "config.h"
73 #ifdef HAVE_INTTYPES_H
74 #include <inttypes.h>
75 #endif
77 #include <sys/types.h>
79 #ifdef HAVE_SYS_PARAM_H
80 #include <sys/param.h>
81 #endif
83 #ifdef HAVE_SYS_STAT_H
84 #include <sys/stat.h>
85 #endif
87 #ifdef HAVE_SYS_UIO_H
88 #include <sys/uio.h>
89 #endif
91 #ifdef HAVE_SYS_TIME_H
92 #include <sys/time.h>
93 #endif
95 #ifdef HAVE_SYS_MMAN_H
96 #include <sys/mman.h>
97 #endif
99 #ifdef HAVE_NETINET_IN_H
100 #include <netinet/in.h>
101 #endif
103 #ifdef HAVE_ERRNO_H
104 #include <errno.h>
105 #endif
107 #ifdef HAVE_FCNTL_H
108 #include <fcntl.h>
109 #endif
111 #include <ctype.h>
112 #include <stdio.h>
113 #include <stdlib.h>
115 #ifdef HAVE_STRING_H
116 #include <string.h>
117 #endif
119 #include <unistd.h>
121 #include "scsi_cmd_codes.h"
123 #include "iscsiprotocol.h"
124 #include "compat.h"
125 #include "iscsiutil.h"
126 #include "device.h"
127 #include "target.h"
128 #include "defs.h"
129 #include "storage.h"
131 #define iSCSI_DEFAULT_LUNS 1
132 #define iSCSI_DEFAULT_BLOCKLEN 512
134 /* End disk configuration */
137 * Globals
139 enum {
140 MAX_RESERVATIONS = 32,
142 ISCSI_FS = 0x03,
143 ISCSI_CONTROL = 0x04
146 #define MB(x) ((x) * 1024 * 1024)
148 /* this struct describes an iscsi LUN */
149 typedef struct iscsi_disk_t {
150 int type; /* type of disk - fs/mmap and fs */
151 char filename[MAXPATHLEN]; /* filename for the disk */
152 uint8_t *buffer; /* buffer for disk read/write ops */
153 uint64_t blockc; /* # of blocks */
154 uint64_t blocklen; /* block size */
155 uint64_t luns; /* # of luns */
156 uint64_t size; /* size of complete disk */
157 nbuuid_t uuid; /* disk's uuid */
158 char *uuid_string; /* uuid string */
159 targv_t *lunv; /* the component devices and extents */
160 uint32_t resc; /* # of reservation keys */
161 uint64_t reskeys[MAX_RESERVATIONS]; /* reservation keys */
162 } iscsi_disk_t;
164 DEFINE_ARRAY(disks_t, iscsi_disk_t);
166 static disks_t disks;
167 static iscsi_disk_t defaults;
169 #ifndef FDATASYNC
171 this means that we probably don't have the fsync_range(2) system call,
172 but no matter - define this here to preserve the abstraction for the
173 disk/extent code
175 #define FDATASYNC 0x0010
176 #endif
179 * Private Interface
181 static int disk_read(target_session_t *, iscsi_scsi_cmd_args_t *,
182 uint32_t, uint16_t, uint8_t);
183 static int disk_write(target_session_t *, iscsi_scsi_cmd_args_t *,
184 uint8_t, uint32_t, uint32_t);
186 /* return the de index and offset within the device for RAID0 */
187 static int
188 raid0_getoff(disc_device_t *dp, uint64_t off, uint32_t *d, uint64_t *de_off)
190 uint64_t o;
192 for (o = 0, *d = 0 ; *d < dp->c ; o += dp->xv[*d].size, (*d)++) {
193 if (off >= o && off < o + dp->xv[*d].size) {
194 break;
197 *de_off = off - o;
198 return (*d < dp->c);
201 /* open the extent's device */
202 static int
203 extent_open(disc_extent_t *xp, int mode, int flags)
205 return xp->fd = open(xp->dev, mode, flags);
208 /* (recursively) open the device's devices */
209 static int
210 device_open(disc_device_t *dp, int flags, int mode)
212 int fd;
213 uint32_t i;
215 for (fd = -1, i = 0 ; i < dp->c ; i++) {
216 switch (dp->xv[i].type) {
217 case DE_DEVICE:
218 fd = device_open(dp->xv[i].u.dp, flags, mode);
219 if (fd < 0) {
220 return -1;
222 break;
223 case DE_EXTENT:
224 fd = extent_open(dp->xv[i].u.xp, flags, mode);
225 if (fd < 0) {
226 return -1;
228 break;
229 default:
230 break;
233 return fd;
236 /* and for the undecided... */
237 static int
238 de_open(disc_de_t *dp, int flags, int mode)
240 switch(dp->type) {
241 case DE_DEVICE:
242 return device_open(dp->u.dp, flags, mode);
243 case DE_EXTENT:
244 return extent_open(dp->u.xp, flags, mode);
245 default:
246 return -1;
250 /* lseek on the extent */
251 static off_t
252 extent_lseek(disc_extent_t *xp, off_t off, int whence)
254 return lseek(xp->fd, (long long)(xp->sacred + off), whence);
257 /* (recursively) lseek on the device's devices */
258 static off_t
259 device_lseek(disc_device_t *dp, off_t off, int whence)
261 uint64_t suboff;
262 off_t ret;
263 uint32_t d;
265 ret = -1;
266 switch(dp->raid) {
267 case 0:
268 if (raid0_getoff(dp, (uint64_t) off, &d, &suboff)) {
269 switch (dp->xv[d].type) {
270 case DE_DEVICE:
271 ret = device_lseek(dp->xv[d].u.dp,
272 (off_t) suboff, whence);
273 if (ret < 0) {
274 return -1;
276 break;
277 case DE_EXTENT:
278 ret = extent_lseek(dp->xv[d].u.xp,
279 (off_t) suboff, whence);
280 if (ret < 0) {
281 return -1;
283 break;
284 default:
285 break;
288 break;
289 case 1:
290 for (d = 0 ; d < dp->c ; d++) {
291 switch (dp->xv[d].type) {
292 case DE_DEVICE:
293 ret = device_lseek(dp->xv[d].u.dp, (off_t)off,
294 whence);
295 if (ret < 0) {
296 return -1;
298 break;
299 case DE_EXTENT:
300 ret = extent_lseek(dp->xv[d].u.xp, (off_t)off,
301 whence);
302 if (ret < 0) {
303 return -1;
305 break;
306 default:
307 break;
310 break;
311 default:
312 break;
314 return dp->off = ret;
317 /* and for the undecided... */
318 static off_t
319 de_lseek(disc_de_t *dp, off_t off, int whence)
321 switch(dp->type) {
322 case DE_DEVICE:
323 return device_lseek(dp->u.dp, off, whence);
324 case DE_EXTENT:
325 return extent_lseek(dp->u.xp, off, whence);
326 default:
327 return -1;
331 /* fsync_range on the extent */
332 static int
333 extent_fsync_range(disc_extent_t *xp, int how, off_t from, off_t len)
335 #ifdef HAVE_FSYNC_RANGE
336 return fsync_range(xp->fd, how, (off_t)(xp->sacred + from), len);
337 #else
338 return fsync(xp->fd);
339 #endif
342 /* (recursively) fsync_range on the device's devices */
343 static int
344 device_fsync_range(disc_device_t *dp, int how, off_t from, off_t len)
346 uint64_t suboff;
347 int ret;
348 uint32_t d;
350 ret = -1;
351 switch(dp->raid) {
352 case 0:
353 if (raid0_getoff(dp, (uint64_t) from, &d, &suboff)) {
354 switch (dp->xv[d].type) {
355 case DE_DEVICE:
356 ret = device_fsync_range(dp->xv[d].u.dp, how,
357 (off_t)suboff, len);
358 if (ret < 0) {
359 return -1;
361 break;
362 case DE_EXTENT:
363 ret = extent_fsync_range(dp->xv[d].u.xp, how,
364 (off_t)suboff, len);
365 if (ret < 0) {
366 return -1;
368 break;
369 default:
370 break;
373 break;
374 case 1:
375 for (d = 0 ; d < dp->c ; d++) {
376 switch (dp->xv[d].type) {
377 case DE_DEVICE:
378 ret = device_fsync_range(dp->xv[d].u.dp, how,
379 from, len);
380 if (ret < 0) {
381 return -1;
383 break;
384 case DE_EXTENT:
385 ret = extent_fsync_range(dp->xv[d].u.xp, how,
386 from, len);
387 if (ret < 0) {
388 return -1;
390 break;
391 default:
392 break;
395 break;
396 default:
397 break;
399 dp->off = (uint64_t) ret;
400 return ret;
403 /* and for the undecided... */
404 static int
405 de_fsync_range(disc_de_t *dp, int how, off_t from, off_t len)
407 switch(dp->type) {
408 case DE_DEVICE:
409 return device_fsync_range(dp->u.dp, how, from, len);
410 case DE_EXTENT:
411 return extent_fsync_range(dp->u.xp, how, from, len);
412 default:
413 return -1;
417 /* read from the extent */
418 static ssize_t
419 extent_read(disc_extent_t *xp, void *buf, size_t cc)
421 return read(xp->fd, buf, cc);
424 /* (recursively) read from the device's devices */
425 static ssize_t
426 device_read(disc_device_t *dp, void *buf, size_t cc)
428 uint64_t suboff;
429 uint64_t got;
430 uint32_t d;
431 ssize_t ret;
432 size_t subcc;
433 char *cbuf;
435 ret = -1;
436 switch(dp->raid) {
437 case 0:
438 for (cbuf = (char *) buf, got = 0 ; got < cc ; got += ret) {
439 if (!raid0_getoff(dp, dp->off, &d, &suboff)) {
440 return -1;
442 if (device_lseek(dp, (off_t)dp->off, SEEK_SET) < 0) {
443 return -1;
445 subcc = MIN(cc - (size_t)got,
446 (size_t)(dp->len - (size_t)dp->off));
447 switch (dp->xv[d].type) {
448 case DE_DEVICE:
449 ret = device_read(dp->xv[d].u.dp,
450 &cbuf[(int)got], subcc);
451 if (ret < 0) {
452 return -1;
454 break;
455 case DE_EXTENT:
456 ret = extent_read(dp->xv[d].u.xp,
457 &cbuf[(int)got], subcc);
458 if (ret < 0) {
459 return -1;
461 break;
462 default:
463 break;
465 dp->off += ret;
467 ret = (ssize_t)got;
468 break;
469 case 1:
470 for (d = 0 ; d < dp->c ; d++) {
471 switch (dp->xv[d].type) {
472 case DE_DEVICE:
473 ret = device_read(dp->xv[d].u.dp, buf, cc);
474 if (ret < 0) {
475 return -1;
477 break;
478 case DE_EXTENT:
479 ret = extent_read(dp->xv[d].u.xp, buf, cc);
480 if (ret < 0) {
481 return -1;
483 break;
484 default:
485 break;
488 dp->off += ret;
489 break;
490 default:
491 break;
493 return ret;
496 /* and for the undecided... */
497 static ssize_t
498 de_read(disc_de_t *dp, void *buf, size_t cc)
500 switch(dp->type) {
501 case DE_DEVICE:
502 return device_read(dp->u.dp, buf, cc);
503 case DE_EXTENT:
504 return extent_read(dp->u.xp, buf, cc);
505 default:
506 return -1;
510 /* write to the extent */
511 static ssize_t
512 extent_write(disc_extent_t *xp, void *buf, size_t cc)
514 return write(xp->fd, buf, cc);
517 /* (recursively) write to the device's devices */
518 static ssize_t
519 device_write(disc_device_t *dp, void *buf, size_t cc)
521 uint64_t suboff;
522 uint64_t done;
523 uint32_t d;
524 ssize_t ret;
525 size_t subcc;
526 char *cbuf;
528 ret = -1;
529 switch(dp->raid) {
530 case 0:
531 for (cbuf = (char *) buf, done = 0 ; done < cc ; done += ret) {
532 if (!raid0_getoff(dp, dp->off, &d, &suboff)) {
533 return -1;
535 subcc = (size_t)MIN(cc - (size_t)done,
536 (size_t)(dp->len - dp->off));
537 if (device_lseek(dp, (off_t)dp->off, SEEK_SET) < 0) {
538 return -1;
540 switch (dp->xv[d].type) {
541 case DE_DEVICE:
542 ret = device_write(dp->xv[d].u.dp,
543 &cbuf[(int)done], subcc);
544 if (ret < 0) {
545 return -1;
547 break;
548 case DE_EXTENT:
549 ret = extent_write(dp->xv[d].u.xp,
550 &cbuf[(int)done], subcc);
551 if (ret < 0) {
552 return -1;
554 break;
555 default:
556 break;
558 dp->off += ret;
560 ret = (ssize_t) done;
561 break;
562 case 1:
563 for (d = 0 ; d < dp->c ; d++) {
564 switch (dp->xv[d].type) {
565 case DE_DEVICE:
566 ret = device_write(dp->xv[d].u.dp, buf, cc);
567 if (ret < 0) {
568 iscsi_err(__FILE__, __LINE__,
569 "device_write RAID1 device "
570 "write failure\n");
571 return -1;
573 break;
574 case DE_EXTENT:
575 ret = extent_write(dp->xv[d].u.xp, buf, cc);
576 if (ret < 0) {
577 iscsi_err(__FILE__, __LINE__,
578 "device_write RAID1 extent "
579 "write failure\n");
580 return -1;
582 break;
583 default:
584 break;
587 dp->off += ret;
588 break;
589 default:
590 break;
592 return ret;
595 /* and for the undecided... */
596 static ssize_t
597 de_write(disc_de_t *dp, void *buf, size_t cc)
599 switch(dp->type) {
600 case DE_DEVICE:
601 return device_write(dp->u.dp, buf, cc);
602 case DE_EXTENT:
603 return extent_write(dp->u.xp, buf, cc);
604 default:
605 return -1;
609 /* return non-zero if the target is writable */
610 static int
611 target_writable(disc_target_t *tp)
613 return !(tp->flags & TARGET_READONLY);
616 /* return size of the extent */
617 static uint64_t
618 extent_getsize(disc_extent_t *xp)
620 return xp->len;
623 /* (recursively) return the size of the device's devices */
624 static uint64_t
625 device_getsize(disc_device_t *dp)
627 uint64_t size;
628 uint32_t d;
630 size = 0;
631 switch(dp->raid) {
632 case 0:
633 for (d = 0 ; d < dp->c ; d++) {
634 switch (dp->xv[d].type) {
635 case DE_DEVICE:
636 size += device_getsize(dp->xv[d].u.dp);
637 break;
638 case DE_EXTENT:
639 size += extent_getsize(dp->xv[d].u.xp);
640 break;
641 default:
642 break;
645 break;
646 case 1:
647 size = dp->len;
648 break;
649 default:
650 break;
652 return size;
655 /* and for the undecided... */
656 static int64_t
657 de_getsize(disc_de_t *dp)
659 switch(dp->type) {
660 case DE_DEVICE:
661 return device_getsize(dp->u.dp);
662 case DE_EXTENT:
663 return extent_getsize(dp->u.xp);
664 default:
665 return -1;
669 /* return a filename for the device or extent */
670 static char *
671 disc_get_filename(disc_de_t *de)
673 switch (de->type) {
674 case DE_EXTENT:
675 return de->u.xp->dev;
676 case DE_DEVICE:
677 return disc_get_filename(&de->u.dp->xv[0]);
678 default:
679 return NULL;
684 * Public Interface (called by utarget and ktarket)
687 /* set various global variables */
688 void
689 device_set_var(const char *var, const char *arg)
691 if (strcmp(var, "blocklen") == 0) {
692 defaults.blocklen = strtoll(arg, (char **)NULL, 10);
693 } else if (strcmp(var, "blocks") == 0) {
694 defaults.blockc = strtoll(arg, (char **)NULL, 10);
695 } else if (strcmp(var, "luns") == 0) {
696 defaults.luns = strtoll(arg, (char **)NULL, 10);
697 } else {
698 (void) fprintf(stderr, "Unrecognised variable: `%s'\n", var);
702 /* allocate some space for a disk/extent, using an lseek, read and
703 * write combination */
704 static int
705 de_allocate(disc_de_t *de, char *filename)
707 off_t size;
708 char block[DEFAULT_TARGET_BLOCK_LEN];
710 size = de_getsize(de);
711 if (de_lseek(de, size - sizeof(block), SEEK_SET) == -1) {
712 iscsi_err(__FILE__, __LINE__,
713 "error seeking \"%s\"\n", filename);
714 return 0;
716 if (de_read(de, block, sizeof(block)) == -1) {
717 iscsi_err(__FILE__, __LINE__,
718 "error reading \"%s\"", filename);
719 return 0;
721 if (de_write(de, block, sizeof(block)) == -1) {
722 iscsi_err(__FILE__, __LINE__,
723 "error writing \"%s\"", filename);
724 return 0;
726 return 1;
729 /* allocate space as desired */
730 static int
731 allocate_space(disc_target_t *tp)
733 uint32_t i;
735 /* Don't perform check for writability in the target here, as the
736 following write() in de_allocate is non-destructive */
737 switch(tp->de.type) {
738 case DE_EXTENT:
739 return de_allocate(&tp->de, tp->target);
740 case DE_DEVICE:
741 for (i = 0 ; i < tp->de.u.dp->c ; i++) {
742 if (!de_allocate(&tp->de.u.dp->xv[i], tp->target)) {
743 return 0;
746 return 1;
747 default:
748 break;
750 return 0;
753 /* copy src to dst, of size `n' bytes, padding any extra with `pad' */
754 static void
755 strpadcpy(uint8_t *dst, size_t dstlen, const char *src, const size_t srclen,
756 char pad)
758 if (srclen < dstlen) {
759 (void) memcpy(dst, src, srclen);
760 (void) memset(&dst[srclen], pad, dstlen - srclen);
761 } else {
762 (void) memcpy(dst, src, dstlen);
766 /* handle REPORT LUNs SCSI command */
767 static int
768 report_luns(uint64_t *data, int64_t luns)
770 uint64_t i;
771 int32_t off;
773 for (i = 0, off = 8 ; i < (uint64_t)luns ; i++, off += sizeof(i)) {
774 data[(int)i] = ISCSI_HTONLL(i);
776 return off;
779 /* handle persistent reserve in command */
780 static int
781 persistent_reserve_in(uint8_t action, uint8_t *data)
783 uint64_t key;
785 switch(action) {
786 case PERSISTENT_RESERVE_IN_READ_KEYS:
787 key = 0; /* simulate "just powered on" */
788 *((uint32_t *)(void *)data) =
789 (uint32_t)ISCSI_HTONL((uint32_t) 0);
790 *((uint32_t *) (void *)data + 4) =
791 (uint32_t) ISCSI_HTONL((uint32_t) sizeof(key));
792 /* length in bytes of list of keys */
793 *((uint64_t *) (void *)data + 8) = (uint64_t) ISCSI_HTONLL(key);
794 return 8 + sizeof(key);
795 case PERSISTENT_RESERVE_IN_REPORT_CAPABILITIES:
796 (void) memset(data, 0x0, 8);
797 /* length is fixed at 8 bytes */
798 *((uint16_t *)(void *)data) =
799 (uint16_t)ISCSI_HTONS((uint16_t)8);
800 data[2] = PERSISTENT_RESERVE_IN_CRH;
801 /* also SIP_C, ATP_C and PTPL_C here */
802 data[3] = 0; /* also TMV and PTPL_A here */
803 data[4] = 0;
804 /* also WR_EX_AR, EX_AC_RD, WR_EX_RD, EX_AC, WR_EX */
805 data[5] = 0; /* also EX_AC_AR here */
806 return 8;
807 default:
808 iscsi_err(__FILE__, __LINE__,
809 "persistent_reserve_in: action %x unrecognised\n",
810 action);
811 return 0;
815 /* initialise the device */
816 int
817 device_init(iscsi_target_t *tgt, targv_t *tvp, disc_target_t *tp)
819 iscsi_disk_t *idisk;
820 int mode;
822 ALLOC(iscsi_disk_t, disks.v, disks.size, disks.c, 10, 10,
823 "device_init", ;);
824 idisk = &disks.v[disks.c];
825 idisk->lunv = tvp;
826 if ((idisk->luns = defaults.luns) == 0) {
827 idisk->luns = iSCSI_DEFAULT_LUNS;
829 idisk->blocklen = atoi(iscsi_target_getvar(tgt, "blocklen"));
830 switch(idisk->blocklen) {
831 case 512:
832 case 1024:
833 case 2048:
834 case 4096:
835 case 8192:
836 break;
837 default:
838 iscsi_err(__FILE__, __LINE__,
839 "Invalid block len %" PRIu64
840 ". Choose one of 512, 1024, 2048, 4096, or 8192.\n",
841 idisk->blocklen);
842 return -1;
844 idisk->size = de_getsize(&tp->de);
845 idisk->blockc = idisk->size / idisk->blocklen;
846 NEWARRAY(uint8_t, idisk->buffer, MB(1), "buffer1", ;);
847 idisk->type = ISCSI_FS;
848 printf("DISK: %" PRIu64 " logical unit%s (%" PRIu64 " blocks, %"
849 PRIu64 " bytes/block), type %s\n",
850 idisk->luns,
851 (idisk->luns == 1) ? "" : "s",
852 idisk->blockc, idisk->blocklen,
853 (idisk->type == ISCSI_FS) ? "iscsi fs" :
854 "iscsi fs mmap");
855 printf("DISK: LUN 0: ");
856 (void) strlcpy(idisk->filename, disc_get_filename(&tp->de),
857 sizeof(idisk->filename));
858 mode = (tp->flags & TARGET_READONLY) ? O_RDONLY : (O_CREAT | O_RDWR);
859 if (de_open(&tp->de, mode, 0666) == -1) {
860 iscsi_err(__FILE__, __LINE__,
861 "error opening \"%s\"\n", idisk->filename);
862 return -1;
864 if (!(tp->flags & TARGET_READONLY) && !allocate_space(tp)) {
865 iscsi_err(__FILE__, __LINE__,
866 "error allocating space for \"%s\"", tp->target);
867 return -1;
869 printf("%" PRIu64 " MB %sdisk storage for \"%s\"\n",
870 (de_getsize(&tp->de) / MB(1)),
871 (tp->flags & TARGET_READONLY) ? "readonly " : "",
872 tp->target);
873 return disks.c++;
876 static void
877 cdb2lba(uint32_t *lba, uint16_t *len, uint8_t *cdb)
879 /* Some platforms (like strongarm) aligns on */
880 /* word boundaries. So HTONL and NTOHL won't */
881 /* work here. */
882 int little_endian = 1;
884 if (*(char *) (void *) &little_endian) {
885 /* little endian */
886 ((uint8_t *) (void *) lba)[0] = cdb[5];
887 ((uint8_t *) (void *) lba)[1] = cdb[4];
888 ((uint8_t *) (void *) lba)[2] = cdb[3];
889 ((uint8_t *) (void *) lba)[3] = cdb[2];
890 ((uint8_t *) (void *) len)[0] = cdb[8];
891 ((uint8_t *) (void *) len)[1] = cdb[7];
892 } else {
893 ((uint8_t *) (void *) lba)[0] = cdb[2];
894 ((uint8_t *) (void *) lba)[1] = cdb[3];
895 ((uint8_t *) (void *) lba)[2] = cdb[4];
896 ((uint8_t *) (void *) lba)[3] = cdb[5];
897 ((uint8_t *) (void *) len)[0] = cdb[7];
898 ((uint8_t *) (void *) len)[1] = cdb[8];
902 /* handle MODE_SENSE_6 and MODE_SENSE_10 commands */
903 static int
904 mode_sense(const int bytes, target_cmd_t *cmd)
906 iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd;
907 uint16_t len;
908 uint8_t *cp;
909 uint8_t *cdb = args->cdb;
910 size_t mode_data_len;
912 switch(bytes) {
913 case 6:
914 cp = args->send_data;
915 len = ISCSI_MODE_SENSE_LEN;
916 mode_data_len = len + 3;
918 iscsi_trace(TRACE_SCSI_CMD, "MODE_SENSE_6\n");
919 (void) memset(cp, 0x0, mode_data_len);
921 cp[0] = mode_data_len;
922 cp[1] = 0;
923 cp[2] = 0;
924 cp[3] = 8; /* block descriptor length */
925 cp[10] = 2; /* density code and block length */
927 args->input = 1;
928 args->length = (unsigned)len;
929 args->status = SCSI_SUCCESS;
930 return 1;
931 case 10:
932 cp = args->send_data;
933 len = ISCSI_MODE_SENSE_LEN;
934 mode_data_len = len + 3;
936 iscsi_trace(TRACE_SCSI_CMD, "MODE_SENSE_10\n");
937 (void) memset(cp, 0x0, mode_data_len);
938 if (cdb[4] == 0) {
939 /* zero length cdb means just return success */
940 args->input = 1;
941 args->length = (unsigned)(mode_data_len);
942 args->status = SCSI_SUCCESS;
943 return 1;
945 if ((cdb[2] & PAGE_CONTROL_MASK) ==
946 PAGE_CONTROL_CHANGEABLE_VALUES) {
947 /* just send back a CHECK CONDITION */
948 args->input = 1;
949 args->length = (unsigned)(len);
950 args->status = SCSI_CHECK_CONDITION;
951 cp[2] = SCSI_SKEY_ILLEGAL_REQUEST;
952 cp[12] = ASC_LUN_UNSUPPORTED;
953 cp[13] = ASCQ_LUN_UNSUPPORTED;
954 return 1;
956 iscsi_trace(TRACE_SCSI_CMD, "PC %02x\n", cdb[2]);
958 cp[0] = mode_data_len;
959 cp[1] = 0;
960 cp[2] = 0;
961 cp[3] = 8; /* block descriptor length */
962 cp[10] = 2; /* density code and block length */
964 args->input = 1;
965 args->length = (unsigned)(len);
966 args->status = SCSI_SUCCESS;
967 return 1;
969 return 0;
972 /* fill in the device serial number vital product data */
973 static uint8_t
974 serial_vpd(uint8_t *data)
976 uint8_t len;
978 data[0] = DISK_PERIPHERAL_DEVICE;
979 data[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
980 len = 16;
981 /* add target device's Unit Serial Number */
982 /* section 7.6.10 of SPC-3 says that if there is no serial number,
983 * use spaces */
984 strpadcpy(&data[4], (size_t)len, " ", strlen(" "), ' ');
985 return len;
988 /* fill in the device identification vital product data */
989 static void
990 device_vpd(iscsi_target_t *tgt, uint8_t *data, uint8_t *rspc,
991 uint8_t *cdbsize, uint8_t lun, char *uuid)
993 uint16_t len;
994 uint8_t *cp;
996 data[0] = DISK_PERIPHERAL_DEVICE;
997 data[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
998 *rspc = 0;
999 cp = &data[4];
1000 /* add target device's IQN */
1001 cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
1002 INQUIRY_DEVICE_CODESET_UTF8;
1003 cp[1] = (INQUIRY_DEVICE_PIV << 7) |
1004 (INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE << 4) |
1005 INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
1006 len = (uint8_t) snprintf((char *)&cp[4],
1007 (unsigned)(*cdbsize - (int)(cp - &data[4])), "%s",
1008 iscsi_target_getvar(tgt, "iqn"));
1009 cp[3] = len;
1010 *rspc += len + 4;
1011 cp += len + 4;
1012 /* add target port's IQN + LUN */
1013 cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
1014 INQUIRY_DEVICE_CODESET_UTF8;
1015 cp[1] = (INQUIRY_DEVICE_PIV << 7) |
1016 (INQUIRY_DEVICE_ASSOCIATION_TARGET_PORT << 4) |
1017 INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
1018 len = (uint8_t) snprintf((char *)&cp[4],
1019 (unsigned)(*cdbsize - (int)(cp - &data[4])),
1020 "%s,t,%#x",
1021 iscsi_target_getvar(tgt, "iqn"),
1022 lun);
1023 cp[3] = len;
1024 *rspc += len + 4;
1025 cp += len + 4;
1026 /* add target port's IQN + LUN extension */
1027 cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
1028 INQUIRY_DEVICE_CODESET_UTF8;
1029 cp[1] = (INQUIRY_DEVICE_PIV << 7) |
1030 (INQUIRY_DEVICE_ASSOCIATION_LOGICAL_UNIT << 4) |
1031 INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
1032 len = (uint8_t) snprintf((char *)&cp[4],
1033 (unsigned) (*cdbsize - (int)(cp - &data[4])),
1034 "%s,L,0x%8.8s%4.4s%4.4s",
1035 iscsi_target_getvar(tgt, "iqn"),
1036 uuid, &uuid[9], &uuid[14]);
1037 cp[3] = len;
1038 *rspc += len + 4;
1039 cp += len + 4;
1040 /* add target's uuid as a T10 identifier */
1041 cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
1042 INQUIRY_DEVICE_CODESET_UTF8;
1043 cp[1] = (INQUIRY_DEVICE_PIV << 7) |
1044 (INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE << 4) |
1045 INQUIRY_IDENTIFIER_TYPE_T10;
1046 strpadcpy(&cp[4], 8, ISCSI_VENDOR, strlen(ISCSI_VENDOR), ' ');
1047 len = 8;
1048 len += (uint8_t) snprintf((char *)&cp[8 + 4],
1049 (unsigned)(*cdbsize - (int)(cp - &data[4])),
1050 "0x%8.8s%4.4s%4.4s",
1051 uuid, &uuid[9], &uuid[14]);
1052 cp[3] = len;
1053 *rspc += len + 4;
1056 static void
1057 version_inquiry(uint8_t *data, uint8_t *cdbsize)
1059 char versionstr[8];
1061 data[0] = DISK_PERIPHERAL_DEVICE;
1062 data[2] = SCSI_VERSION_SPC;
1063 data[4] = *cdbsize - 4; /* Additional length */
1064 data[7] |= (WIDE_BUS_32 | WIDE_BUS_16);
1065 strpadcpy(&data[8], 8, ISCSI_VENDOR, strlen(ISCSI_VENDOR), ' ');
1066 strpadcpy(&data[16], 16, ISCSI_PRODUCT, strlen(ISCSI_PRODUCT), ' ');
1067 (void) snprintf(versionstr, sizeof(versionstr), "%d", ISCSI_VERSION);
1068 strpadcpy(&data[32], 4, versionstr, strlen(versionstr), ' ');
1071 int
1072 device_command(target_session_t *sess, target_cmd_t *cmd)
1074 iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd;
1075 uint32_t status;
1076 uint32_t lba;
1077 uint16_t len;
1078 uint8_t *cdbsize;
1079 uint8_t *rspc;
1080 uint8_t *data;
1081 uint8_t *cdb;
1082 uint8_t lun;
1084 cdb = args->cdb;
1085 lun = (uint8_t) (args->lun >> 32);
1086 cdbsize = &cdb[4];
1089 * added section to return no device equivalent for lun request
1090 * beyond available lun
1092 if (lun >= disks.v[sess->d].luns) {
1093 data = args->send_data;
1094 (void) memset(data, 0x0, (size_t) *cdbsize);
1096 * data[0] = 0x7F; means no device
1098 data[0] = 0x1F; /* device type */
1099 data[0] |= 0x60;/* peripheral qualifier */
1100 args->input = 1;
1101 args->length = cdb[4] + 1;
1102 args->status = SCSI_SUCCESS;
1103 return 0;
1106 lun = (uint8_t) sess->d;
1107 iscsi_trace(TRACE_SCSI_CMD, "SCSI op %#x (lun %d): \n", cdb[0], lun);
1109 switch (cdb[0]) {
1110 case TEST_UNIT_READY:
1111 iscsi_trace(TRACE_SCSI_CMD, "TEST_UNIT_READY\n");
1112 args->status = SCSI_SUCCESS;
1113 args->length = 0;
1114 break;
1116 case INQUIRY:
1117 iscsi_trace(TRACE_SCSI_CMD, "INQUIRY%s\n",
1118 (cdb[1] & INQUIRY_EVPD_BIT) ?
1119 " for Vital Product Data" : "");
1120 data = args->send_data;
1121 args->status = SCSI_SUCCESS;
1122 /* Clear allocated buffer */
1123 (void) memset(data, 0x0, (unsigned) *cdbsize);
1124 if (cdb[1] & INQUIRY_EVPD_BIT) {
1125 rspc = &data[3];
1126 switch(cdb[2]) {
1127 case INQUIRY_UNIT_SERIAL_NUMBER_VPD:
1128 *rspc = serial_vpd(data);
1129 args->length = 16;
1130 break;
1131 case INQUIRY_DEVICE_IDENTIFICATION_VPD:
1132 if (disks.v[sess->d].uuid_string == NULL) {
1133 nbuuid_create(&disks.v[sess->d].uuid,
1134 &status);
1135 nbuuid_to_string(&disks.v[sess->d].uuid,
1136 &disks.v[sess->d].uuid_string,
1137 &status);
1139 device_vpd(sess->target, data, rspc, cdbsize,
1140 lun, disks.v[sess->d].uuid_string);
1141 args->length = *rspc + 6;
1142 break;
1143 case INQUIRY_SUPPORTED_VPD_PAGES:
1144 data[0] = DISK_PERIPHERAL_DEVICE;
1145 data[1] = INQUIRY_SUPPORTED_VPD_PAGES;
1146 *rspc = 3; /* # of supported pages */
1147 data[4] = INQUIRY_SUPPORTED_VPD_PAGES;
1148 data[5] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
1149 data[6] = EXTENDED_INQUIRY_DATA_VPD;
1150 args->length = *cdbsize + 1;
1151 break;
1152 case EXTENDED_INQUIRY_DATA_VPD:
1153 data[0] = DISK_PERIPHERAL_DEVICE;
1154 data[1] = EXTENDED_INQUIRY_DATA_VPD;
1155 data[3] = 0x3c; /* length is defined to be 60 */
1156 data[4] = 0;
1157 data[5] = 0;
1158 args->length = 64;
1159 break;
1160 default:
1161 iscsi_err(__FILE__, __LINE__,
1162 "Unsupported INQUIRY VPD page %x\n",
1163 cdb[2]);
1164 args->status = SCSI_CHECK_CONDITION;
1165 break;
1167 } else {
1168 version_inquiry(data, cdbsize);
1169 args->length = cdb[4] + 1;
1171 if (args->status == SCSI_SUCCESS) {
1172 args->input = 1;
1174 break;
1176 case MODE_SELECT_6:
1177 iscsi_trace(TRACE_SCSI_CMD, "MODE_SELECT_6\n");
1178 args->status = SCSI_SUCCESS;
1179 args->length = 0;
1180 break;
1182 case STOP_START_UNIT:
1183 iscsi_trace(TRACE_SCSI_CMD, "STOP_START_UNIT\n");
1184 args->status = SCSI_SUCCESS;
1185 args->length = 0;
1186 break;
1188 case READ_CAPACITY:
1189 iscsi_trace(TRACE_SCSI_CMD, "READ_CAPACITY\n");
1190 data = args->send_data;
1191 *((uint32_t *)(void *)data) = (uint32_t) ISCSI_HTONL(
1192 (uint32_t) disks.v[sess->d].blockc - 1);
1193 /* Max LBA */
1194 *((uint32_t *)(void *)(data + 4)) = (uint32_t) ISCSI_HTONL(
1195 (uint32_t) disks.v[sess->d].blocklen);
1196 /* Block len */
1197 args->input = 8;
1198 args->length = 8;
1199 args->status = SCSI_SUCCESS;
1200 break;
1202 case WRITE_6:
1203 lba = ISCSI_NTOHL(*((uint32_t *) (void *)cdb)) & 0x001fffff;
1204 if ((len = *cdbsize) == 0) {
1205 len = 256;
1207 iscsi_trace(TRACE_SCSI_CMD,
1208 "WRITE_6(lba %u, len %u blocks)\n", lba, len);
1209 if (disk_write(sess, args, lun, lba, (unsigned) len) != 0) {
1210 iscsi_err(__FILE__, __LINE__,
1211 "disk_write() failed\n");
1212 args->status = SCSI_CHECK_CONDITION;
1214 args->length = 0;
1215 break;
1218 case READ_6:
1219 lba = ISCSI_NTOHL(*((uint32_t *)(void *)cdb)) & 0x001fffff;
1220 if ((len = *cdbsize) == 0) {
1221 len = 256;
1223 iscsi_trace(TRACE_SCSI_CMD,
1224 "READ_6(lba %u, len %u blocks)\n", lba, len);
1225 if (disk_read(sess, args, lba, len, lun) != 0) {
1226 iscsi_err(__FILE__, __LINE__,
1227 "disk_read() failed\n");
1228 args->status = SCSI_CHECK_CONDITION;
1230 args->input = 1;
1231 break;
1233 case MODE_SENSE_6:
1234 mode_sense(6, cmd);
1235 break;
1237 case WRITE_10:
1238 case WRITE_VERIFY:
1239 cdb2lba(&lba, &len, cdb);
1241 iscsi_trace(TRACE_SCSI_CMD,
1242 "WRITE_10 | WRITE_VERIFY(lba %u, len %u blocks)\n",
1243 lba, len);
1244 if (disk_write(sess, args, lun, lba, (unsigned) len) != 0) {
1245 iscsi_err(__FILE__, __LINE__,
1246 "disk_write() failed\n");
1247 args->status = SCSI_CHECK_CONDITION;
1249 args->length = 0;
1250 break;
1252 case READ_10:
1253 cdb2lba(&lba, &len, cdb);
1254 iscsi_trace(TRACE_SCSI_CMD,
1255 "READ_10(lba %u, len %u blocks)\n", lba, len);
1256 if (disk_read(sess, args, lba, len, lun) != 0) {
1257 iscsi_err(__FILE__, __LINE__,
1258 "disk_read() failed\n");
1259 args->status = SCSI_CHECK_CONDITION;
1261 args->input = 1;
1262 break;
1264 case VERIFY:
1265 /* For now just set the status to success. */
1266 args->status = SCSI_SUCCESS;
1267 break;
1269 case SYNC_CACHE:
1270 cdb2lba(&lba, &len, cdb);
1271 iscsi_trace(TRACE_SCSI_CMD,
1272 "SYNC_CACHE (lba %u, len %u blocks)\n", lba, len);
1273 if (de_fsync_range(&disks.v[sess->d].lunv->v[lun].de,
1274 FDATASYNC, lba,
1275 (off_t)(len * disks.v[sess->d].blocklen)) < 0) {
1276 iscsi_err(__FILE__, __LINE__,
1277 "disk_read() failed\n");
1278 args->status = SCSI_CHECK_CONDITION;
1279 } else {
1280 args->status = SCSI_SUCCESS;
1281 args->length = 0;
1283 break;
1285 case LOG_SENSE:
1286 iscsi_trace(TRACE_SCSI_CMD, "LOG_SENSE\n");
1287 args->status = SCSI_SUCCESS;
1288 args->length = 0;
1289 break;
1291 case MODE_SENSE_10:
1292 mode_sense(10, cmd);
1293 break;
1295 case MODE_SELECT_10:
1296 /* XXX still to do */
1297 iscsi_trace(TRACE_SCSI_CMD, "MODE_SELECT_10\n");
1298 args->status = SCSI_SUCCESS;
1299 args->length = 0;
1300 break;
1302 case PERSISTENT_RESERVE_IN:
1303 iscsi_trace(TRACE_SCSI_CMD, "PERSISTENT_RESERVE_IN\n");
1304 args->length = persistent_reserve_in((cdb[1] &
1305 PERSISTENT_RESERVE_IN_SERVICE_ACTION_MASK),
1306 args->send_data);
1307 args->status = SCSI_SUCCESS;
1308 break;
1310 case REPORT_LUNS:
1311 iscsi_trace(TRACE_SCSI_CMD, "REPORT LUNS\n");
1312 args->length = report_luns(
1313 (uint64_t *)(void *)&args->send_data[8],
1314 (off_t)disks.v[sess->d].luns);
1315 *((uint32_t *)(void *)args->send_data) =
1316 ISCSI_HTONL(disks.v[sess->d].luns *
1317 sizeof(uint64_t));
1318 args->input = 8;
1319 args->status = SCSI_SUCCESS;
1320 break;
1322 case RESERVE_6:
1323 iscsi_trace(TRACE_SCSI_CMD, "RESERVE_6\n");
1324 args->status = SCSI_SUCCESS;
1325 args->length = 0;
1326 break;
1328 case RELEASE_6:
1329 iscsi_trace(TRACE_SCSI_CMD, "RELEASE_6\n");
1330 args->status = SCSI_SUCCESS;
1331 args->length = 0;
1332 break;
1334 case RESERVE_10:
1335 iscsi_trace(TRACE_SCSI_CMD, "RESERVE_10\n");
1336 args->status = SCSI_SUCCESS;
1337 args->length = 0;
1338 break;
1340 case RELEASE_10:
1341 iscsi_trace(TRACE_SCSI_CMD, "RELEASE_10\n");
1342 args->status = SCSI_SUCCESS;
1343 args->length = 0;
1344 break;
1346 default:
1347 iscsi_err(__FILE__, __LINE__,
1348 "UNKNOWN OPCODE %#x\n", cdb[0]);
1349 /* to not cause confusion with some initiators */
1350 args->status = SCSI_CHECK_CONDITION;
1351 break;
1353 iscsi_trace(TRACE_SCSI_DEBUG,
1354 "SCSI op %#x: done (status %#x)\n", cdb[0], args->status);
1355 return 0;
1358 int
1359 device_shutdown(target_session_t *sess)
1361 USE_ARG(sess);
1362 return 1;
1366 * Private Interface
1369 static int
1370 disk_write(target_session_t *sess, iscsi_scsi_cmd_args_t *args, uint8_t lun,
1371 uint32_t lba, uint32_t len)
1373 struct iovec sg;
1374 uint64_t byte_offset;
1375 uint64_t bytec;
1376 uint8_t *ptr;
1378 byte_offset = lba * disks.v[sess->d].blocklen;
1379 bytec = len * disks.v[sess->d].blocklen;
1380 ptr = NULL;
1381 iscsi_trace(TRACE_SCSI_DATA,
1382 "writing %" PRIu64
1383 " bytes from socket into device at byte offset %" PRIu64 "\n",
1384 bytec, byte_offset);
1386 if ((unsigned) bytec > MB(1)) {
1387 iscsi_err(__FILE__, __LINE__, "bytec > %u\n", bytec);
1388 NO_CLEANUP;
1389 return -1;
1392 /* Assign ptr for write data */
1393 ptr = disks.v[sess->d].buffer;
1395 /* Have target do data transfer */
1396 sg.iov_base = ptr;
1397 sg.iov_len = (unsigned)bytec;
1398 if (target_transfer_data(sess, args, &sg, 1) != 0) {
1399 iscsi_err(__FILE__, __LINE__,
1400 "target_transfer_data() failed\n");
1402 /* Finish up write */
1403 if (de_lseek(&disks.v[sess->d].lunv->v[lun].de, (off_t)byte_offset,
1404 SEEK_SET) == -1) {
1405 iscsi_err(__FILE__, __LINE__,
1406 "lseek() to offset %" PRIu64 " failed\n",
1407 byte_offset);
1408 return -1;
1410 if (!target_writable(&disks.v[sess->d].lunv->v[lun])) {
1411 iscsi_err(__FILE__, __LINE__,
1412 "write() of %" PRIu64 " bytes failed at offset %"
1413 PRIu64 ", size %" PRIu64 "[READONLY TARGET]\n",
1414 bytec, byte_offset,
1415 de_getsize(&disks.v[sess->d].lunv->v[lun].de));
1416 return -1;
1418 if ((uint64_t)de_write(&disks.v[sess->d].lunv->v[lun].de, ptr,
1419 (unsigned) bytec) != bytec) {
1420 iscsi_err(__FILE__, __LINE__,
1421 "write() of %" PRIu64 " bytes failed at offset %"
1422 PRIu64 ", size %" PRIu64 "\n",
1423 bytec, byte_offset,
1424 de_getsize(&disks.v[sess->d].lunv->v[lun].de));
1425 return -1;
1427 iscsi_trace(TRACE_SCSI_DATA,
1428 "wrote %" PRIu64 " bytes to device OK\n", bytec);
1429 return 0;
1432 static int
1433 disk_read(target_session_t *sess, iscsi_scsi_cmd_args_t *args, uint32_t lba,
1434 uint16_t len, uint8_t lun)
1436 uint64_t byte_offset;
1437 uint64_t bytec;
1438 uint64_t extra;
1439 uint8_t *ptr;
1440 uint32_t n;
1441 int rc;
1443 byte_offset = lba * disks.v[sess->d].blocklen;
1444 bytec = len * disks.v[sess->d].blocklen;
1445 extra = 0;
1446 ptr = NULL;
1447 if (len == 0) {
1448 iscsi_err(__FILE__, __LINE__, "Zero \"len\"\n");
1449 NO_CLEANUP;
1450 return -1;
1452 if (lba > disks.v[sess->d].blockc - 1 ||
1453 (lba + len) > disks.v[sess->d].blockc) {
1454 iscsi_err(__FILE__, __LINE__,
1455 "attempt to read beyond end of media\n"
1456 "max_lba = %" PRIu64 ", requested lba = %u, len = %u\n",
1457 disks.v[sess->d].blockc - 1, lba, len);
1458 return -1;
1460 if ((unsigned) bytec > MB(1)) {
1461 iscsi_err(__FILE__, __LINE__, "bytec > %u\n", bytec);
1462 NO_CLEANUP;
1463 return -1;
1465 ptr = disks.v[sess->d].buffer;
1466 n = 0;
1467 do {
1468 if (de_lseek(&disks.v[sess->d].lunv->v[lun].de,
1469 (off_t)(n + byte_offset), SEEK_SET) == -1) {
1470 iscsi_err(__FILE__, __LINE__, "lseek failed\n");
1471 return -1;
1473 rc = de_read(&disks.v[sess->d].lunv->v[lun].de, ptr + n,
1474 (size_t)(bytec - n));
1475 if (rc <= 0) {
1476 iscsi_err(__FILE__, __LINE__,
1477 "read failed: rc %d errno %d\n", rc, errno);
1478 return -1;
1480 n += rc;
1481 if (n < bytec) {
1482 iscsi_err(__FILE__, __LINE__,
1483 "Got partial file read: %d bytes of %" PRIu64
1484 "\n", rc, bytec - n + rc);
1486 } while (n < bytec);
1487 ((struct iovec *)(void *)args->send_data)[0].iov_base =
1488 ptr + (unsigned) extra;
1489 ((struct iovec *)(void *)args->send_data)[0].iov_len =
1490 (unsigned) bytec;
1491 args->length = (unsigned) bytec;
1492 args->send_sg_len = 1;
1493 args->status = 0;
1494 return 0;