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