mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
676 lines
15 KiB
C++
676 lines
15 KiB
C++
/*
|
|
* UAE - The Un*x Amiga Emulator
|
|
*
|
|
* SCSI tape emulation
|
|
*
|
|
* Copyright 2013 Toni Wilen
|
|
*
|
|
*/
|
|
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
|
|
#include "options.h"
|
|
#include "filesys.h"
|
|
#include "scsi.h"
|
|
#include "blkdev.h"
|
|
#include "zfile.h"
|
|
#include "memory.h"
|
|
#include "threaddep/thread.h"
|
|
#include "a2091.h"
|
|
#include "fsdb.h"
|
|
|
|
int log_tapeemu = 1;
|
|
|
|
#define TAPE_INDEX _T("index.tape")
|
|
|
|
static struct scsi_data_tape *tapeunits[MAX_FILESYSTEM_UNITS];
|
|
|
|
static bool notape (struct scsi_data_tape *tape)
|
|
{
|
|
return tape->tape_dir[0] == 0 || tape->nomedia;
|
|
}
|
|
|
|
static int rl (uae_u8 *p)
|
|
{
|
|
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
|
|
}
|
|
static void wl (uae_u8 *p, int v)
|
|
{
|
|
p[0] = v >> 24;
|
|
p[1] = v >> 16;
|
|
p[2] = v >> 8;
|
|
p[3] = v;
|
|
}
|
|
|
|
void tape_free (struct scsi_data_tape *tape)
|
|
{
|
|
if (!tape)
|
|
return;
|
|
zfile_fclose (tape->zf);
|
|
zfile_fclose (tape->index);
|
|
zfile_closedir_archive (tape->zd);
|
|
xfree(tape);
|
|
for (int i = 0; i < MAX_FILESYSTEM_UNITS; i++) {
|
|
if (tapeunits[i] == tape)
|
|
tapeunits[i] = NULL;
|
|
}
|
|
}
|
|
|
|
static void tape_init (int unit, struct scsi_data_tape *tape, const TCHAR *tape_directory, bool readonly)
|
|
{
|
|
TCHAR path[MAX_DPATH];
|
|
|
|
memset (tape, 0, sizeof (struct scsi_data_tape));
|
|
_tcscpy (tape->tape_dir, tape_directory);
|
|
|
|
tape->blocksize = 512;
|
|
tape->wp = readonly;
|
|
tape->beom = -1;
|
|
tape->nomedia = false;
|
|
tape->unloaded = false;
|
|
|
|
if (my_existsdir (tape->tape_dir)) {
|
|
tape->realdir = true;
|
|
} else {
|
|
tape->zd = zfile_opendir_archive (tape_directory, ZFD_ARCHIVE | ZFD_NORECURSE);
|
|
if (!tape->zd)
|
|
tape->nomedia = true;
|
|
}
|
|
|
|
_tcscpy (path, tape_directory);
|
|
_tcscat (path, FSDB_DIR_SEPARATOR_S);
|
|
_tcscat (path, TAPE_INDEX);
|
|
tape->index = zfile_fopen (path, _T("rb"), ZFD_NORMAL);
|
|
if (tape->index)
|
|
write_log (_T("TAPEEMU INDEX: '%s'\n"), path);
|
|
tapeunits[unit] = tape;
|
|
}
|
|
|
|
struct scsi_data_tape *tape_alloc (int unitnum, const TCHAR *tape_directory, bool readonly)
|
|
{
|
|
struct scsi_data_tape *tape = xcalloc (struct scsi_data_tape, 1);
|
|
|
|
tape_init (unitnum, tape, tape_directory, readonly);
|
|
return tape;
|
|
}
|
|
|
|
void tape_media_change (int unitnum, struct uaedev_config_info *ci)
|
|
{
|
|
struct scsi_data_tape *tape = tapeunits[unitnum];
|
|
if (!tape)
|
|
return;
|
|
tape_init (unitnum, tape, ci->rootdir, ci->readonly);
|
|
}
|
|
|
|
bool tape_get_info (int unitnum, struct device_info *di)
|
|
{
|
|
struct scsi_data_tape *tape = tapeunits[unitnum];
|
|
memset (di, 0, sizeof (struct device_info));
|
|
if (!tape)
|
|
return false;
|
|
di->media_inserted = notape (tape) == false;
|
|
_tcscpy (di->label, tape->tape_dir);
|
|
return true;
|
|
}
|
|
|
|
static void rewind (struct scsi_data_tape *tape)
|
|
{
|
|
zfile_fclose (tape->zf);
|
|
tape->zf = NULL;
|
|
my_closedir (tape->od);
|
|
tape->file_number = 0;
|
|
tape->file_offset = 0;
|
|
tape->od = NULL;
|
|
tape->beom = -1;
|
|
if (tape->index)
|
|
zfile_fseek (tape->index, 0, SEEK_SET);
|
|
if (tape->zd)
|
|
zfile_resetdir_archive (tape->zd);
|
|
}
|
|
|
|
static void erase (struct scsi_data_tape *tape)
|
|
{
|
|
struct my_opendir_s *od;
|
|
if (!tape->realdir)
|
|
return;
|
|
rewind (tape);
|
|
od = my_opendir (tape->tape_dir);
|
|
if (od) {
|
|
for (;;) {
|
|
TCHAR path[MAX_DPATH], filename[MAX_DPATH];
|
|
if (!my_readdir (od, filename))
|
|
break;
|
|
TCHAR *ext = _tcsrchr (filename, '.');
|
|
if (ext && !_tcsicmp (ext, _T(".tape"))) {
|
|
_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, filename);
|
|
if (my_existsfile (path))
|
|
my_unlink (path);
|
|
}
|
|
}
|
|
my_closedir (od);
|
|
}
|
|
}
|
|
|
|
static bool next_file (struct scsi_data_tape *tape)
|
|
{
|
|
zfile_fclose (tape->zf);
|
|
tape->zf = NULL;
|
|
tape->file_offset = 0;
|
|
if (tape->index) {
|
|
TCHAR path[MAX_DPATH];
|
|
TCHAR name[256];
|
|
name[0] = 0;
|
|
zfile_fgets (name, sizeof name / sizeof (TCHAR), tape->index);
|
|
my_trim (name);
|
|
if (name[0] == 0)
|
|
goto end;
|
|
_tcscpy (path, tape->tape_dir);
|
|
_tcscat (path, FSDB_DIR_SEPARATOR_S);
|
|
_tcscat (path, name);
|
|
tape->zf = zfile_fopen (path, _T("rb"), ZFD_NORMAL);
|
|
write_log (_T("TAPEEMU: File '%s'\n"), path);
|
|
} else if (tape->realdir) {
|
|
TCHAR path[MAX_DPATH], filename[MAX_DPATH];
|
|
if (tape->od == NULL)
|
|
tape->od = my_opendir (tape->tape_dir);
|
|
if (!tape->od) {
|
|
tape_free (tape);
|
|
goto end;
|
|
}
|
|
for (;;) {
|
|
if (!my_readdir (tape->od, filename))
|
|
goto end;
|
|
if (_tcsicmp (filename, TAPE_INDEX))
|
|
continue;
|
|
_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, filename);
|
|
if (!my_existsfile (path))
|
|
continue;
|
|
tape->zf = zfile_fopen (path, _T("rb"), 0);
|
|
if (!tape->zf)
|
|
continue;
|
|
break;
|
|
}
|
|
if (tape->zf)
|
|
write_log (_T("TAPEEMU DIR: File '%s'\n"), zfile_getname (tape->zf));
|
|
} else {
|
|
tape->zf = zfile_readdir_archive_open (tape->zd, _T("rb"));
|
|
if (tape->zf)
|
|
write_log (_T("TAPEEMU ARC: File '%s'\n"), zfile_getname (tape->zf));
|
|
}
|
|
if (tape->zf) {
|
|
tape->file_number++;
|
|
return true;
|
|
}
|
|
end:
|
|
write_log (_T("TAPEEMU: end of tape\n"));
|
|
tape->beom = 1;
|
|
return false;
|
|
}
|
|
|
|
static int tape_read (struct scsi_data_tape *tape, uae_u8 *scsi_data, int len, bool *eof)
|
|
{
|
|
int got;
|
|
|
|
*eof = false;
|
|
if (tape->beom > 0) {
|
|
*eof = true;
|
|
return -1;
|
|
}
|
|
|
|
if (!tape->zf) {
|
|
rewind (tape);
|
|
if (!next_file (tape))
|
|
return -1;
|
|
}
|
|
zfile_fseek (tape->zf, tape->file_offset, SEEK_SET);
|
|
got = zfile_fread (scsi_data, 1, len, tape->zf);
|
|
tape->file_offset += got;
|
|
if (got < len) {
|
|
*eof = true;
|
|
next_file (tape);
|
|
}
|
|
return got;
|
|
}
|
|
|
|
static int tape_write (struct scsi_data_tape *tape, uae_u8 *scsi_data, int len)
|
|
{
|
|
TCHAR path[MAX_DPATH], numname[30];
|
|
int exists;
|
|
|
|
if (!tape->realdir)
|
|
return -1;
|
|
_stprintf (numname, _T("%05d.tape"), tape->file_number);
|
|
_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, numname);
|
|
exists = my_existsfile (path);
|
|
struct zfile *zf = zfile_fopen (path, _T("a+b"));
|
|
if (!zf)
|
|
return -1;
|
|
zfile_fseek (zf, 0, SEEK_END);
|
|
len = zfile_fwrite (scsi_data, 1, len, zf);
|
|
zfile_fclose (zf);
|
|
if (!exists) {
|
|
_stprintf (path, _T("%s%s%s"), tape->tape_dir, FSDB_DIR_SEPARATOR_S, TAPE_INDEX);
|
|
zf = zfile_fopen (path, _T("a+b"));
|
|
if (zf) {
|
|
zfile_fputs (zf, numname);
|
|
zfile_fputs (zf, _T("\n"));
|
|
}
|
|
zfile_fclose (zf);
|
|
}
|
|
return len;
|
|
}
|
|
|
|
int scsi_tape_emulate (struct scsi_data_tape *tape, uae_u8 *cmdbuf, int scsi_cmd_len,
|
|
uae_u8 *scsi_data, int *data_len, uae_u8 *r, int *reply_len, uae_u8 *s, int *sense_len)
|
|
{
|
|
uae_s64 len;
|
|
int lr = 0, ls = 0;
|
|
int scsi_len = -1;
|
|
int status = 0;
|
|
int lun;
|
|
bool eof;
|
|
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU: %02X.%02X.%02X.%02X.%02X.%02X\n"),
|
|
cmdbuf[0], cmdbuf[1], cmdbuf[2], cmdbuf[3], cmdbuf[4], cmdbuf[5]);
|
|
|
|
if (cmdbuf[0] == 3) {
|
|
if (tape->beom == -1)
|
|
s[9] |= 0x8; // beginning of media
|
|
if (tape->beom == 1)
|
|
s[2] |= 0x40; // end of media
|
|
if (*sense_len < 0x12)
|
|
*sense_len = 0x12;
|
|
return 0;
|
|
}
|
|
|
|
*reply_len = *sense_len = 0;
|
|
memset (r, 0, 256);
|
|
memset (s, 0, 256);
|
|
s[0] = 0x70;
|
|
|
|
lun = cmdbuf[1] >> 5;
|
|
if (cmdbuf[0] != 0x03 && cmdbuf[0] != 0x12 && lun) {
|
|
status = 2; /* CHECK CONDITION */
|
|
s[0] = 0x70;
|
|
s[2] = 5; /* ILLEGAL REQUEST */
|
|
s[12] = 0x25; /* INVALID LUN */
|
|
ls = 0x12;
|
|
goto err;
|
|
}
|
|
|
|
switch (cmdbuf[0])
|
|
{
|
|
case 0x00: /* TEST UNIT READY */
|
|
if (notape (tape))
|
|
goto notape;
|
|
if (tape->unloaded)
|
|
goto unloaded;
|
|
scsi_len = 0;
|
|
break;
|
|
|
|
case 0x19: /* ERASE */
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU ERASE\n"));
|
|
if (notape (tape))
|
|
goto notape;
|
|
if (tape->unloaded)
|
|
goto unloaded;
|
|
if (tape->wp)
|
|
goto writeprot;
|
|
erase (tape);
|
|
rewind (tape);
|
|
tape->beom = 1;
|
|
scsi_len = 0;
|
|
break;
|
|
|
|
case 0x1b: /* LOAD/UNLOAD */
|
|
{
|
|
bool load = (cmdbuf[4] & 1) != 0;
|
|
bool ret = (cmdbuf[4] & 2) != 0;
|
|
bool eot = (cmdbuf[4] & 4) != 0;
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU LOAD/UNLOAD %d:%d:%d\n"), eot, ret, load);
|
|
if (notape (tape))
|
|
goto notape;
|
|
if (load && eot)
|
|
goto errreq;
|
|
rewind (tape);
|
|
tape->unloaded = !load;
|
|
if (eot) {
|
|
tape->beom = 1;
|
|
} else {
|
|
tape->beom = -1;
|
|
}
|
|
scsi_len = 0;
|
|
break;
|
|
}
|
|
|
|
case 0x01: /* REWIND */
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU: REWIND. IMMED=%d\n"), cmdbuf[1] & 1);
|
|
if (notape (tape))
|
|
goto notape;
|
|
if (tape->unloaded)
|
|
goto unloaded;
|
|
rewind (tape);
|
|
scsi_len = 0;
|
|
break;
|
|
|
|
case 0x11: /* SPACE */
|
|
{
|
|
int code = cmdbuf[1] & 15;
|
|
int count = rl (cmdbuf + 1) & 0xffffff;
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU: SPACE code=%d count=%d\n"), code, count);
|
|
if (notape (tape))
|
|
goto notape;
|
|
if (tape->unloaded)
|
|
goto unloaded;
|
|
if (code >= 2)
|
|
goto errreq;
|
|
if (code == 1) {
|
|
if (!next_file (tape))
|
|
goto endoftape;
|
|
}
|
|
scsi_len = 0;
|
|
}
|
|
break;
|
|
|
|
case 0x10: /* WRITE FILEMARK */
|
|
len = rl (cmdbuf + 1) & 0xffffff;
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU WRITE FILEMARK %lld\n"), len);
|
|
if (notape (tape))
|
|
goto notape;
|
|
if (tape->unloaded)
|
|
goto unloaded;
|
|
if (tape->wp)
|
|
goto writeprot;
|
|
if (len > 0) {
|
|
tape->file_number++;
|
|
tape_write (tape, scsi_data, 0);
|
|
}
|
|
scsi_len = 0;
|
|
break;
|
|
|
|
case 0x0a: /* WRITE (6) */
|
|
len = rl (cmdbuf + 1) & 0xffffff;
|
|
if (cmdbuf[1] & 1)
|
|
len *= tape->blocksize;
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU WRITE %lld (%d, %d)\n"), len, rl (cmdbuf + 1) & 0xffffff, cmdbuf[1] & 1);
|
|
if (notape (tape))
|
|
goto notape;
|
|
if (tape->unloaded)
|
|
goto unloaded;
|
|
if (tape->wp)
|
|
goto writeprot;
|
|
if (tape->beom < 0)
|
|
tape->beom = 0;
|
|
scsi_len = tape_write (tape, scsi_data, len);
|
|
if (scsi_len < 0)
|
|
goto writeprot;
|
|
break;
|
|
|
|
case 0x08: /* READ (6) */
|
|
len = rl (cmdbuf + 1) & 0xffffff;
|
|
if (cmdbuf[1] & 1)
|
|
len *= tape->blocksize;
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU READ %lld (%d, %d)\n"), len, rl (cmdbuf + 1) & 0xffffff, cmdbuf[1] & 1);
|
|
if (notape (tape))
|
|
goto notape;
|
|
if (tape->unloaded)
|
|
goto unloaded;
|
|
if (tape->beom < 0)
|
|
tape->beom = 0;
|
|
scsi_len = tape_read (tape, scsi_data, len, &eof);
|
|
if (log_tapeemu)
|
|
write_log (_T("-> READ %d bytes\n"), scsi_len);
|
|
if ((cmdbuf[1] & 1) && scsi_len > 0 && scsi_len < len) {
|
|
int gap = tape->blocksize - (scsi_len & (tape->blocksize - 1));
|
|
if (gap > 0 && gap < tape->blocksize)
|
|
memset (scsi_data + scsi_len, 0, gap);
|
|
scsi_len += tape->blocksize - 1;
|
|
scsi_len &= ~(tape->blocksize - 1);
|
|
}
|
|
if (scsi_len < 0) {
|
|
tape->beom = 2;
|
|
status = SCSI_STATUS_CHECK_CONDITION;
|
|
s[0] = 0x80 | 0x70;
|
|
s[2] = 8; /* BLANK CHECK */
|
|
if (cmdbuf[1] & 1)
|
|
wl (&s[3], len / tape->blocksize);
|
|
else
|
|
wl (&s[3], len);
|
|
s[12] = 0;
|
|
s[13] = 2; /* End-of-partition/medium detected */
|
|
ls = 0x12;
|
|
} else if (eof) {
|
|
status = SCSI_STATUS_CHECK_CONDITION;
|
|
s[0] = 0x80 | 0x70; // Valid + code
|
|
s[2] = 0x80 | 0; /* File Mark Detected + NO SENSE */
|
|
if (cmdbuf[1] & 1)
|
|
wl (&s[3], (len - scsi_len) / tape->blocksize);
|
|
else
|
|
wl (&s[3], len);
|
|
s[12] = 0;
|
|
s[13] = 1; /* File Mark detected */
|
|
ls = 0x12;
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU READ FILE END, %lld remaining\n"), len - scsi_len);
|
|
}
|
|
break;
|
|
|
|
case 0x5a: // MODE SENSE(10)
|
|
case 0x1a: /* MODE SENSE(6) */
|
|
{
|
|
uae_u8 *p;
|
|
int maxlen;
|
|
bool sense10 = cmdbuf[0] == 0x5a;
|
|
int totalsize, bdsize;
|
|
int pc = cmdbuf[2] >> 6;
|
|
int pcode = cmdbuf[2] & 0x3f;
|
|
int dbd = cmdbuf[1] & 8;
|
|
if (cmdbuf[0] == 0x5a)
|
|
dbd = 1;
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU MODE SENSE PC=%d CODE=%d DBD=%d\n"), pc, pcode, dbd);
|
|
p = r;
|
|
if (sense10) {
|
|
totalsize = 8 - 2;
|
|
maxlen = (cmdbuf[7] << 8) | cmdbuf[8];
|
|
p[2] = 0;
|
|
p[3] = 0;
|
|
p[4] = 0;
|
|
p[5] = 0;
|
|
p[6] = 0;
|
|
p[7] = 0;
|
|
p += 8;
|
|
} else {
|
|
totalsize = 4 - 1;
|
|
maxlen = cmdbuf[4];
|
|
p[1] = 0;
|
|
p[2] = tape->wp ? 0x80 : 0;
|
|
p[3] = 0;
|
|
p += 4;
|
|
}
|
|
bdsize = 0;
|
|
if (!dbd) {
|
|
wl(p + 0, 0);
|
|
wl(p + 4, tape->blocksize);
|
|
bdsize = 8;
|
|
p += bdsize;
|
|
}
|
|
if (pcode)
|
|
goto errreq;
|
|
if (sense10) {
|
|
totalsize += bdsize;
|
|
r[6] = bdsize >> 8;
|
|
r[7] = bdsize & 0xff;
|
|
r[0] = totalsize >> 8;
|
|
r[1] = totalsize & 0xff;
|
|
} else {
|
|
totalsize += bdsize;
|
|
r[3] = bdsize & 0xff;
|
|
r[0] = totalsize & 0xff;
|
|
}
|
|
lr = totalsize + 1;
|
|
if (lr > maxlen)
|
|
lr = maxlen;
|
|
}
|
|
break;
|
|
|
|
case 0x55: // MODE SELECT(10)
|
|
case 0x15: // MODE SELECT(6)
|
|
{
|
|
uae_u8 *p;
|
|
bool mode10 = cmdbuf[0] == 0x55;
|
|
int nb = 0, bl = 512;
|
|
p = scsi_data + 4;
|
|
if (mode10)
|
|
p += 4;
|
|
if (scsi_data[3] >= 8) {
|
|
nb = rl (p) & 0xffffff;
|
|
bl = rl (p + 4) & 0xffffff;
|
|
}
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU MODE SELECT BUFM=%d BDL=%d Density=%d NB=%d BL=%d\n"), (scsi_data[2] & 0x10) != 0, scsi_data[3], p[0], nb, bl);
|
|
if (nb || bl != 512)
|
|
goto err;
|
|
scsi_len = 0;
|
|
break;
|
|
}
|
|
|
|
case 0x05: /* READ BLOCK LIMITS */
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU READ BLOCK LIMITS\n"));
|
|
r[0] = 0;
|
|
r[1] = 0;
|
|
r[2] = 2; // 0x200 = 512
|
|
r[3] = 0;
|
|
r[4] = 2; // 0x200 = 512
|
|
r[5] = 0;
|
|
lr = 6;
|
|
break;
|
|
|
|
case 0x16: /* RESERVE UNIT */
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU RESERVE UNIT\n"));
|
|
scsi_len = 0;
|
|
break;
|
|
|
|
case 0x17: /* RELEASE UNIT */
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU RELEASE UNIT\n"));
|
|
scsi_len = 0;
|
|
break;
|
|
|
|
case 0x1e: /* PREVENT/ALLOW MEDIUM REMOVAL */
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU PREVENT/ALLOW MEDIUM REMOVAL\n"));
|
|
scsi_len = 0;
|
|
break;
|
|
|
|
case 0x12: /* INQUIRY */
|
|
{
|
|
if (log_tapeemu)
|
|
write_log (_T("TAPEEMU INQUIRY\n"));
|
|
if ((cmdbuf[1] & 1) || cmdbuf[2] != 0)
|
|
goto err;
|
|
len = cmdbuf[4];
|
|
if (cmdbuf[1] >> 5) {
|
|
r[0] = 0x7f;
|
|
} else {
|
|
r[0] = INQ_SEQD;
|
|
}
|
|
r[1] |= 0x80; // removable
|
|
r[2] = 2; /* supports SCSI-2 */
|
|
r[3] = 2; /* response data format */
|
|
r[4] = 32; /* additional length */
|
|
r[7] = 0;
|
|
scsi_len = lr = len < 36 ? len : 36;
|
|
r[2] = 2;
|
|
r[3] = 2;
|
|
char *s = ua (_T("UAE"));
|
|
memcpy (r + 8, s, strlen (s));
|
|
xfree (s);
|
|
s = ua (_T("SCSI TAPE"));
|
|
memcpy (r + 16, s, strlen (s));
|
|
xfree (s);
|
|
s = ua (_T("0.1"));
|
|
memcpy (r + 32, s, strlen (s));
|
|
xfree (s);
|
|
for (int i = 8; i < 36; i++) {
|
|
if (r[i] == 0)
|
|
r[i] = 32;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
write_log (_T("TAPEEMU: unsupported scsi command 0x%02X\n"), cmdbuf[0]);
|
|
err:
|
|
status = SCSI_STATUS_CHECK_CONDITION;
|
|
s[0] = 0x70;
|
|
s[2] = SCSI_SK_ILLEGAL_REQ;
|
|
s[12] = SCSI_INVALID_COMMAND;
|
|
ls = 0x12;
|
|
break;
|
|
writeprot:
|
|
status = 2; /* CHECK CONDITION */
|
|
s[0] = 0x70;
|
|
s[2] = 7; /* DATA PROTECT */
|
|
s[12] = 0x27; /* WRITE PROTECTED */
|
|
ls = 0x12;
|
|
break;
|
|
errreq:
|
|
lr = -1;
|
|
status = SCSI_STATUS_CHECK_CONDITION;
|
|
s[0] = 0x70;
|
|
s[2] = SCSI_SK_ILLEGAL_REQ;
|
|
s[12] = SCSI_INVALID_FIELD;
|
|
ls = 0x12;
|
|
break;
|
|
endoftape:
|
|
status = SCSI_STATUS_CHECK_CONDITION;
|
|
s[0] = 0x70;
|
|
s[2] = SCSI_SK_MED_ERR;
|
|
s[12] = 0;
|
|
s[13] = 2; /* End-of-partition/medium detected */
|
|
ls = 0x12;
|
|
break;
|
|
unloaded:
|
|
status = SCSI_STATUS_CHECK_CONDITION;
|
|
s[0] = 0x70;
|
|
s[2] = SCSI_SK_NOT_READY;
|
|
s[12] = SCSI_NOT_READY;
|
|
ls = 0x12;
|
|
break;
|
|
notape:
|
|
status = SCSI_STATUS_CHECK_CONDITION;
|
|
s[0] = 0x70;
|
|
s[2] = SCSI_SK_NOT_READY;
|
|
s[12] = SCSI_MEDIUM_NOT_PRESENT;
|
|
ls = 0x12;
|
|
break;
|
|
}
|
|
*data_len = scsi_len;
|
|
*reply_len = lr;
|
|
*sense_len = ls;
|
|
if (ls > 0) {
|
|
if (tape->beom == 1)
|
|
s[2] |= 0x40;
|
|
if (tape->beom == -1)
|
|
s[9] |= 0x8;
|
|
if (log_tapeemu) {
|
|
write_log (_T("TAPEEMU SENSE: "));
|
|
for (int i = 0; i < ls; i++)
|
|
write_log (_T("%02X."), s[i]);
|
|
write_log (_T("\n"));
|
|
}
|
|
}
|
|
return status;
|
|
}
|