home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 mARCH
/
PCWK3A99.iso
/
Archiwiz
/
Tar320
/
SOURCES.ZIP
/
ASPI.C
< prev
next >
Wrap
Text File
|
1995-08-15
|
27KB
|
857 lines
#include "modern.h"
#ifdef MSDOS
#include <stdio.h>
#include "pctimer.h"
#include "define.h"
#include <string.h>
#define NILTIME 0
#define MINTIME 6 /* ~0.3s */
#define TRESET (unsigned short)SEC2TICK(3)
#define MIDTIME (unsigned short)SEC2TICK(10)
#define MAXTIME (unsigned short)SEC2TICK(300)
#define HALTCPU
#define MAXLEX 8
#define UNKNOWN 255
void far (*ASPI_ptr)(void far *) = (void far (*)())0xffff0000L;
extern int ASPI_entry(void far (* far *)());
#define HA_INQ 0 /* host adapter inquiry */
#define GET_TYPE 1 /* get device type */
#define EXEC_SIO 2 /* execute SCSI I/O command */
#define ABORT_SRB 3 /* abort SCSI I/O command */
#define RESET_DEV 4 /* reset SCSI device */
#define SET_HAP 5 /* set host adapter parameters */
#define GET_DI 6 /* get disk drive information */
#define TAPE 1 /* SCSI device type */
#ifndef byte
# define byte unsigned char
#endif
#define SRBHEAD byte command, status, adapter, flags, reserved[4]
#define MAX_CDB 6 /* Group 0 commands only */
#define MAX_SENCE 14 /* ??? */
struct _srbinquiry {
SRBHEAD, ha_total, ha_type, mgr_id[16], ha_id[16], hap[16];
};
struct _srbgettype {
SRBHEAD, target, lun, devtype;
};
struct _srbabort {
SRBHEAD, pointer[4];
};
struct _srbio {
SRBHEAD, target, lun,
datalength[4], sencelength, databuffer[4], srblink[4], cdblength,
adapter_status, target_status, post_routine[4],
workspace[34], area[MAX_CDB + MAX_SENCE];
};
struct _srbreset {
SRBHEAD, target, lun, dummy[14],
adapter_status, target_status, post_routine[4], workspace[34];
};
struct _cdbtape {
byte opcode, unit, counter[3], control;
};
/* SCSI tape opcodes */
#define S0P_TEST 0 /* test unit ready */
#define S0P_REWIND 1
#define S0P_LIMITS 5 /* read block limits */
#define S0P_READ 8
#define S0P_WRITE 10
#define S0P_WFM 16 /* write file mark */
#define S0P_SPACE 17
#define S0P_INQ 18
#define S0P_MODE 21 /* mode select */
#define S0P_ERASE 25
#define S0P_MSENCE 26 /* mode sence */
/* Transfer direction bits */
#define T_INHERIT 000 /* Command-dependent*/
#define T_READ 010 /* Read from target */
#define T_WRITE 020 /* Write to target */
#define T_NONE 030 /* No data transfer */
#define ASPI_EMPTY 0
#define ASPI_QUEUED 0
#define ASPI_SUCCESS 1
#define ASPI_SENCE 2
#define ASPI_ABORTED 2
#define ASPI_BUSY 8
#define ASPI_INVALID 0x80 /* illegal request */
#define ASPI_NoHA 0x81 /* invalid host adapter */
#define ASPI_ABSENT 0x82 /* device not installed */
#define SCSI_SENCE 0x20
#define SCSI_SENCEOK 0x20
#define SCSI_RECOVER 0x21
#define SCSI_BUSY 0x22
#define SCSI_INVALID 0x25 /* illegal request */
#define SCSI_ATTN 0x26 /* unit attention */
#define SCSI_BLANK 0x28
#define SCSI_ILI 0x35 /* incorrect length indicator */
#define SCSI_EOM 0x36 /* end-of-medium */
#define SCSI_FM 0x37 /* hit file mark */
int aspierrno;
struct { byte code; char *text; } aspierrlist[] = {
{ 0x00, "SCSI request in progress" },
{ 0x01, "SCSI request completed without error"},
{ 0x02, "SCSI request aborted by host" },
{ 0x04, "SCSI request completed with error" },
{ 0x08, "Specified Target/LUN is busy" },
{ 0x11, "Selection timeout" },
{ 0x12, "Data over-run/under-run" },
{ 0x13, "Unexpected Bus Free" },
{ 0x14, "Target bus phase sequence failure" },
{ 0x18, "Reservation conflict" },
{ 0x20, "No sence" }, /* My codes */
{ 0x21, "Recovered error" },
{ 0x22, "Not ready" },
{ 0x23, "Medium error" },
{ 0x24, "Hardware error" },
{ 0x25, "Illegal request" },
{ 0x26, "Unit attention" },
{ 0x27, "Data protect" },
{ 0x28, "Blank check" },
{ 0x29, "Vendor unique" },
{ 0x2A, "Copy aborted" },
{ 0x2b, "Aborted command" },
{ 0x2C, "Equal" },
{ 0x2d, "Volume overflow" },
{ 0x2E, "Miscompare" },
{ 0x2f, "Reserved sence key"},
{ 0x35, "Incorrect length" },
{ 0x36, "End of medium" },
{ 0x37, "File mark reached" },
{ 0x80, "Invalid SCSI request" }, /* ASPI codes again */
{ 0x81, "Invalid Host Adapter Number"},
{ 0x82, "SCSI device not installed" },
};
char *aspierrmsg(int n)
{
static char h[16] = "0123456789ABCDEF";
static char vendor[] = "Vendor unique, class ? code ?h";
static char other[] = "Error ??h";
register i;
for (i=0; i<sizeof(aspierrlist)/sizeof(aspierrlist[0]); i++) {
if (aspierrlist[i].code == n) return aspierrlist[i].text;
}
if (n >= 0x70 && n <= 0xff) {
vendor[21] = n >= 0xf0 ? '0' : h[(n >> 4) & 7];
vendor[28] = h[n & 15];
return vendor;
}
other[6] = h[(n >> 4) & 15];
other[7] = h[ n & 15];
return other;
}
int aspicall(struct _srbio *s, unsigned timeout)
{
unsigned long t0;
struct _srbabort sa;
register unsigned char *p;
*(long *)(s->reserved) = 0L; /* clear reserved field */
(*ASPI_ptr)((void far *)s);
if (s->status != ASPI_QUEUED || timeout == 0) goto test;
for (t0 = pctimer();;) {
if (s->status != ASPI_QUEUED) goto test;
if (pctimer() - t0 > timeout) break;
HALTCPU;
}
/* Timeout expired - abort the request */
sa.command = ABORT_SRB;
sa.adapter = s->adapter;
sa.flags = 0;
*(long *)sa.reserved = 0L;
*(void far * far *)sa.pointer = (void far *)s;
(void)(*ASPI_ptr)((void far *)&sa);
/* Wait till IO aborted */
for (t0=pctimer(); 1 >= pctimer()-t0;) HALTCPU;
if (s->status == ASPI_QUEUED) s->status = ASPI_ABORTED;
test:
if (s->status & 0x80) return s->status;
if (s->adapter_status != ASPI_EMPTY) return s->adapter_status;
if (s->target_status != ASPI_EMPTY) {
/* Is sence area information available? */
if (s->target_status != ASPI_SENCE) return s->target_status;
if (s->command == EXEC_SIO) {
p = s->area + s->cdblength;
/* Take out vendor-unique classes (remap class 0 to 15) */
if ((*p & 0x70) == 0x00) return *p | 0xf0;
if ((*p & 0x70) != 0x70) return *p | 0x80;
/* Take out vendor-unique codes */
if ((*p & 0x0f) != 0x00) return *p & 0x7f;
/* Is incorrect length indicator set? */
if (p[2] & 0x20) return SCSI_ILI;
/* Is nontrivial sence key available? */
if (p[2] & 0x0E) return (p[2] & 15) | SCSI_SENCE;
/* Check for file mark and end-of-medium conditions */
if (p[2] & 0x80) return SCSI_FM;
if (p[2] & 0x40) return SCSI_EOM;
/* Nothing looks like an error */
return (p[2] & 15) | SCSI_SENCE;
}
}
return s->status;
}
#define END_OF_MEDIUM 0x80
#define FIXED_MODE 1
#define NO_RESET 2
#define NO_REWIND 4
#define ERASE 8
#define FM_ON_CLOSE 0x10
#define OPEN_FLAGS 0x1E
static struct {
unsigned long iosize;
unsigned long maxblock; unsigned short minblock;
byte adapter, target, lun, density, flags;
} id = { -1L, 0, 0, 4, 0, 0, 0 };
static long residue;
static byte lastcmd = 0;
static byte ok_to_close = FALSE;
static unsigned to_skip = 0;
int aspisio(int cmd, void *buffer, long length, long cmdlen,
unsigned aspiflags, unsigned cdbflags, unsigned tout)
{
register k;
register byte *p;
struct _srbio s;
s.command = EXEC_SIO;
s.adapter = id.adapter;
s.flags = aspiflags;
*(long *)(s.reserved) = 0L;
s.target = id.target;
s.lun = id.lun;
*(long *)(s.datalength) = length;
s.sencelength = MAX_SENCE;
*(void far * far *)(s.databuffer) = (void far *)buffer;
*(long *)(s.srblink) = 0L;
s.cdblength = 6; /* Group 0 commands only */
*(long *)(s.post_routine) = 0xffff0000L;
((struct _cdbtape *)(s.area))->opcode = lastcmd = cmd;
((struct _cdbtape *)(s.area))->unit = (id.lun << 5) | cdbflags;
((struct _cdbtape *)(s.area))->counter[0] = (byte)(cmdlen >> 16);
((struct _cdbtape *)(s.area))->counter[1] = (byte)(cmdlen >> 8);
((struct _cdbtape *)(s.area))->counter[2] = (byte) cmdlen;
((struct _cdbtape *)(s.area))->control = 0;
/* Clear sence area */ *(p = s.area + s.cdblength) = 0;
k = aspicall(&s, tout);
if (k & SCSI_SENCE && k < 0x70) {
/* Check sence data area */
if (p[2] & 0x40) id.flags |= END_OF_MEDIUM;
else id.flags &= ~END_OF_MEDIUM;
residue = (p[6] | ((unsigned)p[5] << 8)) |
((long)(p[4] | ((unsigned)p[3] << 8)) << 16);
}
return k;
}
int aspiexec(int cmd, unsigned cdbflags, unsigned tout)
{
return aspisio(cmd, NULL, 0L, 0L, T_NONE, cdbflags, tout);
}
int aspitrans(int wr, void *buffer, unsigned length)
{
register k;
unsigned fixed, counter;
if (id.iosize != 0L) {/* fixed mode */
if (length % id.iosize) return (aspierrno=SCSI_ILI, -1);
counter = (unsigned)(length / id.iosize);
fixed = 1;
} else {
if (length < id.minblock || length > id.maxblock)
return (aspierrno=SCSI_ILI, -1);
counter = length;
fixed = 0;
}
if (wr) {
wr = S0P_WRITE; k = T_WRITE;
} else {
wr = S0P_READ; k = T_READ;
}
k = aspisio(wr, buffer, (long)length, (long)counter, k, fixed, MAXTIME);
if (k == ASPI_SUCCESS) return length;
if (k != SCSI_SENCEOK && k != SCSI_RECOVER && k != SCSI_BLANK &&
k != SCSI_EOM && k != SCSI_FM) return (aspierrno=k, -1);
if (!residue) return length;
aspierrno = k;
if (fixed) {
if (residue > 0x10000L/id.minblock) return -1;
residue *= id.minblock;
}
return (unsigned long)residue > length ? -1 : length - (int)residue;
}
long aspiinvoke(int cmd, long counter, int flag)
{
register k;
k = aspisio(cmd, NULL, 0L, counter, T_NONE, flag, MAXTIME);
if (k == ASPI_SUCCESS) return 0L;
if (k != SCSI_SENCEOK && k != SCSI_RECOVER && k != SCSI_BLANK &&
k != SCSI_EOM && k != SCSI_FM) return (aspierrno=k, -0x80000000L);
if (residue) aspierrno = k;
return residue;
}
int aspirewind(void)
{
register k;
if ((k=aspiexec(S0P_REWIND,0,MAXTIME)) != ASPI_SUCCESS) {
if ((k != SCSI_SENCEOK && k != SCSI_EOM && k != SCSI_FM) ||
!(id.flags & END_OF_MEDIUM)) return (aspierrno=k);
}
return ASPI_SUCCESS;
}
int aspierase(int lbit)
{
register k;
k = aspiexec(S0P_ERASE, lbit, MAXTIME);
if (k!=ASPI_SUCCESS && k!=SCSI_SENCEOK && k!=SCSI_EOM)
return (aspierrno=k);
return ASPI_SUCCESS;
}
int aspireset(void)
{
struct _srbreset s;
unsigned long t0;
register i;
s.command = RESET_DEV;
s.adapter = id.adapter;
s.flags = 0;
s.target = id.target;
s.lun = id.lun;
for (i=0; i<sizeof(s.dummy); i++) s.dummy[i] = 0;
*(long *)(s.post_routine) = 0xffff0000L;
*(long *)(s.reserved) = 0L; /* clear reserved field */
(*ASPI_ptr)((void far *)&s);
for (t0 = pctimer(); s.status == ASPI_QUEUED;) {
if (pctimer() - t0 > TRESET) break;
HALTCPU;
}
if (!(s.status & 0x80)) {
if (s.adapter_status != ASPI_EMPTY) return s.adapter_status;
if (s.target_status != ASPI_EMPTY) return s.target_status;
}
return s.status;
}
int aspiread(char *buffer, unsigned length)
{
register k;
if (!cblock) {
if (length > id.maxblock) length = (unsigned)id.maxblock;
else if (length < id.minblock) length = (unsigned)id.minblock;
}
if ((k = aspitrans(0, buffer, length)) == -1) {
(void)fprintf(stderr, "Tar: ASPI read error: %s\n",
aspierrmsg(aspierrno));
}
return k;
}
int aspiwrite(char *buffer, unsigned length)
{
register k;
if (id.flags & END_OF_MEDIUM && lastcmd == S0P_WRITE) {
aspierrno = SCSI_EOM; k = 0;
} else {
k = aspitrans(1, buffer, length);
}
if (k != length) {
(void)fprintf(stderr, "Tar: ASPI write error: %s\n",
aspierrmsg(aspierrno));
}
return k;
}
int aspiback(/* number of 512-byte blocks */ int n)
{
if (aspiinvoke(S0P_SPACE, -1, 0) != 0L) {
(void)fprintf(stderr, "Tar: ASPI seek error: %s\n",
aspierrmsg(aspierrno));
return 0;
}
return n;
}
static int GetType(void)
{
struct _srbgettype s;
s.command = GET_TYPE;
s.adapter = id.adapter;
s.target = id.target;
s.lun = id.lun;
s.flags = 0;
*(long *)(s.reserved) = 0L;
(*ASPI_ptr)((void far *)&s);
if (s.status == ASPI_SUCCESS) return s.devtype;
aspierrno = s.status;
return -1;
}
static int HAInquiry(struct _srbinquiry *s, int adapter)
{
s->command = HA_INQ;
s->adapter = adapter;
s->flags = 0;
*(long *)(s->reserved) = 0L;
(*ASPI_ptr)((void far *)s);
return s->status;
}
int aspicount(int devno)
{
register k;
struct _srbinquiry s;
register ha_max;
/* Initialise device description */
id.maxblock = 0x800000L;
id.minblock = 1;
/* Get number of host adapters */
if ((k=HAInquiry(&s, 0)) != ASPI_SUCCESS) return k;
ha_max = s.ha_total;
/* Search for the tape device with given number */
for (id.adapter = 0; id.adapter < ha_max; id.adapter ++)
for (id.target = 0; id.target < 8; id.target ++)
for (id.lun = 0; id.lun < 8; id.lun ++) {
if ((k = GetType()) == -1) {
if (aspierrno != ASPI_ABSENT) return aspierrno;
} else if (k == TAPE) {
if (devno-- == 0) goto found;
}
}
/* There is no so many tape devices */ return ASPI_ABSENT;
found:
return ASPI_SUCCESS;
}
static int hex(register c)
{
if (c>='0' && c<='9') c -= '0';
else if (c>='A' && c<='F') c -= 'A'-10;
else if (c>='a' && c<='f') c -= 'a'-10;
else c = ERROR;
return c;
}
static int rstrlen(char *s, int size)
{
register i;
for (i=0; s[i] && i<size; i++) {
if (s[i] < ' ' || s[i] >= 127) return 0;
}
while (i>0 && (s[i-1]==' ' || s[i-1]=='\377')) --i;
return i;
}
int aspiparse(char *s)
{
static char already[] = "tape format already defined";
static struct { unsigned short nqic, code; } qiclist[] = {
{11,4}, {120,15}, {150,16}, {320,17}, {525,17}, {1350,18}
};
char lex[MAXLEX+1], *errmsg;
register i, k; register char *p;
for (i=0; i<sizeof(lex) && *s!='.'; i++) {
if (*s == '\0' || *s == ':' || *s == ';' || *s == ',') goto test_name;
lex[i] = *s++;
}
return FALSE;
test_name:
lex[i] = '\0';
if ((lex[0] & ~('z'^'Z')) != 'A' || strnicmp(lex,"ASPI",4)) return FALSE;
if (lex[4]!='\0' && stricmp(lex+4,"MGR$") && stricmp(lex+4,"TAPE"))
return FALSE;
to_skip = 0;
ok_to_close = FALSE;
id.maxblock = 0x800000L;
id.minblock = 1;
id.adapter = UNKNOWN;
id.target = UNKNOWN;
id.lun = UNKNOWN;
id.density = 0;
id.flags = 0;
if (*s) {
while (*++s) {
for (i=0; i<=MAXLEX; ++i, s++) {
if (*s >= 'A' && *s <= 'Z') lex[i] = *s | ('z'^'Z');
else if (*s >= 'a' && *s <= 'z') lex[i] = *s;
else break;
}
if (i < 1 || i > MAXLEX) {
errmsg = "device parameter error"; goto error;
}
lex[i] = '\0'; /* for diagnostic printing */
if (!strncmp("fluent", lex, i)) {
id.flags |= NO_RESET;
} else if (!strncmp("norewind", lex, i)) {
if (to_skip || id.flags & ERASE) goto mutual;
id.flags |= NO_REWIND;
} else if (!strncmp("erase", lex, i)) {
if (to_skip || id.flags & NO_REWIND) goto mutual;
id.flags |= ERASE;
} else if (!strncmp("qic", lex, i)) {
if (id.density) {
errmsg = already; goto error;
}
if (*s == '-') {
++s;
} else {
if (*s == ':') ++s;
if (*s == '=') ++s;
}
for (k=0, i=0; i<5 && *s>='0' && *s<='9'; ++s, i++)
k = (*s - '0') + 10*k;
if (i < 5)
for (i=0; i<dimof(qiclist); i++)
if (qiclist[i].nqic == k) {
id.density = qiclist[i].code; break;
}
if (!id.density) {
errmsg = "invalid QIC number"; goto error;
}
} else {
if (*s == ':') ++s;
if (*s == '=') ++s;
if (strncmp("adapter", lex, i) == 0) {
if (*s<'0' || *s>'7') {
errmsg = "invalid adapter number"; goto error;
}
id.adapter = *s++ & 7;
} else if (strncmp("target", lex, i) == 0) {
if (*s<'0' || *s>'7') {
errmsg = "invalid target number"; goto error;
}
id.target = *s++ & 7;
} else if (strncmp("lun", lex, i) == 0) {
if (*s<'0' || *s>'7') {
errmsg = "invalid LUN number"; goto error;
}
id.lun = *s++ & 7;
} else if (!strncmp("skip", lex, i)) {
if (id.flags & (ERASE|NO_REWIND)) goto mutual;
for (to_skip=0, i=0; i<5 && *s>='0' && *s<='9'; ++i, s++) {
to_skip = (*s - '0') + 10*to_skip;
}
} else if (!strncmp("code", lex, i) ||
!strncmp("density", lex, i)) {
id.density = 0; p = s;
if (*p == '0') ++p;
if ((*p | ('z'^'Z')) == 'x') {
for (i=0, s=p+1; i<2; ++s, i++) {
if ((k = hex(*s)) == ERROR) break;
id.density = k | (id.density << 4);
}
} else {
while (hex(*p)!=ERROR) ++p;
if ((*p | ('z'^'Z')) == 'h') {
for (i=0; i<2; ++s, i++) {
if ((k = hex(*s)) == ERROR) break;
id.density = k | (id.density << 4);
}
if ((*s | ('z'^'Z')) == 'h') ++s;
} else {/* decimal code */
for (i=0; i<4 && *s>='0' && *s<='9'; ++i, s++) {
id.density = (*s - '0') + 10*id.density;
}
}
}
if (!i || ~255 & id.density) {
errmsg = "invalid density code"; goto error;
}
} else {
(void)fprintf(stderr,"Tar: unknown parameter \'%s\'\n",lex);
return ERROR;
}
}
if (*s == '\0') break;
if (*s != ',' && *s != ':' && *s != '.') {
(void)fprintf(stderr,"Tar: invalid character after \'%s\'\n",lex);
return ERROR;
}
}
}
if (ASPI_entry((void far *)&ASPI_ptr) != 0) {
errmsg = "no ASPI manager found"; goto error;
}
if (setdrive ||
(id.adapter==UNKNOWN && id.target==UNKNOWN && id.lun==UNKNOWN)) {
if (id.adapter!=UNKNOWN || id.target!=UNKNOWN || id.lun!=UNKNOWN) {
errmsg = "both device number and SCSI parameters specified";
goto error;
}
if ((k=aspicount(ndrive)) != ASPI_SUCCESS) {
errmsg = k!=ASPI_ABSENT ? aspierrmsg(k) :
"there is no so many tape devices" ;
goto error;
}
} else {
if (id.target == UNKNOWN) {
errmsg = "unknown target number"; goto error;
}
if (id.adapter == UNKNOWN) id.adapter = 0;
if (id.lun == UNKNOWN) id.lun = 0;
if ((k=GetType()) != TAPE) {
errmsg = k == -1 ? aspierrmsg(k) : "not a tape device specified";
goto error;
}
}
if (v_flag) {
struct _srbinquiry s;
if (HAInquiry(&s, id.adapter) != ASPI_SUCCESS) goto reported;
i = rstrlen((char*)s.mgr_id, 16);
k = rstrlen((char*)s.ha_id, 16);
if (!i && !k) goto reported;
(void)fprintf(myout, "Tar: ");
if (i) {
(void)fprintf(myout, "ASPI manager: <%-.*s>", i, s.mgr_id);
if (k) (void)fprintf(myout, ", ");
}
if (k) {
(void)fprintf(myout, "SCSI adapter: <%-.*s>", k, s.ha_id);
}
(void)fprintf(myout, "\n");
reported:;
}
if (a_flag && !(id.flags & NO_REWIND)) id.flags |= FM_ON_CLOSE;
return TRUE;
mutual:
errmsg = "\'erase\', \'norewind\' and \'skip\' are mutaully exclusive";
error:
(void)fprintf(stderr, "Tar: %s\n", errmsg);
return ERROR;
}
static void printape(void)
{
char b[96];
int dlen, ilen=0, plen=0, rlen=0;
/* Inquiry command does not interfere with 'Unit Attension' */
if (aspisio(S0P_INQ, b, 96L, 96L, T_READ, 0, MINTIME) != ASPI_SUCCESS)
return;
if ((dlen = *(unsigned char *)(b+4) + 5) > 8) {
ilen = rstrlen(b+8, 8);
if (dlen > 16) {
plen = rstrlen(b+16, 16);
if (dlen > 32) rlen = rstrlen(b+32, 4);
}
}
if (ilen || plen || rlen) {
(void)fprintf(myout, "Tar: SCSI tape drive:");
if (ilen) (void)fprintf(myout, "\t%-8.*s", ilen, b+8);
if (plen) (void)fprintf(myout, "\t%-.*s", plen, b+16);
if (rlen) (void)fprintf(myout, "\trev. %-.*s", rlen, b+32);
(void)fprintf(myout, "\n");
}
}
int aspisetmode(long bsize, int speed, int bm, int pf)
{
unsigned char b[12];
b[1] = b[0] = 0;
b[2] = (unsigned char)speed;
if (bm) b[2] |= 16;
b[3] = 8; /* block descriptor length */
b[4] = id.density;
b[7] = b[6] = b[5] = 0; /* whole tape */
b[8] = 0; /* reserved */
b[ 9] = (unsigned char)(255 & (bsize >> 16));
b[10] = (unsigned char)(255 & (bsize >> 8));
b[11] = (unsigned char)(255 & bsize);
return aspisio(S0P_MODE, b, 12L, 12L, T_WRITE, (pf ? 16 : 0), MINTIME);
}
static int longrewind(void)
/* Wait until previous operation completed and rewind */
{
register i, k;
unsigned long t0;
for (i=0, t0=pctimer();;) {
if ((k=aspirewind()) == SCSI_ATTN) {
if (++i < 7) continue;
} else if (k == ASPI_BUSY || k == SCSI_BUSY) {
if (pctimer() - t0 < MAXTIME) continue;
}
break;
}
return k;
}
int aspistart(void)
{
register k;
unsigned long t0;
unsigned char b[12];
int gotBL = FALSE, gotMS = FALSE;
extern void printbs(int);
if (!(id.flags & (NO_RESET|NO_REWIND)) && id.density != 127) {
(void)aspireset();
/* Wait until POST and/or clear 'unit attension' condition */
for (k=0, t0=pctimer();;) {
switch (aspiexec(S0P_TEST, 0, MINTIME)) {
case SCSI_ATTN: if (++k < 7) continue; break;
case ASPI_BUSY:
case SCSI_BUSY: if (pctimer() - t0 < MAXTIME) continue;
}
break;
}
}
if (v_flag) printape();
if (!(id.flags & NO_REWIND)) {
if (longrewind() != ASPI_SUCCESS) goto error;
if (id.flags & ERASE) {
if (aspierase(1) != ASPI_SUCCESS) goto error;
if (aspirewind() != ASPI_SUCCESS) goto error;
}
}
id.iosize = 0L;
/* Read block limits */
k = aspisio(S0P_LIMITS, b, 6L, 0L, T_READ, 0, MINTIME);
if (k == ASPI_SUCCESS || k == SCSI_SENCEOK || k == SCSI_EOM) {
id.minblock = b[5] | ((unsigned)b[4] << 8);
id.maxblock = b[3] | ((unsigned)b[2] << 8) | ((unsigned long)b[1]<<16);
if (!id.maxblock) id.maxblock = 0x800000L;
gotBL = TRUE;
}
k = aspisio(S0P_MSENCE, b, 12L, 12L, T_READ, 0, MINTIME);
if ((k == ASPI_SUCCESS || k == SCSI_SENCEOK || k == SCSI_EOM) &&
b[0] >= 12 && b[3] == 8) {
id.iosize = ((unsigned long)b[9]<<16) | ((unsigned)b[10]<<8) | b[11];
gotMS = TRUE;
if (gotBL && id.iosize != 0L) {
if (id.iosize < id.minblock || id.iosize > id.maxblock) {
(void)fprintf(stderr,
"Tar: SCSI blocksize %ld is out of hardware limits (%u-%ld)\n",
id.iosize, id.minblock, id.maxblock);
return ERROR;
}
if (!cblock && id.iosize%BLKSIZE == 0 &&
id.iosize <= BLKSIZE*MAXBLOCK) {
printbs(cblock = (int)(id.iosize / BLKSIZE));
goto ok;
}
}
}
if (gotMS && id.iosize == 0L || !gotMS &&
gotBL && id.minblock != id.maxblock) {
id.flags &= ~FIXED_MODE;
id.iosize = 0L;
if (cblock) {
if ((k = cblock * BLKSIZE) < id.minblock || k > id.maxblock) {
(void)fprintf(stderr,
"Tar: blocksize is out of hardware limits (%d - %ld)\n",
id.minblock / BLKSIZE, id.maxblock / BLKSIZE);
return ERROR;
}
} else if (c_flag) {
printbs(cblock = id.maxblock < BLKSIZE*MAXBLOCK ?
(int)(id.maxblock/BLKSIZE) : MAXBLOCK);
}
} else if (gotMS || gotBL) {
id.flags |= FIXED_MODE;
if (!gotMS) id.iosize = id.minblock;
if ((id.iosize % BLKSIZE || id.iosize > BLKSIZE*MAXBLOCK) &&
(!cblock || id.density==0 || id.density==127)) {
(void)fprintf(stderr,
"Tar: hardware blocksize %ld bytes is not suitable for tar\n",
id.iosize);
}
if (cblock) {
if (id.density!=0 && id.density!=127 &&
(k = cblock*BLKSIZE) >= id.minblock && k <= id.maxblock) {
id.iosize = k;
} else if ((cblock*BLKSIZE) % id.iosize) {
(void)fprintf(stderr,
"Tar: blocksize must be multiple of %ld\n",
id.iosize/BLKSIZE);
}
} else {
printbs(cblock = (int)(id.iosize / BLKSIZE));
}
} else /* !gotMS && !gotBL */ {
if (cblock) {
id.iosize = id.maxblock = id.minblock = BLKSIZE*cblock;
id.flags |= FIXED_MODE;
} else {
id.maxblock = BLKSIZE*MAXBLOCK;
id.minblock = BLKSIZE;
id.flags &= ~FIXED_MODE;
id.iosize = 0L;
}
}
ok:
if (id.density!=0 && id.density != 127) {
for (k=4; k--;) {
if (aspisetmode(id.iosize, 0, k&2, k&1)
!= SCSI_INVALID) break;
}
}
ok_to_close = TRUE;
if (to_skip) {
if (aspisio(S0P_SPACE, NULL, 0L, (long)to_skip, T_NONE, 1, MAXTIME)
!= ASPI_SUCCESS) goto error;
}
return 0;
error:
(void)fprintf(stderr, "Tar: %s\n", aspierrmsg(aspierrno));
return ERROR;
}
void aspiend(void)
{
if (!ok_to_close) return;
if (id.flags & FM_ON_CLOSE || lastcmd == S0P_WRITE) {
if (aspiinvoke(S0P_WFM,
((id.flags & (FM_ON_CLOSE|NO_REWIND)) == FM_ON_CLOSE ? 1L : 0L),
0) != 0L) goto error;
}
if (id.flags & NO_REWIND) return;
if (longrewind() == ASPI_SUCCESS) return;
error:
(void)fprintf(stderr, "Tar: %s\n", aspierrmsg(aspierrno));
}
#endif