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