home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1993 #2
/
Image.iso
/
os2
/
gtak212b.zip
/
SOURCE.ZIP
/
TAPE
/
tape.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-12
|
13KB
|
639 lines
/*****************************************************************************
* $Id: tape.c,v 1.3 1992/09/12 18:10:55 ak Exp $
*****************************************************************************
* $Log: tape.c,v $
* Revision 1.3 1992/09/12 18:10:55 ak
* Added scsi_name
* Added device name support to tctl.c
*
* Revision 1.2 1992/09/02 19:05:22 ak
* Version 2.0
* - EMX version
* - AIX version
* - SCSI-2 commands
* - ADD Driver
* - blocksize support
*
* Revision 1.1.1.1 1992/01/06 20:27:39 ak
* Interface now based on ST01 and ASPI.
* AHA_DRVR no longer supported.
* Files reorganized.
*
* Revision 1.1 1992/01/06 20:27:37 ak
* Initial revision
*
*****************************************************************************/
static char *rcsid = "$Id: tape.c,v 1.3 1992/09/12 18:10:55 ak Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#ifdef __EMX__
#ifndef _far
#define _far
#endif
#endif
#include "scsi.h"
#include "tape.h"
#include "scsitape.h"
#define SenseLength 16
#define SenseAlloc 16
static int target = 4;
static unsigned char cdb [10];
static unsigned char sense_buf [SenseAlloc];
static unsigned char * sense_ptr = sense_buf;
static int sense_len = SenseLength;
static int active;
static long active_nb;
static void * ctrl;
int scsiLevel = 1;
static long blocksize = 512;
static long valid_blocksize = 0;
#define int16(x) ((unsigned)(x)[0] << 8 | (x)[1])
#define int24(x) ((unsigned long)int16(x) << 8 | (x)[2])
#define int32(x) ((unsigned long)int24(x) << 8 | (x)[3])
int
tape_cmd(void *cdb, int cdb_len)
{
return scsi_cmd(target, 0, cdb, cdb_len, sense_ptr, sense_len, (void *)0, 0L, 0);
}
int
tape_read_cmd(void *cdb, int cdb_len, void _far *data, long length)
{
return scsi_cmd(target, 0, cdb, cdb_len, sense_ptr, sense_len, data, length, 1);
}
int
tape_write_cmd(void *cdb, int cdb_len, void _far *data, long length)
{
return scsi_cmd(target, 0, cdb, cdb_len, sense_ptr, sense_len, data, length, 0);
}
static void
init()
{
char *env;
long size;
sense_ptr = sense_buf;
sense_len = SenseLength;
if ((env = getenv("TAPEMODE")) != NULL)
scsiLevel = atoi(env);
else
scsiLevel = senseMode;
}
void
tape_init(void)
{
scsi_init();
init();
}
void
tape_name(char *name)
{
scsi_name(name);
init();
}
void
tape_file(int fd)
{
scsi_file(fd);
init();
}
void
tape_term(void)
{
scsi_term();
}
int
tape_reset(int bus)
{
return scsi_reset(target, 0, bus);
}
void
tape_trace(int level)
{
scsi_trace(level);
}
int
tape_target(int no)
{
int old = target;
target = no;
return old;
}
void
tape_sense(void *data, int len)
{
if (len >= 8 && data) {
sense_ptr = data;
sense_len = len;
} else {
sense_ptr = sense_buf;
sense_len = SenseLength;
}
}
char *
tape_error(int code)
{
switch (code) {
case EndOfData: return "End of data";
case EndOfTape: return "End of tape";
case FileMark: return "File mark";
}
return scsi_error(code);
}
int
tape_inquiry(void *data, int len)
{
cdb[0] = CmdInquiry;
cdb[1] = 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = len;
cdb[5] = 0;
return tape_read_cmd(cdb, 6, data, len);
}
int
tape_mode_sense(int page, void *data, int len)
{
cdb[0] = CmdModeSense;
cdb[1] = 0;
cdb[2] = page;
cdb[3] = 0;
cdb[4] = len;
cdb[5] = 0;
return tape_read_cmd(cdb, 6, data, len);
}
int
tape_mode_select(int page, void *data, int len, int SMP)
{
cdb[0] = CmdModeSelect;
cdb[1] = 0;
cdb[2] = page;
cdb[3] = 0;
cdb[4] = len;
cdb[5] = SMP ? 0x40 : 0x00;
return tape_write_cmd(cdb, 6, data, len);
}
int
tape_rewind(int imed)
{
cdb[0] = SeqRewind;
cdb[1] = imed ? 1 : 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 0;
cdb[5] = 0;
return tape_cmd(cdb, 6);
}
long
tape_tell(void)
{
int rc;
if (scsiLevel >= 2) {
unsigned char addr [20];
cdb[0] = SeqReadPosition;
cdb[1] = 1;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 0;
cdb[5] = 0;
cdb[6] = 0;
cdb[7] = 0;
cdb[8] = 0;
cdb[9] = 0;
if ((rc = tape_read_cmd(cdb, 10, addr, 20)) != 0)
return rc;
return (long)addr[4] << 24 | (long)addr[5] << 16
| (long)addr[6] << 8 | addr[7];
} else {
unsigned char addr [3];
cdb[0] = SeqRequestBlockAddress;
cdb[1] = 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 3;
cdb[5] = 0;
if ((rc = tape_read_cmd(cdb, 6, addr, 3)) != 0)
return rc;
return (long)addr[0] << 16 | (long)addr[1] << 8 | addr[2];
}
}
static int
num_result(int ret, long count, long *actual)
{
if (actual)
*actual = TapeUndefLength;
if (ret == MappedError+0)
return FileMark;
if (ErrorClass(ret) == SenseKey) {
if (actual && sense_ptr[0] & VADD)
*actual = count - int32(sense_ptr+3);
if (ret == SenseKey+NoSense) {
if (sense_ptr[2] & EOM)
return EndOfTape;
if (sense_ptr[2] & FM)
return FileMark;
}
} else if (actual && ret == 0)
*actual = count;
return ret;
}
int
tape_space(int mode, long nitems, long *actual)
{
cdb[0] = SeqSpace;
cdb[1] = mode;
cdb[2] = nitems >> 16;
cdb[3] = nitems >> 8;
cdb[4] = nitems;
cdb[5] = 0;
return num_result(tape_cmd(cdb, 6), nitems, actual);
}
int
tape_seek(int imed, long blkno)
{
if (scsiLevel >= 2) {
cdb[0] = SeqLocate;
cdb[1] = imed ? 5 : 4;
cdb[2] = 0;
cdb[3] = blkno >> 24;
cdb[4] = blkno >> 16;
cdb[5] = blkno >> 8;
cdb[6] = blkno;
cdb[7] = 0;
cdb[8] = 0;
cdb[9] = 0;
return tape_cmd(cdb, 10);
} else {
cdb[0] = SeqSeek;
cdb[1] = imed ? 1 : 0;
cdb[2] = blkno >> 16;
cdb[3] = blkno >> 8;
cdb[4] = blkno;
cdb[5] = 0;
return tape_cmd(cdb, 6);
}
}
static int
rw_result(int ret, long nb, long *actual)
{
if (actual)
*actual = TapeUndefLength;
if (ret == MappedError+0)
return FileMark;
if (ErrorClass(ret) == SenseKey) {
if (actual && sense_ptr[0] & VADD)
*actual = (blocksize ? blocksize : 1)
* (nb - int32(sense_ptr+3));
if (ret == SenseKey+NoSense) {
if (sense_ptr[2] & EOM)
return EndOfTape;
if (sense_ptr[2] & FM)
return FileMark;
}
} else if (actual && ret == 0)
*actual = (blocksize ? blocksize : 1) * nb;
return ret;
}
int
tape_read(void _far *data, long length, long *actual)
{
long nb;
if (!valid_blocksize)
tape_get_blocksize();
nb = blocksize ? length / blocksize : length;
cdb[0] = SeqRead;
cdb[1] = blocksize ? 1 : 0;
cdb[2] = nb >> 16;
cdb[3] = nb >> 8;
cdb[4] = nb;
cdb[5] = 0;
return rw_result(tape_read_cmd(cdb, 6, data, length), nb, actual);
}
int
tape_compare(void _far *data, long length, long *actual)
{
int ret;
long nb;
if (!valid_blocksize)
tape_get_blocksize();
nb = blocksize ? length / blocksize : length;
cdb[0] = SeqVerify;
cdb[1] = blocksize ? 3 : 2;
cdb[2] = nb >> 16;
cdb[3] = nb >> 8;
cdb[4] = nb;
cdb[5] = 0;
return rw_result(tape_write_cmd(cdb, 6, data, length), nb, actual);
}
int
tape_verify(long length, long *actual)
{
int ret;
long nb;
if (!valid_blocksize)
tape_get_blocksize();
nb = blocksize ? length / blocksize : length;
cdb[0] = SeqVerify;
cdb[1] = blocksize ? 1 : 0;
cdb[2] = nb >> 16;
cdb[3] = nb >> 8;
cdb[4] = nb;
cdb[5] = 0;
return rw_result(tape_cmd(cdb, 6), nb, actual);
}
int
tape_write(void _far *data, long length, long *actual)
{
int ret;
long nb;
if (!valid_blocksize)
tape_get_blocksize();
nb = blocksize ? length / blocksize : length;
cdb[0] = SeqWrite;
cdb[1] = blocksize ? 1 : 0;
cdb[2] = nb >> 16;
cdb[3] = nb >> 8;
cdb[4] = nb;
cdb[5] = 0;
return rw_result(tape_write_cmd(cdb, 6, data, length), nb, actual);
}
static void
cleanup(void)
{
if (active) {
while (scsi_wait(&ctrl, sense_ptr, 1) == ComeAgain)
;
active = 0;
}
}
int
tape_buffered_write(void _far *data, long length)
{
int ret;
if (!valid_blocksize)
tape_get_blocksize();
if (ctrl == NULL) {
atexit(cleanup);
ctrl = scsi_alloc();
}
active_nb = blocksize ? length / blocksize : length;
cdb[0] = SeqWrite;
cdb[1] = blocksize ? 1 : 0;
cdb[2] = active_nb >> 16;
cdb[3] = active_nb >> 8;
cdb[4] = active_nb;
cdb[5] = 0;
ret = scsi_start(ctrl, target, 0, cdb, 6, sense_len, data, length, 0);
if (ret == ComeAgain)
active = 1;
return ret;
}
int
tape_buffered_wait(long *actual)
{
int ret;
if (!active)
return NoCommand;
ret = scsi_wait(ctrl, sense_ptr, 1);
active = 0;
return rw_result(ret, active_nb, actual);
}
int
tape_filemark(int imed, long count, long *actual)
{
cdb[0] = SeqWriteFilemarks;
cdb[1] = imed ? 1 : 0;
cdb[2] = count >> 16;
cdb[3] = count >> 8;
cdb[4] = count;
cdb[5] = 0;
return num_result(tape_cmd(cdb, 6), count, actual);
}
int
tape_setmark(int imed, long count, long *actual)
{
cdb[0] = SeqWriteFilemarks;
cdb[1] = imed ? 3 : 2;
cdb[2] = count >> 16;
cdb[3] = count >> 8;
cdb[4] = count;
cdb[5] = 0;
return num_result(tape_cmd(cdb, 6), count, actual);
}
int
tape_erase(void)
{
cdb[0] = SeqErase;
cdb[1] = 1;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 0;
cdb[5] = 0;
return tape_cmd(cdb, 6);
}
long
tape_get_blocksize(void)
{
unsigned char data [12];
int rc;
cdb[0] = CmdModeSense;
cdb[1] = 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 12; /* length of parameter list */
cdb[5] = 0;
if ((rc = tape_read_cmd(cdb, 6, data, 12)) != 0)
return rc;
blocksize = (long)data[9] << 16 | (long)data[10] << 8 | data[11];
valid_blocksize = 1;
scsi_set_blocksize(target, 0, blocksize);
return blocksize;
}
int
tape_set_blocksize(long size)
{
unsigned char data [12];
blocksize = size;
scsi_set_blocksize(target, 0, size);
cdb[0] = CmdModeSelect;
cdb[1] = 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 12; /* length of parameter list */
cdb[5] = 0;
data[0] = 0;
data[1] = 0;
data[2] = 0x10; /* buffered mode */
data[3] = 8; /* block descriptor length */
data[4] = 0; /* density is default */
data[5] = 0;
data[6] = 0;
data[7] = 0;
data[8] = 0;
data[9] = size >> 16;
data[10] = size >> 8;
data[11] = size;
return tape_write_cmd(cdb, 6, data, 12);
}
int
tape_speed(int code)
{
unsigned char data [4];
cdb[0] = CmdModeSelect;
cdb[1] = 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 4; /* length of parameter list */
cdb[5] = 0;
data[0] = 0;
data[1] = 0;
data[2] = 0x10 | code; /* buffered mode */
data[3] = 0; /* block descriptor length */
return tape_write_cmd(cdb, 6, data, 4);
}
int
tape_ready(void)
{
cdb[0] = CmdTestUnitReady;
cdb[1] = 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = 0;
cdb[5] = 0;
return tape_cmd(cdb, 6);
}
int
tape_load(int imed, int retension)
{
cdb[0] = SeqLoad;
cdb[1] = imed != 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = retension ? 03 : 01;
cdb[5] = 0;
return tape_cmd(cdb, 6);
}
int
tape_unload(int imed, int mode)
{
cdb[0] = SeqLoad;
cdb[1] = imed != 0;
cdb[2] = 0;
cdb[3] = 0;
cdb[4] = (scsiLevel >= 2) ? mode & 07 : mode & 03;
cdb[5] = (scsiLevel >= 2) ? 0 : mode & 04 << 6;
return tape_cmd(cdb, 6);
}
void
tape_print_sense(FILE *out, int code)
{
struct Tape_Extended_Sense *p
= (struct Tape_Extended_Sense *) sense_ptr;
if (ErrorClass(code) == ErrorClass(MappedError)) {
fprintf(out, "%s\n", tape_error(code));
return;
}
fprintf(out, "Return code: %s\n", tape_error(code));
fprintf(out, "Sense key: %s\n", senseTab[p->sense_key]);
if (p->filemark || p->end_of_media || p->incorrect_length) {
fprintf(out, " ");
if (p->filemark)
fprintf(out, "Filemark ");
if (p->end_of_media)
fprintf(out, "End-of-media ");
if (p->incorrect_length)
fprintf(out, "Incorrect-length ");
fprintf(out, "\n");
}
switch (senseMode) {
case TDC3600:
fprintf(out, "ERCL+ERCD: %s\n",
find_error(tdc3600ercd, p->u.tdc.error));
fprintf(out, "EXERCD: %s\n",
find_error(tdc3600xercd, p->u.tdc.xerror));
fprintf(out, " blocks=%ld filemarks=%u remaining=%u\n",
int24(p->u.tdc.no_blocks),
int16(p->u.tdc.no_filemarks),
p->u.tdc.no_remaining);
fprintf(out, " recovered=%u underruns=%u marginal=%u\n",
int16(p->u.tdc.no_recovered),
int16(p->u.tdc.no_underruns),
p->u.tdc.no_marginal);
break;
case SCSI2:
fprintf(out, "ASC:: %02X\n", p->u.scsi2.asc);
fprintf(out, "ASCQ: %02X\n", p->u.scsi2.ascq);
fprintf(out, "Description: %s\n",
find_error(scsi2asc,
p->u.scsi2.asc << 8 | p->u.scsi2.ascq));
break;
}
}