home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1993 #2
/
Image.iso
/
os2
/
gtak212b.zip
/
SOURCE.ZIP
/
OS2-ADD
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-12-03
|
16KB
|
685 lines
/*****************************************************************************
* $Id: main.c,v 1.4 1992/12/02 23:58:56 ak Exp $
*****************************************************************************
* $Log: main.c,v $
* Revision 1.4 1992/12/02 23:58:56 ak
* Display trace info when unit is locked by other driver.
*
* Revision 1.3 1992/09/29 09:35:14 ak
* Must allow multiple DrvOpen calls. dup() seems to reopen the driver.
*
* Revision 1.2 1992/09/26 19:29:12 ak
* IOCtlTrace fixed.
*
* Revision 1.1.1.1 1992/09/02 18:58:27 ak
* Initial checkin of OS/2 ADD based SCSI tape device driver.
*
* Revision 1.1 1992/09/02 18:58:25 ak
* Initial revision
*
*****************************************************************************/
static char _far rcsid[] = "$Id: main.c,v 1.4 1992/12/02 23:58:56 ak Exp $";
#include "addtape.h"
#include "tapedrvr.h"
#ifdef __ZTC__
#include <ztc.h>
#else
#include <memory.h>
#endif
#include <string.h>
#define packError(x) ((x) >> 4 & 0xF0 | (x) & 0x0F)
farptr _far _loadds
post(farptr iorb)
{
PUTS(4, " POST\n");
Run((dword)reqpkt);
return iorb;
}
/*
* Abort current operation.
*/
void
abort(void)
{
IORB_DEVICE_CONTROL *iorb = (IORB_DEVICE_CONTROL *)iorb2;
if (!(iorb->iorbh.Status & IORB_DONE))
return;
iorb->iorbh.Length = sizeof(IORB_DEVICE_CONTROL);
iorb->iorbh.UnitHandle = unitinfo->UnitHandle;
iorb->iorbh.CommandCode = IOCC_DEVICE_CONTROL;
iorb->iorbh.CommandModifier = IOCM_ABORT;
iorb->iorbh.RequestControl = IORB_DISABLE_RETRY;
iorb->iorbh.Status = 0;
iorb->iorbh.Timeout = -1;
iorb->Flags = 0;
callADD(&iorb->iorbh);
}
/*
* Call ADD. Wait until done.
*/
void
callADDwait(IORBH *iorb)
{
iorb->RequestControl |= IORB_ASYNC_POST;
iorb->NotifyAddress = post;
callADD(iorb);
int_off();
while (!(iorb->Status & IORB_DONE)) {
PUTS(4, " Waiting for POST\n");
if (Block((dword)reqpkt, Infinite, 1)) {
PUTS(1, "Abort\n");
abort();
continue;
}
int_off();
}
int_on();
}
/*
* Get IORB. Wait until available.
* -> errcode if interrupted.
*/
word
getIORB(ReqPtr p)
{
int_off();
while (reqpkt) {
PUTS(4, " Waiting for IORB\n");
++waiting;
if (Block(paddr_iorb1, Infinite, 1))
return ERROR+DONE+Interrupted;
int_off();
}
int_on();
reqpkt = p;
return 0;
}
/*
* Release IORB.
* Wakeup threads waiting.
*/
void
relIORB(void)
{
reqpkt = 0;
if (waiting) {
waiting = 0;
Run(paddr_iorb1);
}
}
#ifdef DEBUG
void
dump(byte _far *p, int n)
{
int i;
for (i = 0; i < n; ++i) {
putc(' ');
putx(p[i]);
}
}
void
result(IORBH *iorb)
{
puts("\tIORB Status ");
putx(iorb->Status);
puts(", ErrorCode ");
putx(iorb->ErrorCode);
if (iorb->Status & IORB_STATUSBLOCK_AVAIL) {
puts("\n\t status:");
dump((farptr)&status, SizeofStatus);
if (status.sense_len && status.sense_ptr) {
puts("\n\t sense:");
dump(status.sense_ptr, 18);
}
}
putc('\n');
}
#endif
word
mapIORBerror(word errcode)
{
switch (errcode & ~IOERR_RETRY) {
case IOERR_CMD_NOT_SUPPORTED:
case IOERR_CMD_SYNTAX:
return ERROR+DONE+InvalidCommand;
case IOERR_CMD_ABORTED:
return ERROR+DONE+Interrupted;
case IOERR_UNIT_NOT_ALLOCATED:
case IOERR_UNIT_NOT_READY:
case IOERR_UNIT_PWR_OFF:
case IOERR_ADAPTER_TIMEOUT:
case IOERR_ADAPTER_DEVICE_TIMEOUT:
case IOERR_MEDIA_NOT_PRESENT:
return ERROR+DONE+DeviceNotReady;
case IOERR_RBA_LIMIT:
return ERROR+DONE+WriteFault;
case IOERR_RBA_CRC_ERROR:
return ERROR+DONE+CRCError;
case IOERR_MEDIA_WRITE_PROTECT:
return ERROR+DONE+WriteProtected;
case IOERR_MEDIA_NOT_FORMATTED:
case IOERR_MEDIA_NOT_SUPPORTED:
return ERROR+DONE+UnknownMedia;
case IOERR_MEDIA_CHANGED:
return ERROR+DONE+ChangeDisk;
default:
return ERROR+DONE+GeneralFailure;
}
}
word
rw(ReqPtr p, word flags)
{
word rc;
dword count, nb;
IORB_ADAPTER_PASSTHRU *iorb = (IORB_ADAPTER_PASSTHRU *)iorb1;
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 = getIORB(p)) != 0)
return rc;
cdb[0] = (flags & PT_DIRECTION_IN) ? SeqRead : SeqWrite;
cdb[1] = blocksize ? 1 : 0;
cdb[2] = nb >> 16;
cdb[3] = nb >> 8;
cdb[4] = nb;
cdb[5] = 0;
sglist[0].ppXferBuf = p->u.rw.addr;
sglist[0].XferBufLen = count;
memset(&status, 0, SizeofStatus);
status.sense_len = sizeof sense;
status.sense_ptr = sense;
iorb->iorbh.Length = sizeof(IORB_ADAPTER_PASSTHRU);
iorb->iorbh.UnitHandle = unitinfo->UnitHandle;
iorb->iorbh.CommandCode = IOCC_ADAPTER_PASSTHRU;
iorb->iorbh.CommandModifier = IOCM_EXECUTE_CDB;
iorb->iorbh.RequestControl = IORB_DISABLE_RETRY+IORB_REQ_STATUSBLOCK;
iorb->iorbh.StatusBlockLen = SizeofStatus;
iorb->iorbh.pStatusBlock = (nearptr)&status;
iorb->iorbh.Status = 0;
iorb->iorbh.Timeout = -1;
iorb->cSGList = 1;
iorb->pSGList = sglist;
iorb->ppSGList = paddr_sglist;
iorb->ControllerCmdLen = 6;
iorb->pControllerCmd = cdb;
iorb->Flags = flags;
#ifdef DEBUG
if (trace >= 3) {
puts(" R/W CDB:");
dump(cdb, 6);
putc('\n');
}
#endif
callADDwait(&iorb->iorbh);
#ifdef DEBUG
if (trace && iorb->iorbh.Status & ERROR || trace >= 3)
result(&iorb->iorbh);
#endif
relIORB();
p->u.rw.count = blocksize ? nb * blocksize : nb;
if (iorb->iorbh.Status & IORB_STATUSBLOCK_AVAIL
&& status.sense_len && status.sense_ptr) {
if (sense[2] & (FM|EOM)) {
PUTS(4, " EOF\n");
stickyEOF = 1;
}
if (sense[0] & VADD) {
dword info = 0;
for (rc = 3; rc <= 6; ++rc) {
info <<= 8;
info |= sense[rc];
}
switch (blocksize) {
case 512:
info <<= 9;
break;
case 1024:
info <<= 10;
break;
default:
info *= blocksize;
case 0: ;
}
p->u.rw.count -= info;
PUTS(4, " result count=");
PUTD(4, p->u.rw.count);
PUTC(4, '\n');
}
rc = 1;
} else
rc = 0;
if (!(iorb->iorbh.Status & IORB_ERROR))
return DONE;
if (!rc)
return mapIORBerror(iorb->iorbh.ErrorCode);
if (senseMode == Sensekey) {
switch (sense[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 ((sense[0] & ~0x81) != 0x70)
rc = sense[0];
else
switch (senseMode) {
case TDC3600:
rc = sense[14];
break;
default:
rc = sense[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)
{
IORB_UNIT_CONTROL *iorb = (IORB_UNIT_CONTROL *)iorb1;
if (!callADD) {
word rc = startup();
if (rc != DONE)
return rc;
}
PUTS(3, "Open\n");
if (open_count) {
++open_count;
return DONE;
}
iorb->iorbh.Length = sizeof(IORB_UNIT_CONTROL);
iorb->iorbh.UnitHandle = unitinfo->UnitHandle;
iorb->iorbh.CommandCode = IOCC_UNIT_CONTROL;
iorb->iorbh.CommandModifier = IOCM_ALLOCATE_UNIT;
iorb->iorbh.RequestControl = IORB_DISABLE_RETRY;
iorb->iorbh.Status = 0;
iorb->iorbh.Timeout = -1;
iorb->Flags = 0;
callADDwait(&iorb->iorbh);
#ifdef DEBUG
if (trace && iorb->iorbh.Status & ERROR || trace >= 3)
result(&iorb->iorbh);
#endif
stickyEOF = 0;
if (iorb->iorbh.Status & IORB_ERROR) {
if (iorb->iorbh.ErrorCode != IOERR_UNIT_ALLOCATED)
return mapIORBerror(iorb->iorbh.ErrorCode);
PUTS(3, "Unit allocated by another driver\n");
return ERROR+DONE+DeviceNotReady;
}
PUTS(3, "Unit allocated\n");
open_count = 1;
return DONE;
}
word
DrvClose(ReqPtr p)
{
IORB_UNIT_CONTROL *iorb = (IORB_UNIT_CONTROL *)iorb1;
PUTS(3, "Close\n");
if (--open_count)
return DONE;
iorb->iorbh.Length = sizeof(IORB_UNIT_CONTROL);
iorb->iorbh.UnitHandle = unitinfo->UnitHandle;
iorb->iorbh.CommandCode = IOCC_UNIT_CONTROL;
iorb->iorbh.CommandModifier = IOCM_DEALLOCATE_UNIT;
iorb->iorbh.RequestControl = IORB_DISABLE_RETRY;
iorb->iorbh.Status = 0;
iorb->iorbh.Timeout = -1;
iorb->Flags = 0;
callADDwait(&iorb->iorbh);
#ifdef DEBUG
if (trace && iorb->iorbh.Status & ERROR || trace >= 3)
result(&iorb->iorbh);
#endif
if (iorb->iorbh.Status & ERROR)
return mapIORBerror(iorb->iorbh.ErrorCode);
PUTS(3, "Unit deallocated\n");
return DONE;
}
word
DrvRead(ReqPtr p)
{
PUTS(3, "Read\n");
return rw(p, PT_DIRECTION_IN);
}
word
DrvWrite(ReqPtr p, int vfy)
{
PUTS(3, "Write\n");
return rw(p, 0);
}
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:
{
IORB_DEVICE_CONTROL *iorb = (IORB_DEVICE_CONTROL *)iorb1;
PUTS(3, "IOCtl Reset\n");
senseValid = 0;
if ((rc = getIORB(p)) != 0)
return rc;
iorb->iorbh.Length = sizeof(IORB_DEVICE_CONTROL);
iorb->iorbh.UnitHandle = unitinfo->UnitHandle;
iorb->iorbh.CommandCode = IOCC_DEVICE_CONTROL;
iorb->iorbh.CommandModifier = IOCM_RESET;
iorb->iorbh.RequestControl = IORB_DISABLE_RETRY;
iorb->iorbh.Status = 0;
iorb->iorbh.Timeout = -1;
iorb->Flags = 0;
callADDwait(&iorb->iorbh);
relIORB();
if (iorb->iorbh.Status & ERROR)
return ERROR+DONE+packError(iorb->iorbh.ErrorCode);
return DONE;
}
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] = 3;
((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;
}
#ifdef DEBUG
if (trace >= 1) {
puts("Trace level ");
putd(trace);
putc('\n');
}
#endif
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 IOCtlRead+IOCtlSlow:
case IOCtlRead+IOCtlFast:
PUTS(3, "IOCtl Read\n");
read: flags = PT_DIRECTION_IN;
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 = 0;
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:
{ IORB_ADAPTER_PASSTHRU *iorb = (IORB_ADAPTER_PASSTHRU *)iorb1;
if (p->u.ioc.plen < 6 || p->u.ioc.plen > 12)
return ERROR+DONE+TapeInvalidParm;
if ((rc = getIORB(p)) != 0)
return rc;
_fmemcpy(cdb, p->u.ioc.parm, p->u.ioc.plen);
dataLock = Lock(Segment(p->u.ioc.data), LockShort);
sglist[0].ppXferBuf = VirtToPhys(p->u.ioc.data);
sglist[0].XferBufLen = p->u.ioc.dlen;
senseValid = 0;
memset(&status, 0, SizeofStatus);
status.sense_len = sizeof sense;
status.sense_ptr = sense;
iorb->iorbh.Length = sizeof(IORB_ADAPTER_PASSTHRU);
iorb->iorbh.UnitHandle = unitinfo->UnitHandle;
iorb->iorbh.CommandCode = IOCC_ADAPTER_PASSTHRU;
iorb->iorbh.CommandModifier = IOCM_EXECUTE_CDB;
iorb->iorbh.RequestControl = IORB_REQ_STATUSBLOCK + IORB_DISABLE_RETRY;
iorb->iorbh.StatusBlockLen = SizeofStatus;
iorb->iorbh.pStatusBlock = (nearptr)&status;
iorb->iorbh.Status = 0;
iorb->iorbh.Timeout = -1;
iorb->cSGList = 1;
iorb->pSGList = sglist;
iorb->ppSGList = paddr_sglist;
iorb->ControllerCmdLen = p->u.ioc.plen;
iorb->pControllerCmd = cdb;
iorb->Flags = flags;
#ifdef DEBUG
if (trace >= 3) {
puts(" CDB:");
dump(cdb, p->u.ioc.plen);
putc('\n');
}
#endif
callADDwait(&iorb->iorbh);
#ifdef DEBUG
if (trace && iorb->iorbh.Status & ERROR || trace >= 3)
result(&iorb->iorbh);
#endif
relIORB();
Unlock(dataLock);
if (iorb->iorbh.Status & IORB_STATUSBLOCK_AVAIL)
senseValid = 1;
if (iorb->iorbh.Status & IORB_ERROR)
return ERROR+DONE+packError(iorb->iorbh.ErrorCode);
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 > sizeof sense)
return ERROR+DONE+TapeInvalidData;
_fmemcpy((farptr)p->u.ioc.data, sense, p->u.ioc.dlen);
return DONE;
default:
return ERROR+DONE+TapeInvalidFcn;
}
}