Home | History | Annotate | Line # | Download | only in lib
      1 /* $NetBSD: disk.c,v 1.10 2025/07/05 06:50:12 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 (at) 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 				uint64_t, uint32_t, uint8_t);
    184 static int      disk_write(target_session_t *, iscsi_scsi_cmd_args_t *,
    185 				uint8_t, uint64_t, uint32_t);
    186 
    187 /* return the de index and offset within the device for RAID0 */
    188 static int
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    898 cdb2lba(uint32_t *lba, uint16_t *len, uint8_t *cdb)
    899 {
    900 	*lba = be32dec(&cdb[2]);
    901 	*len = be16dec(&cdb[7]);
    902 }
    903 
    904 static void
    905 cdb2lba64(uint64_t *lba64, uint32_t *len32, uint8_t *cdb)
    906 {
    907 	*lba64 = be64dec(&cdb[2]);
    908 	*len32 = be32dec(&cdb[10]);
    909 }
    910 
    911 /* handle MODE_SENSE_6 and MODE_SENSE_10 commands */
    912 static int
    913 mode_sense(const int bytes, target_cmd_t *cmd)
    914 {
    915 	iscsi_scsi_cmd_args_t	*args = cmd->scsi_cmd;
    916 	uint16_t		 len;
    917 	uint8_t			*cp;
    918 	uint8_t			*cdb = args->cdb;
    919 	size_t			 mode_data_len;
    920 
    921 	switch(bytes) {
    922 	case 6:
    923 		cp = args->send_data;
    924 		len = ISCSI_MODE_SENSE_LEN;
    925 		mode_data_len = len + 3;
    926 
    927 		iscsi_trace(TRACE_SCSI_CMD, "MODE_SENSE_6\n");
    928 		(void) memset(cp, 0x0, mode_data_len);
    929 
    930 		cp[0] = mode_data_len;
    931 		cp[1] = 0;
    932 		cp[2] = 0;
    933 		cp[3] = 8;	/* block descriptor length */
    934 		cp[10] = 2;	/* density code and block length */
    935 
    936 		args->input = 1;
    937 		args->length = (unsigned)len;
    938 		args->status = SCSI_SUCCESS;
    939 		return 1;
    940 	case 10:
    941 		cp = args->send_data;
    942 		len = ISCSI_MODE_SENSE_LEN;
    943 		mode_data_len = len + 3;
    944 
    945 		iscsi_trace(TRACE_SCSI_CMD, "MODE_SENSE_10\n");
    946 		(void) memset(cp, 0x0, mode_data_len);
    947 		if (cdb[4] == 0) {
    948 			/* zero length cdb means just return success */
    949 			args->input = 1;
    950 			args->length = (unsigned)(mode_data_len);
    951 			args->status = SCSI_SUCCESS;
    952 			return 1;
    953 		}
    954 		if ((cdb[2] & PAGE_CONTROL_MASK) ==
    955 					PAGE_CONTROL_CHANGEABLE_VALUES) {
    956 			/* just send back a CHECK CONDITION */
    957 			args->input = 1;
    958 			args->length = (unsigned)(len);
    959 			args->status = SCSI_CHECK_CONDITION;
    960 			cp[2] = SCSI_SKEY_ILLEGAL_REQUEST;
    961 			cp[12] = ASC_LUN_UNSUPPORTED;
    962 			cp[13] = ASCQ_LUN_UNSUPPORTED;
    963 			return 1;
    964 		}
    965 		iscsi_trace(TRACE_SCSI_CMD, "PC %02x\n", cdb[2]);
    966 
    967 		cp[0] = mode_data_len;
    968 		cp[1] = 0;
    969 		cp[2] = 0;
    970 		cp[3] = 8;	/* block descriptor length */
    971 		cp[10] = 2;	/* density code and block length */
    972 
    973 		args->input = 1;
    974 		args->length = (unsigned)(len);
    975 		args->status = SCSI_SUCCESS;
    976 		return 1;
    977 	}
    978 	return 0;
    979 }
    980 
    981 /* fill in the device serial number vital product data */
    982 static uint8_t
    983 serial_vpd(uint8_t *data)
    984 {
    985 	uint8_t	len;
    986 
    987 	data[0] = DISK_PERIPHERAL_DEVICE;
    988 	data[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
    989 	len = 16;
    990 	/* add target device's Unit Serial Number */
    991 	/* section 7.6.10 of SPC-3 says that if there is no serial number,
    992 	 * use spaces */
    993 	strpadcpy(&data[4], (size_t)len, " ", strlen(" "), ' ');
    994 	return len;
    995 }
    996 
    997 /* fill in the device identification vital product data */
    998 static void
    999 device_vpd(iscsi_target_t *tgt, uint8_t *data, uint8_t *rspc,
   1000 		uint8_t *cdbsize, uint8_t lun, char *uuid)
   1001 {
   1002 	uint16_t	 len;
   1003 	uint8_t		*cp;
   1004 
   1005 	data[0] = DISK_PERIPHERAL_DEVICE;
   1006 	data[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
   1007 	*rspc = 0;
   1008 	cp = &data[4];
   1009 	/* add target device's IQN */
   1010 	cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
   1011 			INQUIRY_DEVICE_CODESET_UTF8;
   1012 	cp[1] = (INQUIRY_DEVICE_PIV << 7) |
   1013 			(INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE << 4) |
   1014 			INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
   1015 	len = (uint8_t) snprintf((char *)&cp[4],
   1016 			(unsigned)(*cdbsize - (int)(cp - &data[4])), "%s",
   1017 			iscsi_target_getvar(tgt, "iqn"));
   1018 	cp[3] = len;
   1019 	*rspc += len + 4;
   1020 	cp += len + 4;
   1021 	/* add target port's IQN + LUN */
   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_PORT << 4) |
   1026 		INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
   1027 	len = (uint8_t) snprintf((char *)&cp[4],
   1028 				(unsigned)(*cdbsize - (int)(cp - &data[4])),
   1029 				"%s,t,%#x",
   1030 				iscsi_target_getvar(tgt, "iqn"),
   1031 				lun);
   1032 	cp[3] = len;
   1033 	*rspc += len + 4;
   1034 	cp += len + 4;
   1035 	/* add target port's IQN + LUN extension */
   1036 	cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
   1037 		INQUIRY_DEVICE_CODESET_UTF8;
   1038 	cp[1] = (INQUIRY_DEVICE_PIV << 7) |
   1039 		(INQUIRY_DEVICE_ASSOCIATION_LOGICAL_UNIT << 4) |
   1040 		INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME;
   1041 	len = (uint8_t) snprintf((char *)&cp[4],
   1042 				(unsigned) (*cdbsize - (int)(cp - &data[4])),
   1043 				"%s,L,0x%8.8s%4.4s%4.4s",
   1044 				iscsi_target_getvar(tgt, "iqn"),
   1045 				uuid, &uuid[9], &uuid[14]);
   1046 	cp[3] = len;
   1047 	*rspc += len + 4;
   1048 	cp += len + 4;
   1049 	/* add target's uuid as a T10 identifier */
   1050 	cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) |
   1051 		INQUIRY_DEVICE_CODESET_UTF8;
   1052 	cp[1] = (INQUIRY_DEVICE_PIV << 7) |
   1053 		(INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE << 4) |
   1054 		INQUIRY_IDENTIFIER_TYPE_T10;
   1055 	strpadcpy(&cp[4], 8, ISCSI_VENDOR, strlen(ISCSI_VENDOR), ' ');
   1056 	len = 8;
   1057 	len += (uint8_t) snprintf((char *)&cp[8 + 4],
   1058 				(unsigned)(*cdbsize - (int)(cp - &data[4])),
   1059 				"0x%8.8s%4.4s%4.4s",
   1060 				uuid, &uuid[9], &uuid[14]);
   1061 	cp[3] = len;
   1062 	*rspc += len + 4;
   1063 }
   1064 
   1065 static void
   1066 version_inquiry(uint8_t *data, uint8_t *cdbsize)
   1067 {
   1068 	char	versionstr[8];
   1069 
   1070 	data[0] = DISK_PERIPHERAL_DEVICE;
   1071 	data[2] = SCSI_VERSION_SPC;
   1072 	data[4] = *cdbsize - 4;	/* Additional length  */
   1073 	data[7] |= (WIDE_BUS_32 | WIDE_BUS_16);
   1074 	strpadcpy(&data[8], 8, ISCSI_VENDOR, strlen(ISCSI_VENDOR), ' ');
   1075 	strpadcpy(&data[16], 16, ISCSI_PRODUCT, strlen(ISCSI_PRODUCT), ' ');
   1076 	(void) snprintf(versionstr, sizeof(versionstr), "%d", ISCSI_VERSION);
   1077 	strpadcpy(&data[32], 4, versionstr, strlen(versionstr), ' ');
   1078 }
   1079 
   1080 int
   1081 device_command(target_session_t *sess, target_cmd_t *cmd)
   1082 {
   1083 	iscsi_scsi_cmd_args_t  *args = cmd->scsi_cmd;
   1084 	uint32_t        	status;
   1085 	uint32_t		lba;
   1086 	uint64_t		lba64;
   1087 	uint16_t		len;
   1088 	uint32_t		len32;
   1089 	uint8_t			*cdbsize;
   1090 	uint8_t			*rspc;
   1091 	uint8_t			*data;
   1092 	uint8_t			*cdb;
   1093 	uint8_t			lun;
   1094 
   1095 	cdb = args->cdb;
   1096 	lun = (uint8_t) (args->lun >> 48);
   1097 	cdbsize = &cdb[4];
   1098 
   1099 	/*
   1100 	 * added section to return no device equivalent for lun request
   1101 	 * beyond available lun
   1102 	 */
   1103 	if (lun >= disks.v[sess->d].luns) {
   1104 		data = args->send_data;
   1105 		(void) memset(data, 0x0, (size_t) *cdbsize);
   1106 		/*
   1107 		 * data[0] = 0x7F; means no device
   1108 		 */
   1109 		data[0] = 0x1F;	/* device type */
   1110 		data[0] |= 0x60;/* peripheral qualifier */
   1111 		args->input = 1;
   1112 		args->length = cdb[4] + 1;
   1113 		args->status = SCSI_SUCCESS;
   1114 		return 0;
   1115 	}
   1116 
   1117 	lun = (uint8_t) sess->d;
   1118 	iscsi_trace(TRACE_SCSI_CMD, "SCSI op %#x (lun %d): \n", cdb[0], lun);
   1119 
   1120 	switch (cdb[0]) {
   1121 	case TEST_UNIT_READY:
   1122 		iscsi_trace(TRACE_SCSI_CMD, "TEST_UNIT_READY\n");
   1123 		args->status = SCSI_SUCCESS;
   1124 		args->length = 0;
   1125 		break;
   1126 
   1127 	case INQUIRY:
   1128 		iscsi_trace(TRACE_SCSI_CMD, "INQUIRY%s\n",
   1129 				(cdb[1] & INQUIRY_EVPD_BIT) ?
   1130 					" for Vital Product Data" : "");
   1131 		data = args->send_data;
   1132 		args->status = SCSI_SUCCESS;
   1133 		/* Clear allocated buffer */
   1134 		(void) memset(data, 0x0, (unsigned) *cdbsize);
   1135 		if (cdb[1] & INQUIRY_EVPD_BIT) {
   1136 			rspc = &data[3];
   1137 			switch(cdb[2]) {
   1138 			case INQUIRY_UNIT_SERIAL_NUMBER_VPD:
   1139 				*rspc = serial_vpd(data);
   1140 				args->length = 16;
   1141 				break;
   1142 			case INQUIRY_DEVICE_IDENTIFICATION_VPD:
   1143 				if (disks.v[sess->d].uuid_string == NULL) {
   1144 					nbuuid_create(&disks.v[sess->d].uuid,
   1145 						&status);
   1146 					nbuuid_to_string(&disks.v[sess->d].uuid,
   1147 						&disks.v[sess->d].uuid_string,
   1148 						&status);
   1149 				}
   1150 				device_vpd(sess->target, data, rspc, cdbsize,
   1151 					lun, disks.v[sess->d].uuid_string);
   1152 				args->length = *rspc + 6;
   1153 				break;
   1154 			case INQUIRY_SUPPORTED_VPD_PAGES:
   1155 				data[0] = DISK_PERIPHERAL_DEVICE;
   1156 				data[1] = INQUIRY_SUPPORTED_VPD_PAGES;
   1157 				*rspc = 3;	/* # of supported pages */
   1158 				data[4] = INQUIRY_SUPPORTED_VPD_PAGES;
   1159 				data[5] = INQUIRY_DEVICE_IDENTIFICATION_VPD;
   1160 				data[6] = EXTENDED_INQUIRY_DATA_VPD;
   1161 				args->length = *cdbsize + 1;
   1162 				break;
   1163 			case EXTENDED_INQUIRY_DATA_VPD:
   1164 				data[0] = DISK_PERIPHERAL_DEVICE;
   1165 				data[1] = EXTENDED_INQUIRY_DATA_VPD;
   1166 				data[3] = 0x3c;	/* length is defined to be 60 */
   1167 				data[4] = 0;
   1168 				data[5] = 0;
   1169 				args->length = 64;
   1170 				break;
   1171 			default:
   1172 				iscsi_err(__FILE__, __LINE__,
   1173 					"Unsupported INQUIRY VPD page %x\n",
   1174 					cdb[2]);
   1175 				args->status = SCSI_CHECK_CONDITION;
   1176 				break;
   1177 			}
   1178 		} else {
   1179 			version_inquiry(data, cdbsize);
   1180 			args->length = cdb[4] + 1;
   1181 		}
   1182 		if (args->status == SCSI_SUCCESS) {
   1183 			args->input = 1;
   1184 		}
   1185 		break;
   1186 
   1187 	case MODE_SELECT_6:
   1188 		iscsi_trace(TRACE_SCSI_CMD, "MODE_SELECT_6\n");
   1189 		args->status = SCSI_SUCCESS;
   1190 		args->length = 0;
   1191 		break;
   1192 
   1193 	case STOP_START_UNIT:
   1194 		iscsi_trace(TRACE_SCSI_CMD, "STOP_START_UNIT\n");
   1195 		args->status = SCSI_SUCCESS;
   1196 		args->length = 0;
   1197 		break;
   1198 
   1199 	case READ_CAPACITY:
   1200 		iscsi_trace(TRACE_SCSI_CMD, "READ_CAPACITY\n");
   1201 		data = args->send_data;
   1202 		/* Max LBA */
   1203 		be32enc(data, disks.v[sess->d].blockc - 1);
   1204 		/* Block len */
   1205 		be32enc(data + 4, disks.v[sess->d].blocklen);
   1206 		args->input = 8;
   1207 		args->length = 8;
   1208 		args->status = SCSI_SUCCESS;
   1209 		break;
   1210 
   1211 	case READ_CAPACITY_16:
   1212 		iscsi_trace(TRACE_SCSI_CMD, "READ_CAPACITY_16\n");
   1213 		data = args->send_data;
   1214 		/* Max LBA */
   1215 		be64enc(data, disks.v[sess->d].blockc - 1);
   1216 		/* Block len */
   1217 		be32enc(data + 8, disks.v[sess->d].blocklen);
   1218 		args->input = 12;
   1219 		args->length = 12;
   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 WRITE_16:
   1286 	case WRITE_VERIFY_16:
   1287 		cdb2lba64(&lba64, &len32, cdb);
   1288 
   1289 		iscsi_trace(TRACE_SCSI_CMD,
   1290 			"WRITE_16 | WRITE_VERIFY_16(lba %" PRIu64 ", len %u blocks)\n",
   1291 			lba64, len32);
   1292 		if (disk_write(sess, args, lun, lba64, (unsigned) len32) != 0) {
   1293 			iscsi_err(__FILE__, __LINE__,
   1294 					"disk_write() failed\n");
   1295 			args->status = SCSI_CHECK_CONDITION;
   1296 		}
   1297 		args->length = 0;
   1298 		break;
   1299 
   1300 	case READ_16:
   1301 		cdb2lba64(&lba64, &len32, cdb);
   1302 		iscsi_trace(TRACE_SCSI_CMD,
   1303 			"READ_16(lba %" PRIu64 ", len %u blocks)\n",
   1304 			lba64, len32);
   1305 		if (disk_read(sess, args, lba64, len32, lun) != 0) {
   1306 			iscsi_err(__FILE__, __LINE__,
   1307 				"disk_read() failed\n");
   1308 			args->status = SCSI_CHECK_CONDITION;
   1309 		}
   1310 		args->input = 1;
   1311 		break;
   1312 
   1313 	case VERIFY:
   1314 		/* For now just set the status to success. */
   1315 		args->status = SCSI_SUCCESS;
   1316 		break;
   1317 
   1318 	case SYNC_CACHE:
   1319 		cdb2lba(&lba, &len, cdb);
   1320 		iscsi_trace(TRACE_SCSI_CMD,
   1321 			"SYNC_CACHE (lba %u, len %u blocks)\n", lba, len);
   1322 		if (de_fsync_range(&disks.v[sess->d].lunv->v[lun].de,
   1323 				FDATASYNC, lba,
   1324 				(off_t)(len * disks.v[sess->d].blocklen)) < 0) {
   1325 			iscsi_err(__FILE__, __LINE__,
   1326 					"disk_read() failed\n");
   1327 			args->status = SCSI_CHECK_CONDITION;
   1328 		} else {
   1329 			args->status = SCSI_SUCCESS;
   1330 			args->length = 0;
   1331 		}
   1332 		break;
   1333 
   1334 	case LOG_SENSE:
   1335 		iscsi_trace(TRACE_SCSI_CMD, "LOG_SENSE\n");
   1336 		args->status = SCSI_SUCCESS;
   1337 		args->length = 0;
   1338 		break;
   1339 
   1340 	case MODE_SENSE_10:
   1341 		mode_sense(10, cmd);
   1342 		break;
   1343 
   1344 	case MODE_SELECT_10:
   1345 		/* XXX still to do */
   1346 		iscsi_trace(TRACE_SCSI_CMD, "MODE_SELECT_10\n");
   1347 		args->status = SCSI_SUCCESS;
   1348 		args->length = 0;
   1349 		break;
   1350 
   1351 	case PERSISTENT_RESERVE_IN:
   1352 		iscsi_trace(TRACE_SCSI_CMD, "PERSISTENT_RESERVE_IN\n");
   1353 		args->length = persistent_reserve_in((cdb[1] &
   1354 				PERSISTENT_RESERVE_IN_SERVICE_ACTION_MASK),
   1355 				args->send_data);
   1356 		args->status = SCSI_SUCCESS;
   1357 		break;
   1358 
   1359 	case REPORT_LUNS:
   1360 		iscsi_trace(TRACE_SCSI_CMD, "REPORT LUNS\n");
   1361 		args->length = report_luns(args->send_data,
   1362 				disks.v[sess->d].luns);
   1363 		args->input = 8;
   1364 		args->status = SCSI_SUCCESS;
   1365 		break;
   1366 
   1367 	case RESERVE_6:
   1368 		iscsi_trace(TRACE_SCSI_CMD, "RESERVE_6\n");
   1369 		args->status = SCSI_SUCCESS;
   1370 		args->length = 0;
   1371 		break;
   1372 
   1373 	case RELEASE_6:
   1374 		iscsi_trace(TRACE_SCSI_CMD, "RELEASE_6\n");
   1375 		args->status = SCSI_SUCCESS;
   1376 		args->length = 0;
   1377 		break;
   1378 
   1379 	case RESERVE_10:
   1380 		iscsi_trace(TRACE_SCSI_CMD, "RESERVE_10\n");
   1381 		args->status = SCSI_SUCCESS;
   1382 		args->length = 0;
   1383 		break;
   1384 
   1385 	case RELEASE_10:
   1386 		iscsi_trace(TRACE_SCSI_CMD, "RELEASE_10\n");
   1387 		args->status = SCSI_SUCCESS;
   1388 		args->length = 0;
   1389 		break;
   1390 
   1391 	default:
   1392 		iscsi_err(__FILE__, __LINE__,
   1393 			"UNKNOWN OPCODE %#x\n", cdb[0]);
   1394 		/* to not cause confusion with some initiators */
   1395 		args->status = SCSI_CHECK_CONDITION;
   1396 		break;
   1397 	}
   1398 	iscsi_trace(TRACE_SCSI_DEBUG,
   1399 		"SCSI op %#x: done (status %#x)\n", cdb[0], args->status);
   1400 	return 0;
   1401 }
   1402 
   1403 int
   1404 device_shutdown(target_session_t *sess)
   1405 {
   1406 	USE_ARG(sess);
   1407 	return 1;
   1408 }
   1409 
   1410 /*
   1411  * Private Interface
   1412  */
   1413 
   1414 static int
   1415 disk_write(target_session_t *sess, iscsi_scsi_cmd_args_t *args, uint8_t lun,
   1416 		uint64_t lba, uint32_t len)
   1417 {
   1418 	struct iovec    sg;
   1419 	uint64_t        byte_offset;
   1420 	uint64_t        bytec;
   1421 	uint8_t        *ptr;
   1422 	int		result;
   1423 
   1424 	byte_offset = lba * disks.v[sess->d].blocklen;
   1425 	bytec = len * disks.v[sess->d].blocklen;
   1426 	ptr = NULL;
   1427 	iscsi_trace(TRACE_SCSI_DATA,
   1428 		"writing %" PRIu64
   1429 		" bytes from socket into device at byte offset %" PRIu64 "\n",
   1430 		bytec, byte_offset);
   1431 
   1432 	if ((unsigned) bytec > MB(1)) {
   1433 		iscsi_err(__FILE__, __LINE__, "bytec > %" PRIu64 "m\n", bytec);
   1434 		NO_CLEANUP;
   1435 		return -1;
   1436 	}
   1437 
   1438 	/* Assign ptr for write data */
   1439 	ptr = malloc(MB(1));
   1440 
   1441 	/* Have target do data transfer */
   1442 	sg.iov_base = ptr;
   1443 	sg.iov_len = (unsigned)bytec;
   1444 	if (target_transfer_data(sess, args, &sg, 1) != 0) {
   1445 		iscsi_err(__FILE__, __LINE__,
   1446 			"target_transfer_data() failed\n");
   1447 		result = -1;
   1448 		goto out;
   1449 	}
   1450 	/* Finish up write */
   1451 	if (de_lseek(&disks.v[sess->d].lunv->v[lun].de, (off_t)byte_offset,
   1452 				SEEK_SET) == -1) {
   1453 		iscsi_err(__FILE__, __LINE__,
   1454 			"lseek() to offset %" PRIu64 " failed\n",
   1455 			byte_offset);
   1456 		result = -1;
   1457 		goto out;
   1458 	}
   1459 	if (!target_writable(&disks.v[sess->d].lunv->v[lun])) {
   1460 		iscsi_err(__FILE__, __LINE__,
   1461 			"write() of %" PRIu64 " bytes failed at offset %"
   1462 			PRIu64 ", size %" PRIu64 "[READONLY TARGET]\n",
   1463 			bytec, byte_offset,
   1464 			de_getsize(&disks.v[sess->d].lunv->v[lun].de));
   1465 		result = -1;
   1466 		goto out;
   1467 	}
   1468 	if ((uint64_t)de_write(&disks.v[sess->d].lunv->v[lun].de, ptr,
   1469 			(unsigned) bytec) != bytec) {
   1470 		iscsi_err(__FILE__, __LINE__,
   1471 			"write() of %" PRIu64 " bytes failed at offset %"
   1472 			PRIu64 ", size %" PRIu64 "\n",
   1473 			bytec, byte_offset,
   1474 			de_getsize(&disks.v[sess->d].lunv->v[lun].de));
   1475 		result = -1;
   1476 		goto out;
   1477 	}
   1478 	iscsi_trace(TRACE_SCSI_DATA,
   1479 		"wrote %" PRIu64 " bytes to device OK\n", bytec);
   1480 	result = 0;
   1481 out:
   1482 	free(ptr);
   1483 	return result;
   1484 }
   1485 
   1486 static int
   1487 disk_read(target_session_t *sess, iscsi_scsi_cmd_args_t *args, uint64_t lba,
   1488 		uint32_t len, uint8_t lun)
   1489 {
   1490 	uint64_t        byte_offset;
   1491 	uint64_t        bytec;
   1492 	uint64_t        extra;
   1493 	uint8_t        *ptr;
   1494 	uint32_t        n;
   1495 	int             rc;
   1496 	int		result;
   1497 
   1498 	assert(args->send_buffer == NULL);
   1499 	byte_offset = lba * disks.v[sess->d].blocklen;
   1500 	bytec = len * disks.v[sess->d].blocklen;
   1501 	extra = 0;
   1502 	if (len == 0) {
   1503 		iscsi_err(__FILE__, __LINE__, "Zero \"len\"\n");
   1504 		NO_CLEANUP;
   1505 		return -1;
   1506 	}
   1507 	if (lba > disks.v[sess->d].blockc - 1 ||
   1508 	    (lba + len) > disks.v[sess->d].blockc) {
   1509 		iscsi_err(__FILE__, __LINE__,
   1510 			"attempt to read beyond end of media\n"
   1511 			"max_lba = %" PRIu64 ", requested lba = %" PRIu64 ", len = %u\n",
   1512 			disks.v[sess->d].blockc - 1, lba, len);
   1513 		return -1;
   1514 	}
   1515 	if ((unsigned) bytec > MB(1)) {
   1516 		iscsi_err(__FILE__, __LINE__, "bytec > %" PRIu64 "\n", bytec);
   1517 		NO_CLEANUP;
   1518 		return -1;
   1519 	}
   1520 	ptr = malloc(MB(1));
   1521 	n = 0;
   1522 	do {
   1523 		if (de_lseek(&disks.v[sess->d].lunv->v[lun].de,
   1524 				(off_t)(n + byte_offset), SEEK_SET) == -1) {
   1525 			iscsi_err(__FILE__, __LINE__, "lseek failed\n");
   1526 			result = -1;
   1527 			goto out;
   1528 		}
   1529 		rc = de_read(&disks.v[sess->d].lunv->v[lun].de, ptr + n,
   1530 				(size_t)(bytec - n));
   1531 		if (rc <= 0) {
   1532 			iscsi_err(__FILE__, __LINE__,
   1533 				"read failed: rc %d errno %d\n", rc, errno);
   1534 			result = -1;
   1535 			goto out;
   1536 		}
   1537 		n += rc;
   1538 		if (n < bytec) {
   1539 			iscsi_err(__FILE__, __LINE__,
   1540 				"Got partial file read: %d bytes of %" PRIu64
   1541 				"\n", rc, bytec - n + rc);
   1542 		}
   1543 	} while (n < bytec);
   1544 	((struct iovec *)(void *)args->send_data)[0].iov_base =
   1545 			ptr + (unsigned) extra;
   1546 	((struct iovec *)(void *)args->send_data)[0].iov_len =
   1547 			(unsigned) bytec;
   1548 	args->length = (unsigned) bytec;
   1549 	args->send_sg_len = 1;
   1550 	args->status = SCSI_SUCCESS;
   1551 	args->send_buffer = ptr;
   1552 	return 0;
   1553 out:
   1554 	free(ptr);
   1555 	return result;
   1556 }
   1557