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