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