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