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