1 /* $NetBSD: disk.c,v 1.40 2009/06/23 05:11:47 agc Exp $ */
4 * Copyright (c) 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
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
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
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
54 * -The name of Intel Corporation may not be used to endorse or
55 * promote products derived from this software without specific prior
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
73 #ifdef HAVE_INTTYPES_H
77 #include <sys/types.h>
79 #ifdef HAVE_SYS_PARAM_H
80 #include <sys/param.h>
83 #ifdef HAVE_SYS_STAT_H
91 #ifdef HAVE_SYS_TIME_H
95 #ifdef HAVE_SYS_MMAN_H
99 #ifdef HAVE_NETINET_IN_H
100 #include <netinet/in.h>
121 #include "scsi_cmd_codes.h"
123 #include "iscsiprotocol.h"
125 #include "iscsiutil.h"
131 #define iSCSI_DEFAULT_LUNS 1
132 #define iSCSI_DEFAULT_BLOCKLEN 512
134 /* End disk configuration */
140 MAX_RESERVATIONS
= 32,
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 */
164 DEFINE_ARRAY(disks_t
, iscsi_disk_t
);
166 static disks_t disks
;
167 static iscsi_disk_t defaults
;
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
175 #define FDATASYNC 0x0010
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 */
188 raid0_getoff(disc_device_t
*dp
, uint64_t off
, uint32_t *d
, uint64_t *de_off
)
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
) {
201 /* open the extent's device */
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 */
210 device_open(disc_device_t
*dp
, int flags
, int mode
)
215 for (fd
= -1, i
= 0 ; i
< dp
->c
; i
++) {
216 switch (dp
->xv
[i
].type
) {
218 fd
= device_open(dp
->xv
[i
].u
.dp
, flags
, mode
);
224 fd
= extent_open(dp
->xv
[i
].u
.xp
, flags
, mode
);
236 /* and for the undecided... */
238 de_open(disc_de_t
*dp
, int flags
, int mode
)
242 return device_open(dp
->u
.dp
, flags
, mode
);
244 return extent_open(dp
->u
.xp
, flags
, mode
);
250 /* lseek on the extent */
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 */
259 device_lseek(disc_device_t
*dp
, off_t off
, int whence
)
268 if (raid0_getoff(dp
, (uint64_t) off
, &d
, &suboff
)) {
269 switch (dp
->xv
[d
].type
) {
271 ret
= device_lseek(dp
->xv
[d
].u
.dp
,
272 (off_t
) suboff
, whence
);
278 ret
= extent_lseek(dp
->xv
[d
].u
.xp
,
279 (off_t
) suboff
, whence
);
290 for (d
= 0 ; d
< dp
->c
; d
++) {
291 switch (dp
->xv
[d
].type
) {
293 ret
= device_lseek(dp
->xv
[d
].u
.dp
, (off_t
)off
,
300 ret
= extent_lseek(dp
->xv
[d
].u
.xp
, (off_t
)off
,
314 return dp
->off
= ret
;
317 /* and for the undecided... */
319 de_lseek(disc_de_t
*dp
, off_t off
, int whence
)
323 return device_lseek(dp
->u
.dp
, off
, whence
);
325 return extent_lseek(dp
->u
.xp
, off
, whence
);
331 /* fsync_range on the extent */
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
);
338 return fsync(xp
->fd
);
342 /* (recursively) fsync_range on the device's devices */
344 device_fsync_range(disc_device_t
*dp
, int how
, off_t from
, off_t len
)
353 if (raid0_getoff(dp
, (uint64_t) from
, &d
, &suboff
)) {
354 switch (dp
->xv
[d
].type
) {
356 ret
= device_fsync_range(dp
->xv
[d
].u
.dp
, how
,
363 ret
= extent_fsync_range(dp
->xv
[d
].u
.xp
, how
,
375 for (d
= 0 ; d
< dp
->c
; d
++) {
376 switch (dp
->xv
[d
].type
) {
378 ret
= device_fsync_range(dp
->xv
[d
].u
.dp
, how
,
385 ret
= extent_fsync_range(dp
->xv
[d
].u
.xp
, how
,
399 dp
->off
= (uint64_t) ret
;
403 /* and for the undecided... */
405 de_fsync_range(disc_de_t
*dp
, int how
, off_t from
, off_t len
)
409 return device_fsync_range(dp
->u
.dp
, how
, from
, len
);
411 return extent_fsync_range(dp
->u
.xp
, how
, from
, len
);
417 /* read from the extent */
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 */
426 device_read(disc_device_t
*dp
, void *buf
, size_t cc
)
438 for (cbuf
= (char *) buf
, got
= 0 ; got
< cc
; got
+= ret
) {
439 if (!raid0_getoff(dp
, dp
->off
, &d
, &suboff
)) {
442 if (device_lseek(dp
, (off_t
)dp
->off
, SEEK_SET
) < 0) {
445 subcc
= MIN(cc
- (size_t)got
,
446 (size_t)(dp
->len
- (size_t)dp
->off
));
447 switch (dp
->xv
[d
].type
) {
449 ret
= device_read(dp
->xv
[d
].u
.dp
,
450 &cbuf
[(int)got
], subcc
);
456 ret
= extent_read(dp
->xv
[d
].u
.xp
,
457 &cbuf
[(int)got
], subcc
);
470 for (d
= 0 ; d
< dp
->c
; d
++) {
471 switch (dp
->xv
[d
].type
) {
473 ret
= device_read(dp
->xv
[d
].u
.dp
, buf
, cc
);
479 ret
= extent_read(dp
->xv
[d
].u
.xp
, buf
, cc
);
496 /* and for the undecided... */
498 de_read(disc_de_t
*dp
, void *buf
, size_t cc
)
502 return device_read(dp
->u
.dp
, buf
, cc
);
504 return extent_read(dp
->u
.xp
, buf
, cc
);
510 /* write to the extent */
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 */
519 device_write(disc_device_t
*dp
, void *buf
, size_t cc
)
531 for (cbuf
= (char *) buf
, done
= 0 ; done
< cc
; done
+= ret
) {
532 if (!raid0_getoff(dp
, dp
->off
, &d
, &suboff
)) {
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) {
540 switch (dp
->xv
[d
].type
) {
542 ret
= device_write(dp
->xv
[d
].u
.dp
,
543 &cbuf
[(int)done
], subcc
);
549 ret
= extent_write(dp
->xv
[d
].u
.xp
,
550 &cbuf
[(int)done
], subcc
);
560 ret
= (ssize_t
) done
;
563 for (d
= 0 ; d
< dp
->c
; d
++) {
564 switch (dp
->xv
[d
].type
) {
566 ret
= device_write(dp
->xv
[d
].u
.dp
, buf
, cc
);
568 iscsi_err(__FILE__
, __LINE__
,
569 "device_write RAID1 device "
575 ret
= extent_write(dp
->xv
[d
].u
.xp
, buf
, cc
);
577 iscsi_err(__FILE__
, __LINE__
,
578 "device_write RAID1 extent "
595 /* and for the undecided... */
597 de_write(disc_de_t
*dp
, void *buf
, size_t cc
)
601 return device_write(dp
->u
.dp
, buf
, cc
);
603 return extent_write(dp
->u
.xp
, buf
, cc
);
609 /* return non-zero if the target is writable */
611 target_writable(disc_target_t
*tp
)
613 return !(tp
->flags
& TARGET_READONLY
);
616 /* return size of the extent */
618 extent_getsize(disc_extent_t
*xp
)
623 /* (recursively) return the size of the device's devices */
625 device_getsize(disc_device_t
*dp
)
633 for (d
= 0 ; d
< dp
->c
; d
++) {
634 switch (dp
->xv
[d
].type
) {
636 size
+= device_getsize(dp
->xv
[d
].u
.dp
);
639 size
+= extent_getsize(dp
->xv
[d
].u
.xp
);
655 /* and for the undecided... */
657 de_getsize(disc_de_t
*dp
)
661 return device_getsize(dp
->u
.dp
);
663 return extent_getsize(dp
->u
.xp
);
669 /* return a filename for the device or extent */
671 disc_get_filename(disc_de_t
*de
)
675 return de
->u
.xp
->dev
;
677 return disc_get_filename(&de
->u
.dp
->xv
[0]);
684 * Public Interface (called by utarget and ktarket)
687 /* set various global variables */
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);
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 */
705 de_allocate(disc_de_t
*de
, char *filename
)
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
);
716 if (de_read(de
, block
, sizeof(block
)) == -1) {
717 iscsi_err(__FILE__
, __LINE__
,
718 "error reading \"%s\"", filename
);
721 if (de_write(de
, block
, sizeof(block
)) == -1) {
722 iscsi_err(__FILE__
, __LINE__
,
723 "error writing \"%s\"", filename
);
729 /* allocate space as desired */
731 allocate_space(disc_target_t
*tp
)
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
) {
739 return de_allocate(&tp
->de
, tp
->target
);
741 for (i
= 0 ; i
< tp
->de
.u
.dp
->c
; i
++) {
742 if (!de_allocate(&tp
->de
.u
.dp
->xv
[i
], tp
->target
)) {
753 /* copy src to dst, of size `n' bytes, padding any extra with `pad' */
755 strpadcpy(uint8_t *dst
, size_t dstlen
, const char *src
, const size_t srclen
,
758 if (srclen
< dstlen
) {
759 (void) memcpy(dst
, src
, srclen
);
760 (void) memset(&dst
[srclen
], pad
, dstlen
- srclen
);
762 (void) memcpy(dst
, src
, dstlen
);
766 /* handle REPORT LUNs SCSI command */
768 report_luns(uint64_t *data
, int64_t luns
)
773 for (i
= 0, off
= 8 ; i
< (uint64_t)luns
; i
++, off
+= sizeof(i
)) {
774 data
[(int)i
] = ISCSI_HTONLL(i
);
779 /* handle persistent reserve in command */
781 persistent_reserve_in(uint8_t action
, uint8_t *data
)
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 */
804 /* also WR_EX_AR, EX_AC_RD, WR_EX_RD, EX_AC, WR_EX */
805 data
[5] = 0; /* also EX_AC_AR here */
808 iscsi_err(__FILE__
, __LINE__
,
809 "persistent_reserve_in: action %x unrecognised\n",
815 /* initialise the device */
817 device_init(iscsi_target_t
*tgt
, targv_t
*tvp
, disc_target_t
*tp
)
822 ALLOC(iscsi_disk_t
, disks
.v
, disks
.size
, disks
.c
, 10, 10,
824 idisk
= &disks
.v
[disks
.c
];
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
) {
838 iscsi_err(__FILE__
, __LINE__
,
839 "Invalid block len %" PRIu64
840 ". Choose one of 512, 1024, 2048, 4096, or 8192.\n",
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",
851 (idisk
->luns
== 1) ? "" : "s",
852 idisk
->blockc
, idisk
->blocklen
,
853 (idisk
->type
== ISCSI_FS
) ? "iscsi fs" :
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
);
864 if (!(tp
->flags
& TARGET_READONLY
) && !allocate_space(tp
)) {
865 iscsi_err(__FILE__
, __LINE__
,
866 "error allocating space for \"%s\"", tp
->target
);
869 printf("%" PRIu64
" MB %sdisk storage for \"%s\"\n",
870 (de_getsize(&tp
->de
) / MB(1)),
871 (tp
->flags
& TARGET_READONLY
) ? "readonly " : "",
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 */
882 int little_endian
= 1;
884 if (*(char *) (void *) &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];
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 */
904 mode_sense(const int bytes
, target_cmd_t
*cmd
)
906 iscsi_scsi_cmd_args_t
*args
= cmd
->scsi_cmd
;
909 uint8_t *cdb
= args
->cdb
;
910 size_t mode_data_len
;
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
;
924 cp
[3] = 8; /* block descriptor length */
925 cp
[10] = 2; /* density code and block length */
928 args
->length
= (unsigned)len
;
929 args
->status
= SCSI_SUCCESS
;
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
);
939 /* zero length cdb means just return success */
941 args
->length
= (unsigned)(mode_data_len
);
942 args
->status
= SCSI_SUCCESS
;
945 if ((cdb
[2] & PAGE_CONTROL_MASK
) ==
946 PAGE_CONTROL_CHANGEABLE_VALUES
) {
947 /* just send back a CHECK CONDITION */
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
;
956 iscsi_trace(TRACE_SCSI_CMD
, "PC %02x\n", cdb
[2]);
958 cp
[0] = mode_data_len
;
961 cp
[3] = 8; /* block descriptor length */
962 cp
[10] = 2; /* density code and block length */
965 args
->length
= (unsigned)(len
);
966 args
->status
= SCSI_SUCCESS
;
972 /* fill in the device serial number vital product data */
974 serial_vpd(uint8_t *data
)
978 data
[0] = DISK_PERIPHERAL_DEVICE
;
979 data
[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD
;
981 /* add target device's Unit Serial Number */
982 /* section 7.6.10 of SPC-3 says that if there is no serial number,
984 strpadcpy(&data
[4], (size_t)len
, " ", strlen(" "), ' ');
988 /* fill in the device identification vital product data */
990 device_vpd(iscsi_target_t
*tgt
, uint8_t *data
, uint8_t *rspc
,
991 uint8_t *cdbsize
, uint8_t lun
, char *uuid
)
996 data
[0] = DISK_PERIPHERAL_DEVICE
;
997 data
[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD
;
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"));
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])),
1021 iscsi_target_getvar(tgt
, "iqn"),
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]);
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
), ' ');
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]);
1057 version_inquiry(uint8_t *data
, uint8_t *cdbsize
)
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
), ' ');
1072 device_command(target_session_t
*sess
, target_cmd_t
*cmd
)
1074 iscsi_scsi_cmd_args_t
*args
= cmd
->scsi_cmd
;
1085 lun
= (uint8_t) (args
->lun
>> 32);
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 */
1101 args
->length
= cdb
[4] + 1;
1102 args
->status
= SCSI_SUCCESS
;
1106 lun
= (uint8_t) sess
->d
;
1107 iscsi_trace(TRACE_SCSI_CMD
, "SCSI op %#x (lun %d): \n", cdb
[0], lun
);
1110 case TEST_UNIT_READY
:
1111 iscsi_trace(TRACE_SCSI_CMD
, "TEST_UNIT_READY\n");
1112 args
->status
= SCSI_SUCCESS
;
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
) {
1127 case INQUIRY_UNIT_SERIAL_NUMBER_VPD
:
1128 *rspc
= serial_vpd(data
);
1131 case INQUIRY_DEVICE_IDENTIFICATION_VPD
:
1132 if (disks
.v
[sess
->d
].uuid_string
== NULL
) {
1133 nbuuid_create(&disks
.v
[sess
->d
].uuid
,
1135 nbuuid_to_string(&disks
.v
[sess
->d
].uuid
,
1136 &disks
.v
[sess
->d
].uuid_string
,
1139 device_vpd(sess
->target
, data
, rspc
, cdbsize
,
1140 lun
, disks
.v
[sess
->d
].uuid_string
);
1141 args
->length
= *rspc
+ 6;
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;
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 */
1161 iscsi_err(__FILE__
, __LINE__
,
1162 "Unsupported INQUIRY VPD page %x\n",
1164 args
->status
= SCSI_CHECK_CONDITION
;
1168 version_inquiry(data
, cdbsize
);
1169 args
->length
= cdb
[4] + 1;
1171 if (args
->status
== SCSI_SUCCESS
) {
1177 iscsi_trace(TRACE_SCSI_CMD
, "MODE_SELECT_6\n");
1178 args
->status
= SCSI_SUCCESS
;
1182 case STOP_START_UNIT
:
1183 iscsi_trace(TRACE_SCSI_CMD
, "STOP_START_UNIT\n");
1184 args
->status
= SCSI_SUCCESS
;
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);
1194 *((uint32_t *)(void *)(data
+ 4)) = (uint32_t) ISCSI_HTONL(
1195 (uint32_t) disks
.v
[sess
->d
].blocklen
);
1199 args
->status
= SCSI_SUCCESS
;
1203 lba
= ISCSI_NTOHL(*((uint32_t *) (void *)cdb
)) & 0x001fffff;
1204 if ((len
= *cdbsize
) == 0) {
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
;
1219 lba
= ISCSI_NTOHL(*((uint32_t *)(void *)cdb
)) & 0x001fffff;
1220 if ((len
= *cdbsize
) == 0) {
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
;
1239 cdb2lba(&lba
, &len
, cdb
);
1241 iscsi_trace(TRACE_SCSI_CMD
,
1242 "WRITE_10 | WRITE_VERIFY(lba %u, len %u blocks)\n",
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
;
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
;
1265 /* For now just set the status to success. */
1266 args
->status
= SCSI_SUCCESS
;
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
,
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
;
1280 args
->status
= SCSI_SUCCESS
;
1286 iscsi_trace(TRACE_SCSI_CMD
, "LOG_SENSE\n");
1287 args
->status
= SCSI_SUCCESS
;
1292 mode_sense(10, cmd
);
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
;
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
),
1307 args
->status
= SCSI_SUCCESS
;
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
*
1319 args
->status
= SCSI_SUCCESS
;
1323 iscsi_trace(TRACE_SCSI_CMD
, "RESERVE_6\n");
1324 args
->status
= SCSI_SUCCESS
;
1329 iscsi_trace(TRACE_SCSI_CMD
, "RELEASE_6\n");
1330 args
->status
= SCSI_SUCCESS
;
1335 iscsi_trace(TRACE_SCSI_CMD
, "RESERVE_10\n");
1336 args
->status
= SCSI_SUCCESS
;
1341 iscsi_trace(TRACE_SCSI_CMD
, "RELEASE_10\n");
1342 args
->status
= SCSI_SUCCESS
;
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
;
1353 iscsi_trace(TRACE_SCSI_DEBUG
,
1354 "SCSI op %#x: done (status %#x)\n", cdb
[0], args
->status
);
1359 device_shutdown(target_session_t
*sess
)
1370 disk_write(target_session_t
*sess
, iscsi_scsi_cmd_args_t
*args
, uint8_t lun
,
1371 uint32_t lba
, uint32_t len
)
1374 uint64_t byte_offset
;
1378 byte_offset
= lba
* disks
.v
[sess
->d
].blocklen
;
1379 bytec
= len
* disks
.v
[sess
->d
].blocklen
;
1381 iscsi_trace(TRACE_SCSI_DATA
,
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
);
1392 /* Assign ptr for write data */
1393 ptr
= disks
.v
[sess
->d
].buffer
;
1395 /* Have target do data transfer */
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
,
1405 iscsi_err(__FILE__
, __LINE__
,
1406 "lseek() to offset %" PRIu64
" failed\n",
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",
1415 de_getsize(&disks
.v
[sess
->d
].lunv
->v
[lun
].de
));
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",
1424 de_getsize(&disks
.v
[sess
->d
].lunv
->v
[lun
].de
));
1427 iscsi_trace(TRACE_SCSI_DATA
,
1428 "wrote %" PRIu64
" bytes to device OK\n", bytec
);
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
;
1443 byte_offset
= lba
* disks
.v
[sess
->d
].blocklen
;
1444 bytec
= len
* disks
.v
[sess
->d
].blocklen
;
1448 iscsi_err(__FILE__
, __LINE__
, "Zero \"len\"\n");
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
);
1460 if ((unsigned) bytec
> MB(1)) {
1461 iscsi_err(__FILE__
, __LINE__
, "bytec > %u\n", bytec
);
1465 ptr
= disks
.v
[sess
->d
].buffer
;
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");
1473 rc
= de_read(&disks
.v
[sess
->d
].lunv
->v
[lun
].de
, ptr
+ n
,
1474 (size_t)(bytec
- n
));
1476 iscsi_err(__FILE__
, __LINE__
,
1477 "read failed: rc %d errno %d\n", rc
, errno
);
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
=
1491 args
->length
= (unsigned) bytec
;
1492 args
->send_sg_len
= 1;