1 /*
2  * Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31 
32 #include <inttypes.h>
33 #include <stdint.h>
34 
35 #include <assert.h>
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 
63 #if !defined(__GNUC__)
64 #undef __attribute__
65 #define __attribute__(x)
66 #endif
67 
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 {
152 	uint64_t lbpos;				/* logical position */
153 	uint64_t offset;			/* physical position */
154 	uint64_t prev;				/* previous position if not zero */
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 */
162 	uint8_t magic[8];			/* 'ISVTCTRL' (network order) */
163 	uint64_t endian;			/* endian ID = 0x1122334455667788ULL */
164 	uint64_t version;			/* version = 0 */
165 	uint64_t ctlblocklen;			/* ctlblocklen = 128K */
166 
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 */
175 	uint64_t junk1;
176 
177 	uint64_t reserve0[512-12];		/* room for 4K(8x512) */
178 	tape_markpos_t marks[MAX_FILEMARKS];	/* marks[0] = BOT, ..., EOT 32K */
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 {
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 */
213 
214 	uint64_t compalgo;			/* compression algorithm (0=none) */
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 */
243 	tape_markblock_t *markblock;		/* mark block */
244 
245 	uint64_t lblen;				/* logical block length for fixed */
246 	uint64_t lbpos;				/* logical block position */
247 
248 	uint64_t offset;			/* physical offset in virtual tape */
249 	uint64_t prev;				/* previous offset if not zero */
250 	int index;				/* current maker index */
251 
252 	int compalgo;				/* compression algorithme */
253 	int vtcompalgo;				/* compression algorithme in vtape */
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 
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));				\
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
istgt_lu_tape_open(ISTGT_LU_TAPE * spec,int flags,int mode)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
istgt_lu_tape_close(ISTGT_LU_TAPE * spec)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
istgt_lu_tape_seek(ISTGT_LU_TAPE * spec,uint64_t offset)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
istgt_lu_tape_read(ISTGT_LU_TAPE * spec,void * buf,uint64_t nbytes)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
istgt_lu_tape_write(ISTGT_LU_TAPE * spec,const void * buf,uint64_t nbytes)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
istgt_lu_tape_sync(ISTGT_LU_TAPE * spec,uint64_t offset,uint64_t nbytes)356 istgt_lu_tape_sync(ISTGT_LU_TAPE *spec, uint64_t offset __attribute__((__unused__)), uint64_t nbytes __attribute__((__unused__)))
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 
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)
400 
401 
402 static int
istgt_lu_tape_read_native_mark(ISTGT_LU_TAPE * spec,tape_markblock_t * mbp)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);
413 	if (rc < 0 || (uint64_t) rc != marklen) {
414 		ISTGT_ERRLOG("lu_tape_read() failed: rc %"PRId64"\n", rc);
415 		return -1;
416 	}
417 	if (mbp->endian != MARK_ENDIAN) {
418 		/* convert byte order but except magic */
419 		lp = (uint64_t *) mbp;
420 		for (i = 1; i < (int) (marklen / sizeof(uint64_t)); i++) {
421 			lp[i] = SWAP_UINT64(lp[i]);
422 		}
423 	}
424 	return 0;
425 }
426 
427 static int
istgt_lu_tape_write_native_mark(ISTGT_LU_TAPE * spec,tape_markblock_t * mbp)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);
436 	if ((uint64_t) rc != marklen) {
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
istgt_lu_tape_write_padding(ISTGT_LU_TAPE * spec,uint8_t * data)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);
464 		if (rc < 0 || (uint64_t) rc != padlen) {
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
istgt_lu_tape_write_eof(ISTGT_LU_TAPE * spec,int count,uint8_t * data)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 */
502 	ASSERT_PTR_ALIGN64(data);
503 	mbp = (tape_markblock_t *) ((uintptr_t)data);
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
istgt_lu_tape_write_bot(ISTGT_LU_TAPE * spec,uint8_t * data)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 */
568 	ASSERT_PTR_ALIGN64(data);
569 	mbp = (tape_markblock_t *) ((uintptr_t)data);
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
istgt_lu_tape_write_eod(ISTGT_LU_TAPE * spec,uint8_t * data)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 */
631 	ASSERT_PTR_ALIGN64(data);
632 	mbp = (tape_markblock_t *) ((uintptr_t)data);
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
istgt_lu_tape_write_media_check(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t request_len)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)
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
676 	    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
677 		/* WRITE PROTECTED */
678 		data_len
679 			= istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
680 			    ISTGT_SCSI_SENSE_DATA_PROTECT,
681 			    0x27, 0x00);
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,
692 			    ISTGT_SCSI_SENSE_HARDWARE_ERROR,
693 			    0x44, 0x00);
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,
728 				    ISTGT_SCSI_SENSE_VOLUME_OVERFLOW,
729 				    0x00, 0x02);
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
istgt_lu_tape_read_media_check(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t request_len)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)
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,
760 			    ISTGT_SCSI_SENSE_HARDWARE_ERROR,
761 			    0x44, 0x00);
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,
775 			    ISTGT_SCSI_SENSE_MEDIUM_ERROR,
776 			    0x00, 0x02);
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
istgt_lu_tape_prepare_offset(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)787 istgt_lu_tape_prepare_offset(ISTGT_LU_TAPE *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd __attribute__((__unused__)))
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
istgt_lu_tape_write_pending_data(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)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,
834 				    ISTGT_SCSI_SENSE_HARDWARE_ERROR,
835 				    0x44, 0x00);
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
istgt_lu_tape_rewind(ISTGT_LU_TAPE * spec)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
istgt_lu_tape_load_ctlblock(ISTGT_LU_TAPE * spec)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
istgt_lu_tape_save_ctlblock(ISTGT_LU_TAPE * spec)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,
902 	    spec->ctlblock->ctlblocklen);
903 	if (rc < 0 || (uint64_t) rc != spec->ctlblock->ctlblocklen) {
904 		return -1;
905 	}
906 	return rc;
907 }
908 
909 static int
istgt_lu_tape_init_ctlblock(ISTGT_LU_TAPE * spec,int newfile)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
925 		    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)
926 		    || !newfile) {
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;
968 			for (i = 1; i < (int) (CTLBLOCKLEN / sizeof(uint64_t)); i++) {
969 				lp[i] = SWAP_UINT64(lp[i]);
970 			}
971 		}
972 		if (cbp->ctlblocklen == 0ULL
973 		    || cbp->blocklen == 0ULL
974 		    || cbp->marklen == 0ULL
975 		    || cbp->alignment == 0ULL) {
976 			ISTGT_ERRLOG("bad length\n");
977 			return -1;
978 		}
979 		if (cbp->version > CTLVERSION) {
980 			ISTGT_ERRLOG("unsupported tape version 0x%"PRIx64"\n",
981 			    cbp->version);
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
istgt_lu_tape_media_present(ISTGT_LU_TAPE * spec)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
istgt_lu_tape_media_lock(ISTGT_LU_TAPE * spec)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
istgt_lu_tape_load_media(ISTGT_LU_TAPE * spec)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,
1033 		"/dev/null") == 0) {
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
1094 	    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
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
1105 		    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
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) {
1112 			ISTGT_ERRLOG("LU%d: LUN%d: open error(errno=%d)\n",
1113 			    lu->num, spec->lun, errno);
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
1122 	    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
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
istgt_lu_tape_unload_media(ISTGT_LU_TAPE * spec)1148 istgt_lu_tape_unload_media(ISTGT_LU_TAPE *spec)
1149 {
1150 	int rc;
1151 
1152 	if (!istgt_lu_tape_media_present(spec)
1153 	    && !spec->mchanged) {
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
1177 	    && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
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
istgt_lu_tape_change_media(ISTGT_LU_TAPE * spec,char * type,char * flags,char * file,char * size)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
istgt_lu_tape_allocate(ISTGT_LU_TAPE * spec)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);
1314 	if (rc == -1 || (uint64_t) rc != nbytes) {
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
istgt_lu_tape_init(ISTGT_Ptr istgt,ISTGT_LU_Ptr lu)1325 istgt_lu_tape_init(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu)
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",
1342 		    (uint64_t) sizeof(tape_ctlblock_t));
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",
1348 	    lu->num, lu->name);
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",
1352 			    lu->num, i);
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",
1361 		    lu->num, i);
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
1401 			    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
1402 				ro = 1;
1403 			} else {
1404 				ro = 0;
1405 			}
1406 
1407 			printf("LU%d: LUN%d file=%s, size=%"PRIu64", flag=%s\n",
1408 			    lu->num, i, spec->file, spec->size, ro ? "ro" : "rw");
1409 			printf("LU%d: LUN%d %"PRIu64" blocks, %"PRIu64" bytes/block\n",
1410 			    lu->num, i, spec->blockcnt, spec->blocklen);
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",
1417 				    lu->num, i, gb_size, mb_digit,
1418 				    lu->readonly ? "readonly " : "", lu->name);
1419 			} else {
1420 				printf("LU%d: LUN%d %"PRIu64"MB %sstorage for %s\n",
1421 				    lu->num, i, mb_size,
1422 				    lu->readonly ? "readonly " : "", lu->name);
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",
1431 			    lu->num, i);
1432 		}
1433 
1434 		lu->lun[i].spec = spec;
1435 	}
1436 
1437 	return 0;
1438 }
1439 
1440 int
istgt_lu_tape_shutdown(ISTGT_Ptr istgt,ISTGT_LU_Ptr lu)1441 istgt_lu_tape_shutdown(ISTGT_Ptr istgt __attribute__((__unused__)), ISTGT_LU_Ptr lu)
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",
1464 	    lu->num, lu->name);
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",
1468 			    lu->num, i);
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
1486 		    && !(spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
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
istgt_lu_tape_scsi_report_luns(ISTGT_LU_Ptr lu,CONN_Ptr conn,uint8_t * cdb,int sel,uint8_t * data,int alloc_len)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)
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",
1539 			    lu->num, i);
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;
1552 		} else if (lu->maxlun <= 0x4000) {
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
istgt_lu_tape_scsi_inquiry(ISTGT_LU_TAPE * spec,CONN_Ptr conn,uint8_t * cdb,uint8_t * data,int alloc_len)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,
1839 			    spec->lu->inq_serial, ' ');
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,
1863 			    "%s", spec->lu->name);
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,
1885 			    "%s"",t,0x""%4.4x", spec->lu->name, conn->portal.tag);
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,
1900 			    3, 4);
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,
1929 			    3, 4);
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,
1956 			    3, 4);
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,
2132 				    "%s"",t,0x""%4.4x", spec->lu->name, pg_tag);
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 
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 		}							\
2352 	} while (0)
2353 
2354 static int
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)2355 istgt_lu_tape_scsi_mode_sense_page(ISTGT_LU_TAPE *spec, CONN_Ptr conn, uint8_t *cdb, int pc, int page, int subpage, uint8_t *data, int alloc_len)
2356 {
2357 	uint8_t *cp;
2358 	int len = 0;
2359 	int plen;
2360 	int i;
2361 
2362 #if 0
2363 	printf("SENSE pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
2364 #endif
2365 	ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE: pc=%d, page=%2.2x, subpage=%2.2x\n", pc, page, subpage);
2366 
2367 	if (pc == 0x00) {
2368 		/* Current values */
2369 	} else if (pc == 0x01) {
2370 		/* Changeable values */
2371 		if (page != 0x0f) {
2372 			/* not supported */
2373 			return -1;
2374 		}
2375 	} else if (pc == 0x02) {
2376 		/* Default values */
2377 	} else {
2378 		/* Saved values */
2379 	}
2380 
2381 	cp = &data[len];
2382 	switch (page) {
2383 	case 0x00:
2384 		/* Vendor specific */
2385 		break;
2386 	case 0x01:
2387 		/* Read-Write Error Recovery */
2388 		break;
2389 	case 0x02:
2390 		/* Disconnect-Reconnect mode page */
2391 		break;
2392 	case 0x03:
2393 	case 0x04:
2394 	case 0x05:
2395 	case 0x06:
2396 	case 0x07:
2397 	case 0x08:
2398 		/* Reserved */
2399 		break;
2400 	case 0x09:
2401 		/* Obsolete */
2402 		break;
2403 	case 0x0a:
2404 		/* Control mode page */
2405 		break;
2406 	case 0x0b:
2407 	case 0x0c:
2408 	case 0x0d:
2409 	case 0x0e:
2410 		/* Reserved */
2411 		break;
2412 	case 0x0f:
2413 		/* Data Compression */
2414 		ISTGT_TRACELOG(ISTGT_TRACE_SCSI, "MODE_SENSE Data Compression\n");
2415 		if (subpage != 0x00)
2416 			break;
2417 
2418 		plen = 0x0e + 2;
2419 		MODE_SENSE_PAGE_INIT(cp, plen, page, subpage);
2420 		if (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 		}
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
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)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
2600 		    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
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);
2655 	if (plen < 0) {
2656 		return -1;
2657 	}
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
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)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
2680 		    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
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);
2741 	if (plen < 0) {
2742 		return -1;
2743 	}
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
istgt_lu_tape_transfer_data(CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint8_t * buf,size_t bufsize,size_t len)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) {
2758 		ISTGT_ERRLOG("bufsize(%zd) too small\n", bufsize);
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
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)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 {
2772 	size_t hlen, plen;
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
istgt_convert_signed_24bits(uint32_t usval)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
istgt_lu_tape_shrink_media(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t request_len,uint8_t * data)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__)))
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
istgt_lu_tape_scsi_erase(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint8_t * data)2952 istgt_lu_tape_scsi_erase(ISTGT_LU_TAPE *spec, CONN_Ptr conn __attribute__((__unused__)), ISTGT_LU_CMD_Ptr lu_cmd, uint8_t *data)
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
2978 	    || (spec->mflags & ISTGT_LU_FLAG_MEDIA_READONLY)) {
2979 		/* WRITE PROTECTED */
2980 		data_len
2981 			= istgt_lu_tape_build_sense_data(spec, lu_cmd->sense_data,
2982 			    ISTGT_SCSI_SENSE_DATA_PROTECT,
2983 			    0x27, 0x00);
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,
2992 			    ISTGT_SCSI_SENSE_ILLEGAL_REQUEST,
2993 			    0x26, 0x02);
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,
3002 			    ISTGT_SCSI_SENSE_HARDWARE_ERROR,
3003 			    0x44, 0x00);
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,
3016 			    ISTGT_SCSI_SENSE_HARDWARE_ERROR,
3017 			    0x3e, 0x01);
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 	}
3033 	if ((uint64_t) istgt_lu_tape_write(spec, data, request_len) != request_len) {
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 		}
3065 		if ((uint64_t) istgt_lu_tape_write(spec, data, marklen) != marklen) {
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;
3080 			if ((uint64_t) istgt_lu_tape_write(spec, data, wlen) != wlen) {
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;
3089 			if ((uint64_t) istgt_lu_tape_write(spec, data, rest) != rest) {
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
istgt_lu_tape_valid_mark_magic(tape_markblock_t * mbp)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
istgt_lu_tape_search_lbpos(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lbpos,uint8_t * data)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)
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,
3171 			    ISTGT_SCSI_SENSE_MEDIUM_ERROR,
3172 			    0x00, 0x02);
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 */
3179 	ASSERT_PTR_ALIGN64(data);
3180 	mbp = (tape_markblock_t *) ((uintptr_t)data);
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",
3200 		    mbp->lbpos, mbp->lblen, mbp->offset, offset, index_i);
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,
3222 			    ISTGT_SCSI_SENSE_HARDWARE_ERROR,
3223 			    0x44, 0x00);
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
istgt_lu_tape_search_lbpos_fast_reverse(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lbpos,int count,uint8_t * data)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__)))
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
3272 	    || spec->ctlblock->marks[index_i].offset == MARK_END
3273 	    || spec->ctlblock->marks[index_i + 1].offset == MARK_END)
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
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)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,
3345 				    lbpos, count, data);
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,
3394 					    ISTGT_SCSI_SENSE_HARDWARE_ERROR,
3395 					    0x44, 0x00);
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,
3418 					    ISTGT_SCSI_SENSE_BLANK_CHECK,
3419 					    0x00, 0x05);
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,
3464 				    ISTGT_SCSI_SENSE_HARDWARE_ERROR,
3465 				    0x44, 0x00);
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,
3503 			    ISTGT_SCSI_SENSE_ILLEGAL_REQUEST,
3504 			    0x24, 0x00);
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
istgt_lu_tape_scsi_locate(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint32_t loi,uint8_t * data)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
istgt_lu_tape_scsi_read_position(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,int sa,uint8_t * data)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)
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,
3625 			    ISTGT_SCSI_SENSE_ILLEGAL_REQUEST,
3626 			    0x24, 0x00);
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
istgt_lu_tape_build_sense_data(ISTGT_LU_TAPE * spec,uint8_t * data,int sk,int asc,int ascq)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
istgt_lu_tape_build_sense_media(ISTGT_LU_TAPE * spec,uint8_t * data)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
istgt_lu_tape_variable_lbread(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lblen)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;
3743 	ASSERT_PTR_ALIGN64(lu_cmd->iobuf);
3744 	mbp = (tape_markblock_t *) ((uintptr_t)lu_cmd->iobuf);
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",
3754 	    lblen, offset);
3755 #endif /* TAPE_DEBUG */
3756 
3757 	if (request_len > lu_cmd->iobufsize) {
3758 		ISTGT_ERRLOG("request_len(%"PRIu64") > iobufsize(%zu)\n",
3759 		    request_len, lu_cmd->iobufsize);
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
3788 		    " mlbpos %"PRIu64"\n", offset, lbpos, mbp->lbpos);
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);
3809 	if (rc < 0 || (uint64_t) rc != mbp->lblen) {
3810 		ISTGT_ERRLOG("lu_tape_read() failed: rc %"PRId64"\n", rc);
3811 		return -1;
3812 	}
3813 #ifdef TAPE_DEBUG
3814 	ISTGT_TRACELOG(ISTGT_TRACE_LU, "read mlbpos=%"PRIu64", lblen=%"PRIu64
3815 	    ", offset=%"PRIu64"\n", mbp->lbpos, mbp->lblen, offset);
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
istgt_lu_tape_fixed_lbread(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lblen,uint32_t count)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;
3877 	ASSERT_PTR_ALIGN64(lu_cmd->iobuf);
3878 	mbp = (tape_markblock_t *) ((uintptr_t)lu_cmd->iobuf);
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",
3887 	    lblen, count, offset);
3888 #endif /* TAPE_DEBUG */
3889 
3890 	if (request_len > lu_cmd->iobufsize) {
3891 		ISTGT_ERRLOG("request_len(%"PRIu64") > iobufsize(%zu)\n",
3892 		    request_len, lu_cmd->iobufsize);
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
3926 				    " mlbpos %"PRIu64"\n", offset, lbpos, mbp->lbpos);
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);
3947 			if (rc < 0 || (uint64_t) rc != mbp->lblen) {
3948 				ISTGT_ERRLOG("lu_tape_read() failed: rc %"PRId64"\n", rc);
3949 				return -1;
3950 			}
3951 #ifdef TAPE_DEBUG
3952 			ISTGT_TRACELOG(ISTGT_TRACE_LU, "read mlbpos=%"PRIu64", lblen=%"
3953 			    PRIu64", offset=%"PRIu64"\n",
3954 			    mbp->lbpos, mbp->lblen, offset);
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,
3964 				    ISTGT_SCSI_SENSE_NO_SENSE,
3965 				    0x00, 0x00);
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
istgt_lu_tape_variable_lbwrite(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lblen)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;
4035 	ASSERT_PTR_ALIGN64(lu_cmd->iobuf);
4036 	mbp = (tape_markblock_t *) ((uintptr_t)lu_cmd->iobuf);
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",
4045 	    lblen, offset);
4046 #endif /* TAPE_DEBUG */
4047 
4048 	if (request_len > lu_cmd->iobufsize) {
4049 		ISTGT_ERRLOG("request_len(%"PRIu64") > iobufsize(%zu)\n",
4050 		    request_len, lu_cmd->iobufsize);
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,
4078 	    lu_cmd->iobufsize - marklen, lblen);
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
4099 	    ", offset=%"PRIu64"\n", mbp->lbpos, mbp->lblen, offset);
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);
4109 	if ((uint64_t) rc != lblen) {
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
istgt_lu_tape_fixed_lbwrite(ISTGT_LU_TAPE * spec,CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd,uint64_t lblen,uint32_t count)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;
4164 	ASSERT_PTR_ALIGN64(lu_cmd->iobuf);
4165 	mbp = (tape_markblock_t *) ((uintptr_t)lu_cmd->iobuf);
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",
4174 	    lblen, offset);
4175 #endif /* TAPE_DEBUG */
4176 
4177 	if (request_len > lu_cmd->iobufsize) {
4178 		ISTGT_ERRLOG("request_len(%"PRIu64") > iobufsize(%zu)\n",
4179 		    request_len, lu_cmd->iobufsize);
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,
4207 	    lu_cmd->iobufsize - marklen, lblen * count);
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
4230 		    ", offset=%"PRIu64"\n", mbp->lbpos, mbp->lblen, offset);
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);
4240 		if ((uint64_t) rc != lblen) {
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
istgt_lu_tape_reset(ISTGT_LU_Ptr lu,int lun)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
istgt_lu_tape_execute(CONN_Ptr conn,ISTGT_LU_CMD_Ptr lu_cmd)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;
4344 	size_t *sense_len;
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 	}
4372 	if (lun >= (uint64_t) lu->maxlun) {
4373 #ifdef ISTGT_TRACE_TAPE
4374 		ISTGT_ERRLOG("LU%d: LUN%4.4"PRIx64" invalid\n",
4375 		    lu->num, lun);
4376 #endif /* ISTGT_TRACE_TAPE */
4377 		if (cdb[0] == SPC_INQUIRY) {
4378 			allocation_len = DGET16(&cdb[3]);
4379 			if (allocation_len > (size_t) data_alloc_len) {
4380 				ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
4381 				    data_alloc_len);
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;
4393 			lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
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",
4414 	    cdb[0], lu_cmd->lun);
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]);
4446 		if (allocation_len > (size_t) data_alloc_len) {
4447 			ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
4448 			    data_alloc_len);
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,
4454 		    data, data_alloc_len);
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);
4460 		lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
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]);
4478 			if (allocation_len > (size_t) data_alloc_len) {
4479 				ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
4480 				    data_alloc_len);
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,
4492 			    data, data_alloc_len);
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);
4498 			lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
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,
4674 			    lu_cmd->iobufsize, pllen);
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,
4722 			    lu_cmd->iobufsize, pllen);
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];
4788 			if (allocation_len > (size_t) data_alloc_len) {
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) {
4798 				/* INVALID FIELD IN CDB */
4799 				BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
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
4806 			lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
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]);
4829 			if (allocation_len > (size_t) data_alloc_len) {
4830 				ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
4831 				    data_alloc_len);
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) {
4839 				/* INVALID FIELD IN CDB */
4840 				BUILD_SENSE(ILLEGAL_REQUEST, 0x24, 0x00);
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
4847 			lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
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];
4915 			if (allocation_len > (size_t) data_alloc_len) {
4916 				ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
4917 				    data_alloc_len);
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,
4934 			    sk, asc, ascq);
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 
4943 			lu_cmd->data_len = DMIN32((size_t)data_len, lu_cmd->transfer_len);
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,
5089 				request_len) < 0) {
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,
5117 				request_len, data) < 0) {
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]);
5150 			if (allocation_len > (size_t) data_alloc_len) {
5151 				ISTGT_ERRLOG("data_alloc_len(%d) too small\n",
5152 				    data_alloc_len);
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,
5159 			    sa, data);
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,
5201 			    loi, data);
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,
5258 				    "READ_6 transfer %u x blocks %u SILI=%d\n",
5259 				    (uint32_t) lblen, (uint32_t) transfer_len,
5260 				    sili);
5261 				rc = istgt_lu_tape_fixed_lbread(spec, conn, lu_cmd, lblen,
5262 				    (uint32_t) transfer_len);
5263 			} else {
5264 				ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
5265 				    "READ_6 transfer %u SILI=%d\n",
5266 				    (uint32_t) transfer_len, sili);
5267 				rc = istgt_lu_tape_variable_lbread(spec, conn, lu_cmd,
5268 				    transfer_len);
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,
5314 				    "Underflow total=%zu, transfer_len=%u, lblen=%u\n",
5315 				    lu_cmd->data_len, (uint32_t) request_len,
5316 				    (uint32_t) lblen);
5317 #endif /* TAPE_DEBUG */
5318 				/* over size? */
5319 				if (rest > spec->size
5320 				    || spec->offset > spec->size - rest) {
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,
5365 				    lu_cmd->iobufsize, request_len);
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,
5380 				    lu_cmd->iobufsize, request_len);
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,
5398 				    "WRITE_6 transfer %u x blocks %u SILI=%d\n",
5399 				    (uint32_t) lblen, (uint32_t) transfer_len,
5400 				    sili);
5401 				rc = istgt_lu_tape_fixed_lbwrite(spec, conn, lu_cmd, lblen,
5402 				    (uint32_t) transfer_len);
5403 			} else {
5404 				ISTGT_TRACELOG(ISTGT_TRACE_SCSI,
5405 				    "WRITE_6 transfer %u SILI=%d\n",
5406 				    (uint32_t) transfer_len, sili);
5407 				rc = istgt_lu_tape_variable_lbwrite(spec, conn, lu_cmd,
5408 				    transfer_len);
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,
5426 				    "save ctlblock and write EOD\n");
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,
5441 					request_len) < 0) {
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,
5464 				    "Underflow total=%zu, transfer_len=%u, lblen=%u\n",
5465 				    lu_cmd->data_len, (uint32_t) request_len,
5466 				    (uint32_t) lblen);
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,
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);
5511 	return 0;
5512 }
5513