home *** CD-ROM | disk | FTP | other *** search
- /**** BTNtape Handler for SCSI tape drives ****/
- /**** Author: Bob Rethemeyer (drBob@cup.portal.com) ****/
-
- #define VERSDATE "(03.14.94)" /* (DD.MM.YY) */
- #define VERSNAME "BTNtape-RAR 3.0 "
- /* (If you recompile BTN, ^^^ put your initials here!) */
-
- /*--------------------------------------------------------------------------
- * (c) Copyright 1990,1994 Robert Rethemeyer.
- * This software may be freely distributed and redistributed,
- * for non-commercial purposes, provided this notice is included.
- *--------------------------------------------------------------------------
- * BTNtape is an AmigaDOS device handler to make a simple DOS TAPE: device.
- * It converts DOS packets for the device into I/O requests to a
- * "SCSI-direct" compatible device driver. It is based on "my.handler"
- * by Phillip Lindsay and a SCSI-direct program by Robert Mitchell.
- * Seek() handling derived from code by Dennis J. Brueni, 8-24-91.
- * Source is ANSI C compliant. Compile with SAS/C v6.
- *
- * This handler works in conjunction with the accompanying TapeMon program.
- *--------------------------------------------------------------------------
- */
- #define _STRICT_ANSI
- #include <exec/types.h>
- #include <exec/nodes.h>
- #include <exec/lists.h>
- #include <exec/ports.h>
- #include <exec/tasks.h>
- #include <exec/libraries.h>
- #include <exec/io.h>
- #include <exec/memory.h>
- #include <devices/scsidisk.h>
- #include <intuition/intuition.h>
- #include <libraries/dos.h>
- #include <libraries/dosextens.h>
- #include <libraries/filehandler.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include "btn.h"
- #include "tplink.h"
-
- #include <proto/exec.h>
- #include <proto/intuition.h>
- #include <pragmas/exec_pragmas.h>
- #include <pragmas/intuition_pragmas.h>
-
- /* sense keys of interest */
- #define NOS 0x00 /* no sense */
- #define RCV 0x01 /* recovered error */
- #define ILL 0x05 /* illegal request */
- #define UAT 0x06 /* unit attention */
- #define BLC 0x08 /* blank check */
- #define VOF 0x0d /* volume overflow */
- /* pseudo sense keys returned by DoSense */
- #define FMK 0x10 /* filemark */
- #define EOM 0x11 /* end of tape */
- #define ILI 0x12 /* incorr leng */
- #define SERR 0x13 /* SCSI error */
-
- /*======== Global data */
-
- struct ExecBase *SysBase;
- struct IntuitionBase *IntuitionBase=NULL;
- UBYTE *cdb; /* pointer to SCSI command buffer */
- UBYTE *sns; /* pointer to sense data buffer */
- UBYTE *inq; /* pointer to inquiry data */
- struct SCSICmd *cmd; /* pointer to scsidirect command */
- struct IOStdReq *ior; /* pointer to io request structure*/
- UBYTE *TapeBuff[2]={NULL,NULL};/* pointers to 2 tape buffers */
- struct Process *myproc; /* ptr to handler's process struct*/
- struct DosPacket *mypkt; /* ptr to dos packet sent */
- struct tplink *linktp; /* pointer to link structure */
- struct MsgPort *monport=NULL; /* ptr to mon communication msg port */
- struct MsgPort *btnport; /* ptr to btn communication msg port */
- struct BTNmsg monmsg; /* message we will send to tapemon*/
- ULONG blknum; /* block number for io operation */
- ULONG blksize = 512; /* bytes per tape block */
- ULONG numblks = 1; /* number of blocks per io oper */
- ULONG TBSize; /* bytes in a tape buffer */
- ULONG rwlen; /* bytes in a tape read/write */
- ULONG rdlen; /* bytes/blks in a read */
- ULONG expect; /* expect num of bytes transferred*/
- ULONG bugmask = 0; /* 2090A bug circumvention */
- long filenum = -1; /* current file position on tape */
- long lastwrtn= -1; /* last filenum written */
- long actual; /* actual num of bytes transferred*/
- long res1; /* #bytes xfered packet return */
- long Boff; /* current offset in tape buffer */
- long tpsize ; /* tape size in blocks */
- long reserved = 0; /* number of reserved blks at BOT */
- int tapenum; /* tape volume number */
- BOOL inprog = FALSE; /* io operation in progress flag */
- BOOL reten = FALSE; /* retension-on-UAT flag */
- BOOL mbusy = FALSE; /* waiting for reply from tapemon */
- BOOL bswap = FALSE; /* swap-bytes flag */
- BOOL dbug = FALSE; /* print debug info */
- char *z; /* scratch */
- char *devname, nbuf[32]; /* file name reference from Open()*/
- char dbb[80]; /* buffer for monitor messages */
- UBYTE Lun = 0; /* Logical Unit number << 5 */
- UBYTE varblk = 0; /* variable-block flag for SEQ */
- UBYTE fixedbit = 0; /* fixed-block mode bit for SEQ */
- UBYTE versiontag[] = "$VER: " VERSNAME VERSDATE;
- char *cpywr = "(c) Copyright 1990-1994 R. Rethemeyer";
-
- /*********************** Main program ********************************/
- void _main(char *nu)
- {
- struct SCSICmd scsicmd; /* SCSIdirect command buffer */
- UBYTE snsarea[64]; /* sense data buffer */
- UBYTE cmdbuff[16]; /* SCSI command buffer */
- UBYTE inqdata[40]; /* inquiry data buffer */
- struct tplink tpl; /* structure to link hndlr & mon */
- struct DeviceNode *mynode; /* ptr to devnode passed in pkt Arg3 */
- struct MsgPort *mp; /* ptr to io message port */
- struct MsgPort *pktport; /* ptr to process message port */
- struct Message *m;
- struct BTNmsg *b;
- ULONG dvnode; /* ptr to devnode passed in pkt Arg3 */
- ULONG unit=99999; /* device SCSI unit address */
- ULONG bufmemtype=0; /* type of mem for dynamic buffers */
- ULONG gotopos=0; /* position to open at (blk/filemark)*/
- ULONG fmarks=1; /* # file marks for write/skip */
- ULONG pktsig; /* signal mask for process msg port */
- ULONG btnsig=0; /* signal mask for mon comm msg port */
- char *driver; /* name of SCSI device driver */
- UBYTE *dptr; /* ptr to next byte in dos buffer */
- long dflags=0; /* device flags */
- long iostat; /* status of previous read */
- long dcnt; /* count of dos packet bytes to move */
- long mcnt; /* count of bytes to move */
- long rcnt; /* count of bytes moved for read */
- long current; /* current byte position in file */
- long remain; /* bytes remaining in tape buffer */
- long pkcnt; /* flag to indicate data written */
- long x;
- int y=0;
- int opmode=0; /* how has the handler been opened */
- #define CLOSED 0 /* not doing anything */
- #define READING 1 /* reading tape */
- #define WRITING 2 /* writing tape */
- #define CURRPOS 3 /* read current file position */
- #define RAWMODE 4 /* raw command mode */
- #define UMODSEL 5 /* user mode select */
- int Bn; /* current buffer number, 0 or 1 */
- int position; /* how to position tape at Open */
- #define POSREW 0 /* rewind to beginning */
- #define POSNREW 1 /* don't move */
- #define POSAPP 2 /* append to eod (seq) */
- #define POSEND 3 /* append to eod (seq) */
- #define POSSKIP 4 /* skip to file/block */
- int nrflag=POSREW; /* rewind behavior of TAPE: */
- BOOL rewcl = FALSE; /* rewind-on-close flag */
- BOOL eject = FALSE; /* eject-on-close flag */
- BOOL dirty = FALSE; /* buffer has unwritten data in it */
- BOOL atend; /* flags filemark encountered */
- BOOL eot; /* flags end-of-tape encountered */
- BOOL rderr; /* flags error during read */
- BOOL errec = FALSE; /* attempt error recovery flag */
- BOOL aonly = FALSE; /* append-only flag */
- BOOL rdonly =FALSE; /* read-only flag */
- BOOL starting=FALSE;/* flag detects first open message */
- BOOL dos2=FALSE; /* indicates if later OS version */
- int Ctl=CTLIMM; /* Controls overlapped dos/scsi I/O */
- char *termn8 = " TERMINATE BTN ";
- char portname[32] = "BTN_";
- char monpname[32] = "TMON_";
-
- /*======== Startup */
-
- SysBase = *((struct ExecBase **) (4));
- IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
- myproc = (struct Process *) FindTask(0L); /* find this process */
- pktport= &myproc->pr_MsgPort;
- pktsig = 1L << pktport->mp_SigBit;
- WaitPort(pktport); /* wait for startup packet */
- m = GetMsg(pktport);
- mypkt = PKTADR(m);
- /* packet: Arg1=BSTR to name, Arg2=BSTR to startup string, Arg3=BPTR devnode*/
- mynode = (struct DeviceNode *) BADDR(mypkt->dp_Arg3);
- dvnode = (ULONG) mypkt->dp_Arg3;
-
- /*======== Create linkage block for tapemon.
- */
- tpl.cpyw = cpywr;
- tpl.version = "XXXXX " VERSNAME "(" __DATE__ ")";
- tpl.devnode = (void *)mynode;
- tpl.dbb = dbb;
- tpl.unit = &unit;
- tpl.Lun = &Lun;
- tpl.sense = NULL;
- tpl.badparm = FALSE;
- linktp = &tpl;
-
- /*======== Extract info from mountlist Startup parameter. It may be
- ======== enclosed in quotes, and each item is separated by a single '/'.
- ======== First item is always the driver name, others may be in any order.
- */
- z = (char *)BADDR(mypkt->dp_Arg2)+1 ; /* Arg2= BSTR to mountlist 'Startup'*/
- if(*z=='\"') { /* remove quotes if any */
- z++;
- z[strlen(z)-1]= '\0' ;
- }
- driver = tpl.driver = z;
- for(; *z != '/'; z++);
- *(z++) = '\0';
- toUPPER(z);
- while (y!=100) {
- switch(y=getstart(&x)) {
- case 0: /* UN */ unit = (ULONG) x; break;
- case 1: /* BS */ blksize = (ULONG) x; break;
- case 2: /* NB */ numblks = (ULONG) x; break;
- case 3: /* RB */ reserved = x; break;
- case 4: /* BT */ bufmemtype = (ULONG) x; break;
- case 5: /* FM */ fmarks = x & 0xff; break;
- case 6: /* ER */ errec = (x!=0); break;
- case 7: /* OV */ if(!x) Ctl = CTLWAIT; break;
- case 8: /* DF */ dflags = x; break;
- case 9: /* C9 */ if(x) bugmask = 0x01000000; break;
- case 10: /* NR */ nrflag = x ? POSNREW : POSREW; break;
- case 11: /* RT */ reten = (x!=0); break;
- case 12: /* RC */ rewcl = (x!=0); break;
- case 13: /* EC */ eject = (x!=0); break;
- case 14: /* SW */ bswap = (x!=0); break;
- case 15: /* RO */ rdonly= (x!=0); break;
- case 16: /* AO */ aonly = (x!=0); break;
- case 17: /* MR */ starting = (x!=0); break;
- case 18: /* DB */ dbug = (x!=0); break;
- /***case -: * VB * if(x) varblk = 1; break; sorry, vb mode disabled */
- case 99: /* ?? */ tpl.badparm = TRUE; break;
- default: ;
- }
- }
- Lun = (UBYTE) unit; Lun = ((Lun/10-(Lun/100)*10) & 7) << 5;
- rwlen = TBSize = numblks * blksize; /* size of a tape buffer */
-
- cdb = cmdbuff;
- sns = snsarea;
- inq = tpl.inquiry = inqdata;
- cmd = &scsicmd;
- ior = (struct IOStdReq *) CreateExtIO( mp=CreatePort(NULL,0),
- sizeof(struct IOStdReq));
-
- /*======== Open the SCSIdirect device */
-
- if ( OpenDevice(driver,unit,(struct IORequest *)ior,dflags) ) {
- ask("Can't open SCSI-direct",termn8,NULL);
- LEAVE:
- returnpkt(DOSFALSE,ERROR_INVALID_COMPONENT_NAME);
- if(ior) DeleteExtIO((struct IORequest *)ior);
- if(mp) DeletePort(mp);
- CloseLibrary((struct Library *)IntuitionBase);
- return;
- }
-
- /*======== Create the port that TapeMon will
- ======== use to acknowledge Mprintf() requests.
- */
- if( btnport = CreatePort(
- strcat(portname,myproc->pr_Task.tc_Node.ln_Name), 0) )
- {
- btnsig = 1L << btnport->mp_SigBit;
- monmsg.bmsg.mn_ReplyPort = btnport;
-
- /*======== If TapeMon is already running, send it a wakeup message. */
- Forbid();
- if(monport = FindPort(strcat(monpname,myproc->pr_Task.tc_Node.ln_Name)) )
- PutMsg(monport,&monmsg.bmsg);
- Permit();
- if(monport) { WaitPort(btnport); GetMsg(btnport); }
- monport = NULL;
- }
-
- /*======= Find the SCSI device type by INQUIRY. Sequential or direct access?
- */
- if(x=TapeIO(INQUIRY,0,CTLWAIT)) {
- if(x <= HFERR_SelTimeout) {
- ask("Can't select tape drive",termn8,NULL);
- goto LEAVE;
- }
- TapeIO(TSENSE,0,CTLWAIT);
- inq[0] = 0x01; /* assume SEQ */
- inq[8] = 0;
- }
- inq[36] = 0; /* null-terminate vendor info */
- if(SEQ) {
- reserved = 0;
- fixedbit = varblk ^ 0x01; /* fixed or variable block mode */
- rdlen = (fixedbit) ? numblks : TBSize;
- }
- else if(DAC) rdlen = numblks;
- else { ask("UNit is not a tape drive",termn8,NULL); goto LEAVE; }
-
- mynode->dn_Task = &myproc->pr_MsgPort; /* install handler taskid */
- returnpkt(DOSTRUE,0); /* reply to initial packet */
-
- /* =========== The main packet processing loop =============== */
-
- for(;;) {
- if( m = GetMsg(pktport) ) /* Check for packet from DOS */
- mypkt = PKTADR(m);
- else if( m = GetMsg(btnport) ) { /* Check for message from TapeMon */
- if(m->mn_Node.ln_Type == NT_MESSAGE) {
- b = (struct BTNmsg *)m;
- /* Tapemon will send addr of port if it is starting up,
- or NULL if it is shutting down. */
- if(monport && b->mptr) b->mptr = NULL; /* reject extra TapeMon */
- else { monport = b->mptr; b->mptr = linktp; }
- ReplyMsg(m);
- if(!monport) mbusy=FALSE;
- }
- else /*NT_REPLYMSG*/ mbusy=FALSE;
- continue;
- }
- else { /* Nothing to do but Wait() */
- Wait(pktsig | btnsig);
- continue;
- }
-
- #ifdef DBUG
- if(dbug) Mprintf("PACKET=%d %08X %08X %08X\n", mypkt->dp_Type,
- mypkt->dp_Arg1, mypkt->dp_Arg2, mypkt->dp_Arg3);
- #endif
-
- switch(mypkt->dp_Type) {
-
- case ACTION_FINDINPUT: /*----------- Open() ------------*/
- case ACTION_FINDOUTPUT:
- case ACTION_FINDUPDATE:
- if(opmode != CLOSED) {
- returnpkt(DOSFALSE,ERROR_OBJECT_IN_USE);
- Mprintf("Already open\n");
- break;
- }
-
- /* Determine open mode */
- z = (char *)BADDR(mypkt->dp_Arg3);
- x = (UBYTE)(*z);
- devname = (char *)memcpy(nbuf, z+1, x);
- *(devname+x) = '\0';
- toUPPER(devname);
- z = devname;
- if(strchr(devname,':')) while(*(z++)!=':'); /*thx Tero Manninen*/
- if (!strcmp(z,"RAWCMD")) opmode=RAWMODE;
- else if(!strcmp(z,"MODESEL")) opmode=UMODSEL;
- else if(!strcmp(z,"POS")) opmode=CURRPOS;
- else { /* normal read/write */
- opmode = (mypkt->dp_Type==ACTION_FINDINPUT) ? READING : WRITING;
- if (!strcmp(z,"*")) position=POSNREW; /* current position */
- else if(!strcmp(z,"NR")) position=POSNREW; /* current position */
- else if(!strcmp(z,"R")) position=POSREW; /* beginning of tape */
- else if(!strcmp(z,"APP")) position=POSAPP; /* append at end */
- else if(!strcmp(z,"END")) position=POSEND; /* append at end,slow*/
- else if(*z>='0' && *z<='9') { /* specific position */
- gotopos = strtoul(z,NULL,0);
- position=POSSKIP;
- }
- else if(*z=='\0') position = nrflag; /* TAPE: */
- else goto BADNAME;
- }
-
- if(starting) goto FASTOPEN; /* skip stuff on first open from mount */
-
- /* detect illegal combinations */
- if((opmode>=RAWMODE && mypkt->dp_Type==ACTION_FINDINPUT)
- || (opmode==CURRPOS && mypkt->dp_Type!=ACTION_FINDINPUT)
- || (opmode==READING && (position==POSAPP||position==POSEND))
- || (SEQ && opmode==WRITING && position==POSSKIP)
- || (DAC && (position==POSEND||position==POSAPP)) )
- { BADNAME:
- Mprintf("Invalid open name/combo %s\n",devname);
- NOOPEN:
- freestuff();
- opmode=CLOSED;
- returnpkt(DOSFALSE,ERROR_ACTION_NOT_KNOWN);
- break;
- }
- if(SEQ && aonly && opmode==WRITING) {
- if((position==POSNREW && lastwrtn>=0)
- || position==POSAPP
- || position==POSEND) ;
- else { Mprintf("%s is append-only\n",devname);
- goto NOOPEN; }
- }
- if(opmode==WRITING && rdonly) {
- Mprintf("%s is read-only\n",devname);
- goto NOOPEN;
- }
-
- /* Allocate storage for buffers */
- TapeBuff[0] = (UBYTE *) AllocMem(TBSize, bufmemtype | MEMF_CLEAR);
- TapeBuff[1] = (UBYTE *) AllocMem(TBSize, bufmemtype | MEMF_CLEAR);
- if (!TapeBuff[0] || !TapeBuff[1]) {
- freestuff();
- opmode=CLOSED;
- returnpkt(DOSFALSE,ERROR_NO_FREE_STORE);
- Mprintf("Can't get %lu bytes for tape buffers\n",TBSize*2);
- break;
- }
-
- if(opmode<=WRITING) {
-
- /* Check device ready */
- if(x=TapeIO(TREADY,0,CTLWAIT)) {
- y=DoSense(x);
- if(y==UAT) {
- blknum = filenum = reserved; lastwrtn = -1;
- if(reten) if(x=TapeIO(TRETEN,0,CTLWAIT)) DoSense(x);
- }
- else if(y==NOS) ;
- else if(y==ILL) ;
- else {
- GIVEUP:
- freestuff();
- opmode=CLOSED;
- filenum = lastwrtn = -1;
- returnpkt(DOSFALSE,ERROR_DEVICE_NOT_MOUNTED);
- break;
- }
- }
-
- /* Check write-prot, block length */
- if(x=TapeIO(MDSNS,0,CTLWAIT)) DoSense(x);
- else {
- if(opmode==WRITING && (sns[2] & 0x80)) {
- freestuff();
- opmode=CLOSED;
- returnpkt(DOSFALSE,ERROR_DISK_WRITE_PROTECTED);
- break;
- }
- if(sns[3] >= 8) {
- x = *((long *) &sns[8]) & 0x00ffffff; /* get block len */
- if(x != blksize) { /* set block size with Mode Select */
- Mprintf("Current block size = %lu\n",x);
- if(x=TapeIO(MDSET,varblk,CTLWAIT)) DoSense(x);
- else TapeIO(TSENSE,0,CTLWAIT);
- }
- }
- }
-
- /* position the medium at starting spot */
- if(position==POSNREW) gotopos=blknum;
- if(postape(position,fmarks,gotopos)) goto GIVEUP;
-
- /* Get capacity for 3M tape */
- if(DAC) {
- tpsize = 0x7fffffff;
- if(TapeIO(RDCAP,0,CTLWAIT)) TapeIO(TSENSE,0,CTLWAIT);
- else {
- tpsize = (((long)sns[2] << 8) | sns[3]) + 1;
- Mprintf("Capacity: %ld blocks\n", tpsize);
- }
- Mprintf("%s Opened at block %lu\n",devname,blknum);
- }
- else Mprintf("%s Opened at file %ld\n",devname,filenum);
- }
- FASTOPEN:
- dirty=FALSE; inprog=FALSE; Boff=0; pkcnt=0; tapenum=1;
- iostat=0; Bn=0; remain=TBSize; current=0; atend=eot=rderr=FALSE;
- returnpkt(DOSTRUE,0);
- break;
-
-
- case ACTION_END: /*----------- Close() -----------*/
- dcnt=DOSTRUE; mcnt=0; iostat=0;
- switch(opmode) {
- case WRITING:
- if(inprog) iostat = TapeIO(TFINISH,0,CTLWAIT);
- if(iostat) iostat = wrteot(Bn^1,1,iostat);
- if(iostat==0) {
- if(dirty) {
- memset(TapeBuff[Bn]+Boff,0,remain);
- iostat = TapeIO(TWRITE,Bn,CTLWAIT);
- }
- if(iostat) iostat = wrteot(Bn,0,iostat);
- }
- if(iostat) { dcnt=DOSFALSE; Mprintf("Error during write\n"); }
- else if(pkcnt) {
- blknum += actual; x=0;
- if(SEQ) {
- x=TapeIO(WFMARK,fmarks,CTLWAIT);
- lastwrtn = filenum++;
- } else filenum = blknum;
- if(x) DoSense(x);
- }
- break;
- case READING:
- if(inprog) iostat = TapeIO(TFINISH,0,CTLWAIT);
- if(iostat) { if(FMK==DoSense(iostat)) atend=TRUE; }
- if(DAC) filenum = blknum;
- else filenum = atend ? filenum+1 : -1 ;
- lastwrtn = -1;
- break;
- case RAWMODE:
- if(x=TapeIO(RAWCMD,Bn,CTLWAIT)) DoSense(x); break;
- case UMODSEL:
- if(x=TapeIO(USRMODE,Bn,CTLWAIT)) DoSense(x); break;
- case CLOSED:
- dcnt=DOSFALSE; mcnt=ERROR_ACTION_NOT_KNOWN; break;
- case CURRPOS: break;
- }
- returnpkt(dcnt,mcnt);
- freestuff();
- if(starting) starting=FALSE;
- else if(opmode<=WRITING) {
- Mprintf("Closed at block %lu, next file= %ld\n\n",
- blknum,filenum);
- if(rewcl) if(x=(TapeIO(TREWIND,0,CTLWAIT))) DoSense(x);
- if(eject) if(x=(TapeIO(TEJECT,0,CTLWAIT))) DoSense(x);
- }
- opmode=CLOSED;
- break;
-
- case ACTION_READ: /*------- Read(), Seek() --------*/
- case ACTION_SEEK:
- if(opmode!=READING && opmode!=CURRPOS) {
- Mprintf("Function/mode error\n");
- res1 = -1;
- goto RDEND;
- }
- if(opmode==CURRPOS && !atend) { /* reading file position */
- remain = 1 + sprintf(TapeBuff[Bn],"%ld",filenum);
- dirty=atend=TRUE;
- }
- if(mypkt->dp_Type == ACTION_READ) {
- dptr = (UBYTE *) mypkt->dp_Arg2;
- dcnt = res1 = mypkt->dp_Arg3;
- rcnt = 0;
- }
- else { /* ACTION_SEEK */
- if(opmode==CURRPOS) goto BADSEEK;
- rcnt = -1;
- dcnt = mypkt->dp_Arg2; /* offset */
- x = mypkt->dp_Arg3; /* type */
- if(atend || eot || varblk) goto BADSEEK;
- if(x==OFFSET_END) goto BADSEEK;
- if(x==OFFSET_BEGINNING) dcnt -= current;
- /* x==OFFSET_CURRENT, dcnt is correct */
- res1 = current;
- if(dcnt<0) { /* backwards seek, must be to BOF */
- if((dcnt+current)==0) {
- if(SEQ && position == POSNREW) goto BADSEEK;
- if((dcnt+Boff)<0) { /* still in buffer? */
- if(inprog) TapeIO(TFINISH,0,CTLWAIT);
- if(postape(position,fmarks,gotopos)) goto BADSEEK;
- dirty=FALSE; Bn=0;
- }
- current=0; dcnt=0; Boff=0; remain=TBSize;
- }
- else {
- BADSEEK:
- Mprintf("Disallowed seek type=%ld off=%ld curr=%ld\n",
- x,dcnt,current);
- res1 = -1;
- goto RDEND;
- }
- }
- }
- while(dcnt) {
- if(!dirty) { /* need to prefetch first buffer */
- iostat = TapeIO(TREAD,Bn,CTLWAIT);
- remain=0; Bn=1; dirty=TRUE;
- }
- if(remain==0) { /* current buffer exhausted */
- if(rderr) {
- Mprintf("Error during read\n");
- if(errec)
- if(ask(" Ignore READ ERROR?", "IGNORE", "FAIL"))
- rderr=FALSE;
- if(rderr) { res1 = -1; goto RDEND; }
- }
- if(eot) { /* end-of-tape */
- TapeIO(TREWIND,0,CTLWAIT);
- if(NewTape()) {
- iostat=TapeIO(TREAD,(Bn^1),CTLWAIT);
- eot=atend=FALSE;
- }
- else atend=TRUE;
- }
- if(atend) { res1 = rcnt; goto RDEND; }
- if(inprog) iostat = TapeIO(TFINISH,0,CTLWAIT);
- if(iostat) /* check status of previous read */
- switch(DoSense(iostat)) {
- case EOM: eot=TRUE; /* & fall thru */
- case FMK: atend=TRUE; /* & fall thru */
- case RCV: break;
- default: rderr=TRUE;
- }
- remain = actual;
- blknum += actual/blksize; /* numblks; */
- if(!(atend || eot || rderr)) /* start refilling this buffer */
- iostat = TapeIO(TREAD,Bn,Ctl);
- Bn ^= 1; /* switch to other (full) buffer */
- Boff = 0;
- if(bswap) swapbytes(TapeBuff[Bn]);
- }
- mcnt = (dcnt>remain) ? remain : dcnt;
- if(mypkt->dp_Type == ACTION_READ) {
- memcpy (dptr, TapeBuff[Bn]+Boff, mcnt);
- rcnt += mcnt ;
- }
- dcnt -= mcnt ;
- Boff += mcnt ;
- dptr += mcnt ;
- current += mcnt;
- remain -= mcnt ;
- }
- RDEND:
- returnpkt(res1,0);
- break;
-
-
- case ACTION_WRITE: /*----------- Write() -----------*/
- if(opmode < WRITING) {
- Mprintf("Function/mode error\n");
- res1 = -1;
- goto WRTEND;
- }
- pkcnt++;
- dptr = (UBYTE *) mypkt->dp_Arg2;
- dcnt = res1 = mypkt->dp_Arg3;
- while (dcnt) {
- if(dcnt >= remain) {
- memcpy (TapeBuff[Bn]+Boff, dptr, remain);
- if(inprog) iostat = TapeIO(TFINISH,0,CTLWAIT);
- if(iostat) /* check status of previous write */
- if(iostat = wrteot(Bn^1,1,iostat)) { /* possible EOT */
- Mprintf("Error during write\n");
- if(errec)
- if(ask(" Ignore WRITE ERROR?", "IGNORE", "FAIL"))
- iostat=0;
- if(iostat) {
- res1 = -1;
- iostat=0; dirty=FALSE; pkcnt=0;
- goto WRTEND;
- }
- }
- Boff += remain;
- iostat = TapeIO(TWRITE,Bn,Ctl); /* start writing full buffer */
- blknum += actual;
- dcnt -= remain;
- dptr += remain;
- Boff = 0;
- remain= TBSize;
- Bn ^= 1; /* switch to other (empty) buffer */
- dirty = FALSE;
- }
- else {
- memcpy (TapeBuff[Bn]+Boff, dptr, dcnt);
- remain -= dcnt;
- Boff += dcnt;
- dcnt = 0;
- dirty = TRUE;
- }
- }
- WRTEND:
- returnpkt(res1,0);
- break;
-
-
- case ACTION_IS_FILESYSTEM: /* DOS 2+ only */
- dos2 = TRUE;
- returnpkt(DOSFALSE,0);
- break;
-
- case ACTION_CURRENT_VOLUME:
- returnpkt(dvnode,0);
- break;
-
- case ACTION_FLUSH: /* flush buffers, NOOP */
- returnpkt(DOSTRUE,0);
- break;
-
- case ACTION_LOCATE_OBJECT: /* lock */
- if(dos2) returnpkt(DOSFALSE,ERROR_ACTION_NOT_KNOWN);
- else returnpkt(mypkt->dp_Arg1,0);
- break;
-
- case ACTION_FREE_LOCK: /* unlock */
- if(dos2) returnpkt(DOSFALSE,ERROR_ACTION_NOT_KNOWN);
- else returnpkt(DOSTRUE,0);
- break;
-
- case ACTION_SET_PROTECT: /* SetProtection */
- case ACTION_DISK_INFO: /* info */
- returnpkt(DOSFALSE,ERROR_ACTION_NOT_KNOWN);
- break;
-
- default: /* others not supported */
- returnpkt(DOSFALSE,ERROR_ACTION_NOT_KNOWN);
- Mprintf("Unsupported_Pkt=%ld\n",mypkt->dp_Type);
-
- } /* end of switch */
- } /* end of loop */
- } /* end of _main() */
-
- /**************************************************************************/
-
- int DoSense(long iocode)
- {
- UBYTE snskey;
- static char *snstext[] = {
- "NONE" , "RECOVERED ERROR", "NOT READY", "MEDIUM ERROR",
- "HARDWARE ERROR", "ILLEGAL REQUEST", "UNIT ATTENTION", "DATA PROTECT",
- "BLANK CHECK", "KEY=9", "COPY ABORTED", "ABORTED COMMAND", "KEY=C",
- "VOLUME OVERFLOW", "KEY=E", "KEY=F", "FILEMARK", "END-OF-MEDIUM",
- "INCORRECT BLOCK LENGTH"
- };
- static char *sderror[] = {
- "SELF-UNIT", "DMA", "PHASE", "PARITY", "SELECT-TIMEOUT", "BADSTATUS"
- };
-
- if(iocode==0 || iocode==HFERR_BadStatus) {
- TapeIO(TSENSE,0,CTLWAIT);
- if((sns[0] & 0x70)==0x70) { /* extended */
- snskey = sns[2] & 0x0f; /* real sense key */
- if(snskey==0) { /* pseudo sense keys */
- if(sns[2] & 0x20) snskey = ILI;
- if(sns[2] & 0x80) snskey = FMK;
- if(sns[2] & 0x40) snskey = EOM;
- }
- }
- else snskey = sns[0] & 0x0f; /* non-extended */
- linktp->sense = snstext[snskey]; /* keep last error info */
- linktp->xsns1 = sns[12];
- linktp->xsns2 = sns[13];
- linktp->sns = sns; /* flag for tapemon to print all data */
- Mprintf("Sense: %s, other= %02X,%02X\n", snstext[snskey], sns[12],sns[13]);
- linktp->sns = NULL;
- return((int)snskey);
- }
- else if(iocode==FAKEOM) return(EOM); /* DAC only */
- else {
- if(iocode>=40 && iocode<=45)
- Mprintf("SCSI %s ERROR\n",sderror[iocode-40]);
- else Mprintf("SCSI DRIVER ERROR CODE %lu\n",iocode);
- return(SERR);
- }
- }
-
- /**************************************************************************/
- /* postape(): position the tape medium at the place we want to open it
- */
-
- int postape(int how, int fm, long where)
- {
- long x; int y=0; BOOL slow=TRUE;
- switch(how) {
- case POSNREW: /* TAPE:* */
- if(filenum>=0) {
- if(SEQ) blknum = 0;
- break;
- } /* else pos unknown, fall thru and rewind */
- case POSREW: /* TAPE: */
- if(x=TapeIO(TREWIND,0,CTLWAIT)) y=DoSense(x);
- blknum = reserved;
- break;
- case POSAPP: /* TAPE:APP */
- if(x=TapeIO(TSKIPE,0,CTLWAIT)) y=DoSense(x);
- if(lastwrtn<0) filenum = -1;
- slow=FALSE; /* & fall thru */
- case POSEND: /* TAPE:END */
- if((slow && lastwrtn<0) || y==ILL) {
- /* drive doesn't support skip-eod, or tape:end */
- y=0;
- if(!slow) Mprintf("(doing it the hard way)\n");
- if(x=TapeIO(TREWIND,0,CTLWAIT)) DoSense(x);
- while(y==0) { /* skip files until we hit a blank spot */
- Mprintf("Skipping over file %ld\n",filenum);
- if(x=TapeIO(TSKIPF,fm,CTLWAIT)) y=DoSense(x);
- if(y==FMK) y=0;
- filenum++;
- }
- if(y==BLC) { y=0; filenum--; }
- }
- blknum = 0;
- break;
- case POSSKIP: /* TAPE:n */
- if(DAC) blknum = where;
- else { /* SEQ */
- if(x=TapeIO(TREWIND,0,CTLWAIT)) { y=DoSense(x); break; }
- if(fm==0) break;
- Mprintf("Skipping to file %ld\n",where);
- if(x=TapeIO(TSKIPF,where*fm,CTLWAIT)) y=DoSense(x);
- if(y==FMK) y=0;
- blknum = 0;
- }
- filenum = where;
- lastwrtn = -1;
- break;
- }
- if(y) Mprintf("Unable to position tape\n");
- return(y);
- }
-
- /**************************************************************************/
- /* wrteot: handle messiness that happens when writing at end of tape.
- Returns non-zero status if not EOT or tape swap unsuccessful. */
-
- long wrteot(int bfn, int dec, long stat)
- {
- extern long actual;
- long saveboff, nn;
- long residue=0;
- long ios = stat;
- int s = DoSense(ios);
- if(s==EOM || s==VOF) { /* EOT? */
- if(s==VOF && (sns[0]&0xF0)==0xF0) residue = ((long)sns[5]<<8) + sns[6];
- if(residue) Mprintf("Holding %ld unwritten blocks\n",residue);
- if(residue>numblks) { Mprintf("OOPS, data lost!\n"); residue=0; }
- TapeIO(TREWIND,0,CTLWAIT);
- if(NewTape()) { /* ask for new tape */
- /* shift unwritten bytes to start of buffer and rewrite on new tape */
- if(residue) {
- nn = (numblks-residue)*blksize;
- saveboff = Boff;
- Boff = residue*blksize;
- if(nn) memmove(TapeBuff[bfn],TapeBuff[bfn]+nn,Boff);
- blknum = reserved;
- ios=TapeIO(TWRITE,bfn,CTLWAIT);
- if(ios) s=DoSense(ios);
- blknum += actual;
- Boff = saveboff;
- }
- else ios=0;
- }
- }
- if(s==RCV) ios=0; /* ignore recoveries */
- return(ios);
- }
-
- /**************************************************************************/
-
- void freestuff(void)
- {
- if(TapeBuff[0]) FreeMem(TapeBuff[0],TBSize);
- if(TapeBuff[1]) FreeMem(TapeBuff[1],TBSize);
- TapeBuff[0] = TapeBuff[1] = NULL;
- return;
- }
-
- /**************************************************************************/
- /* getstart:
- Given pointer (z) to a string of the form "SS-nn/..."
- returns a number corresponding to SS, the binary value of nn,
- and the pointer is updated to point after the slash.
- */
- int getstart(long *num)
- {
- extern char *z;
- #define NOTFND 99
- #define ENDLST 100
- #define NKEYS 19 /* number of keywords */
- static char *keys[NKEYS] =
- { "UN","BS","NB","RB","BT","FM","ER","OV","DF","C9",
- /* 0 1 2 3 4 5 6 7 8 9 */
-
- "NR","RT","RC","EC","SW","RO","AO","MR","DB"};
- /* 10 11 12 13 14 15 16 17 18 */
- char *ii, *jj; int kk;
-
- if (*z == '\0') return(ENDLST); /* return if end of string */
- for (ii=z; *ii != '-'; ii++); /* find the dash */
- for (jj=z; *jj != '/' && *jj !='\0'; jj++); /* find the slash */
- *ii = '\0'; *jj = '\0'; /* null-terminate name & number */
- *num = (long) strtoul (++ii,NULL,0); /* return converted number */
- ii = z; z = ++jj; /* update ptr to next item */
- for (kk=0; kk <= NKEYS; kk++) { /* search for keyword */
- if (*ii == *keys[kk] && *(ii+1) == *(keys[kk]+1) )
- return(kk); /* return index of keyword if found */
- }
- return(NOTFND); /* didn't find keyword */
- }
-
- /**************************************************************************
- Mprintf requests that the TapeMon program print the message in 'dbb'.
- Since this handler cannot do DOS I/O, it must beg the TapeMon program,
- possibly running in a CLI somewhere, to do the printf for it. If the
- TapeMon is running, it will have sent us a message containing the port
- pointer for TapeMon, so we can send messages to it.
- */
-
- void Mprintf(char *format, ...)
- {
- va_list ap;
-
- va_start(ap,format);
- if(monport) {
- if(mbusy) { /* still waiting for reply from tapemon? Wait.*/
- WaitPort(btnport);
- GetMsg(btnport);
- }
- vsprintf(linktp->dbb,format,ap);
- monmsg.mptr = linktp;
- PutMsg(monport,&monmsg.bmsg);
- mbusy=TRUE;
- }
- va_end(ap);
- return;
- }
-
- /**************************************************************************/
- /* toUPPER: convert string to upper case */
-
- void toUPPER(char *zz)
- {
- for(; *zz != '\0'; zz++) if(*zz >= 'a') *zz -= 0x20;
- return;
- }
-
- /**************************************************************************
- /* swapbytes: swap byte pairs */
-
- void swapbytes(char *zz)
- {
- char x;
- int n;
- long len = TBSize/2;
- for(n=0; n<len; n++) {
- x = *zz;
- *zz = *(zz+1);
- *(zz+1) = x;
- zz += 2;
- }
- return;
- }
-
- /**************************************************************************
- * NewTape() Handles transition to a new tape.
- */
-
- long NewTape(void)
- {
- long choice,s,t,v;
- static char rqm[40];
- Mprintf("Time to insert tape# %d\n",++tapenum);
- sprintf(rqm," Insert tape %d for %s",tapenum,devname);
- do {
- s=NOS;
- choice= ask(rqm," Continue ", " Quit ");
- if(choice)
- do {
- if(t=TapeIO(TREADY,0,CTLWAIT)) s=DoSense(t); /* eat unit-atten */
- else s=NOS;
- if(s==UAT && reten) if(v=TapeIO(TRETEN,0,CTLWAIT)) DoSense(v);
- } while(s==UAT);
- } while(s!=NOS);
- if(choice) {
- if(s=TapeIO(TREWIND,0,CTLWAIT)) DoSense(s);
- if(DAC) blknum=reserved; /* reset block number */
- }
- return(choice);
- }
-
- /**************************************************************************
- * ask() Displays a yes/no requester.
- */
-
- long ask(char *txt, char *yes, char *no)
- {
- #define ITXT { AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,AUTOLEFTEDGE, \
- AUTOTOPEDGE, AUTOITEXTFONT, NULL, NULL }
- static struct IntuiText rtxt[3] = { ITXT, ITXT, ITXT };
- if(!IntuitionBase) return(0);
- rtxt[0].IText = (UBYTE *) txt;
- rtxt[1].IText = (UBYTE *) yes;
- rtxt[2].IText = (UBYTE *) no;
- return(AutoRequest(NULL,&rtxt[0],&rtxt[1],&rtxt[2],NULL,NULL,300,50));
- }
-
-
- /**************************************************************************
- * returnpkt() - reply DOS packet.
- * Adapted from "misc.c" code by Phillip Lindsay (C) Commodore 1986
- */
-
- void returnpkt(ULONG res1, ULONG res2)
- {
- struct Message *mess;
- struct MsgPort *replyport;
-
- #ifdef DBUG
- if(dbug) Mprintf("REPLY %08X %08X\n", res1, res2);
- #endif
-
- mypkt->dp_Res1 = res1;
- mypkt->dp_Res2 = res2;
- replyport = mypkt->dp_Port;
- mess = mypkt->dp_Link;
- mypkt->dp_Port = &myproc->pr_MsgPort;
- mess->mn_Node.ln_Name = (char *) mypkt;
- mess->mn_Node.ln_Succ = NULL;
- mess->mn_Node.ln_Pred = NULL;
-
- PutMsg(replyport,mess);
- }
-
-