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