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