Annotation of embedaddon/istgt/src/istgt_lu_tape.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2011 Daisuke Aoyama <aoyama@peach.ne.jp>.
! 3: * All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: *
! 14: * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 15: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 16: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 17: * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
! 18: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 19: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 20: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 21: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 22: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 23: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 24: * SUCH DAMAGE.
! 25: *
! 26: */
! 27:
! 28: #ifdef HAVE_CONFIG_H
! 29: #include "config.h"
! 30: #endif
! 31:
! 32: #include <inttypes.h>
! 33: #include <stdint.h>
! 34:
! 35: #include <errno.h>
! 36: #include <stdio.h>
! 37: #include <string.h>
! 38: #include <sys/types.h>
! 39: #include <sys/stat.h>
! 40:
! 41: #include <fcntl.h>
! 42: #include <unistd.h>
! 43:
! 44: #ifdef HAVE_UUID_H
! 45: #include <uuid.h>
! 46: #endif
! 47:
! 48: #include <sys/types.h>
! 49: #include <sys/stat.h>
! 50:
! 51: #include "istgt.h"
! 52: #include "istgt_ver.h"
! 53: #include "istgt_log.h"
! 54: #include "istgt_conf.h"
! 55: #include "istgt_sock.h"
! 56: #include "istgt_misc.h"
! 57: #include "istgt_iscsi.h"
! 58: #include "istgt_lu.h"
! 59: #include "istgt_proto.h"
! 60: #include "istgt_scsi.h"
! 61:
! 62: #define TAPE_DEBUG
! 63: //#define ISTGT_TRACE_TAPE
! 64:
! 65: #define DENSITY_DFLT (TAPE_DENSITY_DEFAULT)
! 66: //#define MEDIATYPE_DFLT (TAPE_MEDIATYPE_DLT_III)
! 67: //#define DENSITY_DFLT (TAPE_DENSITY_DLT_III)
! 68: #define MEDIATYPE_DFLT (TAPE_MEDIATYPE_DLT_IV)
! 69: //#define DENSITY_DFLT (TAPE_DENSITY_DLT_IV)
! 70: //#define MEDIATYPE_DFLT (TAPE_MEDIATYPE_SDLT_I)
! 71: //#define DENSITY_DFLT (TAPE_DENSITY_SDLT_I)
! 72: //#define MEDIATYPE_DFLT (TAPE_MEDIATYPE_LTO4)
! 73: //#define DENSITY_DFLT (TAPE_DENSITY_LTO4)
! 74:
! 75: /* Block Alignment for emulation tape */
! 76: #define TAPE_BLOCKLEN 512
! 77: #define TAPE_ALIGNMENT 8
! 78: #define COMPRESSION_DFLT 1
! 79:
! 80: #define ISCSI_DLT 0
! 81: #define ISCSI_LTO 1
! 82:
! 83: #define TAPE_VENDOR "QUANTUM"
! 84: #define TAPE_PRODUCT "DLT8000"
! 85: #define TAPE_REVISION "CX01" /* servo + r/w */
! 86: #define TAPE_MODULE_REV "C001"
! 87: #if 0
! 88: #define TAPE_PRODUCT "DLT4000"
! 89: #define TAPE_REVISION "CD01"
! 90: #define TAPE_MODULE_REV "C001"
! 91: #endif
! 92:
! 93: #if 0
! 94: /* Quantum DLT8000 */
! 95: #define TAPE_MAXIMUM_BLOCK_LENGTH 0x0ffffe
! 96: #define TAPE_MINIMUM_BLOCK_LENGTH 0x000000
! 97: #define TAPE_WRITE_DELAY 200 /* x 100ms */
! 98: /* for multiple of 4bytes */
! 99: #define TAPE_MAXIMUM_BLOCK_LENGTH 0xfffffc
! 100: #define TAPE_MINIMUM_BLOCK_LENGTH 0x000004
! 101: #endif
! 102: /* for multiple of 8bytes */
! 103: #define TAPE_MAXIMUM_BLOCK_LENGTH 0xfffff8
! 104: #define TAPE_MINIMUM_BLOCK_LENGTH 0x000008
! 105: //#define TAPE_WRITE_DELAY 0x000f /* x 100ms */
! 106: #define TAPE_WRITE_DELAY 200 /* x 100ms */
! 107: #define TAPE_COMP_ALGORITHM 0x10 /* IBM IDRC */
! 108:
! 109: #define TAPE_MEDIATYPE_NONE 0x00
! 110: #define TAPE_MEDIATYPE_DLT_CL 0x81
! 111: #define TAPE_MEDIATYPE_DLT_III 0x83
! 112: #define TAPE_MEDIATYPE_DLT_IIIXT 0x84
! 113: #define TAPE_MEDIATYPE_DLT_IV 0x85
! 114: #define TAPE_MEDIATYPE_SDLT_I 0x86
! 115: #define TAPE_MEDIATYPE_SDLT_II 0x87
! 116: #define TAPE_MEDIATYPE_DLT_S4 0x91
! 117: #define TAPE_MEDIATYPE_LTO1 0x18
! 118: #define TAPE_MEDIATYPE_LTO2 0x28
! 119: #define TAPE_MEDIATYPE_LTO3 0x38
! 120: #define TAPE_MEDIATYPE_LTO4 0x48
! 121:
! 122: #define TAPE_DENSITY_DEFAULT 0x00
! 123: #define TAPE_DENSITY_DLT_III 0x19
! 124: #define TAPE_DENSITY_DLT_IV20 0x1a
! 125: #define TAPE_DENSITY_DLT_IV35 0x1b
! 126: #define TAPE_DENSITY_DLT_IV 0x41
! 127: #define TAPE_DENSITY_SDLT_I 0x49
! 128: #define TAPE_DENSITY_SDLT_II 0x4a
! 129: #define TAPE_DENSITY_DLT_S4 0x4b
! 130: #define TAPE_DENSITY_LTO1 0x40
! 131: #define TAPE_DENSITY_LTO2 0x42
! 132: #define TAPE_DENSITY_LTO3 0x44
! 133: #define TAPE_DENSITY_LTO4 0x46
! 134:
! 135: #define CTLBLOCKLEN (128*1024)
! 136: #define CTLMAGIC "ISVTCTRL"
! 137: #define CTLMAGICLEN 8
! 138: #define CTLVERSION 0ULL
! 139: #define CTLENDIAN 0x1122334455667788ULL
! 140: #define MARK_END 0xffffffffffffffffULL
! 141: #define MARK_EOD 0xfffffffffffffffeULL
! 142: #define LBPOS_INVALID 0xffffffffffffffffULL
! 143: #define LBPOS_MAX 0xfffffffffffffffeULL
! 144:
! 145: typedef struct tape_markpos_t {
! 146: uint64_t lbpos; /* logical position */
! 147: uint64_t offset; /* physical position */
! 148: uint64_t prev; /* previous position if not zero */
! 149: uint64_t junk1;
! 150: } tape_markpos_t;
! 151:
! 152: /* Control Block = 128K */
! 153: #define MAX_FILEMARKS (1024)
! 154: typedef struct tape_ctlblock_t {
! 155: /* 16k block 0-2 */
! 156: uint8_t magic[8]; /* 'ISVTCTRL' (network order) */
! 157: uint64_t endian; /* endian ID = 0x1122334455667788ULL */
! 158: uint64_t version; /* version = 0 */
! 159: uint64_t ctlblocklen; /* ctlblocklen = 128K */
! 160:
! 161: uint64_t blocklen; /* blocklen = 512 */
! 162: uint64_t marklen; /* marklen = 128 */
! 163: uint64_t alignment; /* alignment = 8 */
! 164: uint64_t allocate; /* allocate = 0 */
! 165:
! 166: uint64_t type; /* media type = default */
! 167: uint64_t id; /* media ID = empty */
! 168: uint64_t size; /* media size = empty */
! 169: uint64_t junk1;
! 170:
! 171: uint64_t reserve0[512-12]; /* room for 4K(8x512) */
! 172: tape_markpos_t marks[MAX_FILEMARKS]; /* marks[0] = BOT, ..., EOT 32K */
! 173: uint8_t reserve2[(16*1024) - (8*512)];
! 174:
! 175: /* 16k block 3-7 */
! 176: uint8_t reserve3[(16*1024)];
! 177: uint8_t reserve4[(16*1024)];
! 178: uint8_t reserve5[(16*1024)];
! 179: uint8_t reserve6[(16*1024)];
! 180: uint8_t reserve7[(16*1024)];
! 181: } tape_ctlblock_t;
! 182:
! 183: /* physical marker in virtual tape */
! 184: #define MARK_LENGTH 128
! 185: #define MARK_MAXLENGTH (TAPE_BLOCKLEN)
! 186: #define MARK_MAGICLEN 8
! 187: #define MARK_VERSION 0ULL
! 188: #define MARK_ENDIAN 0x1122334455667788ULL
! 189: #define MARK_BOTMAGIC "ISVTBOTB"
! 190: #define MARK_EOTMAGIC "ISVTEOTB"
! 191: #define MARK_EOFMAGIC "ISVTEOFB"
! 192: #define MARK_EODMAGIC "ISVTEODB"
! 193: #define MARK_DATAMAGIC "ISVTDATA"
! 194: #define MARK_COMPALGO_NONE 0
! 195:
! 196: /* Mark Block = 128B */
! 197: typedef struct tape_markblock_t {
! 198: uint8_t magic[8]; /* 'ISVT'+ 'BOTB' / 'DATA' / 'EOFB' */
! 199: uint64_t endian; /* endian ID = 0x1122334455667788ULL */
! 200: uint64_t version; /* version = 0 */
! 201: uint64_t marklen; /* marklen = 128 */
! 202:
! 203: uint64_t lblen; /* logical block length */
! 204: uint64_t lbpos; /* logical block position */
! 205: uint64_t offset; /* self physical offset */
! 206: uint64_t prev; /* previous offset if non zero */
! 207:
! 208: uint64_t compalgo; /* compression algorithm (0=none) */
! 209: uint64_t vtcompalgo; /* VT compression algorithm (0=none) */
! 210: uint64_t vtdecomplen; /* VT decompression length */
! 211: uint64_t junk1;
! 212:
! 213: /* reserved */
! 214: uint64_t reserve[16-12]; /* 128B(8x16) */
! 215: } tape_markblock_t;
! 216:
! 217:
! 218: typedef struct istgt_lu_tape_t {
! 219: ISTGT_LU_Ptr lu;
! 220: int num;
! 221: int lun;
! 222:
! 223: int fd;
! 224: const char *file;
! 225: uint64_t size;
! 226: uint64_t blocklen;
! 227: uint64_t blockcnt;
! 228:
! 229: #ifdef HAVE_UUID_H
! 230: uuid_t uuid;
! 231: #endif /* HAVE_UUID_H */
! 232:
! 233: /* flags */
! 234: int mflags;
! 235:
! 236: tape_ctlblock_t *ctlblock; /* control block */
! 237: tape_markblock_t *markblock; /* mark block */
! 238:
! 239: uint64_t lblen; /* logical block length for fixed */
! 240: uint64_t lbpos; /* logical block position */
! 241:
! 242: uint64_t offset; /* physical offset in virtual tape */
! 243: uint64_t prev; /* previous offset if not zero */
! 244: int index; /* current maker index */
! 245:
! 246: int compalgo; /* compression algorithme */
! 247: int vtcompalgo; /* compression algorithme in vtape */
! 248:
! 249: /* pending flags */
! 250: int need_savectl;
! 251: int need_writeeod;
! 252:
! 253: /* media state */
! 254: volatile int mload;
! 255: volatile int mchanged;
! 256: volatile int mwait;
! 257:
! 258: /* mode flags */
! 259: volatile int lock;
! 260: int compression;
! 261: int bot;
! 262: int eof;
! 263: int eod;
! 264: int eom;
! 265:
! 266: /* SCSI sense code */
! 267: volatile int sense;
! 268:
! 269: /* command information */
! 270: uint32_t info;
! 271: } ISTGT_LU_TAPE;
! 272:
! 273: #define BUILD_SENSE(SK,ASC,ASCQ) \
! 274: do { \
! 275: *sense_len = \
! 276: istgt_lu_tape_build_sense_data(spec, sense_data, \
! 277: ISTGT_SCSI_SENSE_ ## SK, \
! 278: (ASC), (ASCQ)); \
! 279: } while (0)
! 280:
! 281: static int istgt_lu_tape_save_ctlblock(ISTGT_LU_TAPE *spec);
! 282: static int istgt_lu_tape_allocate(ISTGT_LU_TAPE *spec);
! 283: static int istgt_lu_tape_build_sense_data(ISTGT_LU_TAPE *spec, uint8_t *data, int sk, int asc, int ascq);
! 284:
! 285: static int
! 286: istgt_lu_tape_open(ISTGT_LU_TAPE *spec, int flags, int mode)
! 287: {
! 288: int rc;
! 289:
! 290: rc = open(spec->file, flags, mode);
! 291: if (rc < 0) {
! 292: return -1;
! 293: }
! 294: spec->fd = rc;
! 295: return 0;
! 296: }
! 297:
! 298: static int
! 299: istgt_lu_tape_close(ISTGT_LU_TAPE *spec)
! 300: {
! 301: int rc;
! 302:
! 303: if (spec->fd == -1)
! 304: return 0;
! 305: rc = close(spec->fd);
! 306: if (rc < 0) {
! 307: return -1;
! 308: }
! 309: spec->fd = -1;
! 310: return 0;
! 311: }
! 312:
! 313: static int64_t
! 314: istgt_lu_tape_seek(ISTGT_LU_TAPE *spec, uint64_t offset)
! 315: {
! 316: off_t rc;
! 317:
! 318: rc = lseek(spec->fd, (off_t) offset, SEEK_SET);
! 319: if (rc < 0) {
! 320: return -1;
! 321: }
! 322: return 0;
! 323: }
! 324:
! 325: static int64_t
! 326: istgt_lu_tape_read(ISTGT_LU_TAPE *spec, void *buf, uint64_t nbytes)
! 327: {
! 328: int64_t rc;
! 329:
! 330: rc = (int64_t) read(spec->fd, buf, (size_t) nbytes);
! 331: if (rc < 0) {
! 332: return -1;
! 333: }
! 334: return rc;
! 335: }
! 336:
! 337: static int64_t
! 338: istgt_lu_tape_write(ISTGT_LU_TAPE *spec, const void *buf, uint64_t nbytes)
! 339: {
! 340: int64_t rc;
! 341:
! 342: rc = (int64_t) write(spec->fd, buf, (size_t) nbytes);
! 343: if (rc < 0) {
! 344: return -1;
! 345: }
! 346: return rc;
! 347: }
! 348:
! 349: static int64_t
! 350: istgt_lu_tape_sync(ISTGT_LU_TAPE *spec, uint64_t offset, uint64_t nbytes)
! 351: {
! 352: int64_t rc;
! 353:
! 354: rc = (int64_t) fsync(spec->fd);
! 355: if (rc < 0) {
! 356: return -1;
! 357: }
! 358: return rc;
! 359: }
! 360:
! 361: #if 0
! 362: static uint64_t
! 363: swap_uint64(uint64_t val)
! 364: {
! 365: uint64_t r;
! 366: int i;
! 367:
! 368: r = 0;
! 369: for (i = 0; i < sizeof(uint64_t); i++) {
! 370: r |= val & 0xffULL;
! 371: r <<= 8;
! 372: val >>= 8;
! 373: }
! 374: return r;
! 375: }
! 376: #endif
! 377:
! 378: #define SWAP_UINT64(D) \
! 379: ((( (D) >> (56 - 0 )) & 0x00000000000000ffULL) \
! 380: | (((D) << (56 - 0 )) & 0xff00000000000000ULL) \
! 381: | (((D) >> (48 - 8 )) & 0x000000000000ff00ULL) \
! 382: | (((D) << (48 - 8 )) & 0x00ff000000000000ULL) \
! 383: | (((D) >> (40 - 16)) & 0x0000000000ff0000ULL) \
! 384: | (((D) << (40 - 16)) & 0x0000ff0000000000ULL) \
! 385: | (((D) >> (32 - 24)) & 0x00000000ff000000ULL) \
! 386: | (((D) << (32 - 24)) & 0x000000ff00000000ULL))
! 387:
! 388:
! 389: static int
! 390: istgt_lu_tape_read_native_mark(ISTGT_LU_TAPE *spec, tape_markblock_t *mbp)
! 391: {
! 392: uint64_t marklen;
! 393: uint64_t *lp;
! 394: int64_t rc;
! 395: int i;
! 396:
! 397: marklen = spec->ctlblock->marklen;
! 398:
! 399: rc = istgt_lu_tape_read(spec, mbp, marklen);
! 400: if (rc < 0 || rc != marklen) {
! 401: ISTGT_ERRLOG("lu_tape_read() failed: rc %d\n", rc);
! 402: return -1;
! 403: }
! 404: if (mbp->endian != MARK_ENDIAN) {
! 405: /* convert byte order but except magic */
! 406: lp = (uint64_t *) mbp;
! 407: for (i = 1; i < marklen / sizeof(uint64_t); i++) {
! 408: lp[i] = SWAP_UINT64(lp[i]);
! 409: }
! 410: }
! 411: return 0;
! 412: }
! 413:
! 414: static int
! 415: istgt_lu_tape_write_native_mark(ISTGT_LU_TAPE *spec, tape_markblock_t *mbp)
! 416: {
! 417: uint64_t marklen;
! 418: int64_t rc;
! 419:
! 420: marklen = spec->ctlblock->marklen;
! 421:
! 422: rc = istgt_lu_tape_write(spec, mbp, marklen);
! 423: if (rc != marklen) {
! 424: ISTGT_ERRLOG("lu_tape_write() failed at offset %" PRIu64 ", size %" PRIu64 "\n", spec->offset, spec->size);
! 425: return -1;
! 426: }
! 427: return 0;
! 428: }
! 429:
! 430: static int
! 431: istgt_lu_tape_write_padding(ISTGT_LU_TAPE *spec, uint8_t *data)
! 432: {
! 433: uint64_t tape_leader;
! 434: uint64_t offset;
! 435: uint64_t alignment, padlen;
! 436: int64_t rc;
! 437:
! 438: tape_leader = spec->ctlblock->ctlblocklen;
! 439: offset = spec->offset;
! 440: alignment = spec->ctlblock->alignment;
! 441:
! 442: if (offset % alignment) {
! 443: padlen = alignment;
! 444: padlen -= offset % alignment;
! 445: memset(data, 0, alignment);
! 446: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 447: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 448: return -1;
! 449: }
! 450: rc = istgt_lu_tape_write(spec, data, padlen);
! 451: if (rc < 0 || rc != padlen) {
! 452: ISTGT_ERRLOG("lu_tape_write() failed\n");
! 453: return -1;
! 454: }
! 455: offset += padlen;
! 456: spec->offset = offset;
! 457: }
! 458: return 0;
! 459: }
! 460:
! 461: static int
! 462: istgt_lu_tape_write_eof(ISTGT_LU_TAPE *spec, int count, uint8_t *data)
! 463: {
! 464: tape_markblock_t *mbp;
! 465: uint64_t tape_leader;
! 466: uint64_t lbpos, offset, prev, version, marklen;
! 467: int index_i;
! 468: int i;
! 469:
! 470: if (count <= 0) {
! 471: // flush buffer
! 472: return 0;
! 473: }
! 474:
! 475: if (istgt_lu_tape_write_padding(spec, data) < 0) {
! 476: ISTGT_ERRLOG("lu_tape_write_padding() failed\n");
! 477: return -1;
! 478: }
! 479:
! 480: tape_leader = spec->ctlblock->ctlblocklen;
! 481: lbpos = spec->lbpos;
! 482: offset = spec->offset;
! 483: prev = spec->prev;
! 484: index_i = spec->index;
! 485: version = spec->ctlblock->version;
! 486: marklen = spec->ctlblock->marklen;
! 487:
! 488: /* prepare mark */
! 489: mbp = (tape_markblock_t *) data;
! 490: memset(mbp, 0, marklen);
! 491: memcpy(mbp->magic, MARK_EOFMAGIC, MARK_MAGICLEN);
! 492: mbp->endian = MARK_ENDIAN;
! 493: mbp->version = MARK_VERSION;
! 494: mbp->marklen = marklen;
! 495: mbp->lblen = 0ULL;
! 496: mbp->compalgo = 0ULL;
! 497: mbp->vtcompalgo = 0ULL;
! 498: mbp->vtdecomplen = 0ULL;
! 499:
! 500: /* seek to current physical position */
! 501: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 502: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 503: return -1;
! 504: }
! 505:
! 506: /* write EOF N blocks */
! 507: for (i = 0; i < count; i++) {
! 508: mbp->lbpos = lbpos;
! 509: mbp->offset = offset;
! 510: mbp->prev = prev;
! 511: index_i++;
! 512: spec->ctlblock->marks[index_i].lbpos = lbpos;
! 513: spec->ctlblock->marks[index_i].offset = offset;
! 514: spec->ctlblock->marks[index_i].prev = prev;
! 515: spec->ctlblock->marks[index_i + 1].lbpos = MARK_END;
! 516: spec->ctlblock->marks[index_i + 1].offset = MARK_END;
! 517: spec->ctlblock->marks[index_i + 1].prev = offset + marklen;
! 518: spec->index = index_i;
! 519: spec->offset = offset;
! 520: if (istgt_lu_tape_write_native_mark(spec, mbp) < 0) {
! 521: ISTGT_ERRLOG("istgt_lu_tape_write_native_mark() failed\n");
! 522: spec->prev = 0ULL;
! 523: return -1;
! 524: }
! 525: lbpos++;
! 526: prev = offset;
! 527: offset += marklen;
! 528: /* update information */
! 529: spec->lbpos = lbpos;
! 530: spec->prev = prev;
! 531: spec->offset = offset;
! 532: spec->eof = 1;
! 533: }
! 534: return 0;
! 535: }
! 536:
! 537: static int
! 538: istgt_lu_tape_write_bot(ISTGT_LU_TAPE *spec, uint8_t *data)
! 539: {
! 540: tape_markblock_t *mbp;
! 541: uint64_t tape_leader;
! 542: uint64_t lbpos, offset, prev, version, marklen;
! 543: int index_i;
! 544:
! 545: tape_leader = spec->ctlblock->ctlblocklen;
! 546: lbpos = 0ULL;
! 547: offset = 0ULL;
! 548: prev = 0ULL;
! 549: index_i = 0ULL;
! 550: version = spec->ctlblock->version;
! 551: marklen = spec->ctlblock->marklen;
! 552:
! 553: /* prepare mark */
! 554: mbp = (tape_markblock_t *) data;
! 555: memset(mbp, 0, marklen);
! 556: memcpy(mbp->magic, MARK_BOTMAGIC, MARK_MAGICLEN);
! 557: mbp->endian = MARK_ENDIAN;
! 558: mbp->version = MARK_VERSION;
! 559: mbp->marklen = marklen;
! 560: mbp->lblen = 0ULL;
! 561: mbp->compalgo = 0ULL;
! 562: mbp->vtcompalgo = 0ULL;
! 563: mbp->vtdecomplen = 0ULL;
! 564:
! 565: /* seek to current physical position */
! 566: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 567: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 568: return -1;
! 569: }
! 570:
! 571: /* write BOT block */
! 572: mbp->lbpos = lbpos;
! 573: mbp->offset = offset;
! 574: mbp->prev = prev;
! 575: index_i++;
! 576: spec->ctlblock->marks[index_i].lbpos = lbpos;
! 577: spec->ctlblock->marks[index_i].offset = offset;
! 578: spec->ctlblock->marks[index_i].prev = prev;
! 579: spec->ctlblock->marks[index_i + 1].lbpos = MARK_END;
! 580: spec->ctlblock->marks[index_i + 1].offset = MARK_END;
! 581: spec->ctlblock->marks[index_i + 1].prev = offset + marklen;
! 582: spec->index = index_i;
! 583: spec->offset = offset;
! 584: if (istgt_lu_tape_write_native_mark(spec, mbp) < 0) {
! 585: ISTGT_ERRLOG("lu_tape_write_native_mark() failed\n");
! 586: spec->prev = 0ULL;
! 587: return -1;
! 588: }
! 589: lbpos++;
! 590: prev = offset;
! 591: offset += marklen;
! 592: /* update information */
! 593: spec->lbpos = lbpos;
! 594: spec->prev = prev;
! 595: spec->offset = offset;
! 596: return 0;
! 597: }
! 598:
! 599: static int
! 600: istgt_lu_tape_write_eod(ISTGT_LU_TAPE *spec, uint8_t *data)
! 601: {
! 602: tape_markblock_t *mbp;
! 603: uint64_t tape_leader;
! 604: uint64_t lbpos, offset, prev, version, marklen;
! 605: int index_i;
! 606:
! 607: tape_leader = spec->ctlblock->ctlblocklen;
! 608: lbpos = spec->lbpos;
! 609: offset = spec->offset;
! 610: prev = spec->prev;
! 611: index_i = spec->index;
! 612: version = spec->ctlblock->version;
! 613: marklen = spec->ctlblock->marklen;
! 614:
! 615: /* prepare mark */
! 616: mbp = (tape_markblock_t *) data;
! 617: memset(mbp, 0, marklen);
! 618: memcpy(mbp->magic, MARK_EODMAGIC, MARK_MAGICLEN);
! 619: mbp->endian = MARK_ENDIAN;
! 620: mbp->version = MARK_VERSION;
! 621: mbp->marklen = marklen;
! 622: mbp->lblen = 0ULL;
! 623: mbp->compalgo = 0ULL;
! 624: mbp->vtcompalgo = 0ULL;
! 625: mbp->vtdecomplen = 0ULL;
! 626:
! 627: /* seek to current physical position */
! 628: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 629: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 630: return -1;
! 631: }
! 632:
! 633: /* write EOD block */
! 634: mbp->lbpos = lbpos;
! 635: mbp->offset = offset;
! 636: mbp->prev = prev;
! 637: if (istgt_lu_tape_write_native_mark(spec, mbp) < 0) {
! 638: ISTGT_ERRLOG("lu_tape_write_native_mark() failed\n");
! 639: return -1;
! 640: }
! 641: /* no update information */
! 642: return 0;
! 643: }
! 644:
! 645: static int
! 646: istgt_lu_tape_write_media_check(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t request_len)
! 647: {
! 648: uint64_t tape_leader;
! 649: uint64_t extendsize;
! 650: uint64_t mediasize;
! 651: uint64_t offset;
! 652: int data_len;
! 653:
! 654: tape_leader = spec->ctlblock->ctlblocklen;
! 655: mediasize = spec->size;
! 656: offset = spec->offset;
! 657:
! 658: /* writable media? */
! 659: if (spec->lu->readonly
! 660: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 661: /* WRITE PROTECTED */
! 662: data_len
! 663: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 664: ISTGT_SCSI_SENSE_DATA_PROTECT,
! 665: 0x27, 0x00);
! 666: lu_cmd->sense_data_len = data_len;
! 667: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 668: return -1;
! 669: }
! 670:
! 671: /* always keep control block */
! 672: if (mediasize < tape_leader) {
! 673: /* INTERNAL TARGET FAILURE */
! 674: data_len
! 675: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 676: ISTGT_SCSI_SENSE_HARDWARE_ERROR,
! 677: 0x44, 0x00);
! 678: lu_cmd->sense_data_len = data_len;
! 679: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 680: return -1;
! 681: }
! 682: mediasize -= tape_leader;
! 683:
! 684: /* request can store? */
! 685: if (request_len > mediasize || offset > mediasize - request_len) {
! 686: /* determine extend size */
! 687: extendsize = request_len / ISTGT_LU_MEDIA_EXTEND_UNIT;
! 688: extendsize *= ISTGT_LU_MEDIA_EXTEND_UNIT;
! 689: if (request_len % ISTGT_LU_MEDIA_EXTEND_UNIT) {
! 690: extendsize += ISTGT_LU_MEDIA_EXTEND_UNIT;
! 691: }
! 692: /* can handle? */
! 693: if (mediasize < MARK_END - 1 - tape_leader - extendsize) {
! 694: if (spec->mflags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) {
! 695: /* OK dynamic allocation */
! 696: mediasize += extendsize;
! 697: } else if (spec->mflags & ISTGT_LU_FLAG_MEDIA_EXTEND) {
! 698: /* OK extend media size */
! 699: mediasize += extendsize;
! 700: } else {
! 701: /* no space virtual EOM */
! 702: goto eom_error;
! 703: }
! 704: } else {
! 705: eom_error:
! 706: /* physical EOM */
! 707: spec->eom = 1;
! 708: /* END-OF-PARTITION/MEDIUM DETECTED */
! 709: /* VOLUME OVERFLOW */
! 710: data_len
! 711: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 712: ISTGT_SCSI_SENSE_VOLUME_OVERFLOW,
! 713: 0x00, 0x02);
! 714: lu_cmd->sense_data_len = data_len;
! 715: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 716: return -1;
! 717: }
! 718: }
! 719:
! 720: /* update information */
! 721: spec->size = tape_leader + mediasize;
! 722:
! 723: /* complete check, ready to write */
! 724: return 0;
! 725: }
! 726:
! 727: static int
! 728: istgt_lu_tape_read_media_check(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t request_len)
! 729: {
! 730: uint64_t tape_leader;
! 731: uint64_t mediasize;
! 732: uint64_t offset;
! 733: int data_len;
! 734:
! 735: tape_leader = spec->ctlblock->ctlblocklen;
! 736: mediasize = spec->size;
! 737: offset = spec->offset;
! 738:
! 739: /* always keep control block */
! 740: if (mediasize < tape_leader) {
! 741: /* INTERNAL TARGET FAILURE */
! 742: data_len
! 743: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 744: ISTGT_SCSI_SENSE_HARDWARE_ERROR,
! 745: 0x44, 0x00);
! 746: lu_cmd->sense_data_len = data_len;
! 747: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 748: return -1;
! 749: }
! 750: mediasize -= tape_leader;
! 751:
! 752: /* request can seek? */
! 753: if (request_len > mediasize || offset > mediasize - request_len) {
! 754: /* physical EOM */
! 755: spec->eom = 1;
! 756: /* END-OF-PARTITION/MEDIUM DETECTED */
! 757: data_len
! 758: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 759: ISTGT_SCSI_SENSE_MEDIUM_ERROR,
! 760: 0x00, 0x02);
! 761: lu_cmd->sense_data_len = data_len;
! 762: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 763: return -1;
! 764: }
! 765:
! 766: /* complete check, ready to read */
! 767: return 0;
! 768: }
! 769:
! 770: static int
! 771: istgt_lu_tape_prepare_offset(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
! 772: {
! 773: uint64_t lbpos, offset, prev, marklen;
! 774: int index_i;
! 775:
! 776: lbpos = spec->lbpos;
! 777: offset = spec->offset;
! 778: prev = spec->prev;
! 779: index_i = spec->index;
! 780: marklen = spec->ctlblock->marklen;
! 781:
! 782: /* position to logical block zero */
! 783: if (spec->bot) {
! 784: spec->bot = 0;
! 785: spec->eof = spec->eod = spec->eom = 0;
! 786: offset = 0;
! 787: prev = offset;
! 788: offset += marklen;
! 789: lbpos++;
! 790: }
! 791:
! 792: if (spec->eom || offset == MARK_END) {
! 793: spec->eom = 1;
! 794: spec->bot = spec->eof = spec->eod = 0;
! 795: }
! 796:
! 797: /* update information */
! 798: spec->index = index_i;
! 799: spec->lbpos = lbpos;
! 800: spec->prev = prev;
! 801: spec->offset = offset;
! 802: return 0;
! 803: }
! 804:
! 805: static int
! 806: istgt_lu_tape_write_pending_data(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
! 807: {
! 808: uint64_t marklen;
! 809: int data_len;
! 810:
! 811: if (spec->need_savectl) {
! 812: if (istgt_lu_tape_save_ctlblock(spec) < 0) {
! 813: ISTGT_ERRLOG("lu_tape_save_ctlblock() failed\n");
! 814: io_failure:
! 815: /* INTERNAL TARGET FAILURE */
! 816: data_len
! 817: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 818: ISTGT_SCSI_SENSE_HARDWARE_ERROR,
! 819: 0x44, 0x00);
! 820: lu_cmd->sense_data_len = data_len;
! 821: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 822: return 0;
! 823: }
! 824: spec->need_savectl = 0;
! 825: }
! 826: if (spec->need_writeeod) {
! 827: marklen = spec->ctlblock->marklen;
! 828: if (istgt_lu_tape_write_media_check(spec, conn, lu_cmd, marklen) < 0) {
! 829: goto io_failure;
! 830: }
! 831: if (istgt_lu_tape_write_eod(spec, lu_cmd->data) < 0) {
! 832: ISTGT_ERRLOG("lu_tape_write_eod() failed\n");
! 833: goto io_failure;
! 834: }
! 835: spec->need_writeeod = 0;
! 836: }
! 837: return 0;
! 838: }
! 839:
! 840: static int
! 841: istgt_lu_tape_rewind(ISTGT_LU_TAPE *spec)
! 842: {
! 843: uint64_t lbpos, offset, prev;
! 844: int index_i;
! 845:
! 846: /* position to BOT */
! 847: spec->bot = 1;
! 848: spec->eof = spec->eod = spec->eom = 0;
! 849: index_i = 0;
! 850: lbpos = spec->ctlblock->marks[index_i].lbpos;
! 851: offset = spec->ctlblock->marks[index_i].offset;
! 852: prev = spec->ctlblock->marks[index_i].prev;
! 853:
! 854: /* update information */
! 855: spec->index = index_i;
! 856: spec->lbpos = lbpos;
! 857: spec->prev = prev;
! 858: spec->offset = offset;
! 859: return 0;
! 860: }
! 861:
! 862: static int
! 863: istgt_lu_tape_load_ctlblock(ISTGT_LU_TAPE *spec)
! 864: {
! 865: int64_t rc;
! 866:
! 867: if (istgt_lu_tape_seek(spec, 0) == -1) {
! 868: return -1;
! 869: }
! 870: rc = istgt_lu_tape_read(spec, spec->ctlblock, CTLBLOCKLEN);
! 871: if (rc < 0 || rc != CTLBLOCKLEN) {
! 872: return -1;
! 873: }
! 874: return rc;
! 875: }
! 876:
! 877: static int
! 878: istgt_lu_tape_save_ctlblock(ISTGT_LU_TAPE *spec)
! 879: {
! 880: int64_t rc;
! 881:
! 882: if (istgt_lu_tape_seek(spec, 0) == -1) {
! 883: return -1;
! 884: }
! 885: rc = istgt_lu_tape_write(spec, spec->ctlblock,
! 886: spec->ctlblock->ctlblocklen);
! 887: if (rc < 0 || rc != spec->ctlblock->ctlblocklen) {
! 888: return -1;
! 889: }
! 890: return rc;
! 891: }
! 892:
! 893: static int
! 894: istgt_lu_tape_init_ctlblock(ISTGT_LU_TAPE *spec, int newfile)
! 895: {
! 896: tape_ctlblock_t *cbp;
! 897: uint64_t *lp;
! 898: int rc;
! 899: int i;
! 900:
! 901: cbp = spec->ctlblock;
! 902:
! 903: rc = istgt_lu_tape_load_ctlblock(spec);
! 904: if (rc < 0) {
! 905: return -1;
! 906: }
! 907: if (memcmp(cbp->magic, CTLMAGIC, CTLMAGICLEN) != 0) {
! 908: if (spec->lu->readonly
! 909: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)
! 910: || !newfile) {
! 911: ISTGT_ERRLOG("Can not initialize \"%s\"\n", spec->file);
! 912: return -1;
! 913: }
! 914: /* initialize control block */
! 915: memset(cbp, 0, CTLBLOCKLEN);
! 916: memcpy(cbp->magic, CTLMAGIC, CTLMAGICLEN);
! 917: cbp->marks[0].offset = 0ULL;
! 918: cbp->marks[0].lbpos = 0ULL;
! 919: cbp->marks[0].prev = 0ULL;
! 920: cbp->marks[1].offset = MARK_END;
! 921: cbp->marks[1].lbpos = MARK_END;
! 922: cbp->marks[1].prev = 0ULL;
! 923: cbp->endian = CTLENDIAN;
! 924: cbp->version = CTLVERSION;
! 925: cbp->ctlblocklen = (uint64_t) CTLBLOCKLEN;
! 926: cbp->blocklen = (uint64_t) TAPE_BLOCKLEN;
! 927: cbp->marklen = (uint64_t) MARK_LENGTH;
! 928: cbp->alignment = (uint64_t) TAPE_ALIGNMENT;
! 929: cbp->allocate = 0ULL;
! 930: cbp->type = 0ULL;
! 931: cbp->id = 0ULL;
! 932: cbp->size = 0ULL;
! 933: rc = istgt_lu_tape_save_ctlblock(spec);
! 934: if (rc < 0) {
! 935: ISTGT_ERRLOG("lu_tape_save_ctlblock() failed\n");
! 936: return -1;
! 937: }
! 938: rc = istgt_lu_tape_write_bot(spec, (uint8_t *) spec->markblock);
! 939: if (rc < 0) {
! 940: ISTGT_ERRLOG("lu_tape_write_bot() failed\n");
! 941: return -1;
! 942: }
! 943: rc = istgt_lu_tape_write_eod(spec, (uint8_t *) spec->markblock);
! 944: if (rc < 0) {
! 945: ISTGT_ERRLOG("lu_tape_write_eod() failed\n");
! 946: return -1;
! 947: }
! 948: } else {
! 949: if (cbp->endian != CTLENDIAN) {
! 950: /* convert byte order but except magic */
! 951: lp = (uint64_t *) cbp;
! 952: for (i = 1; i < CTLBLOCKLEN / sizeof(uint64_t); i++) {
! 953: lp[i] = SWAP_UINT64(lp[i]);
! 954: }
! 955: }
! 956: if (cbp->ctlblocklen == 0ULL
! 957: || cbp->blocklen == 0ULL
! 958: || cbp->marklen == 0ULL
! 959: || cbp->alignment == 0ULL) {
! 960: ISTGT_ERRLOG("bad length\n");
! 961: return -1;
! 962: }
! 963: if (cbp->version > CTLVERSION) {
! 964: ISTGT_ERRLOG("unsupported tape version 0x%"PRIx64"\n",
! 965: cbp->version);
! 966: return -1;
! 967: }
! 968: if (cbp->marklen > MARK_MAXLENGTH) {
! 969: ISTGT_ERRLOG("marklen is too long\n");
! 970: return -1;
! 971: }
! 972: }
! 973: return 0;
! 974: }
! 975:
! 976: int
! 977: istgt_lu_tape_media_present(ISTGT_LU_TAPE *spec)
! 978: {
! 979: if (spec->mload) {
! 980: return 1;
! 981: }
! 982: return 0;
! 983: }
! 984:
! 985: int
! 986: istgt_lu_tape_media_lock(ISTGT_LU_TAPE *spec)
! 987: {
! 988: if (spec->lock) {
! 989: return 1;
! 990: }
! 991: return 0;
! 992: }
! 993:
! 994: int
! 995: istgt_lu_tape_load_media(ISTGT_LU_TAPE *spec)
! 996: {
! 997: ISTGT_LU_Ptr lu;
! 998: int flags;
! 999: int newfile;
! 1000: int rc;
! 1001:
! 1002: if (istgt_lu_tape_media_present(spec)) {
! 1003: /* media present */
! 1004: return -1;
! 1005: }
! 1006: if (spec->mchanged) {
! 1007: /* changed soon */
! 1008: return -1;
! 1009: }
! 1010:
! 1011: lu = spec->lu;
! 1012: if (lu->lun[spec->lun].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
! 1013: ISTGT_ERRLOG("LU%d: not removable\n", lu->num);
! 1014: return -1;
! 1015: }
! 1016: if (strcasecmp(lu->lun[spec->lun].u.removable.file,
! 1017: "/dev/null") == 0) {
! 1018: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: empty\n", lu->num);
! 1019: spec->file = NULL;
! 1020: spec->size = 0;
! 1021: spec->mflags = 0;
! 1022: spec->blocklen = TAPE_BLOCKLEN;
! 1023: spec->blockcnt = spec->size / spec->blocklen;
! 1024: spec->compalgo = TAPE_COMP_ALGORITHM;
! 1025: spec->vtcompalgo = MARK_COMPALGO_NONE;
! 1026: spec->compression = COMPRESSION_DFLT;
! 1027: spec->lblen = 0ULL; /* default to variable length */
! 1028: spec->index = 0; /* position to BOT */
! 1029: spec->lbpos = 0ULL;
! 1030: spec->offset = 0ULL;
! 1031: spec->prev = 0ULL;
! 1032: spec->bot = 0;
! 1033: spec->eof = spec->eod = spec->eom = 0;
! 1034: spec->prev = spec->offset;
! 1035: spec->need_savectl = 0;
! 1036: spec->need_writeeod = 0;
! 1037: return 0;
! 1038: }
! 1039: spec->file = lu->lun[spec->lun].u.removable.file;
! 1040: spec->size = lu->lun[spec->lun].u.removable.size;
! 1041: spec->mflags = lu->lun[spec->lun].u.removable.flags;
! 1042: spec->blocklen = TAPE_BLOCKLEN;
! 1043: spec->blockcnt = spec->size / spec->blocklen;
! 1044: spec->compalgo = TAPE_COMP_ALGORITHM;
! 1045: spec->vtcompalgo = MARK_COMPALGO_NONE;
! 1046: spec->compression = COMPRESSION_DFLT;
! 1047: spec->lblen = 0ULL; /* default to variable length */
! 1048: spec->index = 0; /* position to BOT */
! 1049: spec->lbpos = 0ULL;
! 1050: spec->offset = 0ULL;
! 1051: spec->prev = 0ULL;
! 1052: spec->bot = 1;
! 1053: spec->eof = spec->eod = spec->eom = 0;
! 1054: spec->prev = spec->offset;
! 1055: spec->need_savectl = 0;
! 1056: spec->need_writeeod = 0;
! 1057:
! 1058: spec->mload = 0;
! 1059: spec->mchanged = 1;
! 1060: spec->mwait = 3;
! 1061:
! 1062: if (access(spec->file, W_OK) != 0) {
! 1063: if (errno != ENOENT) {
! 1064: spec->mflags |= ISTGT_LU_FLAG_MEDIA_READONLY;
! 1065: }
! 1066: } else {
! 1067: struct stat st;
! 1068: rc = stat(spec->file, &st);
! 1069: if (rc != 0 || !S_ISREG(st.st_mode)) {
! 1070: spec->mflags |= ISTGT_LU_FLAG_MEDIA_READONLY;
! 1071: } else {
! 1072: if ((st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) == 0) {
! 1073: spec->mflags |= ISTGT_LU_FLAG_MEDIA_READONLY;
! 1074: }
! 1075: }
! 1076: }
! 1077: if (spec->lu->readonly
! 1078: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 1079: flags = O_RDONLY;
! 1080: } else {
! 1081: flags = O_RDWR;
! 1082: }
! 1083: newfile = 0;
! 1084: rc = istgt_lu_tape_open(spec, flags, 0666);
! 1085: if (rc < 0) {
! 1086: /* new file? */
! 1087: newfile = 1;
! 1088: if (spec->lu->readonly
! 1089: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 1090: flags = O_RDONLY;
! 1091: } else {
! 1092: flags = (O_CREAT | O_EXCL | O_RDWR);
! 1093: }
! 1094: rc = istgt_lu_tape_open(spec, flags, 0666);
! 1095: if (rc < 0) {
! 1096: ISTGT_ERRLOG("LU%d: LUN%d: open error\n", lu->num, spec->lun);
! 1097: return -1;
! 1098: }
! 1099: if (lu->lun[spec->lun].u.removable.size < ISTGT_LU_MEDIA_SIZE_MIN) {
! 1100: lu->lun[spec->lun].u.removable.size = ISTGT_LU_MEDIA_SIZE_MIN;
! 1101: }
! 1102: }
! 1103:
! 1104: if (spec->lu->readonly
! 1105: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 1106: /* readonly */
! 1107: } else {
! 1108: if (newfile == 0) {
! 1109: /* existing file check */
! 1110: if (istgt_lu_tape_init_ctlblock(spec, newfile) < 0) {
! 1111: ISTGT_ERRLOG("lu_tape_init_ctlblock() failed\n");
! 1112: return -1;
! 1113: }
! 1114: }
! 1115: rc = istgt_lu_tape_allocate(spec);
! 1116: if (rc < 0) {
! 1117: ISTGT_ERRLOG("LU%d: LUN%d: allocate error\n", lu->num, spec->lun);
! 1118: return -1;
! 1119: }
! 1120: }
! 1121: /* initialize filemarks */
! 1122: if (istgt_lu_tape_init_ctlblock(spec, newfile) < 0) {
! 1123: ISTGT_ERRLOG("lu_tape_init_ctlblock() failed\n");
! 1124: return -1;
! 1125: }
! 1126: istgt_lu_tape_rewind(spec);
! 1127: return 0;
! 1128: }
! 1129:
! 1130: int
! 1131: istgt_lu_tape_unload_media(ISTGT_LU_TAPE *spec)
! 1132: {
! 1133: int rc;
! 1134:
! 1135: if (!istgt_lu_tape_media_present(spec)
! 1136: && !spec->mchanged) {
! 1137: /* media absent */
! 1138: return 0;
! 1139: }
! 1140: if (istgt_lu_tape_media_lock(spec)) {
! 1141: return -1;
! 1142: }
! 1143:
! 1144: if (spec->need_savectl) {
! 1145: if (istgt_lu_tape_save_ctlblock(spec) < 0) {
! 1146: ISTGT_ERRLOG("lu_tape_save_ctlblock() failed\n");
! 1147: return -1;
! 1148: }
! 1149: spec->need_savectl = 0;
! 1150: }
! 1151: if (spec->need_writeeod) {
! 1152: if (istgt_lu_tape_write_eod(spec, (uint8_t *) spec->markblock) < 0) {
! 1153: ISTGT_ERRLOG("write_eod() failed\n");
! 1154: return -1;
! 1155: }
! 1156: spec->need_writeeod = 0;
! 1157: }
! 1158:
! 1159: if (!spec->lu->readonly
! 1160: && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 1161: rc = istgt_lu_tape_sync(spec, 0, spec->size);
! 1162: if (rc < 0) {
! 1163: ISTGT_ERRLOG("lu_tape_sync() failed\n");
! 1164: return -1;
! 1165: }
! 1166: }
! 1167: rc = (int64_t) istgt_lu_tape_close(spec);
! 1168: if (rc < 0) {
! 1169: ISTGT_ERRLOG("lu_tape_close() failed\n");
! 1170: return -1;
! 1171: }
! 1172:
! 1173: spec->file = NULL;
! 1174: spec->size = 0;
! 1175: spec->mflags = 0;
! 1176: spec->blocklen = TAPE_BLOCKLEN;
! 1177: spec->blockcnt = spec->size / spec->blocklen;
! 1178: spec->compalgo = TAPE_COMP_ALGORITHM;
! 1179: spec->vtcompalgo = MARK_COMPALGO_NONE;
! 1180: spec->compression = COMPRESSION_DFLT;
! 1181: spec->lblen = 0ULL; /* default to variable length */
! 1182: spec->index = 0; /* position to BOT */
! 1183: spec->lbpos = 0ULL;
! 1184: spec->offset = 0ULL;
! 1185: spec->prev = 0ULL;
! 1186: spec->bot = 0;
! 1187: spec->eof = spec->eod = spec->eom = 0;
! 1188: spec->prev = spec->offset;
! 1189: spec->need_savectl = 0;
! 1190: spec->need_writeeod = 0;
! 1191:
! 1192: spec->mload = 0;
! 1193: spec->mchanged = 0;
! 1194: spec->mwait = 3;
! 1195:
! 1196: return 0;
! 1197: }
! 1198:
! 1199: int
! 1200: istgt_lu_tape_change_media(ISTGT_LU_TAPE *spec, char *type, char *flags, char *file, char *size)
! 1201: {
! 1202: ISTGT_LU_Ptr lu;
! 1203: char *mfile;
! 1204: uint64_t msize;
! 1205: int mflags;
! 1206: int rc;
! 1207:
! 1208: if (istgt_lu_tape_media_lock(spec)) {
! 1209: return -1;
! 1210: }
! 1211:
! 1212: lu = spec->lu;
! 1213: if (lu->lun[spec->lun].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
! 1214: ISTGT_ERRLOG("LU%d: not removable\n", lu->num);
! 1215: return -1;
! 1216: }
! 1217:
! 1218: if (strcmp(type, "-") == 0) {
! 1219: /* use VT image */
! 1220: ;
! 1221: } else {
! 1222: ISTGT_ERRLOG("unsupported media type\n");
! 1223: return -1;
! 1224: }
! 1225:
! 1226: mfile = xstrdup(file);
! 1227: mflags = istgt_lu_parse_media_flags(flags);
! 1228: msize = istgt_lu_parse_media_size(file, size, &mflags);
! 1229:
! 1230: rc = istgt_lu_tape_unload_media(spec);
! 1231: if (rc < 0) {
! 1232: return -1;
! 1233: }
! 1234:
! 1235: /* replace */
! 1236: xfree(lu->lun[spec->lun].u.removable.file);
! 1237: lu->lun[spec->lun].u.removable.file = mfile;
! 1238: lu->lun[spec->lun].u.removable.size = msize;
! 1239: lu->lun[spec->lun].u.removable.flags = mflags;
! 1240:
! 1241: /* reload */
! 1242: rc = istgt_lu_tape_load_media(spec);
! 1243: if (rc < 0) {
! 1244: (void) istgt_lu_tape_unload_media(spec);
! 1245: }
! 1246: if (spec->file == NULL) {
! 1247: (void) istgt_lu_tape_unload_media(spec);
! 1248: }
! 1249: spec->mwait = 5;
! 1250: return rc;
! 1251: }
! 1252:
! 1253: static int
! 1254: istgt_lu_tape_allocate(ISTGT_LU_TAPE *spec)
! 1255: {
! 1256: uint8_t *data;
! 1257: uint64_t fsize;
! 1258: uint64_t size;
! 1259: uint64_t blocklen;
! 1260: uint64_t offset;
! 1261: uint64_t nbytes;
! 1262: int64_t rc;
! 1263:
! 1264: size = spec->size;
! 1265: blocklen = spec->blocklen;
! 1266: nbytes = blocklen;
! 1267: data = xmalloc(nbytes);
! 1268: memset(data, 0, nbytes);
! 1269:
! 1270: fsize = istgt_lu_get_filesize(spec->file);
! 1271: if (fsize > size) {
! 1272: xfree(data);
! 1273: return 0;
! 1274: }
! 1275:
! 1276: offset = size - nbytes;
! 1277: rc = istgt_lu_tape_seek(spec, offset);
! 1278: if (rc == -1) {
! 1279: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 1280: xfree(data);
! 1281: return -1;
! 1282: }
! 1283: rc = istgt_lu_tape_read(spec, data, nbytes);
! 1284: /* EOF is OK */
! 1285: if (rc == -1) {
! 1286: ISTGT_ERRLOG("lu_tape_read() failed\n");
! 1287: xfree(data);
! 1288: return -1;
! 1289: }
! 1290: rc = istgt_lu_tape_seek(spec, offset);
! 1291: if (rc == -1) {
! 1292: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 1293: xfree(data);
! 1294: return -1;
! 1295: }
! 1296: rc = istgt_lu_tape_write(spec, data, nbytes);
! 1297: if (rc == -1 || rc != nbytes) {
! 1298: ISTGT_ERRLOG("lu_tape_write() failed\n");
! 1299: xfree(data);
! 1300: return -1;
! 1301: }
! 1302:
! 1303: xfree(data);
! 1304: return 0;
! 1305: }
! 1306:
! 1307: int
! 1308: istgt_lu_tape_init(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
! 1309: {
! 1310: ISTGT_LU_TAPE *spec;
! 1311: uint64_t gb_size;
! 1312: uint64_t mb_size;
! 1313: #ifdef HAVE_UUID_H
! 1314: uint32_t status;
! 1315: #endif /* HAVE_UUID_H */
! 1316: int mb_digit;
! 1317: int ro;
! 1318: int rc;
! 1319: int i;
! 1320:
! 1321: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_tape_init\n");
! 1322:
! 1323: if (sizeof(tape_ctlblock_t) != CTLBLOCKLEN) {
! 1324: ISTGT_ERRLOG("Invalid ctlblock len %" PRIu64 ".\n",
! 1325: sizeof(tape_ctlblock_t));
! 1326: return -1;
! 1327: }
! 1328:
! 1329: printf("LU%d TAPE UNIT\n", lu->num);
! 1330: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
! 1331: lu->num, lu->name);
! 1332: for (i = 0; i < lu->maxlun; i++) {
! 1333: if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
! 1334: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
! 1335: lu->num, i);
! 1336: lu->lun[i].spec = NULL;
! 1337: continue;
! 1338: }
! 1339: if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
! 1340: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
! 1341: return -1;
! 1342: }
! 1343: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d removable\n",
! 1344: lu->num, i);
! 1345:
! 1346: spec = xmalloc(sizeof *spec);
! 1347: memset(spec, 0, sizeof *spec);
! 1348: spec->lu = lu;
! 1349: spec->num = lu->num;
! 1350: spec->lun = i;
! 1351: spec->fd = -1;
! 1352:
! 1353: #ifdef HAVE_UUID_H
! 1354: uuid_create(&spec->uuid, &status);
! 1355: if (status != uuid_s_ok) {
! 1356: ISTGT_ERRLOG("LU%d: LUN%d: uuid_create() failed\n", lu->num, i);
! 1357: xfree(spec);
! 1358: return -1;
! 1359: }
! 1360: #endif /* HAVE_UUID_H */
! 1361:
! 1362: spec->ctlblock = xmalloc(CTLBLOCKLEN);
! 1363: spec->markblock = xmalloc(MARK_MAXLENGTH);
! 1364:
! 1365: spec->mload = 0;
! 1366: spec->mchanged = 0;
! 1367: spec->mwait = 0;
! 1368: rc = istgt_lu_tape_load_media(spec);
! 1369: if (rc < 0) {
! 1370: ISTGT_ERRLOG("lu_tape_load_media() failed\n");
! 1371: xfree(spec->markblock);
! 1372: xfree(spec->ctlblock);
! 1373: xfree(spec);
! 1374: return -1;
! 1375: }
! 1376:
! 1377: if (spec->file != NULL) {
! 1378: /* initial state */
! 1379: spec->mload = 1;
! 1380: spec->mchanged = 0;
! 1381: spec->mwait = 0;
! 1382:
! 1383: if (spec->lu->readonly
! 1384: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 1385: ro = 1;
! 1386: } else {
! 1387: ro = 0;
! 1388: }
! 1389:
! 1390: printf("LU%d: LUN%d file=%s, size=%"PRIu64", flag=%s\n",
! 1391: lu->num, i, spec->file, spec->size, ro ? "ro" : "rw");
! 1392: printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
! 1393: lu->num, i, spec->blockcnt, spec->blocklen);
! 1394:
! 1395: gb_size = spec->size / ISTGT_LU_1GB;
! 1396: mb_size = (spec->size % ISTGT_LU_1GB) / ISTGT_LU_1MB;
! 1397: if (gb_size > 0) {
! 1398: mb_digit = (int) (((mb_size * 100) / 1024) / 10);
! 1399: printf("LU%d: LUN%d %"PRIu64".%dGB %sstorage for %s\n",
! 1400: lu->num, i, gb_size, mb_digit,
! 1401: lu->readonly ? "readonly " : "", lu->name);
! 1402: } else {
! 1403: printf("LU%d: LUN%d %"PRIu64"MB %sstorage for %s\n",
! 1404: lu->num, i, mb_size,
! 1405: lu->readonly ? "readonly " : "", lu->name);
! 1406: }
! 1407: } else {
! 1408: /* initial state */
! 1409: spec->mload = 0;
! 1410: spec->mchanged = 0;
! 1411: spec->mwait = 0;
! 1412:
! 1413: printf("LU%d: LUN%d empty slot\n",
! 1414: lu->num, i);
! 1415: }
! 1416:
! 1417: lu->lun[i].spec = spec;
! 1418: }
! 1419:
! 1420: return 0;
! 1421: }
! 1422:
! 1423: int
! 1424: istgt_lu_tape_shutdown(ISTGT_Ptr istgt, ISTGT_LU_Ptr lu)
! 1425: {
! 1426: ISTGT_LU_CMD lu_cmd;
! 1427: ISTGT_LU_TAPE *spec;
! 1428: uint8_t *data;
! 1429: int alloc_len;
! 1430: int rc;
! 1431: int i;
! 1432:
! 1433: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "istgt_lu_tape_shutdown\n");
! 1434:
! 1435: alloc_len = 65536;
! 1436: data = xmalloc(alloc_len);
! 1437: memset(&lu_cmd, 0, sizeof lu_cmd);
! 1438: lu_cmd.iobuf = data;
! 1439: lu_cmd.iobufsize = alloc_len;
! 1440: lu_cmd.data = data;
! 1441: lu_cmd.data_len = 0;
! 1442: lu_cmd.alloc_len = alloc_len;
! 1443: lu_cmd.sense_data = data;
! 1444: lu_cmd.sense_alloc_len = alloc_len;
! 1445:
! 1446: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d TargetName=%s\n",
! 1447: lu->num, lu->name);
! 1448: for (i = 0; i < lu->maxlun; i++) {
! 1449: if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
! 1450: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
! 1451: lu->num, i);
! 1452: continue;
! 1453: }
! 1454: if (lu->lun[i].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
! 1455: ISTGT_ERRLOG("LU%d: unsupported type\n", lu->num);
! 1456: xfree(data);
! 1457: return -1;
! 1458: }
! 1459: spec = (ISTGT_LU_TAPE *) lu->lun[i].spec;
! 1460:
! 1461: /* flush pending data */
! 1462: rc = istgt_lu_tape_write_pending_data(spec, NULL, &lu_cmd);
! 1463: if (rc < 0) {
! 1464: ISTGT_ERRLOG("lu_tape_write_pending_data() failed\n");
! 1465: /* ignore error for other cleanup */
! 1466: }
! 1467:
! 1468: if (!spec->lu->readonly
! 1469: && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 1470: rc = istgt_lu_tape_sync(spec, 0, spec->size);
! 1471: if (rc < 0) {
! 1472: //ISTGT_ERRLOG("LU%d: lu_tape_sync() failed\n", lu->num);
! 1473: /* ignore error */
! 1474: }
! 1475: }
! 1476: rc = istgt_lu_tape_close(spec);
! 1477: if (rc < 0) {
! 1478: //ISTGT_ERRLOG("LU%d: lu_tape_close() failed\n", lu->num);
! 1479: /* ignore error */
! 1480: }
! 1481: xfree(spec->ctlblock);
! 1482: xfree(spec->markblock);
! 1483: xfree(spec);
! 1484: lu->lun[i].spec = NULL;
! 1485: }
! 1486:
! 1487: xfree(data);
! 1488: return 0;
! 1489: }
! 1490:
! 1491: static int
! 1492: istgt_lu_tape_scsi_report_luns(ISTGT_LU_Ptr lu, CONN_Ptr conn, uint8_t *cdb, int sel, uint8_t *data, int alloc_len)
! 1493: {
! 1494: uint64_t fmt_lun, lun, method;
! 1495: int hlen = 0, len = 0;
! 1496: int i;
! 1497:
! 1498: if (alloc_len < 8) {
! 1499: return -1;
! 1500: }
! 1501:
! 1502: if (sel == 0x00) {
! 1503: /* logical unit with addressing method */
! 1504: } else if (sel == 0x01) {
! 1505: /* well known logical unit */
! 1506: } else if (sel == 0x02) {
! 1507: /* logical unit */
! 1508: } else {
! 1509: return -1;
! 1510: }
! 1511:
! 1512: /* LUN LIST LENGTH */
! 1513: DSET32(&data[0], 0);
! 1514: /* Reserved */
! 1515: DSET32(&data[4], 0);
! 1516: hlen = 8;
! 1517:
! 1518: for (i = 0; i < lu->maxlun; i++) {
! 1519: if (lu->lun[i].type == ISTGT_LU_LUN_TYPE_NONE) {
! 1520: #if 0
! 1521: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "LU%d: LUN%d none\n",
! 1522: lu->num, i);
! 1523: #endif
! 1524: continue;
! 1525: }
! 1526: if (alloc_len - (hlen + len) < 8) {
! 1527: return -1;
! 1528: }
! 1529: lun = (uint64_t) i;
! 1530: if (lu->maxlun <= 0x0100) {
! 1531: /* below 256 */
! 1532: method = 0x00U;
! 1533: fmt_lun = (method & 0x03U) << 62;
! 1534: fmt_lun |= (lun & 0x00ffU) << 48;
! 1535: } else if (lu->maxlun <= 0x4000U) {
! 1536: /* below 16384 */
! 1537: method = 0x01U;
! 1538: fmt_lun = (method & 0x03U) << 62;
! 1539: fmt_lun |= (lun & 0x3fffU) << 48;
! 1540: } else {
! 1541: /* XXX */
! 1542: fmt_lun = 0;
! 1543: }
! 1544: /* LUN */
! 1545: DSET64(&data[hlen + len], fmt_lun);
! 1546: len += 8;
! 1547: }
! 1548: /* LUN LIST LENGTH */
! 1549: DSET32(&data[0], len);
! 1550: return hlen + len;
! 1551: }
! 1552:
! 1553: static int
! 1554: istgt_lu_tape_scsi_inquiry(ISTGT_LU_TAPE *spec, CONN_Ptr conn, uint8_t *cdb, uint8_t *data, int alloc_len)
! 1555: {
! 1556: char buf[MAX_TMPBUF];
! 1557: uint64_t LUI, TPI;
! 1558: uint8_t *cp, *cp2;
! 1559: int hlen = 0, len = 0, plen, plen2;
! 1560: int pc;
! 1561: int pq, pd;
! 1562: int rmb;
! 1563: int evpd;
! 1564: int pg_tag;
! 1565: int i, j;
! 1566:
! 1567: if (alloc_len < 0xff) {
! 1568: return -1;
! 1569: }
! 1570:
! 1571: pq = 0x00;
! 1572: pd = SPC_PERIPHERAL_DEVICE_TYPE_TAPE;
! 1573: rmb = 1;
! 1574:
! 1575: LUI = istgt_get_lui(spec->lu->name, spec->lun & 0xffffU);
! 1576: TPI = istgt_get_lui(spec->lu->name, conn->portal.tag << 16);
! 1577:
! 1578: pc = cdb[2];
! 1579: evpd = BGET8(&cdb[1], 0);
! 1580: if (evpd) {
! 1581: /* Vital product data */
! 1582: switch (pc) {
! 1583: case SPC_VPD_SUPPORTED_VPD_PAGES:
! 1584: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 1585: BDSET8W(&data[0], pq, 7, 3);
! 1586: BDADD8W(&data[0], pd, 4, 5);
! 1587: /* PAGE CODE */
! 1588: data[1] = pc;
! 1589: /* Reserved */
! 1590: data[2] = 0;
! 1591: /* PAGE LENGTH */
! 1592: data[3] = 0;
! 1593: hlen = 4;
! 1594:
! 1595: #if 0
! 1596: data[4] = SPC_VPD_SUPPORTED_VPD_PAGES; /* 0x00 */
! 1597: data[5] = SPC_VPD_UNIT_SERIAL_NUMBER; /* 0x80 */
! 1598: data[6] = SPC_VPD_DEVICE_IDENTIFICATION; /* 0x83 */
! 1599: data[7] = SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES; /* 0x85 */
! 1600: data[8] = SPC_VPD_EXTENDED_INQUIRY_DATA; /* 0x86 */
! 1601: data[9] = SPC_VPD_MODE_PAGE_POLICY; /* 0x87 */
! 1602: data[10]= SPC_VPD_SCSI_PORTS; /* 0x88 */
! 1603: len = 11 - hlen;
! 1604:
! 1605: /* for DLT8000 */
! 1606: data[4] = SPC_VPD_SUPPORTED_VPD_PAGES; /* 0x00 */
! 1607: data[5] = SPC_VPD_UNIT_SERIAL_NUMBER; /* 0x80 */
! 1608: data[6] = 0xc0; /* Firmware Build Information */
! 1609: data[7] = 0xc1; /* Subsystem Components Revision */
! 1610: len = 8 - hlen;
! 1611: #else
! 1612: /* for DLT-S4 */
! 1613: data[4] = SPC_VPD_SUPPORTED_VPD_PAGES; /* 0x00 */
! 1614: data[5] = SPC_VPD_UNIT_SERIAL_NUMBER; /* 0x80 */
! 1615: data[6] = SPC_VPD_DEVICE_IDENTIFICATION; /* 0x83 */
! 1616: data[7] = 0xb0; /* Sequential-Access Device Capabilities */
! 1617: data[8] = 0xb1; /* Manufacturer-assigned Serial Number */
! 1618: data[9] = 0xc0; /* Firmware Build Information */
! 1619: data[10] = 0xc1; /* Subsystem Components Revision */
! 1620: len = 11 - hlen;
! 1621: #endif
! 1622:
! 1623: /* PAGE LENGTH */
! 1624: data[3] = len;
! 1625: break;
! 1626:
! 1627: case SPC_VPD_UNIT_SERIAL_NUMBER:
! 1628: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 1629: BDSET8W(&data[0], pq, 7, 3);
! 1630: BDADD8W(&data[0], pd, 4, 5);
! 1631: /* PAGE CODE */
! 1632: data[1] = pc;
! 1633: /* Reserved */
! 1634: data[2] = 0;
! 1635: /* PAGE LENGTH */
! 1636: data[3] = 0;
! 1637: hlen = 4;
! 1638:
! 1639: /* PRODUCT SERIAL NUMBER */
! 1640: len = strlen(spec->lu->inq_serial);
! 1641: if (len > MAX_LU_SERIAL_STRING) {
! 1642: len = MAX_LU_SERIAL_STRING;
! 1643: }
! 1644: istgt_strcpy_pad(&data[4], len, spec->lu->inq_serial, ' ');
! 1645:
! 1646: /* PAGE LENGTH */
! 1647: data[3] = len;
! 1648: break;
! 1649:
! 1650: case SPC_VPD_DEVICE_IDENTIFICATION:
! 1651: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 1652: BDSET8W(&data[0], pq, 7, 3);
! 1653: BDADD8W(&data[0], pd, 4, 5);
! 1654: /* PAGE CODE */
! 1655: data[1] = pc;
! 1656: /* PAGE LENGTH */
! 1657: DSET16(&data[2], 0);
! 1658: hlen = 4;
! 1659:
! 1660: /* Identification descriptor 1 */
! 1661: /* Vendor-Unique Logical Unit Identifier */
! 1662: cp = &data[hlen + len];
! 1663:
! 1664: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1665: BDSET8W(&cp[0], 0, 7, 4);
! 1666: BDADD8W(&cp[0], SPC_VPD_CODE_SET_ASCII, 3, 4);
! 1667: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1668: BDSET8W(&cp[1], 0, 7, 1); /* PIV */
! 1669: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
! 1670: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_T10_VENDOR_ID, 3, 4);
! 1671: /* Reserved */
! 1672: cp[2] = 0;
! 1673: /* IDENTIFIER LENGTH */
! 1674: cp[3] = 0;
! 1675:
! 1676: /* IDENTIFIER */
! 1677: /* T10 VENDOR IDENTIFICATION */
! 1678: istgt_strcpy_pad(&cp[4], 8, spec->lu->inq_vendor, ' ');
! 1679: /* PRODUCT IDENTIFICATION */
! 1680: istgt_strcpy_pad(&cp[16], 16, spec->lu->inq_product, ' ');
! 1681: /* PRODUCT SERIAL NUMBER */
! 1682: istgt_strcpy_pad(&cp[32], 10, spec->lu->inq_serial, ' ');
! 1683: plen = 8 + 16 + 10;
! 1684:
! 1685: cp[3] = plen;
! 1686: len += 4 + plen;
! 1687:
! 1688: /* Identification descriptor 2 */
! 1689: /* Logical Unit NAA Identifier */
! 1690: cp = &data[hlen + len];
! 1691:
! 1692: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1693: BDSET8W(&cp[0], 0, 7, 4);
! 1694: //BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_FC, 7, 4);
! 1695: //BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_SAS, 7, 4);
! 1696: BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
! 1697: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1698: BDSET8W(&cp[1], 1, 7, 1); /* PIV */
! 1699: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
! 1700: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_NAA, 3, 4);
! 1701: /* Reserved */
! 1702: cp[2] = 0;
! 1703: /* IDENTIFIER LENGTH */
! 1704: cp[3] = 0;
! 1705:
! 1706: /* IDENTIFIER */
! 1707: /* NAA Identifier (WWNN) */
! 1708: plen = istgt_lu_set_lid(&cp[4], LUI);
! 1709:
! 1710: cp[3] = plen;
! 1711: len += 4 + plen;
! 1712:
! 1713: /* Identification descriptor 3 */
! 1714: /* Port NAA Identifier */
! 1715: cp = &data[hlen + len];
! 1716:
! 1717: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1718: BDSET8W(&cp[0], 0, 7, 4);
! 1719: //BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_FC, 7, 4);
! 1720: //BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_SAS, 7, 4);
! 1721: BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
! 1722: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1723: BDSET8W(&cp[1], 1, 7, 1); /* PIV */
! 1724: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
! 1725: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_NAA, 3, 4);
! 1726: /* Reserved */
! 1727: cp[2] = 0;
! 1728: /* IDENTIFIER LENGTH */
! 1729: cp[3] = 0;
! 1730:
! 1731: /* IDENTIFIER */
! 1732: /* NAA Identifier (WWPN) */
! 1733: plen = istgt_lu_set_lid(&cp[4], TPI);
! 1734:
! 1735: cp[3] = plen;
! 1736: len += 4 + plen;
! 1737:
! 1738: /* Identification descriptor 4 */
! 1739: /* Relative Target Port Identifier */
! 1740: cp = &data[hlen + len];
! 1741:
! 1742: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1743: BDSET8W(&cp[0], 0, 7, 4);
! 1744: //BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_FC, 7, 4);
! 1745: //BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_SAS, 7, 4);
! 1746: BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
! 1747: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1748: BDSET8W(&cp[1], 1, 7, 1); /* PIV */
! 1749: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
! 1750: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_RELATIVE_TARGET_PORT,
! 1751: 3, 4);
! 1752: /* Reserved */
! 1753: cp[2] = 0;
! 1754: /* IDENTIFIER LENGTH */
! 1755: cp[3] = 0;
! 1756:
! 1757: /* IDENTIFIER */
! 1758: /* Obsolete */
! 1759: DSET16(&cp[4], 0);
! 1760: /* Relative Target Port Identifier */
! 1761: DSET16(&cp[6], 1); /* port1 as port A */
! 1762: //DSET16(&cp[6], 2); /* port2 as port B */
! 1763: plen = 4;
! 1764:
! 1765: cp[3] = plen;
! 1766: len += 4 + plen;
! 1767:
! 1768: #undef LU_ISCSI_IDENTIFIER
! 1769: #ifdef LU_ISCSI_IDENTIFIER
! 1770: /* Identification descriptor 1 */
! 1771: /* Logical Unit */
! 1772: cp = &data[hlen + len];
! 1773:
! 1774: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1775: BDSET8W(&cp[0], 0, 7, 4);
! 1776: BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
! 1777: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1778: BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */
! 1779: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
! 1780: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_NAA, 3, 4);
! 1781: /* Reserved */
! 1782: cp[2] = 0;
! 1783: /* IDENTIFIER LENGTH */
! 1784: cp[3] = 0;
! 1785:
! 1786: /* IDENTIFIER */
! 1787: #if 0
! 1788: /* 16bytes ID */
! 1789: plen = istgt_lu_set_extid(&cp[4], 0, LUI);
! 1790: #else
! 1791: plen = istgt_lu_set_lid(&cp[4], LUI);
! 1792: #endif
! 1793:
! 1794: cp[3] = plen;
! 1795: len += 4 + plen;
! 1796:
! 1797: /* Identification descriptor 2 */
! 1798: /* T10 VENDOR IDENTIFICATION */
! 1799: cp = &data[hlen + len];
! 1800:
! 1801: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1802: BDSET8W(&cp[0], 0, 7, 4);
! 1803: BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
! 1804: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1805: BDSET8W(&cp[1], 0, 7, 1); /* PIV=0 */
! 1806: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_LOGICAL_UNIT, 5, 2);
! 1807: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_T10_VENDOR_ID, 3, 4);
! 1808: /* Reserved */
! 1809: cp[2] = 0;
! 1810: /* IDENTIFIER LENGTH */
! 1811: cp[3] = 0;
! 1812:
! 1813: /* IDENTIFIER */
! 1814: /* T10 VENDOR IDENTIFICATION */
! 1815: istgt_strcpy_pad(&cp[4], 8, spec->lu->inq_vendor, ' ');
! 1816: plen = 8;
! 1817: /* VENDOR SPECIFIC IDENTIFIER */
! 1818: /* PRODUCT IDENTIFICATION */
! 1819: istgt_strcpy_pad(&cp[12], 16, spec->lu->inq_product, ' ');
! 1820: /* PRODUCT SERIAL NUMBER */
! 1821: istgt_strcpy_pad(&cp[28], MAX_LU_SERIAL_STRING,
! 1822: spec->lu->inq_serial, ' ');
! 1823: plen += 16 + MAX_LU_SERIAL_STRING;
! 1824:
! 1825: cp[3] = plen;
! 1826: len += 4 + plen;
! 1827:
! 1828: /* Identification descriptor 3 */
! 1829: /* Target Device */
! 1830: cp = &data[hlen + len];
! 1831:
! 1832: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1833: BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
! 1834: BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
! 1835: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1836: BDSET8W(&cp[1], 1, 7, 1); /* PIV */
! 1837: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_DEVICE, 5, 2);
! 1838: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
! 1839: /* Reserved */
! 1840: cp[2] = 0;
! 1841: /* IDENTIFIER LENGTH */
! 1842: cp[3] = 0;
! 1843:
! 1844: /* IDENTIFIER */
! 1845: plen = snprintf((char *) &cp[4], MAX_TARGET_NAME,
! 1846: "%s",
! 1847: spec->lu->name);
! 1848: cp[3] = plen;
! 1849: len += 4 + plen;
! 1850:
! 1851: /* Identification descriptor 4 */
! 1852: /* Target Port */
! 1853: cp = &data[hlen + len];
! 1854:
! 1855: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1856: BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
! 1857: BDADD8W(&cp[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
! 1858: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1859: BDSET8W(&cp[1], 1, 7, 1); /* PIV */
! 1860: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
! 1861: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
! 1862: /* Reserved */
! 1863: cp[2] = 0;
! 1864: /* IDENTIFIER LENGTH */
! 1865: cp[3] = 0;
! 1866:
! 1867: /* IDENTIFIER */
! 1868: plen = snprintf((char *) &cp[4], MAX_TARGET_NAME,
! 1869: "%s"",t,0x""%4.4x",
! 1870: spec->lu->name,
! 1871: conn->portal.tag);
! 1872: cp[3] = plen;
! 1873: len += 4 + plen;
! 1874:
! 1875: /* Identification descriptor 5 */
! 1876: /* Relative Target Port */
! 1877: cp = &data[hlen + len];
! 1878:
! 1879: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1880: BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
! 1881: BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
! 1882: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1883: BDSET8W(&cp[1], 1, 7, 1); /* PIV */
! 1884: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
! 1885: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_RELATIVE_TARGET_PORT,
! 1886: 3, 4);
! 1887: /* Reserved */
! 1888: cp[2] = 0;
! 1889: /* IDENTIFIER LENGTH */
! 1890: cp[3] = 0;
! 1891:
! 1892: /* IDENTIFIER */
! 1893: /* Obsolete */
! 1894: DSET16(&cp[4], 0);
! 1895: /* Relative Target Port Identifier */
! 1896: //DSET16(&cp[6], 1); /* port1 as port A */
! 1897: //DSET16(&cp[6], 2); /* port2 as port B */
! 1898: DSET16(&cp[6], (uint16_t) (1 + conn->portal.idx));
! 1899: plen = 4;
! 1900:
! 1901: cp[3] = plen;
! 1902: len += 4 + plen;
! 1903:
! 1904: /* Identification descriptor 6 */
! 1905: /* Target port group */
! 1906: cp = &data[hlen + len];
! 1907:
! 1908: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1909: BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
! 1910: BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
! 1911: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1912: BDSET8W(&cp[1], 1, 7, 1); /* PIV */
! 1913: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
! 1914: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_TARGET_PORT_GROUP,
! 1915: 3, 4);
! 1916: /* Reserved */
! 1917: cp[2] = 0;
! 1918: /* IDENTIFIER LENGTH */
! 1919: cp[3] = 0;
! 1920:
! 1921: /* IDENTIFIER */
! 1922: /* Reserved */
! 1923: DSET16(&cp[4], 0);
! 1924: /* TARGET PORT GROUP */
! 1925: DSET16(&cp[6], (uint16_t) (conn->portal.tag));
! 1926: plen = 4;
! 1927:
! 1928: cp[3] = plen;
! 1929: len += 4 + plen;
! 1930:
! 1931: /* Identification descriptor 7 */
! 1932: /* Logical unit group */
! 1933: cp = &data[hlen + len];
! 1934:
! 1935: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 1936: BDSET8W(&cp[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
! 1937: BDADD8W(&cp[0], SPC_VPD_CODE_SET_BINARY, 3, 4);
! 1938: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 1939: BDSET8W(&cp[1], 1, 7, 1); /* PIV */
! 1940: BDADD8W(&cp[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
! 1941: BDADD8W(&cp[1], SPC_VPD_IDENTIFIER_TYPE_LOGICAL_UNIT_GROUP,
! 1942: 3, 4);
! 1943: /* Reserved */
! 1944: cp[2] = 0;
! 1945: /* IDENTIFIER LENGTH */
! 1946: cp[3] = 0;
! 1947:
! 1948: /* IDENTIFIER */
! 1949: /* Reserved */
! 1950: DSET16(&cp[4], 0);
! 1951: /* LOGICAL UNIT GROUP */
! 1952: DSET16(&cp[6], (uint16_t) (spec->lu->num));
! 1953: plen = 4;
! 1954:
! 1955: cp[3] = plen;
! 1956: len += 4 + plen;
! 1957: #endif /* LU_ISCSI_IDENTIFIER */
! 1958:
! 1959: /* PAGE LENGTH */
! 1960: if (len > 0xffff) {
! 1961: len = 0xffff;
! 1962: }
! 1963: DSET16(&data[2], len);
! 1964: break;
! 1965:
! 1966: case SPC_VPD_EXTENDED_INQUIRY_DATA:
! 1967: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 1968: BDSET8W(&data[0], pq, 7, 3);
! 1969: BDADD8W(&data[0], pd, 4, 5);
! 1970: /* PAGE CODE */
! 1971: data[1] = pc;
! 1972: /* Reserved */
! 1973: data[2] = 0;
! 1974: /* PAGE LENGTH */
! 1975: data[3] = 0;
! 1976: hlen = 4;
! 1977:
! 1978: /* RTO(3) GRD_CHK(2) APP_CHK(1) REF_CHK(0) */
! 1979: data[4] = 0;
! 1980: /* GROUP_SUP(4) PRIOR_SUP(3) HEADSUP(2) ORDSUP(1) SIMPSUP(0) */
! 1981: data[5] = 0;
! 1982: /* NV_SUP(1) V_SUP(0) */
! 1983: data[6] = 0;
! 1984: /* Reserved[7-63] */
! 1985: memset(&data[7], 0, (64 - 7));
! 1986: len = 64 - hlen;
! 1987:
! 1988: /* PAGE LENGTH */
! 1989: data[3] = len;
! 1990: break;
! 1991:
! 1992: case SPC_VPD_MANAGEMENT_NETWORK_ADDRESSES:
! 1993: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 1994: BDSET8W(&data[0], pq, 7, 3);
! 1995: BDADD8W(&data[0], pd, 4, 5);
! 1996: /* PAGE CODE */
! 1997: data[1] = pc;
! 1998: /* PAGE LENGTH */
! 1999: DSET16(&data[2], 0);
! 2000: hlen = 4;
! 2001:
! 2002: #if 0
! 2003: /* Network services descriptor N */
! 2004: cp = &data[hlen + len];
! 2005:
! 2006: /* ASSOCIATION(6-5) SERVICE TYPE(4-0) */
! 2007: BDSET8W(&cp[0], 0x00, 6, 2);
! 2008: BDADD8W(&cp[0], 0x00, 4, 5);
! 2009: /* Reserved */
! 2010: cp[1] = 0;
! 2011: /* NETWORK ADDRESS LENGTH */
! 2012: DSET16(&cp[2], 0);
! 2013: /* NETWORK ADDRESS */
! 2014: cp[4] = 0;
! 2015: /* ... */
! 2016: plen = 0;
! 2017: DSET16(&cp[2], plen);
! 2018: len += 4 + plen;
! 2019: #endif
! 2020:
! 2021: /* PAGE LENGTH */
! 2022: if (len > 0xffff) {
! 2023: len = 0xffff;
! 2024: }
! 2025: DSET16(&data[2], len);
! 2026: break;
! 2027:
! 2028: case SPC_VPD_MODE_PAGE_POLICY:
! 2029: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 2030: BDSET8W(&data[0], pq, 7, 3);
! 2031: BDADD8W(&data[0], pd, 4, 5);
! 2032: /* PAGE CODE */
! 2033: data[1] = pc;
! 2034: /* PAGE LENGTH */
! 2035: DSET16(&data[2], 0);
! 2036: hlen = 4;
! 2037:
! 2038: /* Mode page policy descriptor 1 */
! 2039: cp = &data[hlen + len];
! 2040:
! 2041: /* POLICY PAGE CODE(5-0) */
! 2042: BDSET8W(&cp[0], 0x3f, 5, 6); /* all page code */
! 2043: /* POLICY SUBPAGE CODE */
! 2044: cp[1] = 0xff; /* all sub page */
! 2045: /* MLUS(7) MODE PAGE POLICY(1-0) */
! 2046: //BDSET8(&cp[2], 1, 7); /* multiple logical units share */
! 2047: BDSET8(&cp[2], 0, 7); /* own copy */
! 2048: BDADD8W(&cp[2], 0x00, 1, 2); /* Shared */
! 2049: //BDADD8W(&cp[2], 0x01, 1, 2); /* Per target port */
! 2050: //BDADD8W(&cp[2], 0x02, 1, 2); /* Per initiator port */
! 2051: //BDADD8W(&cp[2], 0x03, 1, 2); /* Per I_T nexus */
! 2052: /* Reserved */
! 2053: cp[3] = 0;
! 2054: len += 4;
! 2055:
! 2056: /* PAGE LENGTH */
! 2057: if (len > 0xffff) {
! 2058: len = 0xffff;
! 2059: }
! 2060: DSET16(&data[2], len);
! 2061: break;
! 2062:
! 2063: case SPC_VPD_SCSI_PORTS:
! 2064: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 2065: BDSET8W(&data[0], pq, 7, 3);
! 2066: BDADD8W(&data[0], pd, 4, 5);
! 2067: /* PAGE CODE */
! 2068: data[1] = pc;
! 2069: /* PAGE LENGTH */
! 2070: DSET16(&data[2], 0);
! 2071: hlen = 4;
! 2072:
! 2073: /* Identification descriptor list */
! 2074: for (i = 0; i < spec->lu->maxmap; i++) {
! 2075: pg_tag = spec->lu->map[i].pg_tag;
! 2076: /* skip same pg_tag */
! 2077: for (j = 0; j < i; j++) {
! 2078: if (spec->lu->map[j].pg_tag == pg_tag) {
! 2079: goto skip_pg_tag;
! 2080: }
! 2081: }
! 2082:
! 2083: /* Identification descriptor N */
! 2084: cp = &data[hlen + len];
! 2085:
! 2086: /* Reserved */
! 2087: DSET16(&cp[0], 0);
! 2088: /* RELATIVE PORT IDENTIFIER */
! 2089: DSET16(&cp[2], (uint16_t) (1 + pg_tag));
! 2090: /* Reserved */
! 2091: DSET16(&cp[4], 0);
! 2092: /* INITIATOR PORT TRANSPORTID LENGTH */
! 2093: DSET16(&cp[6], 0);
! 2094: /* Reserved */
! 2095: DSET16(&cp[8], 0);
! 2096: /* TARGET PORT DESCRIPTORS LENGTH */
! 2097: DSET16(&cp[10], 0);
! 2098: len += 12;
! 2099:
! 2100: plen2 = 0;
! 2101: /* Target port descriptor 1 */
! 2102: cp2 = &data[hlen + len + plen2];
! 2103:
! 2104: /* PROTOCOL IDENTIFIER(7-4) CODE SET(3-0) */
! 2105: BDSET8W(&cp2[0], SPC_PROTOCOL_IDENTIFIER_ISCSI, 7, 4);
! 2106: BDADD8W(&cp2[0], SPC_VPD_CODE_SET_UTF8, 3, 4);
! 2107: /* PIV(7) ASSOCIATION(5-4) IDENTIFIER TYPE(3-0) */
! 2108: BDSET8W(&cp2[1], 1, 7, 1); /* PIV */
! 2109: BDADD8W(&cp2[1], SPC_VPD_ASSOCIATION_TARGET_PORT, 5, 2);
! 2110: BDADD8W(&cp2[1], SPC_VPD_IDENTIFIER_TYPE_SCSI_NAME, 3, 4);
! 2111: /* Reserved */
! 2112: cp2[2] = 0;
! 2113: /* IDENTIFIER LENGTH */
! 2114: cp2[3] = 0;
! 2115:
! 2116: /* IDENTIFIER */
! 2117: plen = snprintf((char *) &cp2[4], MAX_TARGET_NAME,
! 2118: "%s"",t,0x""%4.4x",
! 2119: spec->lu->name,
! 2120: pg_tag);
! 2121: cp2[3] = plen;
! 2122: plen2 += 4 + plen;
! 2123:
! 2124: /* TARGET PORT DESCRIPTORS LENGTH */
! 2125: DSET16(&cp[10], plen2);
! 2126: len += plen2;
! 2127: skip_pg_tag:
! 2128: ;
! 2129: }
! 2130:
! 2131: /* PAGE LENGTH */
! 2132: if (len > 0xffff) {
! 2133: len = 0xffff;
! 2134: }
! 2135: DSET16(&data[2], len);
! 2136: break;
! 2137:
! 2138: /* for DLT-S4 */
! 2139: case 0xb0: /* Sequential-Access Device Capabilities */
! 2140: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 2141: BDSET8W(&data[0], pq, 7, 3);
! 2142: BDADD8W(&data[0], pd, 4, 5);
! 2143: /* PAGE CODE */
! 2144: data[1] = pc;
! 2145: /* Reserved */
! 2146: data[2] = 0;
! 2147: /* PAGE LENGTH */
! 2148: data[3] = 0;
! 2149: hlen = 4;
! 2150:
! 2151: len = 0x4;
! 2152: memset(&data[4], 0, len);
! 2153: //BSET8(&data[4], 0); /* WORM */
! 2154:
! 2155: /* PAGE LENGTH */
! 2156: data[3] = len;
! 2157: break;
! 2158:
! 2159: case 0xb1: /* Manufacturer-assigned Serial Number */
! 2160: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 2161: BDSET8W(&data[0], pq, 7, 3);
! 2162: BDADD8W(&data[0], pd, 4, 5);
! 2163: /* PAGE CODE */
! 2164: data[1] = pc;
! 2165: /* Reserved */
! 2166: data[2] = 0;
! 2167: /* PAGE LENGTH */
! 2168: data[3] = 0;
! 2169: hlen = 4;
! 2170:
! 2171: len = 0x10;
! 2172: memset(&data[4], 0, len);
! 2173:
! 2174: /* Manufacturer Serial Number */
! 2175: snprintf(buf, sizeof buf, "%16.16d", 0);
! 2176: istgt_strcpy_pad(&data[4], 16, buf, ' ');
! 2177:
! 2178: /* PAGE LENGTH */
! 2179: data[3] = len;
! 2180: break;
! 2181:
! 2182: /* for DLT8000 */
! 2183: case 0xc0: /* Firmware Build Information */
! 2184: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 2185: BDSET8W(&data[0], pq, 7, 3);
! 2186: BDADD8W(&data[0], pd, 4, 5);
! 2187: /* PAGE CODE */
! 2188: data[1] = pc;
! 2189: /* Reserved */
! 2190: data[2] = 0;
! 2191: /* PAGE LENGTH */
! 2192: data[3] = 0;
! 2193: hlen = 4;
! 2194:
! 2195: len = 0x20;
! 2196: memset(&data[4], 0, len);
! 2197:
! 2198: /* PAGE LENGTH */
! 2199: data[3] = len;
! 2200: break;
! 2201:
! 2202: case 0xc1: /* Subsystem Components Revision */
! 2203: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 2204: BDSET8W(&data[0], pq, 7, 3);
! 2205: BDADD8W(&data[0], pd, 4, 5);
! 2206: /* PAGE CODE */
! 2207: data[1] = pc;
! 2208: /* Reserved */
! 2209: data[2] = 0;
! 2210: /* PAGE LENGTH */
! 2211: data[3] = 0;
! 2212: hlen = 4;
! 2213:
! 2214: len = 0x14;
! 2215: memset(&data[4], 0, len);
! 2216:
! 2217: /* Media Loader Present Flag */
! 2218: data[18] = 0;
! 2219: /* Library Present Flag */
! 2220: data[19] = 0;
! 2221:
! 2222: /* PAGE LENGTH */
! 2223: data[3] = len;
! 2224: break;
! 2225:
! 2226: default:
! 2227: if (pc >= 0xc0 && pc <= 0xff) {
! 2228: ISTGT_WARNLOG("Vendor specific INQUIRY VPD page 0x%x\n", pc);
! 2229: } else {
! 2230: ISTGT_ERRLOG("unsupported INQUIRY VPD page 0x%x\n", pc);
! 2231: }
! 2232: return -1;
! 2233: }
! 2234: } else {
! 2235: /* Standard INQUIRY data */
! 2236: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 2237: BDSET8W(&data[0], pq, 7, 3);
! 2238: BDADD8W(&data[0], pd, 4, 5);
! 2239: /* RMB(7) */
! 2240: BDSET8W(&data[1], rmb, 7, 1);
! 2241: /* VERSION */
! 2242: /* See SPC3/SBC2/MMC4/SAM2 for more details */
! 2243: data[2] = SPC_VERSION_SPC3;
! 2244: /* NORMACA(5) HISUP(4) RESPONSE DATA FORMAT(3-0) */
! 2245: BDSET8W(&data[3], 2, 3, 4); /* format 2 */
! 2246: /* ADDITIONAL LENGTH */
! 2247: data[4] = 0;
! 2248: hlen = 5;
! 2249:
! 2250: /* SCCS(7) ACC(6) TPGS(5-4) 3PC(3) PROTECT(0) */
! 2251: data[5] = 0;
! 2252: /* BQUE(7) ENCSERV(6) VS(5) MULTIP(4) MCHNGR(3) ADDR16(0) */
! 2253: data[6] = 0;
! 2254: /* WBUS16(5) SYNC(4) LINKED(3) CMDQUE(1) VS(0) */
! 2255: data[7] = 0;
! 2256: /* T10 VENDOR IDENTIFICATION */
! 2257: istgt_strcpy_pad(&data[8], 8, spec->lu->inq_vendor, ' ');
! 2258: /* PRODUCT IDENTIFICATION */
! 2259: istgt_strcpy_pad(&data[16], 16, spec->lu->inq_product, ' ');
! 2260: /* PRODUCT REVISION LEVEL */
! 2261: istgt_strcpy_pad(&data[32], 4, spec->lu->inq_revision, ' ');
! 2262: /* Vendor specific */
! 2263: memset(&data[36], 0x20, 20);
! 2264: #if 1
! 2265: /* for Quantum DLT */
! 2266: /* Product Family(7-4) Released Firmware(3-0) */
! 2267: //BDSET8W(&data[36], 5, 7, 4); /* 20/40GB */
! 2268: BDSET8W(&data[36], 11, 7, 4); /* 40/80GB */
! 2269: BDSET8W(&data[36], 1, 3, 4); /* Vxxx firmware */
! 2270: /* Firmware Major Version # */
! 2271: data[37] = 0x01;
! 2272: /* Firmware Minor Version # */
! 2273: data[38] = 0x00;
! 2274: /* EEPROM Format Major Version # */
! 2275: data[39] = 0x01;
! 2276: /* EEPROM Format Minor Version # */
! 2277: data[40] = 0x00;
! 2278: /* Firmware Personality */
! 2279: data[41] = 0x04; /* OEM family */
! 2280: /* Firmware Sub-Personality */
! 2281: data[42] = 0x01; /* primary firmware personality variant */
! 2282: /* Vendor Unique Subtype */
! 2283: data[43] = 0x00;
! 2284: /* Controller Hardware Version # */
! 2285: data[44] = 0x01;
! 2286: /* Drive EEPROM Version # */
! 2287: data[45] = 0x01;
! 2288: /* Drive Hardware Version # */
! 2289: data[46] = 0x01;
! 2290: /* Media Loader Firmware Version # */
! 2291: data[47] = 0x00;
! 2292: /* Media Loader Hardware Version # */
! 2293: data[48] = 0x00;
! 2294: /* Media Loader Mechanical Version # */
! 2295: data[49]= 0x00;
! 2296: /* Media Loader Present Flag */
! 2297: data[50] = 0;
! 2298: /* Library Present Flag */
! 2299: data[51] = 0;
! 2300: /* Module Revision */
! 2301: istgt_strcpy_pad(&data[54], 4, TAPE_MODULE_REV, ' ');
! 2302: #endif
! 2303: /* CLOCKING(3-2) QAS(1) IUS(0) */
! 2304: data[56] = 0;
! 2305: /* Reserved */
! 2306: data[57] = 0;
! 2307: /* VERSION DESCRIPTOR 1-8 */
! 2308: DSET16(&data[58], 0x0960); /* iSCSI (no version claimed) */
! 2309: DSET16(&data[60], 0x0300); /* SPC-3 (no version claimed) */
! 2310: DSET16(&data[62], 0x0360); /* SSC-2 (no version claimed) */
! 2311: DSET16(&data[64], 0x0040); /* SAM-2 (no version claimed) */
! 2312: DSET16(&data[66], 0x0000);
! 2313: DSET16(&data[68], 0x0000);
! 2314: DSET16(&data[70], 0x0000);
! 2315: DSET16(&data[72], 0x0000);
! 2316: /* Reserved[74-95] */
! 2317: memset(&data[74], 0, (96 - 74));
! 2318: /* Vendor specific parameters[96-n] */
! 2319: //data[96] = 0;
! 2320: len = 96 - hlen;
! 2321:
! 2322: /* ADDITIONAL LENGTH */
! 2323: data[4] = len;
! 2324: }
! 2325:
! 2326: return hlen + len;
! 2327: }
! 2328:
! 2329: #define MODE_SENSE_PAGE_INIT(B,L,P,SP) \
! 2330: do { \
! 2331: memset((B), 0, (L)); \
! 2332: if ((SP) != 0x00) { \
! 2333: (B)[0] = (P) | 0x40; /* PAGE + SPF=1 */ \
! 2334: (B)[1] = (SP); \
! 2335: DSET16(&(B)[2], (L) - 4); \
! 2336: } else { \
! 2337: (B)[0] = (P); \
! 2338: (B)[1] = (L) - 2; \
! 2339: } \
! 2340: } while (0)
! 2341:
! 2342: static int
! 2343: istgt_lu_tape_scsi_mode_sense_page(ISTGT_LU_TAPE *spec, CONN_Ptr conn, uint8_t *cdb, int pc, int page, int subpage, uint8_t *data, int alloc_len)
! 2344: {
! 2345: uint8_t *cp;
! 2346: int len = 0;
! 2347: int plen;
! 2348: int i;
! 2349:
! 2350: #if 0
! 2351: printf("SENSE pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
! 2352: #endif
! 2353: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE: pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
! 2354:
! 2355: if (pc == 0x00) {
! 2356: /* Current values */
! 2357: } else if (pc == 0x01) {
! 2358: /* Changeable values */
! 2359: if (page != 0x08) {
! 2360: /* not supported */
! 2361: return 0;
! 2362: }
! 2363: } else if (pc == 0x02) {
! 2364: /* Default values */
! 2365: } else {
! 2366: /* Saved values */
! 2367: }
! 2368:
! 2369: cp = &data[len];
! 2370: switch (page) {
! 2371: case 0x00:
! 2372: /* Vendor specific */
! 2373: break;
! 2374: case 0x01:
! 2375: /* Read-Write Error Recovery */
! 2376: break;
! 2377: case 0x02:
! 2378: /* Disconnect-Reconnect mode page */
! 2379: break;
! 2380: case 0x03:
! 2381: case 0x04:
! 2382: case 0x05:
! 2383: case 0x06:
! 2384: case 0x07:
! 2385: case 0x08:
! 2386: /* Reserved */
! 2387: break;
! 2388: case 0x09:
! 2389: /* Obsolete */
! 2390: break;
! 2391: case 0x0a:
! 2392: /* Control mode page */
! 2393: break;
! 2394: case 0x0b:
! 2395: case 0x0c:
! 2396: case 0x0d:
! 2397: case 0x0e:
! 2398: /* Reserved */
! 2399: break;
! 2400: case 0x0f:
! 2401: /* Data Compression */
! 2402: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Data Compression\n");
! 2403: if (subpage != 0x00)
! 2404: break;
! 2405:
! 2406: plen = 0x0e + 2;
! 2407: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
! 2408: if (spec->compression) {
! 2409: BDADD8(&cp[2], 1, 7); /* DCE=1 compression enable */
! 2410: } else {
! 2411: BDADD8(&cp[2], 0, 7); /* DCE=0 compression disable */
! 2412: }
! 2413: //BDADD8(&cp[2], 0, 6); /* DCC=0 not support compression */
! 2414: BDADD8(&cp[2], 1, 6); /* DCC=1 support compression */
! 2415: BDADD8(&cp[3], 1, 7); /* DDE=1 decompression enable */
! 2416: BDADD8W(&cp[3], 0, 6, 2); /* RED=0 not support */
! 2417: /* COMPRESSION ALGORITHM */
! 2418: //DSET32(&cp[4], 0);
! 2419: //DSET32(&cp[4], 0x03); /* IBM ALDC with 512 byte buffer */
! 2420: //DSET32(&cp[4], 0x04); /* IBM ALDC with 1024 byte buffer */
! 2421: //DSET32(&cp[4], 0x05); /* IBM ALDC with 2048 byte buffer */
! 2422: //DSET32(&cp[4], 0x10); /* IBM IDRC */
! 2423: DSET32(&cp[4], TAPE_COMP_ALGORITHM);
! 2424: /* DECOMPRESSION ALGORITHM */
! 2425: //DSET32(&cp[8], 0);
! 2426: DSET32(&cp[8], TAPE_COMP_ALGORITHM);
! 2427: len += plen;
! 2428: break;
! 2429: case 0x10:
! 2430: /* Device Configuration */
! 2431: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Device Configuration\n");
! 2432: if (subpage != 0x00)
! 2433: break;
! 2434:
! 2435: plen = 0x0e + 2;
! 2436: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
! 2437: /* WRITE DELAY TIME */
! 2438: DSET16(&cp[6], TAPE_WRITE_DELAY);
! 2439: /* RSMK(5) */
! 2440: BDADD8(&data[8], 0, 5); /* report setmarks not support */
! 2441: /* LOIS(6) */
! 2442: BDADD8(&data[8], 1, 6);
! 2443: /* EEG(4) SEW(3) */
! 2444: BDADD8(&data[10], 1, 4);
! 2445: BDADD8(&data[10], 1, 3);
! 2446: /* SELECT DATA COMPRESSION ALGORITHM */
! 2447: if (spec->compression) {
! 2448: data[14] = 1; /* data compression is enabled */
! 2449: }
! 2450: len += plen;
! 2451: break;
! 2452: case 0x11:
! 2453: /* Medium Partition */
! 2454: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Medium Partition\n");
! 2455: if (subpage != 0x00)
! 2456: break;
! 2457:
! 2458: plen = 0x08 + 2;
! 2459: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
! 2460: len += plen;
! 2461: break;
! 2462: case 0x12:
! 2463: /* Obsolete */
! 2464: break;
! 2465: case 0x13:
! 2466: /* Obsolete */
! 2467: break;
! 2468: case 0x14:
! 2469: /* Obsolete */
! 2470: break;
! 2471: case 0x15:
! 2472: case 0x16:
! 2473: case 0x17:
! 2474: /* Reserved */
! 2475: break;
! 2476: case 0x18:
! 2477: /* Protocol Specific LUN */
! 2478: break;
! 2479: case 0x19:
! 2480: /* Protocol Specific Port */
! 2481: break;
! 2482: case 0x1a:
! 2483: /* Power Condition */
! 2484: break;
! 2485: case 0x1b:
! 2486: /* Reserved */
! 2487: break;
! 2488: case 0x1c:
! 2489: /* Informational Exceptions Control */
! 2490: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Informational Exceptions Control\n");
! 2491: if (subpage != 0x00)
! 2492: break;
! 2493:
! 2494: plen = 0x0a + 2;
! 2495: MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
! 2496: len += plen;
! 2497: break;
! 2498: case 0x1d:
! 2499: case 0x1e:
! 2500: case 0x1f:
! 2501: /* Reserved */
! 2502: break;
! 2503: case 0x20:
! 2504: case 0x21:
! 2505: case 0x22:
! 2506: case 0x23:
! 2507: case 0x24:
! 2508: case 0x25:
! 2509: case 0x26:
! 2510: case 0x27:
! 2511: case 0x28:
! 2512: case 0x29:
! 2513: case 0x2a:
! 2514: case 0x2b:
! 2515: case 0x2c:
! 2516: case 0x2d:
! 2517: case 0x2e:
! 2518: case 0x2f:
! 2519: case 0x30:
! 2520: case 0x31:
! 2521: case 0x32:
! 2522: case 0x33:
! 2523: case 0x34:
! 2524: case 0x35:
! 2525: case 0x36:
! 2526: case 0x37:
! 2527: case 0x38:
! 2528: case 0x39:
! 2529: case 0x3a:
! 2530: case 0x3b:
! 2531: case 0x3c:
! 2532: case 0x3d:
! 2533: case 0x3e:
! 2534: /* Vendor-specific */
! 2535: break;
! 2536: case 0x3f:
! 2537: switch (subpage) {
! 2538: case 0x00:
! 2539: /* All mode pages */
! 2540: for (i = 0x00; i < 0x3e; i ++) {
! 2541: len += istgt_lu_tape_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
! 2542: }
! 2543: break;
! 2544: case 0xff:
! 2545: /* All mode pages and subpages */
! 2546: for (i = 0x00; i < 0x3e; i ++) {
! 2547: len += istgt_lu_tape_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0x00, &cp[len], alloc_len);
! 2548: }
! 2549: for (i = 0x00; i < 0x3e; i ++) {
! 2550: len += istgt_lu_tape_scsi_mode_sense_page(spec, conn, cdb, pc, i, 0xff, &cp[len], alloc_len);
! 2551: }
! 2552: break;
! 2553: default:
! 2554: /* 0x01-0x3e: Reserved */
! 2555: break;
! 2556: }
! 2557: }
! 2558:
! 2559: return len;
! 2560: }
! 2561:
! 2562: static int
! 2563: istgt_lu_tape_scsi_mode_sense6(ISTGT_LU_TAPE *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int pc, int page, int subpage, uint8_t *data, int alloc_len)
! 2564: {
! 2565: uint8_t *cp;
! 2566: int hlen = 0, len = 0, plen;
! 2567: int total;
! 2568: int llbaa = 0;
! 2569:
! 2570: data[0] = 0; /* Mode Data Length */
! 2571: if (spec->mload) {
! 2572: //data[1] = 0; /* Medium Type (no media) */
! 2573: //data[1] = TAPE_MEDIATYPE_LTO; /* Medium Type (LTO) */
! 2574: data[1] = MEDIATYPE_DFLT; /* Medium Type */
! 2575: data[2] = 0; /* Device-Specific Parameter */
! 2576: if (spec->lu->readonly
! 2577: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 2578: BDADD8(&data[2], 1, 7); /* WP */
! 2579: }
! 2580: } else {
! 2581: data[1] = 0; /* Medium Type (no media) */
! 2582: data[2] = 0; /* Device-Specific Parameter */
! 2583: }
! 2584: BDADD8W(&data[2], 1, 6, 3); /* Buffed Mode=1 */
! 2585: data[3] = 0; /* Block Descripter Length */
! 2586: hlen = 4;
! 2587:
! 2588: cp = &data[4];
! 2589: if (dbd) { /* Disable Block Descripters */
! 2590: len = 0;
! 2591: } else {
! 2592: if (llbaa) {
! 2593: if (spec->mload) {
! 2594: /* Number of Blocks */
! 2595: DSET64(&cp[0], 0ULL); /* all of the remaining */
! 2596: /* Reserved */
! 2597: DSET32(&cp[8], 0);
! 2598: /* Block Length */
! 2599: DSET32(&cp[12], (uint32_t) spec->lblen);
! 2600: } else {
! 2601: /* Number of Blocks */
! 2602: DSET64(&cp[0], 0ULL); /* all of the remaining */
! 2603: /* Reserved */
! 2604: DSET32(&cp[8], 0);
! 2605: /* Block Length */
! 2606: DSET32(&cp[12], 0);
! 2607: }
! 2608: len = 16;
! 2609: } else {
! 2610: if (spec->mload) {
! 2611: /* Number of Blocks */
! 2612: DSET32(&cp[0], 0); /* all of the remaining */
! 2613: /* Block Length */
! 2614: DSET32(&cp[4], (uint32_t) spec->lblen);
! 2615: cp[0] = DENSITY_DFLT; /* Density Code */
! 2616: cp[4] = 0; /* Reserved */
! 2617: } else {
! 2618: /* Number of Blocks */
! 2619: DSET32(&cp[0], 0); /* all of the remaining */
! 2620: /* Block Length */
! 2621: DSET32(&cp[4], 0);
! 2622: cp[0] = 0; /* Density Code */
! 2623: cp[4] = 0; /* Reserved */
! 2624: }
! 2625: len = 8;
! 2626: }
! 2627: cp += len;
! 2628: }
! 2629: data[3] = len; /* Block Descripter Length */
! 2630:
! 2631: plen = istgt_lu_tape_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
! 2632: cp += plen;
! 2633:
! 2634: total = hlen + len + plen;
! 2635: data[0] = total - 1; /* Mode Data Length */
! 2636:
! 2637: return total;
! 2638: }
! 2639:
! 2640: static int
! 2641: istgt_lu_tape_scsi_mode_sense10(ISTGT_LU_TAPE *spec, CONN_Ptr conn, uint8_t *cdb, int dbd, int llbaa, int pc, int page, int subpage, uint8_t *data, int alloc_len)
! 2642: {
! 2643: uint8_t *cp;
! 2644: int hlen = 0, len = 0, plen;
! 2645: int total;
! 2646:
! 2647: DSET16(&data[0], 0); /* Mode Data Length */
! 2648: if (spec->mload) {
! 2649: //data[2] = 0; /* Medium Type (no media) */
! 2650: //data[2] = TAPE_MEDIATYPE_LTO; /* Medium Type (DLT) */
! 2651: data[2] = MEDIATYPE_DFLT; /* Medium Type */
! 2652: data[3] = 0; /* Device-Specific Parameter */
! 2653: if (spec->lu->readonly
! 2654: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 2655: BDADD8(&data[3], 1, 7); /* WP */
! 2656: }
! 2657: } else {
! 2658: data[2] = 0; /* Medium Type (no media) */
! 2659: data[3] = 0; /* Device-Specific Parameter */
! 2660: }
! 2661: BDADD8W(&data[3], 1, 6, 3); /* Buffed Mode=1 */
! 2662: if (llbaa) {
! 2663: BDSET8(&data[4], 1, 1); /* Long LBA */
! 2664: } else {
! 2665: BDSET8(&data[4], 0, 1); /* Short LBA */
! 2666: }
! 2667: data[5] = 0; /* Reserved */
! 2668: DSET16(&data[6], 0); /* Block Descripter Length */
! 2669: hlen = 8;
! 2670:
! 2671: cp = &data[8];
! 2672: if (dbd) { /* Disable Block Descripters */
! 2673: len = 0;
! 2674: } else {
! 2675: if (llbaa) {
! 2676: if (spec->mload) {
! 2677: /* Number of Blocks */
! 2678: DSET64(&cp[0], 0ULL); /* all of the remaining */
! 2679: /* Reserved */
! 2680: DSET32(&cp[8], 0);
! 2681: /* Block Length */
! 2682: DSET32(&cp[12], (uint32_t) spec->lblen);
! 2683: } else {
! 2684: /* Number of Blocks */
! 2685: DSET64(&cp[0], 0ULL); /* all of the remaining */
! 2686: /* Reserved */
! 2687: DSET32(&cp[8], 0);
! 2688: /* Block Length */
! 2689: DSET32(&cp[12], 0);
! 2690: }
! 2691: len = 16;
! 2692: } else {
! 2693: if (spec->mload) {
! 2694: /* Number of Blocks */
! 2695: DSET32(&cp[0], 0); /* all of the remaining */
! 2696: /* Block Length */
! 2697: DSET32(&cp[4], (uint32_t) spec->lblen);
! 2698: cp[0] = DENSITY_DFLT; /* Density Code */
! 2699: cp[4] = 0; /* Reserved */
! 2700: } else {
! 2701: /* Number of Blocks */
! 2702: DSET32(&cp[0], 0); /* all of the remaining */
! 2703: /* Block Length */
! 2704: DSET32(&cp[4], 0);
! 2705: cp[0] = 0; /* Density Code */
! 2706: cp[4] = 0; /* Reserved */
! 2707: }
! 2708: len = 8;
! 2709: }
! 2710: cp += len;
! 2711: }
! 2712: DSET16(&data[6], len); /* Block Descripter Length */
! 2713:
! 2714: plen = istgt_lu_tape_scsi_mode_sense_page(spec, conn, cdb, pc, page, subpage, &cp[0], alloc_len);
! 2715: cp += plen;
! 2716:
! 2717: total = hlen + len + plen;
! 2718: DSET16(&data[0], total - 2); /* Mode Data Length */
! 2719:
! 2720: return total;
! 2721: }
! 2722:
! 2723: static int
! 2724: istgt_lu_tape_transfer_data(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *buf, size_t bufsize, size_t len)
! 2725: {
! 2726: int rc;
! 2727:
! 2728: if (len > bufsize) {
! 2729: ISTGT_ERRLOG("bufsize(%d) too small\n", bufsize);
! 2730: return -1;
! 2731: }
! 2732: rc = istgt_iscsi_transfer_out(conn, lu_cmd, buf, bufsize, len);
! 2733: if (rc < 0) {
! 2734: ISTGT_ERRLOG("iscsi_transfer_out()\n");
! 2735: return -1;
! 2736: }
! 2737: return 0;
! 2738: }
! 2739:
! 2740: static int
! 2741: istgt_lu_tape_scsi_mode_select_page(ISTGT_LU_TAPE *spec, CONN_Ptr conn, uint8_t *cdb, int pf, int sp, uint8_t *data, size_t len)
! 2742: {
! 2743: int ps, spf, page, subpage;
! 2744: int hlen, plen;
! 2745: int rc;
! 2746:
! 2747: if (pf == 0) {
! 2748: /* vendor specific */
! 2749: return 0;
! 2750: }
! 2751:
! 2752: if (len < 1)
! 2753: return 0;
! 2754: ps = BGET8(&data[0], 7);
! 2755: spf = BGET8(&data[0], 6);
! 2756: page = data[0] & 0x3f;
! 2757: if (spf) {
! 2758: /* Sub_page mode page format */
! 2759: hlen = 4;
! 2760: if (len < hlen)
! 2761: return 0;
! 2762: subpage = data[1];
! 2763:
! 2764: plen = DGET16(&data[2]);
! 2765: } else {
! 2766: /* Page_0 mode page format */
! 2767: hlen = 2;
! 2768: if (len < hlen)
! 2769: return 0;
! 2770: subpage = 0;
! 2771: plen = data[1];
! 2772: }
! 2773: plen += hlen;
! 2774: if (len < plen)
! 2775: return 0;
! 2776:
! 2777: #if 0
! 2778: printf("SELECT ps=%d, page=%2.2x, subpage=%2.2x\n", ps, page, subpage);
! 2779: #endif
! 2780: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT: ps=%d, page=%2.2x, subpage=%2.2x\n", ps, page, subpage);
! 2781: switch (page) {
! 2782: case 0x0f:
! 2783: /* Data Compression */
! 2784: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Data Compression\n");
! 2785: {
! 2786: int dce, dde, red;
! 2787: uint32_t compalgo, decompalgo;
! 2788:
! 2789: if (subpage != 0x00)
! 2790: break;
! 2791: if (plen != 0x0e + hlen) {
! 2792: /* unknown format */
! 2793: break;
! 2794: }
! 2795:
! 2796: dce = BGET8(&data[2], 7); /* DCE */
! 2797: dde = BGET8(&data[3], 7); /* DDE */
! 2798: red = BGET8W(&data[3], 6, 2); /* RED */
! 2799:
! 2800: compalgo = DGET32(&data[4]);
! 2801: decompalgo = DGET32(&data[8]);
! 2802:
! 2803: switch (compalgo) {
! 2804: case 0x00: /* default by hard */
! 2805: compalgo = TAPE_COMP_ALGORITHM;
! 2806: case 0x03: /* ALDC 512 */
! 2807: case 0x04: /* ALDC 1024 */
! 2808: case 0x05: /* ALDC 2048 */
! 2809: case 0x10: /* IDRC */
! 2810: spec->compalgo = compalgo;
! 2811: spec->vtcompalgo = MARK_COMPALGO_NONE;
! 2812: break;
! 2813: default:
! 2814: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "unsupported Compression Algorithm\n");
! 2815: /* force to default */
! 2816: spec->compalgo = TAPE_COMP_ALGORITHM;
! 2817: spec->vtcompalgo = MARK_COMPALGO_NONE;
! 2818: break;
! 2819: }
! 2820:
! 2821: if (dce) {
! 2822: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Data compression enable\n");
! 2823: spec->compression = 1;
! 2824: } else {
! 2825: spec->compression = 0;
! 2826: }
! 2827: if (dde) {
! 2828: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Data decompression enable\n");
! 2829: }
! 2830: break;
! 2831: }
! 2832: case 0x10:
! 2833: /* Device Configuration */
! 2834: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SELECT Device Configuration\n");
! 2835: {
! 2836: if (subpage != 0x00)
! 2837: break;
! 2838: if (plen != 0x0e + hlen) {
! 2839: /* unknown format */
! 2840: break;
! 2841: }
! 2842: break;
! 2843: }
! 2844: default:
! 2845: /* not supported */
! 2846: break;
! 2847: }
! 2848:
! 2849: len -= plen;
! 2850: if (len != 0) {
! 2851: rc = istgt_lu_tape_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[plen], len);
! 2852: if (rc < 0) {
! 2853: return rc;
! 2854: }
! 2855: }
! 2856: return 0;
! 2857: }
! 2858:
! 2859: static int
! 2860: istgt_convert_signed_24bits(uint32_t usval)
! 2861: {
! 2862: int value;
! 2863:
! 2864: /* 24bits two's complement notation */
! 2865: if (usval > 0x007fffff) {
! 2866: usval -= 1;
! 2867: usval = ~usval;
! 2868: usval &= 0x00ffffff;
! 2869: value = (int) usval;
! 2870: value = -value;
! 2871: } else {
! 2872: value = (int) usval;
! 2873: }
! 2874: return value;
! 2875: }
! 2876:
! 2877: #define THREAD_YIELD do { istgt_yield(); usleep(1000); } while (0)
! 2878:
! 2879: static int
! 2880: istgt_lu_tape_shrink_media(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t request_len, uint8_t *data)
! 2881: {
! 2882: struct stat st;
! 2883: uint64_t mediasize;
! 2884: uint64_t marklen;
! 2885: uint32_t mediaflags;
! 2886: int fd;
! 2887:
! 2888: fd = spec->fd;
! 2889: mediasize = spec->size;
! 2890: mediaflags = spec->mflags;
! 2891: marklen = spec->ctlblock->marklen;
! 2892:
! 2893: if (fstat(fd, &st) == -1) {
! 2894: ISTGT_ERRLOG("fstat() failed\n");
! 2895: return -1;
! 2896: }
! 2897:
! 2898: if (S_ISREG(st.st_mode)) {
! 2899: /* media is file */
! 2900: if (mediaflags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) {
! 2901: if (request_len < ISTGT_LU_MEDIA_SIZE_MIN) {
! 2902: request_len = ISTGT_LU_MEDIA_SIZE_MIN;
! 2903: }
! 2904: mediasize = request_len;
! 2905: #ifdef TAPE_DEBUG
! 2906: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "Shrink: %" PRIu64 " -> %" PRIu64 "\n", st.st_size, request_len);
! 2907: #endif /* TAPE_DEBUG */
! 2908: /* truncate */
! 2909: if (ftruncate(fd, request_len) == -1) {
! 2910: ISTGT_ERRLOG("ftruncate() failed\n");
! 2911: return -1;
! 2912: }
! 2913: fsync(fd);
! 2914: spec->size = mediasize;
! 2915: }
! 2916: } else {
! 2917: /* media is not file */
! 2918: }
! 2919: return 0;
! 2920: }
! 2921:
! 2922: static int
! 2923: istgt_lu_tape_scsi_erase(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *data)
! 2924: {
! 2925: struct stat st;
! 2926: uint64_t mediasize;
! 2927: uint64_t ctlblocklen;
! 2928: uint64_t marklen;
! 2929: uint64_t request_len;
! 2930: uint32_t mediaflags;
! 2931: int data_len;
! 2932: int newfile;
! 2933: int fd;
! 2934:
! 2935: fd = spec->fd;
! 2936: mediasize = spec->size;
! 2937: mediaflags = spec->mflags;
! 2938:
! 2939: ctlblocklen = spec->ctlblock->ctlblocklen;
! 2940: marklen = spec->ctlblock->marklen;
! 2941: if (ctlblocklen < CTLBLOCKLEN) {
! 2942: ctlblocklen = CTLBLOCKLEN;
! 2943: }
! 2944: if (marklen < MARK_LENGTH) {
! 2945: marklen = MARK_LENGTH;
! 2946: }
! 2947:
! 2948: if (spec->lu->readonly
! 2949: || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 2950: /* WRITE PROTECTED */
! 2951: data_len
! 2952: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 2953: ISTGT_SCSI_SENSE_DATA_PROTECT,
! 2954: 0x27, 0x00);
! 2955: lu_cmd->sense_data_len = data_len;
! 2956: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 2957: return -1;
! 2958: }
! 2959: if (!spec->bot) {
! 2960: /* PARAMETER VALUE INVALID */
! 2961: data_len
! 2962: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 2963: ISTGT_SCSI_SENSE_ILLEGAL_REQUEST,
! 2964: 0x26, 0x02);
! 2965: lu_cmd->sense_data_len = data_len;
! 2966: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 2967: return -1;
! 2968: }
! 2969: if (spec->lu->lun[spec->lun].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
! 2970: /* INTERNAL TARGET FAILURE */
! 2971: data_len
! 2972: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 2973: ISTGT_SCSI_SENSE_HARDWARE_ERROR,
! 2974: 0x44, 0x00);
! 2975: lu_cmd->sense_data_len = data_len;
! 2976: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 2977: return -1;
! 2978: }
! 2979:
! 2980: /* low I/O */
! 2981: if (fstat(fd, &st) == -1) {
! 2982: ISTGT_ERRLOG("fstat() failed\n");
! 2983: io_failure:
! 2984: /* LOGICAL UNIT FAILURE */
! 2985: data_len
! 2986: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 2987: ISTGT_SCSI_SENSE_HARDWARE_ERROR,
! 2988: 0x3e, 0x01);
! 2989: lu_cmd->sense_data_len = data_len;
! 2990: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 2991: return -1;
! 2992: }
! 2993:
! 2994: /* clear ctlblock + BOT + EOD */
! 2995: request_len = ctlblocklen + marklen * 2;
! 2996: spec->ctlblock->marks[1].offset = MARK_END;
! 2997: spec->ctlblock->marks[1].lbpos = MARK_END;
! 2998: spec->ctlblock->marks[1].prev = 0ULL;
! 2999: memset(data, 0, request_len);
! 3000: if (istgt_lu_tape_seek(spec, 0) == -1) {
! 3001: ISTGT_ERRLOG("lu_tape_lseek() failed\n");
! 3002: goto io_failure;
! 3003: }
! 3004: if (istgt_lu_tape_write(spec, data, request_len) != request_len) {
! 3005: ISTGT_ERRLOG("lu_tape_write() failed\n");
! 3006: goto io_failure;
! 3007: }
! 3008: fsync(fd);
! 3009: /* initialize filemarks */
! 3010: newfile = 1;
! 3011: if (istgt_lu_tape_init_ctlblock(spec, newfile) < 0) {
! 3012: ISTGT_ERRLOG("lu_tape_init_ctlblock() failed\n");
! 3013: goto io_failure;
! 3014: }
! 3015: fsync(fd);
! 3016:
! 3017: if (S_ISREG(st.st_mode)) {
! 3018: /* media is file */
! 3019: /* truncate and extend */
! 3020: if (ftruncate(fd, request_len) == -1) {
! 3021: ISTGT_ERRLOG("ftruncate() failed\n");
! 3022: goto io_failure;
! 3023: }
! 3024: fsync(fd);
! 3025: if (mediaflags & ISTGT_LU_FLAG_MEDIA_DYNAMIC) {
! 3026: if (request_len < ISTGT_LU_MEDIA_SIZE_MIN) {
! 3027: request_len = ISTGT_LU_MEDIA_SIZE_MIN;
! 3028: }
! 3029: mediasize = request_len;
! 3030: }
! 3031: memset(data, 0, marklen);
! 3032: if (istgt_lu_tape_seek(spec, (mediasize - marklen)) == -1) {
! 3033: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 3034: goto io_failure;
! 3035: }
! 3036: if (istgt_lu_tape_write(spec, data, marklen) != marklen) {
! 3037: ISTGT_ERRLOG("istgt_lu_tape_write() failed\n");
! 3038: goto io_failure;
! 3039: }
! 3040: fsync(fd);
! 3041: spec->size = mediasize;
! 3042: } else {
! 3043: /* media is not file */
! 3044: uint64_t offset, wlen, rest;
! 3045: /* clear with 256K */
! 3046: offset = request_len;
! 3047: wlen = 256*1024;
! 3048: memset(data, 0, wlen);
! 3049: for ( ; offset < mediasize - wlen; offset += wlen) {
! 3050: THREAD_YIELD;
! 3051: if (istgt_lu_tape_write(spec, data, wlen) != wlen) {
! 3052: ISTGT_ERRLOG("lu_tape_write() failed\n");
! 3053: goto io_failure;
! 3054: }
! 3055: }
! 3056: /* clear rest size */
! 3057: rest = mediasize % wlen;
! 3058: if (rest != 0) {
! 3059: THREAD_YIELD;
! 3060: if (istgt_lu_tape_write(spec, data, rest) != rest) {
! 3061: ISTGT_ERRLOG("lu_tape_write() failed\n");
! 3062: goto io_failure;
! 3063: }
! 3064: }
! 3065: THREAD_YIELD;
! 3066: fsync(fd);
! 3067: }
! 3068:
! 3069: /* rewind */
! 3070: istgt_lu_tape_rewind(spec);
! 3071:
! 3072: /* complete erase */
! 3073: lu_cmd->data_len = 0;
! 3074: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3075: return 0;
! 3076: }
! 3077:
! 3078: static int
! 3079: istgt_lu_tape_valid_mark_magic(tape_markblock_t *mbp)
! 3080: {
! 3081: if (mbp == NULL)
! 3082: return 0;
! 3083: if (memcmp(mbp->magic, MARK_BOTMAGIC, MARK_MAGICLEN) == 0)
! 3084: return 1;
! 3085: if (memcmp(mbp->magic, MARK_EOTMAGIC, MARK_MAGICLEN) == 0)
! 3086: return 1;
! 3087: if (memcmp(mbp->magic, MARK_EOFMAGIC, MARK_MAGICLEN) == 0)
! 3088: return 1;
! 3089: if (memcmp(mbp->magic, MARK_EODMAGIC, MARK_MAGICLEN) == 0)
! 3090: return 1;
! 3091: if (memcmp(mbp->magic, MARK_DATAMAGIC, MARK_MAGICLEN) == 0)
! 3092: return 1;
! 3093: return 0;
! 3094: }
! 3095:
! 3096: static int
! 3097: istgt_lu_tape_search_lbpos(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lbpos, uint8_t *data)
! 3098: {
! 3099: tape_markblock_t *mbp;
! 3100: uint64_t tape_leader;
! 3101: uint64_t marklen, alignment, padlen;
! 3102: uint64_t lbpos1, offset1, lbpos2, offset2;
! 3103: uint64_t offset, prev;
! 3104: int found_lbpos = 0;
! 3105: int data_len;
! 3106: int index_i;
! 3107: int rc;
! 3108: int i;
! 3109:
! 3110: tape_leader = spec->ctlblock->ctlblocklen;
! 3111: marklen = spec->ctlblock->marklen;
! 3112: alignment = spec->ctlblock->alignment;
! 3113:
! 3114: #ifdef TAPE_DEBUG
! 3115: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "search lbpos=%" PRIu64 "\n", lbpos);
! 3116: #endif /* TAPE_DEBUG */
! 3117: /* firset step, jump near position by EOF */
! 3118: index_i = -1;
! 3119: for (i = 0; i < MAX_FILEMARKS - 1; i++) {
! 3120: offset1 = spec->ctlblock->marks[i].offset;
! 3121: offset2 = spec->ctlblock->marks[i + 1].offset;
! 3122: lbpos1 = spec->ctlblock->marks[i].lbpos;
! 3123: lbpos2 = spec->ctlblock->marks[i + 1].lbpos;
! 3124: if (offset1 == MARK_END) {
! 3125: /* no more marks */
! 3126: break;
! 3127: }
! 3128: if (offset2 == MARK_END) {
! 3129: /* adjust to real media size */
! 3130: offset2 = spec->size;
! 3131: }
! 3132: /* lbpos within EOFs? */
! 3133: if (lbpos >= lbpos1 && lbpos < lbpos2) {
! 3134: index_i = i;
! 3135: break;
! 3136: }
! 3137: }
! 3138: if (index_i < 0) {
! 3139: /* END-OF-PARTITION/MEDIUM DETECTED */
! 3140: data_len
! 3141: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 3142: ISTGT_SCSI_SENSE_MEDIUM_ERROR,
! 3143: 0x00, 0x02);
! 3144: lu_cmd->sense_data_len = data_len;
! 3145: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3146: return -1;
! 3147: }
! 3148:
! 3149: /* next step, search in file */
! 3150: mbp = (tape_markblock_t *) data;
! 3151: prev = spec->ctlblock->marks[index_i].prev;
! 3152: found_lbpos = 0;
! 3153: for (offset = offset1; offset < offset2; ) {
! 3154: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 3155: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 3156: break;
! 3157: }
! 3158: rc = istgt_lu_tape_read_native_mark(spec, mbp);
! 3159: if (rc < 0) {
! 3160: ISTGT_ERRLOG("lu_tape_read_native_mark() failed: rc %d\n", rc);
! 3161: break;
! 3162: }
! 3163: /* check in logical block */
! 3164: if (!istgt_lu_tape_valid_mark_magic(mbp)) {
! 3165: ISTGT_ERRLOG("bad magic offset %" PRIu64 "\n", offset);
! 3166: break;
! 3167: }
! 3168: #ifdef TAPE_DEBUG
! 3169: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "read mlbpos=%" PRIu64 ", mlblen=%" PRIu64 ", moffset=%" PRIu64 ", offset=%" PRIu64 ", index=%d\n",
! 3170: mbp->lbpos, mbp->lblen, mbp->offset, offset, index_i);
! 3171: #endif /* TAPE_DEBUG */
! 3172: if (lbpos == mbp->lbpos) {
! 3173: found_lbpos = 1;
! 3174: offset = mbp->offset;
! 3175: break;
! 3176: }
! 3177:
! 3178: /* next offset to read */
! 3179: prev = offset;
! 3180: offset += marklen + mbp->lblen;
! 3181: if (offset % alignment) {
! 3182: padlen = alignment;
! 3183: padlen -= offset % alignment;
! 3184: offset += padlen;
! 3185: }
! 3186: }
! 3187: if (!found_lbpos) {
! 3188: /* within EOFs, but not found */
! 3189: /* INTERNAL TARGET FAILURE */
! 3190: data_len
! 3191: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 3192: ISTGT_SCSI_SENSE_HARDWARE_ERROR,
! 3193: 0x44, 0x00);
! 3194: lu_cmd->sense_data_len = data_len;
! 3195: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3196: return -1;
! 3197: }
! 3198:
! 3199: #ifdef TAPE_DEBUG
! 3200: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "set lbpos=%" PRIu64 ", offset=%" PRIu64 ", index=%d\n", lbpos, offset, index_i);
! 3201: #endif /* TAPE_DEBUG */
! 3202: /* update information */
! 3203: spec->index = index_i;
! 3204: spec->lbpos = lbpos;
! 3205: spec->prev = prev;
! 3206: spec->offset = offset;
! 3207:
! 3208: spec->bot = spec->eof = spec->eod = spec->eom = 0;
! 3209: if (index_i == 0 && offset == 0) {
! 3210: spec->bot = 1;
! 3211: } else if (offset == spec->ctlblock->marks[index_i].offset) {
! 3212: if (offset == MARK_END) {
! 3213: spec->eom = 1;
! 3214: } else {
! 3215: spec->eof = 1;
! 3216: }
! 3217: }
! 3218:
! 3219: /* complete search, new position to lbpos */
! 3220: lu_cmd->data_len = 0;
! 3221: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3222: return 0;
! 3223: }
! 3224:
! 3225: static int
! 3226: istgt_lu_tape_search_lbpos_fast_reverse(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lbpos, int count, uint8_t *data)
! 3227: {
! 3228: uint64_t xlbpos, offset, prev;
! 3229: int index_i;
! 3230:
! 3231: xlbpos = spec->lbpos;
! 3232: offset = spec->offset;
! 3233: prev = spec->prev;
! 3234: index_i = spec->index;
! 3235:
! 3236: /* now only support -1 */
! 3237: if (count != -1)
! 3238: return -1;
! 3239:
! 3240: /* END mark is special */
! 3241: if (offset == MARK_END
! 3242: || spec->ctlblock->marks[index_i].offset == MARK_END
! 3243: || spec->ctlblock->marks[index_i + 1].offset == MARK_END)
! 3244: return -1;
! 3245:
! 3246: /* this lbpos have previous offset? */
! 3247: if (lbpos != xlbpos)
! 3248: return -1;
! 3249: if (offset == spec->ctlblock->marks[index_i + 1].offset
! 3250: && spec->ctlblock->marks[index_i + 1].prev != 0ULL) {
! 3251: /* get from EOF mark */
! 3252: offset = spec->ctlblock->marks[index_i + 1].prev;
! 3253: lbpos = spec->ctlblock->marks[index_i + 1].lbpos;
! 3254: lbpos--;
! 3255: prev = 0ULL;
! 3256:
! 3257: #ifdef TAPE_DEBUG
! 3258: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "set lbpos=%" PRIu64 ", offset=%" PRIu64 ", index=%d\n", lbpos, offset, index_i);
! 3259: #endif /* TAPE_DEBUG */
! 3260: /* update information */
! 3261: spec->index = index_i;
! 3262: spec->lbpos = lbpos;
! 3263: spec->prev = prev;
! 3264: spec->offset = offset;
! 3265:
! 3266: spec->bot = spec->eof = spec->eod = spec->eom = 0;
! 3267: if (index_i == 0 && offset == 0) {
! 3268: spec->bot = 1;
! 3269: } else if (offset == spec->ctlblock->marks[index_i].offset) {
! 3270: if (offset == MARK_END) {
! 3271: spec->eom = 1;
! 3272: } else {
! 3273: spec->eof = 1;
! 3274: }
! 3275: }
! 3276:
! 3277: /* complete search, new position to lbpos */
! 3278: lu_cmd->data_len = 0;
! 3279: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3280: return 0;
! 3281: }
! 3282:
! 3283: /* no method for fast reverse */
! 3284: return -1;
! 3285: }
! 3286:
! 3287: static int
! 3288: istgt_lu_tape_scsi_space(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int code, int count, uint8_t *data)
! 3289: {
! 3290: uint64_t lbpos, offset, prev;
! 3291: int found_bot = 0, found_eom = 0;
! 3292: int data_len;
! 3293: int index_i;
! 3294: int i;
! 3295:
! 3296: if (code != 0x03 && count == 0) {
! 3297: /* no-op except EOD */
! 3298: lu_cmd->data_len = 0;
! 3299: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3300: return 0;
! 3301: }
! 3302:
! 3303: lbpos = spec->lbpos;
! 3304: offset = spec->offset;
! 3305: prev = spec->prev;
! 3306: index_i = spec->index;
! 3307:
! 3308: if (code == 0x00) {
! 3309: /* Logical blocks */
! 3310: if (count < 0) {
! 3311: /* reverse */
! 3312: /* first check search cache etc. */
! 3313: data_len
! 3314: = istgt_lu_tape_search_lbpos_fast_reverse(spec, conn, lu_cmd,
! 3315: lbpos, count, data);
! 3316: if (data_len > 0) {
! 3317: /* scsi condition met */
! 3318: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3319: return data_len;
! 3320: } else if (data_len == 0) {
! 3321: /* found position */
! 3322: lu_cmd->data_len = 0;
! 3323: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3324: return 0;
! 3325: }
! 3326: count = -count;
! 3327: if (lbpos < (uint64_t) count) {
! 3328: lbpos = 0ULL;
! 3329: } else {
! 3330: lbpos -= (uint64_t) count;
! 3331: }
! 3332: } else if (count > 0) {
! 3333: /* forward */
! 3334: if ((uint64_t) count > LBPOS_MAX - lbpos) {
! 3335: lbpos = LBPOS_MAX;
! 3336: } else {
! 3337: lbpos += (uint64_t) count;
! 3338: }
! 3339: }
! 3340:
! 3341: /* search in file (logical blocks) */
! 3342: data_len = istgt_lu_tape_search_lbpos(spec, conn, lu_cmd, lbpos, data);
! 3343: if (data_len != 0) {
! 3344: /* sense data build by function */
! 3345: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3346: return data_len;
! 3347: }
! 3348: } else if (code == 0x01) {
! 3349: /* Filemarks */
! 3350: if (count < 0) {
! 3351: /* reverse */
! 3352: for (i = 0; i > count; i--) {
! 3353: if (index_i + i == 0) {
! 3354: found_bot = 1;
! 3355: break;
! 3356: }
! 3357: }
! 3358: index_i += i;
! 3359: offset = spec->ctlblock->marks[index_i].offset;
! 3360: if (offset == MARK_END) {
! 3361: /* INTERNAL TARGET FAILURE */
! 3362: data_len
! 3363: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 3364: ISTGT_SCSI_SENSE_HARDWARE_ERROR,
! 3365: 0x44, 0x00);
! 3366: lu_cmd->sense_data_len = data_len;
! 3367: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3368: return data_len;
! 3369: }
! 3370: /* position to EOF */
! 3371: lbpos = spec->ctlblock->marks[index_i + 1].lbpos;
! 3372: offset = spec->ctlblock->marks[index_i + 1].offset;
! 3373: prev = spec->ctlblock->marks[index_i + 1].prev;
! 3374: } else if (count > 0) {
! 3375: /* forward */
! 3376: for (i = 0; i < count; i++) {
! 3377: if (spec->ctlblock->marks[index_i + i].offset == MARK_END) {
! 3378: found_eom = 1;
! 3379: break;
! 3380: }
! 3381: }
! 3382: index_i += i;
! 3383: offset = spec->ctlblock->marks[index_i].offset;
! 3384: if (found_eom || offset == MARK_END) {
! 3385: /* END-OF-DATA DETECTED */
! 3386: data_len
! 3387: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 3388: ISTGT_SCSI_SENSE_BLANK_CHECK,
! 3389: 0x00, 0x05);
! 3390: DSET32(&data[2+3], (uint32_t) count - i);
! 3391: lu_cmd->sense_data_len = data_len;
! 3392: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3393: return data_len;
! 3394: }
! 3395: lbpos = spec->ctlblock->marks[index_i].lbpos;
! 3396: /* position to next block of EOF */
! 3397: prev = offset;
! 3398: offset += spec->ctlblock->marklen;
! 3399: lbpos++;
! 3400: }
! 3401:
! 3402: #ifdef TAPE_DEBUG
! 3403: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "set lbpos=%" PRIu64 ", offset=%" PRIu64 ", index=%d\n", lbpos, offset, index_i);
! 3404: #endif /* TAPE_DEBUG */
! 3405: /* update information */
! 3406: spec->index = index_i;
! 3407: spec->lbpos = lbpos;
! 3408: spec->prev = prev;
! 3409: spec->offset = offset;
! 3410:
! 3411: spec->bot = spec->eof = spec->eod = spec->eom = 0;
! 3412: if (index_i == 0 && offset == 0) {
! 3413: spec->bot = 1;
! 3414: } else if (offset == spec->ctlblock->marks[index_i].offset) {
! 3415: if (offset == MARK_END) {
! 3416: spec->eom = 1;
! 3417: } else {
! 3418: spec->eof = 1;
! 3419: }
! 3420: }
! 3421: } else if (code == 0x03) {
! 3422: /* End-of-data */
! 3423: index_i = -1;
! 3424: for (i = 0; i < MAX_FILEMARKS ; i++) {
! 3425: if (spec->ctlblock->marks[i].offset == MARK_END) {
! 3426: index_i = i;
! 3427: break;
! 3428: }
! 3429: }
! 3430: if (index_i <= 0) {
! 3431: /* INTERNAL TARGET FAILURE */
! 3432: data_len
! 3433: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 3434: ISTGT_SCSI_SENSE_HARDWARE_ERROR,
! 3435: 0x44, 0x00);
! 3436: lu_cmd->sense_data_len = data_len;
! 3437: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3438: return data_len;
! 3439: }
! 3440:
! 3441: /* skip EOT (position to last EOF) */
! 3442: index_i--;
! 3443: lbpos = spec->ctlblock->marks[index_i].lbpos;
! 3444: offset = spec->ctlblock->marks[index_i].offset;
! 3445: /* position to next block of EOF */
! 3446: prev = offset;
! 3447: offset += spec->ctlblock->marklen;
! 3448: lbpos++;
! 3449:
! 3450: #ifdef TAPE_DEBUG
! 3451: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "set lbpos=%" PRIu64 ", offset=%" PRIu64 ", index=%d\n", lbpos, offset, index_i);
! 3452: #endif /* TAPE_DEBUG */
! 3453: /* update information */
! 3454: spec->index = index_i;
! 3455: spec->lbpos = lbpos;
! 3456: spec->prev = prev;
! 3457: spec->offset = offset;
! 3458:
! 3459: spec->bot = spec->eof = spec->eod = spec->eom = 0;
! 3460: if (index_i == 0 && offset == 0) {
! 3461: spec->bot = 1;
! 3462: } else if (offset == spec->ctlblock->marks[index_i].offset) {
! 3463: if (offset == MARK_END) {
! 3464: spec->eom = 1;
! 3465: } else {
! 3466: spec->eof = 1;
! 3467: }
! 3468: }
! 3469: } else {
! 3470: /* INVALID FIELD IN CDB */
! 3471: data_len
! 3472: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 3473: ISTGT_SCSI_SENSE_ILLEGAL_REQUEST,
! 3474: 0x24, 0x00);
! 3475: lu_cmd->sense_data_len = data_len;
! 3476: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3477: return data_len;
! 3478: }
! 3479:
! 3480: /* complete space command, new position to lbpos */
! 3481: lu_cmd->data_len = 0;
! 3482: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3483: return 0;
! 3484: }
! 3485:
! 3486: static int
! 3487: istgt_lu_tape_scsi_locate(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint32_t loi, uint8_t *data)
! 3488: {
! 3489: uint64_t lbpos;
! 3490: int data_len;
! 3491:
! 3492: if (loi == 0) {
! 3493: /* position to zero (BOT) */
! 3494: istgt_lu_tape_rewind(spec);
! 3495: lu_cmd->data_len = 0;
! 3496: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3497: return 0;
! 3498: }
! 3499:
! 3500: lbpos = (uint64_t) loi;
! 3501:
! 3502: /* search logical block */
! 3503: data_len = istgt_lu_tape_search_lbpos(spec, conn, lu_cmd, lbpos, data);
! 3504: if (data_len != 0) {
! 3505: /* sense data build by function */
! 3506: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3507: return data_len;
! 3508: }
! 3509:
! 3510: /* complete locate command, new position to lbpos */
! 3511: lu_cmd->data_len = 0;
! 3512: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3513: return 0;
! 3514: }
! 3515:
! 3516: static int
! 3517: istgt_lu_tape_scsi_read_position(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, int sa, uint8_t *data)
! 3518: {
! 3519: uint64_t lbpos;
! 3520: int data_len;
! 3521:
! 3522: lbpos = spec->lbpos;
! 3523:
! 3524: switch (sa) {
! 3525: case 0x00:
! 3526: /* 0x00 SHORT FORM -- BLOCK ID */
! 3527: case 0x01:
! 3528: /* 0x01 SHORT FORM -- VENDOR-SPECIFIC */
! 3529: data_len = 20;
! 3530: memset(&data[0], 0, data_len);
! 3531:
! 3532: /* BOP(7) EOP(6) LOCU(5) BYCU(4) LOLU(2) PERR(1) */
! 3533: /* only one partision is supported, BOT/EOT equal BOP/EOP */
! 3534: if (lbpos == 0ULL) {
! 3535: BSET8(&data[0], 7); /* BOP=1 */
! 3536: }
! 3537: if (spec->eom) {
! 3538: BSET8(&data[0], 6); /* EOP=1 */
! 3539: }
! 3540: /* logical object count unknown */
! 3541: BSET8(&data[0], 5); /* LOCU=1 */
! 3542: /* byte count unknown */
! 3543: BSET8(&data[0], 4); /* BYCU=1 */
! 3544: /* logical object location unknown */
! 3545: //BSET8(&data[0], 2); /* LOLU=1 */
! 3546: if (lbpos > 0xffffffffULL) {
! 3547: BSET8(&data[0], 0); /* PERR=1 */
! 3548: }
! 3549:
! 3550: /* PARTITION NUMBER */
! 3551: data[1] = 0;
! 3552: /* FIRST LOGICAL OBJECT LOCATION */
! 3553: DSET32(&data[4], (uint32_t)lbpos);
! 3554: /* LAST LOGICAL OBJECT LOCATION */
! 3555: DSET32(&data[8], 0);
! 3556: /* NUMBER OF LOGICAL OBJECTS IN OBJECT BUFFER */
! 3557: DSET24(&data[13], 0);
! 3558: /* NUMBER OF BYTES IN OBJECT BUFFER */
! 3559: DSET32(&data[16], 0);
! 3560: break;
! 3561:
! 3562: case 0x06:
! 3563: /* LONG FORM */
! 3564: data_len = 32;
! 3565: memset(&data[0], 0, data_len);
! 3566:
! 3567: /* BOP(7) EOP(6) MPU(3) LONU(2) */
! 3568: /* only one partision is supported, BOT/EOT equal BOP/EOP */
! 3569: if (lbpos == 0ULL) {
! 3570: BSET8(&data[0], 7); /* BOP=1 */
! 3571: }
! 3572: if (spec->eom) {
! 3573: BSET8(&data[0], 6); /* EOP=1 */
! 3574: }
! 3575:
! 3576: /* mark position unknown */
! 3577: BSET8(&data[0], 3); /* MPU=1 */
! 3578: /* logical object number unknown */
! 3579: //BSET8(&data[0], 2); /* LONU=1 */
! 3580:
! 3581: /* PARTITION NUMBER */
! 3582: DSET32(&data[4], 0);
! 3583: /* LOGICAL OBJECT NUMBER */
! 3584: DSET64(&data[8], lbpos);
! 3585: /* LOGICAL FILE IDENTIFIER */
! 3586: DSET64(&data[16], 0ULL);
! 3587: /* LOGICAL SET IDENTIFIER */
! 3588: DSET64(&data[24], 0ULL);
! 3589: break;
! 3590:
! 3591: default:
! 3592: /* INVALID FIELD IN CDB */
! 3593: data_len
! 3594: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 3595: ISTGT_SCSI_SENSE_ILLEGAL_REQUEST,
! 3596: 0x24, 0x00);
! 3597: lu_cmd->sense_data_len = data_len;
! 3598: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3599: return -1;
! 3600: }
! 3601:
! 3602: lu_cmd->data_len = data_len;
! 3603: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3604: return 0;
! 3605: }
! 3606:
! 3607: static int
! 3608: istgt_lu_tape_build_sense_data(ISTGT_LU_TAPE *spec, uint8_t *data, int sk, int asc, int ascq)
! 3609: {
! 3610: uint8_t *cp;
! 3611: int hlen = 0, len = 0, plen;
! 3612: int total;
! 3613: int data_len;
! 3614:
! 3615: data_len = istgt_lu_scsi_build_sense_data(data, sk, asc, ascq);
! 3616: hlen = 2;
! 3617: if (data_len < (hlen + 18)) {
! 3618: return data_len;
! 3619: }
! 3620:
! 3621: cp = &data[hlen + len];
! 3622: len = 8;
! 3623:
! 3624: /* FILEMARK(7) EOM(6) ILI(5) SENSE KEY(3-0) */
! 3625: if (spec != NULL && spec->eof) {
! 3626: BSET8(&cp[2], 7); /* FILEMARK=1 */
! 3627: }
! 3628: if (spec != NULL && spec->eom) {
! 3629: BSET8(&cp[2], 6); /* EOM=1 */
! 3630: }
! 3631:
! 3632: /* Additional sense bytes */
! 3633:
! 3634: /* for DLT8000 */
! 3635: /* Internal Status Code */
! 3636: cp[18] = 0;
! 3637: //cp[18] = 0x86; /* Directory Bad */
! 3638: /* Tape Motion Hours */
! 3639: DSET16(&cp[19], 0);
! 3640: /* Power On Hours */
! 3641: DSET32(&cp[21], 0);
! 3642: /* Tape Remaining */
! 3643: DSET32(&cp[25], 0);
! 3644: //DSET32(&cp[25], (uint32_t) (spec->size / spec->ctlblock->blocklen));
! 3645: /* Reserved */
! 3646: cp[29] = 0;
! 3647: plen = 30 - len;
! 3648:
! 3649: /* ADDITIONAL SENSE LENGTH */
! 3650: cp[7] = plen;
! 3651:
! 3652: total = hlen + len + plen;
! 3653:
! 3654: /* SenseLength */
! 3655: DSET16(&data[0], total - 2);
! 3656:
! 3657: return total;
! 3658: }
! 3659:
! 3660: static int
! 3661: istgt_lu_tape_build_sense_media(ISTGT_LU_TAPE *spec, uint8_t *data)
! 3662: {
! 3663: uint8_t *sense_data;
! 3664: int *sense_len;
! 3665: int data_len;
! 3666:
! 3667: sense_data = data;
! 3668: sense_len = &data_len;
! 3669: *sense_len = 0;
! 3670:
! 3671: if (!spec->mload && !spec->mchanged) {
! 3672: /* MEDIUM NOT PRESENT */
! 3673: BUILD_SENSE(NOT_READY, 0x3a, 0x00);
! 3674: return data_len;
! 3675: }
! 3676: if (spec->mchanged) {
! 3677: /* MEDIUM NOT PRESENT */
! 3678: BUILD_SENSE(NOT_READY, 0x3a, 0x00);
! 3679: return data_len;
! 3680: #if 0
! 3681: /* LOGICAL UNIT NOT READY, CAUSE NOT REPORTABLE */
! 3682: BUILD_SENSE(NOT_READY, 0x04, 0x00);
! 3683: return data_len;
! 3684: /* LOGICAL UNIT IS IN PROCESS OF BECOMING READY */
! 3685: BUILD_SENSE(NOT_READY, 0x04, 0x01);
! 3686: return data_len;
! 3687: #endif
! 3688: }
! 3689: return 0;
! 3690: }
! 3691:
! 3692: static int
! 3693: istgt_lu_tape_variable_lbread(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lblen)
! 3694: {
! 3695: tape_markblock_t *mbp;
! 3696: uint8_t *data;
! 3697: uint64_t mediasize;
! 3698: uint64_t tape_leader;
! 3699: uint64_t marklen, alignment, padlen;
! 3700: uint64_t lbpos, offset, prev;
! 3701: uint64_t blen;
! 3702: uint64_t total;
! 3703: uint64_t request_len;
! 3704: uint32_t u;
! 3705: int64_t rc;
! 3706:
! 3707: mediasize = spec->size;
! 3708: tape_leader = spec->ctlblock->ctlblocklen;
! 3709: marklen = spec->ctlblock->marklen;
! 3710: alignment = spec->ctlblock->alignment;
! 3711: lbpos = spec->lbpos;
! 3712: offset = spec->offset;
! 3713: mbp = (tape_markblock_t *) lu_cmd->iobuf;
! 3714: data = (uint8_t *) lu_cmd->iobuf + marklen;
! 3715: total = 0ULL;
! 3716: u = 0;
! 3717: /* header + data + EOD */
! 3718: request_len = marklen + lblen + marklen;
! 3719: spec->info = (uint32_t) lblen;
! 3720:
! 3721: #ifdef TAPE_DEBUG
! 3722: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Read: %"PRIu64" (%"PRIu64")\n",
! 3723: lblen, offset);
! 3724: #endif /* TAPE_DEBUG */
! 3725:
! 3726: if (request_len > lu_cmd->iobufsize) {
! 3727: ISTGT_ERRLOG("request_len(%"PRIu64") > iobufsize(%u)\n",
! 3728: request_len, lu_cmd->iobufsize);
! 3729: return -1;
! 3730: }
! 3731:
! 3732: /* read media check */
! 3733: if (istgt_lu_tape_read_media_check(spec, conn, lu_cmd, request_len) < 0) {
! 3734: /* INFORMATION */
! 3735: DSET32(&lu_cmd->sense_data[2+3], (uint32_t) spec->info);
! 3736: /* not I/O error */
! 3737: return 0;
! 3738: }
! 3739:
! 3740: /* position to virtual tape mark */
! 3741: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 3742: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 3743: return -1;
! 3744: }
! 3745: /* virtual tape mark */
! 3746: rc = istgt_lu_tape_read_native_mark(spec, mbp);
! 3747: if (rc < 0) {
! 3748: ISTGT_ERRLOG("lu_tape_read_native_mark() failed\n");
! 3749: return -1;
! 3750: }
! 3751: if (!istgt_lu_tape_valid_mark_magic(mbp)) {
! 3752: ISTGT_ERRLOG("bad magic offset %"PRIu64"\n", offset);
! 3753: return -1;
! 3754: }
! 3755: if (lbpos != mbp->lbpos) {
! 3756: ISTGT_ERRLOG("bad position offset %"PRIu64" lbpos %"PRIu64
! 3757: " mlbpos %"PRIu64"\n", offset, lbpos, mbp->lbpos);
! 3758: return -1;
! 3759: }
! 3760: if (memcmp(mbp->magic, MARK_EOFMAGIC, MARK_MAGICLEN) == 0) {
! 3761: #ifdef TAPE_DEBUG
! 3762: ISTGT_TRACELOG(ISTGT_TRACE_LU, "EOF found\n");
! 3763: #endif /* TAPE_DEBUG */
! 3764: /* EOF detected */
! 3765: spec->eof = 1;
! 3766: goto early_return;
! 3767: }
! 3768: if (memcmp(mbp->magic, MARK_EODMAGIC, MARK_MAGICLEN) == 0) {
! 3769: #ifdef TAPE_DEBUG
! 3770: ISTGT_TRACELOG(ISTGT_TRACE_LU, "EOD found\n");
! 3771: #endif /* TAPE_DEBUG */
! 3772: /* EOD detected */
! 3773: spec->eod = 1;
! 3774: goto early_return;
! 3775: }
! 3776: /* user data */
! 3777: rc = istgt_lu_tape_read(spec, data + total, mbp->lblen);
! 3778: if (rc < 0 || rc != mbp->lblen) {
! 3779: ISTGT_ERRLOG("lu_tape_read() failed: rc %d\n", rc);
! 3780: return -1;
! 3781: }
! 3782: #ifdef TAPE_DEBUG
! 3783: ISTGT_TRACELOG(ISTGT_TRACE_LU, "read mlbpos=%"PRIu64", lblen=%"PRIu64
! 3784: ", offset=%"PRIu64"\n", mbp->lbpos, mbp->lblen, offset);
! 3785: #endif /* TAPE_DEBUG */
! 3786: /* 1 block OK */
! 3787: spec->info -= (uint32_t) lblen;
! 3788: /* next offset to read */
! 3789: prev = offset;
! 3790: offset += marklen + mbp->lblen;
! 3791: if (offset % alignment) {
! 3792: padlen = alignment;
! 3793: padlen -= offset % alignment;
! 3794: offset += padlen;
! 3795: }
! 3796: lbpos++;
! 3797: /* update information */
! 3798: spec->lbpos = lbpos;
! 3799: spec->prev = prev;
! 3800: spec->offset = offset;
! 3801:
! 3802: if (lblen > mbp->lblen) {
! 3803: blen = mbp->lblen;
! 3804: } else {
! 3805: blen = lblen;
! 3806: }
! 3807: #ifdef TAPE_DEBUG
! 3808: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Read %"PRIu64" bytes\n", blen);
! 3809: #endif /* TAPE_DEBUG */
! 3810: total += blen;
! 3811: u++;
! 3812:
! 3813: early_return:
! 3814: #ifdef TAPE_DEBUG
! 3815: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Read %"PRIu64" bytes total\n", total);
! 3816: #endif /* TAPE_DEBUG */
! 3817: lu_cmd->data = data;
! 3818: lu_cmd->data_len = total;
! 3819: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3820: return 0;
! 3821: }
! 3822:
! 3823: static int
! 3824: istgt_lu_tape_fixed_lbread(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lblen, uint32_t count)
! 3825: {
! 3826: tape_markblock_t *mbp;
! 3827: uint8_t *data;
! 3828: uint64_t mediasize;
! 3829: uint64_t tape_leader;
! 3830: uint64_t marklen, alignment, padlen;
! 3831: uint64_t lbpos, offset, prev;
! 3832: uint64_t blen;
! 3833: uint64_t total;
! 3834: uint64_t request_len;
! 3835: uint64_t rest;
! 3836: uint32_t u;
! 3837: int data_len;
! 3838: int64_t rc;
! 3839:
! 3840: mediasize = spec->size;
! 3841: tape_leader = spec->ctlblock->ctlblocklen;
! 3842: marklen = spec->ctlblock->marklen;
! 3843: alignment = spec->ctlblock->alignment;
! 3844: lbpos = spec->lbpos;
! 3845: offset = spec->offset;
! 3846: mbp = (tape_markblock_t *) lu_cmd->iobuf;
! 3847: data = (uint8_t *) lu_cmd->iobuf + marklen;
! 3848: total = 0ULL;
! 3849: /* (header + data) x N + EOD */
! 3850: request_len = ((marklen + lblen) * (uint64_t) count) + marklen;
! 3851: spec->info = count;
! 3852:
! 3853: #ifdef TAPE_DEBUG
! 3854: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Read: %"PRIu64" x %u (%"PRIu64")\n",
! 3855: lblen, count, offset);
! 3856: #endif /* TAPE_DEBUG */
! 3857:
! 3858: if (request_len > lu_cmd->iobufsize) {
! 3859: ISTGT_ERRLOG("request_len(%"PRIu64") > iobufsize(%u)\n",
! 3860: request_len, lu_cmd->iobufsize);
! 3861: return -1;
! 3862: }
! 3863:
! 3864: /* read media check */
! 3865: if (istgt_lu_tape_read_media_check(spec, conn, lu_cmd, request_len) < 0) {
! 3866: /* INFORMATION */
! 3867: DSET32(&lu_cmd->sense_data[2+3], (uint32_t) spec->info);
! 3868: /* not I/O error */
! 3869: return 0;
! 3870: }
! 3871:
! 3872: /* position to virtual tape mark */
! 3873: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 3874: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 3875: return -1;
! 3876: }
! 3877:
! 3878: rest = 0ULL;
! 3879: /* read N blocks */
! 3880: for (u = 0; u < count; u++) {
! 3881: if (rest == 0) {
! 3882: /* virtual tape mark */
! 3883: rc = istgt_lu_tape_read_native_mark(spec, mbp);
! 3884: if (rc < 0) {
! 3885: ISTGT_ERRLOG("lu_tape_read_native_mark() failed\n");
! 3886: return -1;
! 3887: }
! 3888: if (!istgt_lu_tape_valid_mark_magic(mbp)) {
! 3889: ISTGT_ERRLOG("bad magic offset %"PRIu64"\n", offset);
! 3890: return -1;
! 3891: }
! 3892: if (lbpos != mbp->lbpos) {
! 3893: ISTGT_ERRLOG("bad position offset %"PRIu64" lbpos %"PRIu64
! 3894: " mlbpos %"PRIu64"\n", offset, lbpos, mbp->lbpos);
! 3895: return -1;
! 3896: }
! 3897: if (memcmp(mbp->magic, MARK_EOFMAGIC, MARK_MAGICLEN) == 0) {
! 3898: #ifdef TAPE_DEBUG
! 3899: ISTGT_TRACELOG(ISTGT_TRACE_LU, "EOF found\n");
! 3900: #endif /* TAPE_DEBUG */
! 3901: /* EOF detected */
! 3902: spec->eof = 1;
! 3903: goto early_return;
! 3904: }
! 3905: if (memcmp(mbp->magic, MARK_EODMAGIC, MARK_MAGICLEN) == 0) {
! 3906: #ifdef TAPE_DEBUG
! 3907: ISTGT_TRACELOG(ISTGT_TRACE_LU, "EOD found\n");
! 3908: #endif /* TAPE_DEBUG */
! 3909: /* EOD detected */
! 3910: spec->eod = 1;
! 3911: goto early_return;
! 3912: }
! 3913: /* user data */
! 3914: rc = istgt_lu_tape_read(spec, data + total, mbp->lblen);
! 3915: if (rc < 0 || rc != mbp->lblen) {
! 3916: ISTGT_ERRLOG("lu_tape_read() failed: rc %d\n", rc);
! 3917: return -1;
! 3918: }
! 3919: #ifdef TAPE_DEBUG
! 3920: ISTGT_TRACELOG(ISTGT_TRACE_LU, "read mlbpos=%"PRIu64", lblen=%"
! 3921: PRIu64", offset=%"PRIu64"\n",
! 3922: mbp->lbpos, mbp->lblen, offset);
! 3923: #endif /* TAPE_DEBUG */
! 3924: rest = mbp->lblen;
! 3925: }
! 3926: /* check logical block size */
! 3927: if ((rest > lblen * (count - u))
! 3928: || rest < lblen) {
! 3929: /* incorrect length */
! 3930: data_len
! 3931: = istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
! 3932: ISTGT_SCSI_SENSE_NO_SENSE,
! 3933: 0x00, 0x00);
! 3934: BSET8(&lu_cmd->sense_data[2+2], 5); /* ILI=1 */
! 3935: //spec->info = count - u;
! 3936: /* INFORMATION */
! 3937: DSET32(&lu_cmd->sense_data[2+3], spec->info);
! 3938: lu_cmd->sense_data_len = data_len;
! 3939: lu_cmd->data = data;
! 3940: lu_cmd->data_len = total;
! 3941: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 3942: return -1;
! 3943: } else {
! 3944: /* 1 block OK */
! 3945: spec->info--;
! 3946: rest -= lblen;
! 3947: blen = lblen;
! 3948: }
! 3949:
! 3950: /* buffer empty? */
! 3951: if (rest == 0) {
! 3952: /* next offset to read */
! 3953: prev = offset;
! 3954: offset += marklen + mbp->lblen;
! 3955: if (offset % alignment) {
! 3956: padlen = alignment;
! 3957: padlen -= offset % alignment;
! 3958: offset += padlen;
! 3959: }
! 3960: lbpos++;
! 3961: /* update information */
! 3962: spec->lbpos = lbpos;
! 3963: spec->prev = prev;
! 3964: spec->offset = offset;
! 3965: }
! 3966:
! 3967: #ifdef TAPE_DEBUG
! 3968: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Read %"PRIu64" bytes\n", blen);
! 3969: #endif /* TAPE_DEBUG */
! 3970: total += blen;
! 3971: }
! 3972:
! 3973: early_return:
! 3974: #ifdef TAPE_DEBUG
! 3975: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Read %"PRIu64" bytes total\n", total);
! 3976: #endif /* TAPE_DEBUG */
! 3977: lu_cmd->data = data;
! 3978: lu_cmd->data_len = total;
! 3979: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 3980: return 0;
! 3981: }
! 3982:
! 3983: static int
! 3984: istgt_lu_tape_variable_lbwrite(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lblen)
! 3985: {
! 3986: tape_markblock_t *mbp;
! 3987: uint8_t *data;
! 3988: uint64_t mediasize;
! 3989: uint64_t tape_leader;
! 3990: uint64_t marklen, alignment, padlen;
! 3991: uint64_t lbpos, offset, prev;
! 3992: uint64_t total;
! 3993: uint64_t request_len;
! 3994: int64_t rc;
! 3995:
! 3996: mediasize = spec->size;
! 3997: tape_leader = spec->ctlblock->ctlblocklen;
! 3998: marklen = spec->ctlblock->marklen;
! 3999: alignment = spec->ctlblock->alignment;
! 4000: lbpos = spec->lbpos;
! 4001: offset = spec->offset;
! 4002: prev = spec->prev;
! 4003: mbp = (tape_markblock_t *) lu_cmd->iobuf;
! 4004: data = (uint8_t *) lu_cmd->iobuf + marklen;
! 4005: total = 0ULL;
! 4006: /* header + data + EOD */
! 4007: request_len = marklen + lblen + marklen;
! 4008: spec->info = (uint32_t) lblen;
! 4009:
! 4010: #ifdef TAPE_DEBUG
! 4011: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Write: %"PRIu64" (%"PRIu64")\n",
! 4012: lblen, offset);
! 4013: #endif /* TAPE_DEBUG */
! 4014:
! 4015: if (request_len > lu_cmd->iobufsize) {
! 4016: ISTGT_ERRLOG("request_len(%"PRIu64") > iobufsize(%u)\n",
! 4017: request_len, lu_cmd->iobufsize);
! 4018: return -1;
! 4019: }
! 4020:
! 4021: /* prepare mark */
! 4022: memset(mbp, 0, marklen);
! 4023: memcpy(mbp->magic, MARK_DATAMAGIC, MARK_MAGICLEN);
! 4024: mbp->endian = MARK_ENDIAN;
! 4025: mbp->version = MARK_VERSION;
! 4026: mbp->marklen = marklen;
! 4027: mbp->lblen = lblen;
! 4028: if (spec->compression) {
! 4029: /* not supported yet */
! 4030: mbp->compalgo = spec->compalgo;
! 4031: mbp->vtcompalgo = MARK_COMPALGO_NONE;
! 4032: mbp->vtdecomplen = 0ULL;
! 4033: } else {
! 4034: mbp->compalgo = 0ULL;
! 4035: mbp->vtcompalgo = MARK_COMPALGO_NONE;
! 4036: mbp->vtdecomplen = 0ULL;
! 4037: }
! 4038:
! 4039: mbp->lbpos = lbpos;
! 4040: mbp->offset = offset;
! 4041: mbp->prev = prev;
! 4042:
! 4043: /* DATAOUT */
! 4044: rc = istgt_lu_tape_transfer_data(conn, lu_cmd, data,
! 4045: lu_cmd->iobufsize - marklen, lblen);
! 4046: if (rc < 0) {
! 4047: ISTGT_ERRLOG("lu_tape_transfer_data() failed\n");
! 4048: return -1;
! 4049: }
! 4050:
! 4051: /* write media check */
! 4052: if (istgt_lu_tape_write_media_check(spec, conn, lu_cmd, request_len) < 0) {
! 4053: /* INFORMATION */
! 4054: DSET32(&lu_cmd->sense_data[2+3], (uint32_t) spec->info);
! 4055: /* not I/O error */
! 4056: return 0;
! 4057: }
! 4058:
! 4059: /* position to virtual tape mark */
! 4060: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 4061: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 4062: return -1;
! 4063: }
! 4064: #ifdef TAPE_DEBUG
! 4065: ISTGT_TRACELOG(ISTGT_TRACE_LU, "write mlbpos=%"PRIu64", lblen=%"PRIu64
! 4066: ", offset=%"PRIu64"\n", mbp->lbpos, mbp->lblen, offset);
! 4067: #endif /* TAPE_DEBUG */
! 4068: /* virtual tape mark */
! 4069: rc = istgt_lu_tape_write_native_mark(spec, mbp);
! 4070: if (rc < 0) {
! 4071: ISTGT_ERRLOG("lu_tape_write_native_mark() failed\n");
! 4072: return -1;
! 4073: }
! 4074: /* user data */
! 4075: rc = istgt_lu_tape_write(spec, data + total, lblen);
! 4076: if (rc != lblen) {
! 4077: ISTGT_ERRLOG("lu_tape_write() failed\n");
! 4078: return -1;
! 4079: }
! 4080: /* 1 block OK */
! 4081: spec->info -= (uint32_t) lblen;
! 4082: /* next offset to read */
! 4083: prev = offset;
! 4084: offset += marklen + mbp->lblen;
! 4085: if (offset % alignment) {
! 4086: padlen = alignment;
! 4087: padlen -= offset % alignment;
! 4088: offset += padlen;
! 4089: }
! 4090: lbpos++;
! 4091: /* update information */
! 4092: spec->lbpos = lbpos;
! 4093: spec->prev = prev;
! 4094: spec->offset = offset;
! 4095:
! 4096: mbp->lbpos = lbpos;
! 4097: mbp->offset = offset;
! 4098: mbp->prev = prev;
! 4099:
! 4100: total += lblen;
! 4101:
! 4102: #ifdef TAPE_DEBUG
! 4103: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Wrote %"PRIu64" bytes\n", total);
! 4104: #endif /* TAPE_DEBUG */
! 4105: lu_cmd->data_len = total;
! 4106: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4107: return 0;
! 4108: }
! 4109:
! 4110: static int
! 4111: istgt_lu_tape_fixed_lbwrite(ISTGT_LU_TAPE *spec, CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd, uint64_t lblen, uint32_t count)
! 4112: {
! 4113: tape_markblock_t *mbp;
! 4114: uint8_t *data;
! 4115: uint64_t mediasize;
! 4116: uint64_t tape_leader;
! 4117: uint64_t marklen, alignment, padlen;
! 4118: uint64_t lbpos, offset, prev;
! 4119: uint64_t total;
! 4120: uint64_t request_len;
! 4121: uint32_t u;
! 4122: int64_t rc;
! 4123:
! 4124: mediasize = spec->size;
! 4125: tape_leader = spec->ctlblock->ctlblocklen;
! 4126: marklen = spec->ctlblock->marklen;
! 4127: alignment = spec->ctlblock->alignment;
! 4128: lbpos = spec->lbpos;
! 4129: offset = spec->offset;
! 4130: prev = spec->prev;
! 4131: mbp = (tape_markblock_t *) lu_cmd->iobuf;
! 4132: data = (uint8_t *) lu_cmd->iobuf + marklen;
! 4133: total = 0ULL;
! 4134: /* (header + data) x N + EOD */
! 4135: request_len = ((marklen + lblen) * (uint64_t) count) + marklen;
! 4136: spec->info = count;
! 4137:
! 4138: #ifdef TAPE_DEBUG
! 4139: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Write: %"PRIu64" (%"PRIu64")\n",
! 4140: lblen, offset);
! 4141: #endif /* TAPE_DEBUG */
! 4142:
! 4143: if (request_len > lu_cmd->iobufsize) {
! 4144: ISTGT_ERRLOG("request_len(%"PRIu64") > iobufsize(%u)\n",
! 4145: request_len, lu_cmd->iobufsize);
! 4146: return -1;
! 4147: }
! 4148:
! 4149: /* prepare mark */
! 4150: memset(mbp, 0, marklen);
! 4151: memcpy(mbp->magic, MARK_DATAMAGIC, MARK_MAGICLEN);
! 4152: mbp->endian = MARK_ENDIAN;
! 4153: mbp->version = MARK_VERSION;
! 4154: mbp->marklen = marklen;
! 4155: mbp->lblen = lblen;
! 4156: if (spec->compression) {
! 4157: /* not supported yet */
! 4158: mbp->compalgo = spec->compalgo;
! 4159: mbp->vtcompalgo = MARK_COMPALGO_NONE;
! 4160: mbp->vtdecomplen = 0ULL;
! 4161: } else {
! 4162: mbp->compalgo = 0ULL;
! 4163: mbp->vtcompalgo = MARK_COMPALGO_NONE;
! 4164: mbp->vtdecomplen = 0ULL;
! 4165: }
! 4166:
! 4167: mbp->lbpos = lbpos;
! 4168: mbp->offset = offset;
! 4169: mbp->prev = prev;
! 4170:
! 4171: /* DATAOUT */
! 4172: rc = istgt_lu_tape_transfer_data(conn, lu_cmd, data,
! 4173: lu_cmd->iobufsize - marklen, lblen * count);
! 4174: if (rc < 0) {
! 4175: ISTGT_ERRLOG("lu_tape_transfer_data() failed\n");
! 4176: return -1;
! 4177: }
! 4178:
! 4179: /* write media check */
! 4180: if (istgt_lu_tape_write_media_check(spec, conn, lu_cmd, request_len) < 0) {
! 4181: /* INFORMATION */
! 4182: DSET32(&lu_cmd->sense_data[2+3], (uint32_t) spec->info);
! 4183: /* not I/O error */
! 4184: return 0;
! 4185: }
! 4186:
! 4187: /* position to virtual tape mark */
! 4188: if (istgt_lu_tape_seek(spec, (tape_leader + offset)) == -1) {
! 4189: ISTGT_ERRLOG("lu_tape_seek() failed\n");
! 4190: return -1;
! 4191: }
! 4192: /* write N blocks */
! 4193: for (u = 0; u < count; u++) {
! 4194: #ifdef TAPE_DEBUG
! 4195: ISTGT_TRACELOG(ISTGT_TRACE_LU, "write mlbpos=%"PRIu64", lblen=%"PRIu64
! 4196: ", offset=%"PRIu64"\n", mbp->lbpos, mbp->lblen, offset);
! 4197: #endif /* TAPE_DEBUG */
! 4198: /* virtual tape mark */
! 4199: rc = istgt_lu_tape_write_native_mark(spec, mbp);
! 4200: if (rc < 0) {
! 4201: ISTGT_ERRLOG("lu_tape_write_native_mark() failed\n");
! 4202: return -1;
! 4203: }
! 4204: /* user data */
! 4205: rc = istgt_lu_tape_write(spec, data + total, lblen);
! 4206: if (rc != lblen) {
! 4207: ISTGT_ERRLOG("lu_tape_write() failed\n");
! 4208: return -1;
! 4209: }
! 4210: /* 1 block OK */
! 4211: spec->info--;
! 4212: /* next offset to read */
! 4213: prev = offset;
! 4214: offset += marklen + mbp->lblen;
! 4215: if (offset % alignment) {
! 4216: padlen = alignment;
! 4217: padlen -= offset % alignment;
! 4218: offset += padlen;
! 4219: }
! 4220: lbpos++;
! 4221: /* update information */
! 4222: spec->lbpos = lbpos;
! 4223: spec->prev = prev;
! 4224: spec->offset = offset;
! 4225:
! 4226: mbp->lbpos = lbpos;
! 4227: mbp->offset = offset;
! 4228: mbp->prev = prev;
! 4229:
! 4230: total += lblen;
! 4231: }
! 4232:
! 4233: #ifdef TAPE_DEBUG
! 4234: ISTGT_TRACELOG(ISTGT_TRACE_LU, "Wrote %"PRIu64" bytes\n", total);
! 4235: #endif /* TAPE_DEBUG */
! 4236: lu_cmd->data_len = total;
! 4237: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4238: return 0;
! 4239: }
! 4240:
! 4241: int
! 4242: istgt_lu_tape_reset(ISTGT_LU_Ptr lu, int lun)
! 4243: {
! 4244: ISTGT_LU_TAPE *spec;
! 4245: int flags;
! 4246: int rc;
! 4247:
! 4248: if (lu == NULL) {
! 4249: return -1;
! 4250: }
! 4251: if (lun >= lu->maxlun) {
! 4252: return -1;
! 4253: }
! 4254: if (lu->lun[lun].type == ISTGT_LU_LUN_TYPE_NONE) {
! 4255: return -1;
! 4256: }
! 4257: if (lu->lun[lun].type != ISTGT_LU_LUN_TYPE_REMOVABLE) {
! 4258: return -1;
! 4259: }
! 4260: spec = (ISTGT_LU_TAPE *) lu->lun[lun].spec;
! 4261:
! 4262: if (spec->lock) {
! 4263: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "unlock by reset\n");
! 4264: spec->lock = 0;
! 4265: }
! 4266:
! 4267: /* re-open file */
! 4268: if (!spec->lu->readonly
! 4269: && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
! 4270: rc = istgt_lu_tape_sync(spec, 0, spec->size);
! 4271: if (rc < 0) {
! 4272: ISTGT_ERRLOG("LU%d: LUN%d: lu_tape_sync() failed\n",
! 4273: lu->num, lun);
! 4274: /* ignore error */
! 4275: }
! 4276: }
! 4277: rc = istgt_lu_tape_close(spec);
! 4278: if (rc < 0) {
! 4279: ISTGT_ERRLOG("LU%d: LUN%d: lu_tape_close() failed\n",
! 4280: lu->num, lun);
! 4281: /* ignore error */
! 4282: }
! 4283: flags = (lu->readonly || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY))
! 4284: ? O_RDONLY : O_RDWR;
! 4285: rc = istgt_lu_tape_open(spec, flags, 0666);
! 4286: if (rc < 0) {
! 4287: ISTGT_ERRLOG("LU%d: LUN%d: lu_tape_open() failed\n",
! 4288: lu->num, lun);
! 4289: return -1;
! 4290: }
! 4291:
! 4292: return 0;
! 4293: }
! 4294:
! 4295: int
! 4296: istgt_lu_tape_execute(CONN_Ptr conn, ISTGT_LU_CMD_Ptr lu_cmd)
! 4297: {
! 4298: ISTGT_LU_Ptr lu;
! 4299: ISTGT_LU_TAPE *spec;
! 4300: uint8_t *data;
! 4301: uint8_t *cdb;
! 4302: uint64_t fmt_lun;
! 4303: uint64_t lun;
! 4304: uint64_t method;
! 4305: uint32_t allocation_len;
! 4306: int data_len;
! 4307: int data_alloc_len;
! 4308: uint32_t transfer_len;
! 4309: uint8_t *sense_data;
! 4310: int *sense_len;
! 4311: int rc;
! 4312:
! 4313: if (lu_cmd == NULL)
! 4314: return -1;
! 4315: lu = lu_cmd->lu;
! 4316: if (lu == NULL) {
! 4317: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4318: return -1;
! 4319: }
! 4320: spec = NULL;
! 4321: cdb = lu_cmd->cdb;
! 4322: data = lu_cmd->data;
! 4323: data_alloc_len = lu_cmd->alloc_len;
! 4324: sense_data = lu_cmd->sense_data;
! 4325: sense_len = &lu_cmd->sense_data_len;
! 4326: *sense_len = 0;
! 4327:
! 4328: fmt_lun = lu_cmd->lun;
! 4329: method = (fmt_lun >> 62) & 0x03U;
! 4330: fmt_lun = fmt_lun >> 48;
! 4331: if (method == 0x00U) {
! 4332: lun = fmt_lun & 0x00ffU;
! 4333: } else if (method == 0x01U) {
! 4334: lun = fmt_lun & 0x3fffU;
! 4335: } else {
! 4336: lun = 0xffffU;
! 4337: }
! 4338: if (lun >= lu->maxlun) {
! 4339: #ifdef ISTGT_TRACE_TAPE
! 4340: ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
! 4341: lu->num, lun);
! 4342: #endif /* ISTGT_TRACE_TAPE */
! 4343: if (cdb[0] == SPC_INQUIRY) {
! 4344: allocation_len = DGET16(&cdb[3]);
! 4345: if (allocation_len > data_alloc_len) {
! 4346: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
! 4347: data_alloc_len);
! 4348: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4349: return -1;
! 4350: }
! 4351: memset(data, 0, allocation_len);
! 4352: /* PERIPHERAL QUALIFIER(7-5) PERIPHERAL DEVICE TYPE(4-0) */
! 4353: BDSET8W(&data[0], 0x03, 7, 3);
! 4354: BDADD8W(&data[0], 0x1f, 4, 5);
! 4355: data_len = 96;
! 4356: memset(&data[1], 0, data_len - 1);
! 4357: /* ADDITIONAL LENGTH */
! 4358: data[4] = data_len - 5;
! 4359: lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
! 4360: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4361: return 0;
! 4362: } else {
! 4363: /* LOGICAL UNIT NOT SUPPORTED */
! 4364: BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
! 4365: lu_cmd->data_len = 0;
! 4366: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4367: return 0;
! 4368: }
! 4369: }
! 4370: spec = (ISTGT_LU_TAPE *) lu->lun[lun].spec;
! 4371: if (spec == NULL) {
! 4372: /* LOGICAL UNIT NOT SUPPORTED */
! 4373: BUILD_SENSE(ILLEGAL_REQUEST, 0x25, 0x00);
! 4374: lu_cmd->data_len = 0;
! 4375: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4376: return 0;
! 4377: }
! 4378:
! 4379: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SCSI OP=0x%x, LUN=0x%16.16"PRIx64"\n",
! 4380: cdb[0], lu_cmd->lun);
! 4381: #ifdef ISTGT_TRACE_TAPE
! 4382: if (cdb[0] != SPC_TEST_UNIT_READY) {
! 4383: istgt_scsi_dump_cdb(cdb);
! 4384: }
! 4385: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "mload=%d, mchanged=%d, mwait=%d\n", spec->mload, spec->mchanged, spec->mwait);
! 4386: #endif /* ISTGT_TRACE_TAPE */
! 4387:
! 4388: if (cdb[0] == SSC_WRITE_6 || cdb[0] == SSC_WRITE_FILEMARKS_6) {
! 4389: /* write operation (no sync) */
! 4390: } else {
! 4391: /* non write operation */
! 4392: if (spec->need_savectl || spec->need_writeeod) {
! 4393: /* flush pending data */
! 4394: if (istgt_lu_tape_write_pending_data(spec, conn, lu_cmd) < 0) {
! 4395: ISTGT_ERRLOG("lu_tape_write_pending_data() failed\n");
! 4396: lu_cmd->data_len = 0;
! 4397: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4398: return 0;
! 4399: }
! 4400: }
! 4401: }
! 4402:
! 4403: switch (cdb[0]) {
! 4404: case SPC_INQUIRY:
! 4405: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "INQUIRY\n");
! 4406: if (lu_cmd->R_bit == 0) {
! 4407: ISTGT_ERRLOG("R_bit == 0\n");
! 4408: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4409: return -1;
! 4410: }
! 4411: allocation_len = DGET16(&cdb[3]);
! 4412: if (allocation_len > data_alloc_len) {
! 4413: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
! 4414: data_alloc_len);
! 4415: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4416: return -1;
! 4417: }
! 4418: memset(data, 0, allocation_len);
! 4419: data_len = istgt_lu_tape_scsi_inquiry(spec, conn, cdb,
! 4420: data, data_alloc_len);
! 4421: if (data_len < 0) {
! 4422: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4423: break;
! 4424: }
! 4425: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "INQUIRY", data, data_len);
! 4426: lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
! 4427: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4428: break;
! 4429:
! 4430: case SPC_REPORT_LUNS:
! 4431: {
! 4432: int sel;
! 4433:
! 4434: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REPORT LUNS\n");
! 4435: if (lu_cmd->R_bit == 0) {
! 4436: ISTGT_ERRLOG("R_bit == 0\n");
! 4437: return -1;
! 4438: }
! 4439:
! 4440: sel = cdb[2];
! 4441: ISTGT_TRACELOG(ISTGT_TRACE_DEBUG, "sel=%x\n", sel);
! 4442:
! 4443: allocation_len = DGET32(&cdb[6]);
! 4444: if (allocation_len > data_alloc_len) {
! 4445: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
! 4446: data_alloc_len);
! 4447: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4448: return -1;
! 4449: }
! 4450: if (allocation_len < 16) {
! 4451: /* INVALID FIELD IN CDB */
! 4452: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
! 4453: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4454: break;
! 4455: }
! 4456: memset(data, 0, allocation_len);
! 4457: data_len = istgt_lu_tape_scsi_report_luns(lu, conn, cdb, sel,
! 4458: data, data_alloc_len);
! 4459: if (data_len < 0) {
! 4460: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4461: break;
! 4462: }
! 4463: ISTGT_TRACEDUMP(ISTGT_TRACE_DEBUG, "REPORT LUNS", data, data_len);
! 4464: lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
! 4465: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4466: }
! 4467: break;
! 4468:
! 4469: case SPC_TEST_UNIT_READY:
! 4470: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "TEST_UNIT_READY\n");
! 4471: {
! 4472: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4473:
! 4474: /* media state change? */
! 4475: if (spec->mchanged) {
! 4476: /* wait OS polling */
! 4477: if (spec->mwait > 0) {
! 4478: spec->mwait--;
! 4479: } else {
! 4480: /* load new media */
! 4481: spec->mchanged = 0;
! 4482: spec->mload = 1;
! 4483: }
! 4484: }
! 4485:
! 4486: if (data_len != 0) {
! 4487: *sense_len = data_len;
! 4488: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4489: break;
! 4490: }
! 4491:
! 4492: /* OK media present */
! 4493: lu_cmd->data_len = 0;
! 4494: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4495: break;
! 4496: }
! 4497:
! 4498: case SSC_LOAD_UNLOAD:
! 4499: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LOAD_UNLOAD\n");
! 4500: {
! 4501: int hold, eot, reten, load;
! 4502:
! 4503: hold = BGET8(&cdb[4], 3);
! 4504: eot = BGET8(&cdb[4], 2);
! 4505: reten = BGET8(&cdb[4], 1);
! 4506: load = BGET8(&cdb[4], 0);
! 4507:
! 4508: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4509: if (data_len != 0) {
! 4510: *sense_len = data_len;
! 4511: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4512: break;
! 4513: }
! 4514:
! 4515: if (load) {
! 4516: if (!spec->mload) {
! 4517: if (istgt_lu_tape_load_media(spec) < 0) {
! 4518: ISTGT_ERRLOG("lu_tape_load_media() failed\n");
! 4519: /* INTERNAL TARGET FAILURE */
! 4520: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
! 4521: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4522: break;
! 4523: }
! 4524: /* OK load */
! 4525: }
! 4526: if (hold) {
! 4527: /* loding tape to unit */
! 4528: } else {
! 4529: /* loding tape to unit and potision to zero */
! 4530: istgt_lu_tape_rewind(spec);
! 4531: }
! 4532: } else {
! 4533: if (hold) {
! 4534: /* if media in unit, position by eot,reten */
! 4535: } else {
! 4536: /* unload tape from unit */
! 4537: if (!spec->lock) {
! 4538: if (!spec->mload) {
! 4539: lu_cmd->data_len = 0;
! 4540: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4541: break;
! 4542: }
! 4543: if (istgt_lu_tape_unload_media(spec) < 0) {
! 4544: ISTGT_ERRLOG("lu_tape_unload_media() failed\n");
! 4545: /* INTERNAL TARGET FAILURE */
! 4546: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
! 4547: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4548: break;
! 4549: }
! 4550: /* OK unload */
! 4551: } else {
! 4552: /* MEDIUM REMOVAL PREVENTED */
! 4553: BUILD_SENSE(ILLEGAL_REQUEST, 0x53, 0x02);
! 4554: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4555: break;
! 4556: }
! 4557: }
! 4558: }
! 4559:
! 4560: lu_cmd->data_len = 0;
! 4561: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4562: break;
! 4563: }
! 4564:
! 4565: case SPC_PREVENT_ALLOW_MEDIUM_REMOVAL:
! 4566: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "PREVENT_ALLOW_MEDIUM_REMOVAL\n");
! 4567: {
! 4568: int persistent, prevent;
! 4569:
! 4570: persistent = BGET8(&cdb[4], 1);
! 4571: prevent = BGET8(&cdb[4], 0);
! 4572:
! 4573: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4574: if (data_len != 0) {
! 4575: *sense_len = data_len;
! 4576: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4577: break;
! 4578: }
! 4579:
! 4580: if (persistent) {
! 4581: if (prevent) {
! 4582: /* Persistent Prevent */
! 4583: } else {
! 4584: /* Persistent Allow */
! 4585: }
! 4586: } else {
! 4587: if (prevent) {
! 4588: /* Locked */
! 4589: spec->lock = 1;
! 4590: } else {
! 4591: /* Unlocked */
! 4592: spec->lock = 0;
! 4593: }
! 4594: }
! 4595:
! 4596: lu_cmd->data_len = 0;
! 4597: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4598: break;
! 4599: }
! 4600:
! 4601: case SSC_READ_BLOCK_LIMITS:
! 4602: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_BLOCK_LIMITS\n");
! 4603: {
! 4604: if (lu_cmd->R_bit == 0) {
! 4605: ISTGT_ERRLOG("R_bit == 0\n");
! 4606: return -1;
! 4607: }
! 4608:
! 4609: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4610: if (data_len != 0) {
! 4611: *sense_len = data_len;
! 4612: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4613: break;
! 4614: }
! 4615:
! 4616: data_len = 6;
! 4617: /* GRANULARITY */
! 4618: data[0] = 0;
! 4619: /* MAXIMUM BLOCK LENGTH LIMIT */
! 4620: DSET24(&data[1], TAPE_MAXIMUM_BLOCK_LENGTH);
! 4621: /* MINIMUM BLOCK LENGTH LIMIT */
! 4622: DSET16(&data[4], TAPE_MINIMUM_BLOCK_LENGTH);
! 4623:
! 4624: lu_cmd->data_len = data_len;
! 4625: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4626: break;
! 4627: }
! 4628:
! 4629: case SPC_MODE_SELECT_6:
! 4630: {
! 4631: int pf, sp, pllen;
! 4632: int mdlen, mt, dsp, bdlen;
! 4633:
! 4634: pf = BGET8(&cdb[1], 4);
! 4635: sp = BGET8(&cdb[1], 0);
! 4636: pllen = cdb[4]; /* Parameter List Length */
! 4637:
! 4638: /* Data-Out */
! 4639: rc = istgt_lu_tape_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
! 4640: lu_cmd->iobufsize, pllen);
! 4641: if (rc < 0) {
! 4642: ISTGT_ERRLOG("lu_tape_transfer_data() failed\n");
! 4643: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4644: break;
! 4645: }
! 4646: #if 0
! 4647: istgt_dump("MODE SELECT(6)", lu_cmd->iobuf, pllen);
! 4648: #endif
! 4649: data = lu_cmd->iobuf;
! 4650: mdlen = data[0]; /* Mode Data Length */
! 4651: mt = data[1]; /* Medium Type */
! 4652: dsp = data[2]; /* Device-Specific Parameter */
! 4653: bdlen = data[3]; /* Block Descriptor Length */
! 4654:
! 4655: if (bdlen > 0) {
! 4656: /* Short LBA mode parameter block descriptor */
! 4657: /* data[4]-data[7] Number of Blocks */
! 4658: /* data[8]-data[11] Block Length */
! 4659: spec->lblen = (uint64_t) (DGET32(&data[8]) & 0x00ffffffU);
! 4660: #ifdef TAPE_DEBUG
! 4661: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "set to lblen=%"PRIu64"\n", spec->lblen);
! 4662: #endif /* TAPE_DEBUG */
! 4663: }
! 4664:
! 4665: /* page data */
! 4666: data_len = istgt_lu_tape_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[4 + bdlen], pllen - (4 + bdlen));
! 4667: if (data_len != 0) {
! 4668: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4669: break;
! 4670: }
! 4671: lu_cmd->data_len = pllen;
! 4672: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4673: break;
! 4674: }
! 4675:
! 4676: case SPC_MODE_SELECT_10:
! 4677: {
! 4678: int pf, sp, pllen;
! 4679: int mdlen, mt, dsp, bdlen;
! 4680: int llba;
! 4681:
! 4682: pf = BGET8(&cdb[1], 4);
! 4683: sp = BGET8(&cdb[1], 0);
! 4684: pllen = DGET16(&cdb[7]); /* Parameter List Length */
! 4685:
! 4686: /* Data-Out */
! 4687: rc = istgt_lu_tape_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
! 4688: lu_cmd->iobufsize, pllen);
! 4689: if (rc < 0) {
! 4690: ISTGT_ERRLOG("lu_tape_transfer_data() failed\n");
! 4691: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4692: break;
! 4693: }
! 4694: #if 0
! 4695: istgt_dump("MODE SELECT(10)", lu_cmd->iobuf, pllen);
! 4696: #endif
! 4697: data = lu_cmd->iobuf;
! 4698: mdlen = DGET16(&data[0]); /* Mode Data Length */
! 4699: mt = data[2]; /* Medium Type */
! 4700: dsp = data[3]; /* Device-Specific Parameter */
! 4701: llba = BGET8(&data[4], 0); /* Long LBA */
! 4702: bdlen = DGET16(&data[6]); /* Block Descriptor Length */
! 4703:
! 4704: if (llba) {
! 4705: if (bdlen > 0) {
! 4706: /* Long LBA mode parameter block descriptor */
! 4707: /* data[8]-data[15] Number of Blocks */
! 4708: /* data[16]-data[19] Reserved */
! 4709: /* data[20]-data[23] Block Length */
! 4710: spec->lblen = (uint64_t) DGET32(&data[20]);
! 4711: #ifdef TAPE_DEBUG
! 4712: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "set to lblen=%"PRIu64"\n", spec->lblen);
! 4713: #endif /* TAPE_DEBUG */
! 4714: }
! 4715: } else {
! 4716: if (bdlen > 0) {
! 4717: /* Short LBA mode parameter block descriptor */
! 4718: /* data[8]-data[11] Number of Blocks */
! 4719: /* data[12]-data[15] Block Length */
! 4720: spec->lblen = (uint64_t) (DGET32(&data[12]) & 0x00ffffffU);
! 4721: #ifdef TAPE_DEBUG
! 4722: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "set to lblen=%"PRIu64"\n", spec->lblen);
! 4723: #endif /* TAPE_DEBUG */
! 4724: }
! 4725: }
! 4726:
! 4727: /* page data */
! 4728: data_len = istgt_lu_tape_scsi_mode_select_page(spec, conn, cdb, pf, sp, &data[8 + bdlen], pllen - (8 + bdlen));
! 4729: if (data_len != 0) {
! 4730: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4731: break;
! 4732: }
! 4733: lu_cmd->data_len = pllen;
! 4734: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4735: break;
! 4736: }
! 4737:
! 4738: case SPC_MODE_SENSE_6:
! 4739: {
! 4740: int dbd, pc, page, subpage;
! 4741:
! 4742: if (lu_cmd->R_bit == 0) {
! 4743: ISTGT_ERRLOG("R_bit == 0\n");
! 4744: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4745: return -1;
! 4746: }
! 4747:
! 4748: dbd = BGET8(&cdb[1], 3);
! 4749: pc = BGET8W(&cdb[2], 7, 2);
! 4750: page = BGET8W(&cdb[2], 5, 6);
! 4751: subpage = cdb[3];
! 4752:
! 4753: allocation_len = cdb[4];
! 4754: if (allocation_len > data_alloc_len) {
! 4755: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
! 4756: data_alloc_len);
! 4757: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4758: return -1;
! 4759: }
! 4760: memset(data, 0, allocation_len);
! 4761:
! 4762: data_len = istgt_lu_tape_scsi_mode_sense6(spec, conn, cdb, dbd, pc, page, subpage, data, data_alloc_len);
! 4763: if (data_len < 0) {
! 4764: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4765: break;
! 4766: }
! 4767: #if 0
! 4768: istgt_dump("MODE SENSE(6)", data, data_len);
! 4769: #endif
! 4770: lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
! 4771: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4772: break;
! 4773: }
! 4774:
! 4775: case SPC_MODE_SENSE_10:
! 4776: {
! 4777: int dbd, pc, page, subpage;
! 4778: int llbaa;
! 4779:
! 4780: if (lu_cmd->R_bit == 0) {
! 4781: ISTGT_ERRLOG("R_bit == 0\n");
! 4782: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4783: return -1;
! 4784: }
! 4785:
! 4786: llbaa = BGET8(&cdb[1], 4);
! 4787: dbd = BGET8(&cdb[1], 3);
! 4788: pc = BGET8W(&cdb[2], 7, 2);
! 4789: page = BGET8W(&cdb[2], 5, 6);
! 4790: subpage = cdb[3];
! 4791:
! 4792: allocation_len = DGET16(&cdb[7]);
! 4793: if (allocation_len > data_alloc_len) {
! 4794: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
! 4795: data_alloc_len);
! 4796: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4797: return -1;
! 4798: }
! 4799: memset(data, 0, allocation_len);
! 4800:
! 4801: data_len = istgt_lu_tape_scsi_mode_sense10(spec, conn, cdb, llbaa, dbd, pc, page, subpage, data, data_alloc_len);
! 4802: if (data_len < 0) {
! 4803: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4804: break;
! 4805: }
! 4806: #if 0
! 4807: istgt_dump("MODE SENSE(10)", data, data_len);
! 4808: #endif
! 4809: lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
! 4810: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4811: break;
! 4812: }
! 4813:
! 4814: case SPC_LOG_SELECT:
! 4815: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LOG_SELECT\n");
! 4816: /* INVALID COMMAND OPERATION CODE */
! 4817: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
! 4818: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4819: break;
! 4820:
! 4821: case SPC_LOG_SENSE:
! 4822: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LOG_SENSE\n");
! 4823: #if 0
! 4824: /* INVALID FIELD IN CDB */
! 4825: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
! 4826: /* INVALID FIELD IN PARAMETER LIST */
! 4827: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x00);
! 4828: /* PARAMETER NOT SUPPORTED */
! 4829: BUILD_SENSE(ILLEGAL_REQUEST, 0x26, 0x01);
! 4830: #endif
! 4831: /* INVALID COMMAND OPERATION CODE */
! 4832: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
! 4833: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4834: break;
! 4835:
! 4836: case SPC_REQUEST_SENSE:
! 4837: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REQUEST_SENSE\n");
! 4838: {
! 4839: int desc;
! 4840: int sk, asc, ascq;
! 4841:
! 4842: if (lu_cmd->R_bit == 0) {
! 4843: ISTGT_ERRLOG("R_bit == 0\n");
! 4844: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4845: return -1;
! 4846: }
! 4847:
! 4848: desc = BGET8(&cdb[1], 0);
! 4849: if (desc != 0) {
! 4850: /* INVALID FIELD IN CDB */
! 4851: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
! 4852: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4853: break;
! 4854: }
! 4855:
! 4856: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4857:
! 4858: /* media state change? */
! 4859: if (spec->mchanged) {
! 4860: /* wait OS polling */
! 4861: if (spec->mwait > 0) {
! 4862: spec->mwait--;
! 4863: } else {
! 4864: /* load new media */
! 4865: spec->mchanged = 0;
! 4866: spec->mload = 1;
! 4867: }
! 4868: }
! 4869:
! 4870: if (data_len != 0) {
! 4871: *sense_len = data_len;
! 4872: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4873: break;
! 4874: }
! 4875:
! 4876: allocation_len = cdb[4];
! 4877: if (allocation_len > data_alloc_len) {
! 4878: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
! 4879: data_alloc_len);
! 4880: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4881: return -1;
! 4882: }
! 4883: memset(data, 0, allocation_len);
! 4884:
! 4885: if (!spec->sense) {
! 4886: /* NO ADDITIONAL SENSE INFORMATION */
! 4887: sk = ISTGT_SCSI_SENSE_NO_SENSE;
! 4888: asc = 0x00;
! 4889: ascq = 0x00;
! 4890: } else {
! 4891: sk = (spec->sense >> 16) & 0xffU;
! 4892: asc = (spec->sense >> 8) & 0xffU;
! 4893: ascq = spec->sense & 0xffU;
! 4894: }
! 4895: data_len = istgt_lu_tape_build_sense_data(spec, sense_data,
! 4896: sk, asc, ascq);
! 4897: if (data_len < 0 || data_len < 2) {
! 4898: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4899: break;
! 4900: }
! 4901: /* omit SenseLength */
! 4902: data_len -= 2;
! 4903: memcpy(data, sense_data + 2, data_len);
! 4904:
! 4905: lu_cmd->data_len = DMIN32(data_len, lu_cmd->transfer_len);
! 4906: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4907: break;
! 4908: }
! 4909:
! 4910: case SSC_ERASE_6:
! 4911: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "ERASE_6\n");
! 4912: {
! 4913: int xlong;
! 4914:
! 4915: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4916: if (data_len != 0) {
! 4917: *sense_len = data_len;
! 4918: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4919: break;
! 4920: }
! 4921:
! 4922: xlong = BGET8(&cdb[1], 0);
! 4923:
! 4924: if (!xlong) {
! 4925: /* short no operation */
! 4926: lu_cmd->data_len = 0;
! 4927: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4928: break;
! 4929: }
! 4930: data_len = istgt_lu_tape_scsi_erase(spec, conn, lu_cmd, data);
! 4931: if (data_len != 0) {
! 4932: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4933: break;
! 4934: }
! 4935: lu_cmd->data_len = 0;
! 4936: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4937: break;
! 4938: }
! 4939:
! 4940: case SSC_REWIND:
! 4941: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "REWIND\n");
! 4942: {
! 4943: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4944: if (data_len != 0) {
! 4945: *sense_len = data_len;
! 4946: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4947: break;
! 4948: }
! 4949:
! 4950: /* position to BOT */
! 4951: istgt_lu_tape_rewind(spec);
! 4952: lu_cmd->data_len = 0;
! 4953: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4954: break;
! 4955: }
! 4956:
! 4957: case SSC_SPACE_6:
! 4958: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SPACE_6\n");
! 4959: {
! 4960: int code;
! 4961: int count;
! 4962:
! 4963: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4964: if (data_len != 0) {
! 4965: *sense_len = data_len;
! 4966: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4967: break;
! 4968: }
! 4969:
! 4970: code = BGET8W(&cdb[1], 3, 4);
! 4971: count = istgt_convert_signed_24bits(DGET24(&cdb[2]));
! 4972:
! 4973: #ifdef TAPE_DEBUG
! 4974: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "SPACE %d (code = %d)\n", count, code);
! 4975: #endif /* TAPE_DEBUG */
! 4976: data_len = istgt_lu_tape_scsi_space(spec, conn, lu_cmd, code,
! 4977: count, data);
! 4978: if (data_len != 0) {
! 4979: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4980: break;
! 4981: }
! 4982: lu_cmd->data_len = 0;
! 4983: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 4984: break;
! 4985: }
! 4986:
! 4987: case SSC_WRITE_FILEMARKS_6:
! 4988: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "WRITE_FILEMARKS_6\n");
! 4989: {
! 4990: uint64_t request_len;
! 4991: uint64_t marklen;
! 4992: int wsmk;
! 4993: int count;
! 4994:
! 4995: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 4996: if (data_len != 0) {
! 4997: *sense_len = data_len;
! 4998: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 4999: break;
! 5000: }
! 5001:
! 5002: wsmk = BGET8(&cdb[1], 1);
! 5003: count = (int) DGET24(&cdb[2]);
! 5004:
! 5005: #ifdef TAPE_DEBUG
! 5006: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "WRITE_FILEMARK %d\n", count);
! 5007: #endif /* TAPE_DEBUG */
! 5008: if (wsmk) {
! 5009: /* INVALID FIELD IN CDB */
! 5010: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
! 5011: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5012: break;
! 5013: }
! 5014: if (count == 0) {
! 5015: /* no mark but flush buffer */
! 5016: if (spec->need_savectl || spec->need_writeeod) {
! 5017: /* flush pending data */
! 5018: rc = istgt_lu_tape_write_pending_data(spec, conn, lu_cmd);
! 5019: if (rc < 0) {
! 5020: ISTGT_ERRLOG("lu_tape_write_pending_data() failed\n");
! 5021: lu_cmd->data_len = 0;
! 5022: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5023: return 0;
! 5024: }
! 5025: }
! 5026: lu_cmd->data_len = 0;
! 5027: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5028: break;
! 5029: }
! 5030: if (spec->index + 1 + count > MAX_FILEMARKS - 1) {
! 5031: /* INVALID FIELD IN CDB */
! 5032: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
! 5033: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5034: break;
! 5035: }
! 5036:
! 5037: istgt_lu_tape_prepare_offset(spec, conn, lu_cmd);
! 5038: if (spec->eom) {
! 5039: /* END-OF-PARTITION/MEDIUM DETECTED */
! 5040: BUILD_SENSE(VOLUME_OVERFLOW, 0x00, 0x02);
! 5041: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5042: break;
! 5043: }
! 5044:
! 5045: /* EOF x N + EOD */
! 5046: marklen = spec->ctlblock->marklen;
! 5047: request_len = marklen * (uint64_t) count;
! 5048: request_len += marklen;
! 5049: /* write media check */
! 5050: if (istgt_lu_tape_write_media_check(spec, conn, lu_cmd,
! 5051: request_len) < 0) {
! 5052: /* sense data build by function */
! 5053: break;
! 5054: }
! 5055: /* actual wirte to media */
! 5056: if (istgt_lu_tape_write_eof(spec, count, data) < 0) {
! 5057: ISTGT_ERRLOG("lu_tape_write_eof() failed\n");
! 5058: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5059: break;
! 5060: }
! 5061: if (istgt_lu_tape_write_eod(spec, data) < 0) {
! 5062: ISTGT_ERRLOG("lu_tape_write_eod() failed\n");
! 5063: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5064: break;
! 5065: }
! 5066: spec->need_writeeod = 0;
! 5067: if (istgt_lu_tape_save_ctlblock(spec) < 0) {
! 5068: ISTGT_ERRLOG("lu_tape_save_ctlblock() failed\n");
! 5069: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5070: break;
! 5071: }
! 5072: spec->need_savectl = 0;
! 5073: /* dynamic/extend media handle here */
! 5074: /* Control + DATA(BOT/File/EOF) + EOD */
! 5075: request_len = spec->ctlblock->ctlblocklen;
! 5076: request_len += spec->offset;
! 5077: request_len += marklen;
! 5078: if (istgt_lu_tape_shrink_media(spec, conn, lu_cmd,
! 5079: request_len, data) < 0) {
! 5080: ISTGT_ERRLOG("lu_tape_shrink_media() failed\n");
! 5081: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5082: break;
! 5083: }
! 5084: /* write done */
! 5085:
! 5086: lu_cmd->data_len = 0;
! 5087: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5088: break;
! 5089: }
! 5090:
! 5091: case SSC_READ_POSITION:
! 5092: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "READ_POSITION\n");
! 5093: {
! 5094: int sa;
! 5095:
! 5096: if (lu_cmd->R_bit == 0) {
! 5097: ISTGT_ERRLOG("R_bit == 0\n");
! 5098: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5099: return -1;
! 5100: }
! 5101:
! 5102: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 5103: if (data_len != 0) {
! 5104: *sense_len = data_len;
! 5105: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5106: break;
! 5107: }
! 5108:
! 5109: sa = BGET8W(&cdb[1], 4, 5);
! 5110:
! 5111: allocation_len = DGET16(&cdb[7]);
! 5112: if (allocation_len > data_alloc_len) {
! 5113: ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
! 5114: data_alloc_len);
! 5115: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5116: return -1;
! 5117: }
! 5118: memset(data, 0, allocation_len);
! 5119:
! 5120: data_len = istgt_lu_tape_scsi_read_position(spec, conn, lu_cmd,
! 5121: sa, data);
! 5122: if (data_len != 0) {
! 5123: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5124: break;
! 5125: }
! 5126: #if 0
! 5127: istgt_dump("READ_POSITION", data, lu_cmd->data_len);
! 5128: #endif
! 5129: lu_cmd->data_len = DMIN32(lu_cmd->data_len, lu_cmd->transfer_len);
! 5130: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5131: break;
! 5132: }
! 5133:
! 5134: case SSC_LOCATE_10:
! 5135: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LOCATE_10\n");
! 5136: {
! 5137: uint32_t loi;
! 5138: int bt, cp, partition;
! 5139:
! 5140: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 5141: if (data_len != 0) {
! 5142: *sense_len = data_len;
! 5143: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5144: break;
! 5145: }
! 5146:
! 5147: bt = BGET8(&cdb[1], 2);
! 5148: cp = BGET8(&cdb[1], 1);
! 5149: loi = DGET32(&cdb[3]);
! 5150: partition = cdb[8];
! 5151:
! 5152: if (cp) {
! 5153: /* INVALID FIELD IN CDB */
! 5154: BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
! 5155: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5156: break;
! 5157: }
! 5158:
! 5159: #ifdef TAPE_DEBUG
! 5160: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "LOCATE %u\n", loi);
! 5161: #endif /* TAPE_DEBUG */
! 5162: data_len = istgt_lu_tape_scsi_locate(spec, conn, lu_cmd,
! 5163: loi, data);
! 5164: if (data_len != 0) {
! 5165: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5166: break;
! 5167: }
! 5168: lu_cmd->data_len = 0;
! 5169: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5170: break;
! 5171: }
! 5172:
! 5173: case SSC_READ_6:
! 5174: {
! 5175: int sili, fixed;
! 5176: uint64_t lblen;
! 5177: uint64_t request_len;
! 5178: uint64_t rest;
! 5179:
! 5180: if (lu_cmd->R_bit == 0) {
! 5181: ISTGT_ERRLOG("R_bit == 0\n");
! 5182: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5183: return -1;
! 5184: }
! 5185:
! 5186: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 5187: if (data_len != 0) {
! 5188: *sense_len = data_len;
! 5189: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5190: break;
! 5191: }
! 5192:
! 5193: sili = BGET8(&cdb[1], 1);
! 5194: fixed = BGET8(&cdb[1], 0);
! 5195: transfer_len = DGET24(&cdb[2]);
! 5196: lblen = spec->lblen;
! 5197:
! 5198: if (fixed) {
! 5199: request_len = (uint64_t) transfer_len * lblen;
! 5200: } else {
! 5201: request_len = (uint64_t) transfer_len;
! 5202: }
! 5203:
! 5204: istgt_lu_tape_prepare_offset(spec, conn, lu_cmd);
! 5205: if (spec->eom) {
! 5206: /* END-OF-PARTITION/MEDIUM DETECTED */
! 5207: BUILD_SENSE(MEDIUM_ERROR, 0x00, 0x02);
! 5208: /* INFORMATION */
! 5209: DSET32(&lu_cmd->sense_data[2+3], (uint32_t) transfer_len);
! 5210: lu_cmd->data_len = 0;
! 5211: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5212: break;
! 5213: }
! 5214:
! 5215: /* clear EOF/EOD before reading */
! 5216: spec->eof = spec->eod = 0;
! 5217:
! 5218: if (fixed) {
! 5219: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
! 5220: "READ_6 transfer %u x blocks %u SILI=%d\n",
! 5221: (uint32_t) lblen, (uint32_t) transfer_len,
! 5222: sili);
! 5223: rc = istgt_lu_tape_fixed_lbread(spec, conn, lu_cmd, lblen,
! 5224: (uint32_t) transfer_len);
! 5225: } else {
! 5226: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
! 5227: "READ_6 transfer %u SILI=%d\n",
! 5228: (uint32_t) transfer_len, sili);
! 5229: rc = istgt_lu_tape_variable_lbread(spec, conn, lu_cmd,
! 5230: transfer_len);
! 5231: }
! 5232: if (rc < 0) {
! 5233: ISTGT_ERRLOG("lu_tape_lbread() failed\n");
! 5234: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5235: break;
! 5236: }
! 5237: if (lu_cmd->status != ISTGT_SCSI_STATUS_GOOD) {
! 5238: /* sense data build by function */
! 5239: break;
! 5240: }
! 5241: rest = request_len - lu_cmd->data_len;
! 5242:
! 5243: #if 0
! 5244: istgt_dump("READ", lu_cmd->iobuf, 256);
! 5245: #endif
! 5246:
! 5247: if (spec->eof) {
! 5248: /* position to EOF */
! 5249: spec->index++;
! 5250: spec->offset = spec->ctlblock->marks[spec->index].offset;
! 5251: spec->lbpos = spec->ctlblock->marks[spec->index].lbpos;
! 5252: spec->prev = spec->ctlblock->marks[spec->index].prev;
! 5253: /* position to next block of EOF */
! 5254: spec->lbpos++;
! 5255: spec->prev = spec->offset;
! 5256: spec->offset += spec->ctlblock->marklen;
! 5257: /* FILEMARK DETECTED */
! 5258: BUILD_SENSE(NO_SENSE, 0x00, 0x01);
! 5259: /* INFORMATION */
! 5260: DSET32(&lu_cmd->sense_data[2+3], spec->info);
! 5261: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5262: break;
! 5263: }
! 5264: if (spec->eod) {
! 5265: /* END-OF-DATA DETECTED */
! 5266: BUILD_SENSE(BLANK_CHECK, 0x00, 0x05);
! 5267: /* INFORMATION */
! 5268: DSET32(&lu_cmd->sense_data[2+3], spec->info);
! 5269: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5270: break;
! 5271: }
! 5272:
! 5273: if (lu_cmd->data_len < request_len) {
! 5274: #ifdef TAPE_DEBUG
! 5275: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
! 5276: "Underflow total=%u, transfer_len=%u, lblen=%u\n",
! 5277: lu_cmd->data_len, (uint32_t) request_len,
! 5278: (uint32_t) lblen);
! 5279: #endif /* TAPE_DEBUG */
! 5280: /* over size? */
! 5281: if (rest > spec->size
! 5282: || spec->offset > spec->size - rest) {
! 5283: spec->eom = 1;
! 5284: /* END-OF-PARTITION/MEDIUM DETECTED */
! 5285: BUILD_SENSE(MEDIUM_ERROR, 0x00, 0x02);
! 5286: /* INFORMATION */
! 5287: DSET32(&lu_cmd->sense_data[2+3], spec->info);
! 5288: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5289: break;
! 5290: }
! 5291: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5292: break;
! 5293: }
! 5294:
! 5295: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5296: break;
! 5297: }
! 5298:
! 5299: case SSC_WRITE_6:
! 5300: {
! 5301: int sili, fixed;
! 5302: uint64_t lblen;
! 5303: uint64_t request_len;
! 5304: uint64_t rest;
! 5305: int index_i;
! 5306:
! 5307: if (lu_cmd->W_bit == 0) {
! 5308: ISTGT_ERRLOG("W_bit == 0\n");
! 5309: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5310: return -1;
! 5311: }
! 5312:
! 5313: sili = BGET8(&cdb[1], 1);
! 5314: fixed = BGET8(&cdb[1], 0);
! 5315: transfer_len = DGET24(&cdb[2]);
! 5316: lblen = spec->lblen;
! 5317:
! 5318: if (fixed) {
! 5319: request_len = (uint64_t) transfer_len * lblen;
! 5320: } else {
! 5321: request_len = (uint64_t) transfer_len;
! 5322: }
! 5323:
! 5324: data_len = istgt_lu_tape_build_sense_media(spec, sense_data);
! 5325: if (data_len != 0) {
! 5326: rc = istgt_lu_tape_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
! 5327: lu_cmd->iobufsize, request_len);
! 5328: if (rc < 0) {
! 5329: ISTGT_ERRLOG("lu_tape_transfer_data() failed\n");
! 5330: lu_cmd->data_len = 0;
! 5331: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5332: break;
! 5333: }
! 5334: *sense_len = data_len;
! 5335: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5336: break;
! 5337: }
! 5338:
! 5339: istgt_lu_tape_prepare_offset(spec, conn, lu_cmd);
! 5340: if (spec->eom) {
! 5341: rc = istgt_lu_tape_transfer_data(conn, lu_cmd, lu_cmd->iobuf,
! 5342: lu_cmd->iobufsize, request_len);
! 5343: if (rc < 0) {
! 5344: ISTGT_ERRLOG("lu_tape_transfer_data() failed\n");
! 5345: lu_cmd->data_len = 0;
! 5346: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5347: break;
! 5348: }
! 5349: /* END-OF-PARTITION/MEDIUM DETECTED */
! 5350: BUILD_SENSE(VOLUME_OVERFLOW, 0x00, 0x02);
! 5351: /* INFORMATION */
! 5352: DSET32(&lu_cmd->sense_data[2+3], (uint32_t) transfer_len);
! 5353: lu_cmd->data_len = 0;
! 5354: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5355: break;
! 5356: }
! 5357:
! 5358: if (fixed) {
! 5359: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
! 5360: "WRITE_6 transfer %u x blocks %u SILI=%d\n",
! 5361: (uint32_t) lblen, (uint32_t) transfer_len,
! 5362: sili);
! 5363: rc = istgt_lu_tape_fixed_lbwrite(spec, conn, lu_cmd, lblen,
! 5364: (uint32_t) transfer_len);
! 5365: } else {
! 5366: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
! 5367: "WRITE_6 transfer %u SILI=%d\n",
! 5368: (uint32_t) transfer_len, sili);
! 5369: rc = istgt_lu_tape_variable_lbwrite(spec, conn, lu_cmd,
! 5370: transfer_len);
! 5371: }
! 5372: if (rc < 0) {
! 5373: ISTGT_ERRLOG("lu_tape_lbwrite() failed\n");
! 5374: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5375: break;
! 5376: }
! 5377: if (lu_cmd->status != ISTGT_SCSI_STATUS_GOOD) {
! 5378: /* sense data build by function */
! 5379: break;
! 5380: }
! 5381: rest = request_len - lu_cmd->data_len;
! 5382:
! 5383: /* clean up marks after this file */
! 5384: index_i = spec->index;
! 5385: if (spec->ctlblock->marks[index_i + 1].offset != MARK_END) {
! 5386: #ifdef TAPE_DEBUG
! 5387: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
! 5388: "save ctlblock and write EOD\n");
! 5389: #endif /* TAPE_DEBUG */
! 5390: spec->ctlblock->marks[index_i + 1].offset = MARK_END;
! 5391: spec->ctlblock->marks[index_i + 1].lbpos = MARK_END;
! 5392: spec->ctlblock->marks[index_i + 1].prev = spec->offset;
! 5393: if (istgt_lu_tape_save_ctlblock(spec) < 0) {
! 5394: ISTGT_ERRLOG("lu_tape_save_ctlblock() failed\n");
! 5395: write_failure:
! 5396: /* INTERNAL TARGET FAILURE */
! 5397: BUILD_SENSE(HARDWARE_ERROR, 0x44, 0x00);
! 5398: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5399: break;
! 5400: }
! 5401: request_len = spec->ctlblock->marklen;
! 5402: if (istgt_lu_tape_write_media_check(spec, conn, lu_cmd,
! 5403: request_len) < 0) {
! 5404: goto write_failure;
! 5405: }
! 5406: if (istgt_lu_tape_write_eod(spec, lu_cmd->data) < 0) {
! 5407: ISTGT_ERRLOG("lu_tape_write_eod() failed\n");
! 5408: goto write_failure;
! 5409: }
! 5410: } else {
! 5411: /* pending some blocks for performance */
! 5412: spec->ctlblock->marks[index_i + 1].prev = spec->offset;
! 5413: spec->need_savectl = 1;
! 5414: spec->need_writeeod = 1;
! 5415: }
! 5416:
! 5417: #if 0
! 5418: if (spec->index == 2) {
! 5419: istgt_dump("WRITE", lu_cmd->iobuf, 256);
! 5420: }
! 5421: #endif
! 5422:
! 5423: if (lu_cmd->data_len < request_len) {
! 5424: #ifdef TAPE_DEBUG
! 5425: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
! 5426: "Underflow total=%u, transfer_len=%u, lblen=%u\n",
! 5427: lu_cmd->data_len, (uint32_t) request_len,
! 5428: (uint32_t) lblen);
! 5429: #endif /* TAPE_DEBUG */
! 5430: spec->eom = 1;
! 5431: /* WRITE ERROR */
! 5432: BUILD_SENSE(MEDIUM_ERROR, 0x0c, 0x00);
! 5433: /* INFORMATION */
! 5434: DSET32(&lu_cmd->sense_data[2+3], spec->info);
! 5435: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5436: break;
! 5437: }
! 5438:
! 5439: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5440: break;
! 5441: }
! 5442:
! 5443: /* XXX TODO: fix */
! 5444: case SPC2_RELEASE_6:
! 5445: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_6\n");
! 5446: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5447: break;
! 5448: case SPC2_RELEASE_10:
! 5449: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RELEASE_10\n");
! 5450: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5451: break;
! 5452: case SPC2_RESERVE_6:
! 5453: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_6\n");
! 5454: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5455: break;
! 5456: case SPC2_RESERVE_10:
! 5457: ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "RESERVE_10\n");
! 5458: lu_cmd->status = ISTGT_SCSI_STATUS_GOOD;
! 5459: break;
! 5460:
! 5461: default:
! 5462: ISTGT_ERRLOG("unsupported SCSI OP=0x%x\n", cdb[0]);
! 5463: /* INVALID COMMAND OPERATION CODE */
! 5464: BUILD_SENSE(ILLEGAL_REQUEST, 0x20, 0x00);
! 5465: lu_cmd->status = ISTGT_SCSI_STATUS_CHECK_CONDITION;
! 5466: break;
! 5467: }
! 5468:
! 5469: ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
! 5470: "SCSI OP=0x%x, LUN=0x%16.16"PRIx64" status=0x%x,"
! 5471: " complete\n",
! 5472: cdb[0], lu_cmd->lun, lu_cmd->status);
! 5473: return 0;
! 5474: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>