home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1993 #2
/
Image.iso
/
os2
/
gtak212b.zip
/
SOURCE.ZIP
/
OS2-ASPI
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-14
|
13KB
|
603 lines
/*****************************************************************************
* $Id: main.c,v 2.1 1992/11/14 21:00:20 ak Exp $
*****************************************************************************
* $Log: main.c,v $
* Revision 2.1 1992/11/14 21:00:20 ak
* OS/2 2.00.1 ASPI
*
* Revision 1.1.1.1 1992/01/06 20:16:27 ak
* Alpha version.
*
* Revision 1.1 1992/01/06 20:16:25 ak
* Initial revision
*
*****************************************************************************/
static char _far rcsid[] = "$Id: main.c,v 2.1 1992/11/14 21:00:20 ak Exp $";
#include "aspitape.h"
#include "tapedrvr.h"
#include <libx.h>
#include <ztc.h>
#define INCL_DOSDEVICES
#include <os2.h>
typedef void (_far *FcnPtr) (word, SRB _far *);
extern void _far postEntry (unsigned, unsigned long);
#define min(a,b) ((a) < (b) ? (a) : (b))
void
aspi(SRB *p)
{
if (aspiHandle)
DosDevIOCtl((PBYTE)0, (PBYTE)p, 0x40, 0x80, aspiHandle);
else if (inProtMode())
(*(FcnPtr)aspiEntry.prot)(aspiEntry.protDS, p);
else
(*(FcnPtr)aspiEntry.real)(aspiEntry.realDS, p);
}
void
post(dword paddrSRB)
{
PUTS(4, " POST\n");
Run((dword)reqpkt);
}
/*
* Issue Abort SRB command.
*/
static void
abort(dword paddr)
{
if (srb2.status == SRB_Busy)
return;
srb2.cmd = SRB_Abort;
srb2.ha_num = adapter;
srb2.flags = 0;
srb2.u.abt.phys_addr_srb = paddr;
aspi(&srb2);
}
/*
* Call ASPI. Wait until done.
*/
void
aspiWait(SRB *p)
{
srb.flags |= SRB_Post;
srb.u.cmd.realpost = Pointer(header.realCS, Offset((dword)postEntry));
srb.u.cmd.realDS = header.realDS;
srb.u.cmd.protpost = Pointer(header.protCS, Offset((dword)postEntry));
srb.u.cmd.protDS = header.protDS;
aspi(p);
int_off();
while (p->status == SRB_Busy || p->status == SRB_BusyPost) {
PUTS(4, " Waiting for POST\n");
if (Block((dword)reqpkt, Infinite, 1)) {
PUTS(1, "Abort\n");
abort(paddrSRB);
continue;
}
int_off();
}
int_on();
}
/*
* Get SRB. Wait until available.
* -> errcode if interrupted.
*/
word
getSRB(ReqPtr p)
{
int_off();
while (reqpkt) {
PUTS(4, " Waiting for SRB\n");
++waiting;
if (Block(paddrSRB, Infinite, 1))
return ERROR+DONE+Interrupted;
int_off();
}
int_on();
reqpkt = p;
return 0;
}
/*
* Release SRB.
* Wakeup threads waiting.
*/
void
relSRB(void)
{
reqpkt = 0;
if (waiting) {
waiting = 0;
Run(paddrSRB);
}
}
#ifdef DEBUG
static void
dump(byte _far *p, int n)
{
int i;
for (i = 0; i < n; ++i) {
putc(' ');
putx(p[i]);
}
}
static void
status(SRB *p)
{
puts(" ASPI status: ");
putx(p->status);
puts(", HA status: ");
putx(p->u.cmd.ha_status);
puts(", target status: ");
putx(p->u.cmd.target_status);
if (p->u.cmd.target_status == CheckStatus) {
puts(", sense data:\n\t");
dump(p->u.cmd.cdb_st + p->u.cmd.cdb_len,
min(p->u.cmd.sense_len, 16));
}
putc('\n');
}
#endif
static word
rw(ReqPtr p, byte flags)
{
word rc;
dword count, nb;
count = p->u.rw.count;
p->u.rw.count = 0;
if (stickyEOF) {
PUTS(4, " still EOF\n");
return DONE;
}
if (blocksize) {
dword rem;
switch (blocksize) {
case 512:
nb = count >> 9;
rem = count & 0x1FF;
break;
case 1024:
nb = count >> 10;
rem = count & 0x3FF;
break;
default:
nb = count / blocksize;
rem = count % blocksize;
}
if (rem)
return ERROR+DONE+InvalidParam;
} else
nb = count;
if ((rc = getSRB(p)) != 0)
return rc;
srb.cmd = SRB_Command;
srb.ha_num = adapter;
srb.flags = flags;
srb.u.cmd.target = target;
srb.u.cmd.lun = 0;
srb.u.cmd.data_len = count;
srb.u.cmd.sense_len = 20;
srb.u.cmd.data_ptr = p->u.rw.addr;
srb.u.cmd.phys_addr_srb = paddrSRB;
srb.u.cmd.cdb_len = 6;
srb.u.cmd.cdb_st[0] = flags & SRB_Read ? SeqRead : SeqWrite;
srb.u.cmd.cdb_st[1] = blocksize ? 1 : 0;
srb.u.cmd.cdb_st[2] = nb >> 16;
srb.u.cmd.cdb_st[3] = nb >> 8;
srb.u.cmd.cdb_st[4] = nb;
srb.u.cmd.cdb_st[5] = 0x00;
#ifdef DEBUG
if (trace >= 3) {
puts(" R/W CDB:");
dump(srb.u.cmd.cdb_st, 6);
putc('\n');
}
#endif
aspiWait(&srb);
#ifdef DEBUG
if (trace >= 3)
status(&srb);
#endif
relSRB();
switch (srb.status) {
case SRB_Done:
p->u.rw.count = count;
return DONE;
case SRB_Aborted:
return ERROR+DONE+Interrupted;
case SRB_Error:
break;
case SRB_InvalidHA:
case SRB_BadDevice:
return ERROR+DONE+DeviceNotReady;
default:
return ERROR+DONE+GeneralFailure;
}
switch (srb.u.cmd.ha_status) {
case 0x00: /* No host adapter detected error */
break;
case 0x11: /* Selection timeout */
return ERROR+DONE+DeviceNotReady;
default:
return ERROR+DONE+GeneralFailure;
}
switch (srb.u.cmd.target_status) {
case SRB_NoStatus:
p->u.rw.count = count;
return DONE;
case SRB_CheckStatus:
senseValid = 20;
break;
case SRB_LUN_Busy:
case SRB_Reserved:
return ERROR+DONE+DeviceNotReady;
default:
return ERROR+DONE+GeneralFailure;
}
#ifdef DEBUG
if (trace && trace < 3)
status(&srb);
#endif
if (srb.u.cmd.cdb_st[6+2] & VADD) {
dword info = 0;
for (rc = 6+3; rc <= 6+6; ++rc) {
info <<= 8;
info |= srb.u.cmd.cdb_st[rc];
}
switch (blocksize) {
case 512:
info <<= 9;
break;
case 1024:
info <<= 10;
break;
default:
info *= blocksize;
case 0: ;
}
p->u.rw.count = count - (info << 9);
PUTS(4, " result count=");
PUTD(4, p->u.rw.count);
PUTC(4, '\n');
} else
p->u.rw.count = count;
if (srb.u.cmd.cdb_st[6+2] & (FM|EOM)) {
PUTS(4, " EOF\n");
stickyEOF = 1;
}
if (senseMode == Sensekey) {
switch (srb.u.cmd.cdb_st[6+2] & 0x0F) {
case NoSense:
case BlankCheck:
return DONE;
case RecoveredData:
return ERROR+DONE+CRCError;
case NotReady:
case Hardware:
case UnitAttention:
return ERROR+DONE+DeviceNotReady;
case MediaError:
return ERROR+DONE+ReadFault;
case WriteProtected:
return ERROR+DONE+WriteProtect;
case MediaOverflow:
return ERROR+DONE+NoPaper;
case AbortedCommand:
return ERROR+DONE+Interrupted;
default:
return ERROR+DONE+GeneralFailure;
}
}
if ((srb.u.cmd.cdb_st[6+0] & ~0x81) != 0x70)
rc = srb.u.cmd.cdb_st[6+0];
else
switch (senseMode) {
case TDC3600:
rc = srb.u.cmd.cdb_st[6+14];
break;
default:
rc = srb.u.cmd.cdb_st[6+12];
}
switch (senseMode) {
case TDC3600:
switch (rc) {
case 0x00: /* ok */
return DONE;
case 0x02: /* hardware error */
case 0x04: /* not ready */
case 0x09: /* not loaded */
return ERROR+DONE+DeviceNotReady;
case 0x0A: /* insufficient capacity */
return ERROR+DONE+NoPaper;
case 0x11: /* uncorrectable data error */
return ERROR+DONE+ReadFault;
case 0x14: /* empty cartridge */
case 0x1C: /* file mark detected */
case 0x34: /* read EOM */
PUTS(4, " EOF\n");
stickyEOF = 1;
return DONE;
case 0x17: /* write protected */
return ERROR+DONE+WriteProtect;
case 0x19: /* bad block found */
return ERROR+DONE+WriteFault;
case 0x30:
return ERROR+DONE+ChangeDisk;
case 0x33: /* append error */
return ERROR+DONE+SeekError;
default:
return ERROR+DONE+GeneralFailure;
}
case SCSI2:
switch (rc) {
case 0x00: /* end-of-data */
case 0x14: /* end-of-data not found / filemark */
PUTS(4, " EOF\n");
stickyEOF = 1;
return DONE;
case 0x30: /* cannot read medium */
return ERROR+DONE+UnknownMedia;
case 0x52: /* cartridge fault */
case 0x05: /* selection failure */
case 0x40: /* device failure */
case 0x04: /* not ready */
case 0x25: /* LUN not supported */
case 0x3A: /* medium not present */
return ERROR+DONE+DeviceNotReady;
case 0x03: /* excessive write errors */
case 0x0C: /* write error */
return ERROR+DONE+WriteFault;
case 0x21: /* block address out of range */
case 0x15: /* positioning error */
case 0x50: /* write append error */
return ERROR+DONE+SeekError;
case 0x53: /* media load failed */
case 0x29: /* power-up or reset */
return ERROR+DONE+ChangeDisk;
case 0x31: /* media format corrupted */
case 0x11: /* read retries exhausted */
return ERROR+DONE+ReadFault;
case 0x17: /* recovered error */
return ERROR+DONE+CRCError;
case 0x27: /* write protected */
return ERROR+DONE+WriteProtect;
default:
return ERROR+DONE+GeneralFailure;
}
default:
return ERROR+DONE+GeneralFailure;
}
}
word
DrvOpen(ReqPtr p)
{
if (!inProtMode())
return ERROR+DONE+InvalidCommand;
senseValid = 0;
stickyEOF = 0;
return DONE;
}
word
DrvClose(ReqPtr p)
{
return DONE;
}
word
DrvRead(ReqPtr p)
{
return rw(p, SRB_Read);
}
word
DrvWrite(ReqPtr p, int vfy)
{
return rw(p, SRB_Write);
}
word
DrvIOCtl(ReqPtr p)
{
handle dataLock;
byte flags;
word rc;
if (p->u.ioc.cat < 0x80)
return ERROR+DONE+InvalidCommand;
if (p->u.ioc.cat != 0x80)
return ERROR+DONE+TapeInvalidFcn;
stickyEOF = 0;
switch (p->u.ioc.fcn) {
case IOCtlBusReset:
case IOCtlDevReset:
PUTS(3, "IOCtl Reset\n");
senseValid = 0;
if ((rc = getSRB(p)) != 0)
return rc;
srb.u.res.target = target;
srb.u.res.lun = 0;
aspiWait(&srb);
relSRB();
if (srb.status == SRB_Done)
return DONE;
if (srb.status & 0x80)
return ERROR+DONE+ErrASPIDriver1+(srb.status & 0x1F);
return ERROR+DONE+ErrASPIDriver2+(srb.status & 0x1F);
case IOCtlLevel:
PUTS(3, "IOCtl Level\n");
if (VerifyAccess(p->u.ioc.data, 2, VerifyWrite))
return ERROR+DONE+InvalidParam;
((byte _far *)p->u.ioc.data)[0] = ASPIdriver;
((byte _far *)p->u.ioc.data)[1] = senseMode;
return DONE;
case IOCtlTrace:
PUTS(3, "IOCtl Trace\n");
if (p->u.ioc.dlen >= 1) {
if (VerifyAccess(p->u.ioc.data, 1, VerifyWrite))
return ERROR+DONE+InvalidParam;
*(byte _far *)p->u.ioc.data = trace;
}
if (p->u.ioc.plen >= 1) {
if (VerifyAccess(p->u.ioc.parm, 1, VerifyRead))
return ERROR+DONE+InvalidParam;
trace = *(byte _far *)p->u.ioc.parm;
}
return DONE;
case IOCtlBlocksize:
PUTS(3, "IOCtl Blocksize\n");
if (p->u.ioc.dlen >= 4) {
if (VerifyAccess(p->u.ioc.data, 4, VerifyWrite))
return ERROR+DONE+InvalidParam;
*(dword _far *)p->u.ioc.data = blocksize;
}
if (p->u.ioc.plen >= 4) {
if (VerifyAccess(p->u.ioc.parm, 4, VerifyRead))
return ERROR+DONE+InvalidParam;
blocksize = *(dword _far *)p->u.ioc.data;
}
return DONE;
case IOCtlSlow:
case IOCtlFast:
PUTS(3, "IOCtl Unchecked Command\n");
flags = 0;
goto unchecked;
case IOCtlRead+IOCtlSlow:
case IOCtlRead+IOCtlFast:
PUTS(3, "IOCtl Read\n");
read: flags = SRB_Read;
unchecked:
if (VerifyAccess(p->u.ioc.parm, p->u.ioc.plen, VerifyRead))
return ERROR+DONE+TapeInvalidParm;
if (p->u.ioc.dlen
&& VerifyAccess(p->u.ioc.data, p->u.ioc.dlen, VerifyWrite))
return ERROR+DONE+TapeInvalidData;
goto checked;
case IOCtlWrite+IOCtlSlow:
case IOCtlWrite+IOCtlFast:
PUTS(3, "IOCtl Write\n");
flags = SRB_Write;
if (VerifyAccess(p->u.ioc.parm, p->u.ioc.plen, VerifyRead))
return ERROR+DONE+TapeInvalidParm;
if (p->u.ioc.dlen
&& VerifyAccess(p->u.ioc.data, p->u.ioc.dlen, VerifyRead))
return ERROR+DONE+TapeInvalidData;
checked:
if (p->u.ioc.plen < 6 || p->u.ioc.plen > 12)
return ERROR+DONE+TapeInvalidParm;
if ((rc = getSRB(p)) != 0)
return rc;
dataLock = Lock(Segment(p->u.ioc.data), LockShort);
senseValid = 0;
srb.cmd = SRB_Command;
srb.status = 0;
srb.ha_num = adapter;
srb.flags = flags;
srb.u.cmd.target = target;
srb.u.cmd.lun = 0;
srb.u.cmd.data_len = p->u.ioc.dlen;
#if SenseLength
srb.u.cmd.sense_len = SenseLength;
#else
srb.u.cmd.sense_len = MaxCDBStatus - p->u.ioc.plen;
#endif
if (p->u.ioc.dlen)
srb.u.cmd.data_ptr = VirtToPhys(p->u.ioc.data);
srb.u.cmd.phys_addr_srb = paddrSRB;
srb.u.cmd.cdb_len = p->u.ioc.plen;
_fmemcpy(srb.u.cmd.cdb_st, p->u.ioc.parm, p->u.ioc.plen);
#ifdef DEBUG
if (trace >= 3) {
puts(" CDB:");
dump(srb.u.cmd.cdb_st, srb.u.cmd.cdb_len);
putc('\n');
}
#endif
aspiWait(&srb);
#ifdef DEBUG
if (trace >= 3)
status(&srb);
#endif
relSRB();
Unlock(dataLock);
if (srb.u.cmd.target_status == CheckStatus)
senseValid = srb.u.cmd.sense_len;
if (srb.status != SRB_Done && srb.status != SRB_Error)
return ERROR+DONE
+(srb.status & 0x80 ? ErrASPIDriver2 : ErrASPIDriver1)
+(srb.status & 0x1F);
if (srb.u.cmd.ha_status)
return ERROR+DONE+ErrHostAdapter
+(srb.u.cmd.ha_status & 0x1F);
if (srb.u.cmd.target_status)
return ERROR+DONE+ErrTargetStatus
+(srb.u.cmd.target_status & 0x1F);
return DONE;
case IOCtlSense:
PUTS(3, "IOCtl Sense\n");
if (!senseValid) {
PUTS(3, " No sense data\n");
return ERROR+DONE+TapeNoSenseData;
}
PUTS(3, " Valid sense data\n");
if (p->u.ioc.dlen > senseValid)
return ERROR+DONE+TapeInvalidData;
_fmemcpy((farptr)p->u.ioc.data,
srb.u.cmd.cdb_st + srb.u.cmd.cdb_len,
p->u.ioc.dlen);
return DONE;
default:
return ERROR+DONE+TapeInvalidFcn;
}
}