home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 498b.lha / BTNtape_v2.0 / tape.c < prev    next >
C/C++ Source or Header  |  1991-04-08  |  25KB  |  661 lines

  1. /****     BTNtape Handler for SCSI tape drives        ****/
  2. /**** Author: Bob Rethemeyer  (DrBob@cup.portal.com)  ****/
  3.  
  4. #define TVERSION "-BTNTAPE V2.0 RAR-" ## __DATE__
  5.  
  6. /*  (c) Copyright 1990, 1991  Robert Rethemeyer.
  7.  *  This software may be freely distributed and redistributed,
  8.  *  for non-commercial purposes, provided this notice is included.
  9.  *-----------------------------------------------------------------------
  10.  *  BTNtape is an AmigaDOS device handler to make a simple DOS TAPE: device.
  11.  *  It converts DOS packets for the device into I/O requests to a
  12.  *  "SCSI-direct" compatible device driver.  It is based on "my.handler"
  13.  *  by Phillip Lindsay and a SCSI-direct program by Robert Mitchell.
  14.  *  Source is ANSI C compliant.  Compile with SAS/C v5 or Manx v5.
  15.  *
  16.  *  This handler works in conjunction with the accompanying TapeMon program.
  17.  *----------------------------------------------------------------------------
  18.  */
  19.  
  20. #include <exec/types.h>
  21. #include <exec/nodes.h>
  22. #include <exec/lists.h>
  23. #include <exec/ports.h>
  24. #include <exec/tasks.h>
  25. #include <exec/libraries.h>
  26. #include <exec/io.h>
  27. #include <exec/memory.h>
  28. #include <devices/scsidisk.h>
  29. #include <intuition/intuition.h>
  30. #include <libraries/dos.h>
  31. #include <libraries/dosextens.h>
  32. #include <libraries/filehandler.h>
  33. #include <stdio.h>
  34. #include <string.h>
  35.  
  36. #if defined AZTEC_C
  37.   #include <functions.h>
  38. /*#define strtoul strtol */
  39. #elif defined LATTICE
  40.   #include <proto/exec.h>
  41.   #include <proto/intuition.h>
  42. #endif
  43.  
  44. #include "tape.h"
  45. #include "tplink.h"
  46.  
  47. /* sense keys */
  48. #define NOS 0x00  /* no sense */
  49. #define RCV 0x01  /* recovered error */
  50. #define UAT 0x06  /* unit attention */
  51. #define VOF 0x0d  /* volume overflow */
  52. /* pseudo sense keys returned by DoSense */
  53. #define FMK 0x10  /* filemark */
  54. #define EOM 0x11  /* end of tape */
  55. #define ILI 0x12  /* incorr leng */
  56. #define SERR 0x13 /* SCSI error  */
  57.  
  58. struct things {  /* a collection of things we will have to alloc */
  59.          UBYTE cmdbuff[16];         /* SCSI command buff */
  60.          UBYTE snsarea[64];         /* sense data buffer */
  61.          UBYTE inqdata[40];         /* inquiry data buff */
  62.          struct SCSICmd scsicmd;    /* SCSIdirect cmd buff */
  63.          UBYTE pad[16];  /* SCSICmd is smaller in old include files */
  64.          } ;
  65.  
  66. /*======== Global data */
  67.  
  68. struct IntuitionBase *IntuitionBase;
  69. UBYTE           *cdb;          /* pointer to tape command buffer */
  70. UBYTE           *sns;          /* pointer to sense data buffer   */
  71. UBYTE           *inq;          /* pointer to inquiry data        */
  72. struct SCSICmd  *cmd;          /* pointer to scsidirect command  */
  73. struct IOStdReq *ior;          /* pointer to io request structure*/
  74. UBYTE           *TapeBuff[2]   /* pointers to 2 tape buffers     */
  75.                             ={NULL,NULL};
  76. struct tplink   *linktp;       /* pointer to link structure      */
  77. ULONG  blknum;                 /* block number for io operation  */
  78. ULONG  blksize = 512;          /* bytes per tape block           */
  79. ULONG  numblks = 1;            /* number of blocks per io oper   */
  80. ULONG  TBSize;                 /* bytes in a tape buffer         */
  81. ULONG  rwlen;                  /* bytes in a tape read/write     */
  82. ULONG  tranlen;                /* bytes/blks in a read/write     */
  83. ULONG  bugmask = 0;            /* 2090A bug circumvention        */
  84. ULONG  fmarks  = 1;            /* # file marks for write/skip    */
  85. long   tpsize ;                /* tape size in blocks            */
  86. long   reserved = 0;           /* number of reserved blks at BOT */
  87. int    tapenum;                /* tape volume number             */
  88. int    inprog = FALSE;         /* io operation in progress flag  */
  89. char   *z;                     /* scratch                        */
  90. char   *devname, nbuf[32];     /* file name reference from Open()*/
  91. char   dbb[80];                /* buffer for monitor messages    */
  92. UBYTE  Lun = 0;                /* Logical Unit number << 5       */
  93. UBYTE  fixedbit = 0;           /* fixed-block mode bit for SEQ   */
  94.  
  95. /***********************  Main program  ********************************/
  96. #ifdef AZTEC_C
  97.   #pragma intfunc(_main())
  98. #endif
  99. void _main(void)
  100. {
  101.  struct tplink      tpl;       /* structure to link hndlr & mon     */
  102.  struct Process     *myproc;   /* ptr to handler's process struct   */
  103.  struct DosPacket   *mypkt;    /* ptr to dos packet sent            */
  104.  struct DeviceNode  *mynode;   /* ptr to devnode passed in pkt Arg3 */
  105.  struct things      *xarea;    /* ptr to dynamic misc. areas        */
  106.  ULONG   dvnode;        /* ptr to devnode passed in pkt Arg3 */
  107.  ULONG   unit=99999;    /* device SCSI unit address          */
  108.  ULONG   bufmemtype=0;  /* type of mem for dynamic buffers   */
  109.  ULONG   gotopos=0;     /* position to open at (blk/filemark)*/
  110.  char    *driver;       /* name of SCSI device driver        */
  111.  UBYTE   *dptr;         /* ptr to next byte in dos buffer    */
  112.  long    dflags=0;      /* device flags                      */
  113.  long    iostat;        /* status of previous read           */
  114.  long    dcnt;          /* count of dos packet bytes to move */
  115.  long    mcnt;          /* count of bytes to move            */
  116.  long    Boff;          /* current offset in tape buffer     */
  117.  long    remain;        /* bytes remaining in tape buffer    */
  118.  long    Supra=FALSE;   /* flag for Supra circumvention      */
  119.  long    pkcnt;         /* flag to indicate data written     */
  120.  long    x;
  121.  int     y=0;
  122.  int     opmode=0;      /* how has the handler been opened   */
  123.     #define CLOSED  0       /* not doing anything */
  124.     #define READING 1       /* reading tape */
  125.     #define WRITING 2       /* writing tape */
  126.     #define RAWMODE 3       /* raw command mode */
  127.     #define UMODSEL 4       /* user mode select */
  128.  int     Bn;            /* current buffer number, 0 or 1     */
  129.  int     dirty=FALSE;   /* buffer has unwritten data in it   */
  130.  int     Ctl=CTLIMM;    /* Controls overlapped dos/scsi I/O  */
  131.  BYTE    acksig;        /* monitor acknowledge signal number */
  132.  UBYTE   varblk = 0;    /* variable-block flag for SEQ       */
  133.  
  134. /*======== Startup */
  135.  
  136.  IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
  137.  myproc  = (struct Process *) FindTask(0L);          /* find this process */
  138.  mypkt = taskwait();                           /* wait for startup packet */
  139.  /* packet: Arg1=BSTR to name, Arg2=BSTR to startup string, Arg3=BPTR devnode*/
  140.  mynode = (struct DeviceNode *) BADDR(mypkt->dp_Arg3);
  141.  dvnode = (ULONG) mypkt->dp_Arg3;
  142.  
  143. /*======== Create linkage for the tape monitor:  install pointer to tplink
  144.   ======== structure in the free pointer of the task block, so the tape
  145.   ======== monitor can find it after FindTask().
  146. */
  147.  tpl.keyword = "TapeHandler";
  148.  tpl.version = TVERSION;
  149.  tpl.devnode = (void *)mynode;
  150.  tpl.dbb     = dbb;
  151.  tpl.unit    = &unit;
  152.  tpl.Lun     = &Lun;
  153.  linktp = &tpl;
  154.  ((struct Task *)myproc)->tc_UserData = (APTR) linktp;
  155.  
  156. /*======== Extract info from mountlist Startup parameter. It may be
  157.   ======== enclosed in quotes, and each item is separated by a single '/'.
  158.   ======== First item is always the driver name, others may be in any order.
  159. */
  160.  z = (char *)BADDR(mypkt->dp_Arg2)+1 ;  /* Arg2= BSTR to mountlist 'Startup'*/
  161.  if(*z=='\"')  {                      /* remove quotes if any */
  162.      z++;
  163.      z[strlen(z)-1]= '\0' ;
  164.  }
  165.  driver = tpl.driver = z;
  166.  for(; *z != '/'; z++);
  167.  *(z++) = '\0';
  168.  toUPPER(z);
  169.  while (y!=100) {
  170.    switch(y=getstart(&x)) {
  171.      case 0:  /* UN */  unit = (ULONG) x;  break;
  172.      case 1:  /* LU */  Lun  = ((UBYTE)x & 7) << 5 ;  break;
  173.      case 2:  /* BS */  blksize = (ULONG) x;  break;
  174.      case 3:  /* NB */  numblks = (ULONG) x;  break;
  175.      case 4:  /* RB */  reserved = x;  break;
  176.      case 5:  /* BT */  bufmemtype = (ULONG) x;  break;
  177.      case 6:  /* FM */  fmarks = x & 0xff;  break;
  178.      case 7:  /* VB */  if(x) varblk = 1;   break;
  179.      case 8:  /* OV */  if(!x) Ctl = CTLWAIT; break;
  180.      case 9:  /* DF */  dflags = x; break;
  181.      case 10: /* SU */  Supra = x;  break;
  182.      case 11: /* C9 */  if(x) bugmask = 0x01000000; break;
  183.      case 99: /* ?? */  tpl.badparm=TRUE; break;
  184.      default: ;
  185.    }
  186.  }
  187.  rwlen = TBSize = numblks * blksize;   /* size of a tape buffer */
  188.  if(Supra)  rwlen = 0;
  189.  
  190. /*======== Allocate some memory for non-data buffers */
  191.  
  192.  if( !(xarea = (struct things *)
  193.            AllocMem(sizeof(struct things), bufmemtype | MEMF_CLEAR) ))
  194.            { returnpkt(mypkt,DOSFALSE,ERROR_NO_FREE_STORE);
  195.              CloseLibrary((struct Library *)IntuitionBase);
  196.              return;
  197.            }
  198.  cdb = &xarea->cmdbuff[0];
  199.  sns = &xarea->snsarea[0];
  200.  inq = tpl.inquiry = &xarea->inqdata[0];
  201.  cmd = &xarea->scsicmd;
  202.  ior = (struct IOStdReq *) CreateExtIO( CreatePort(0,0),
  203.                                          sizeof(struct IOStdReq));
  204.  
  205. /*======== Open the SCSIdirect device */
  206.  
  207.  if ( OpenDevice(driver,unit,(struct IORequest *)ior,dflags)  )  {
  208.     returnpkt(mypkt,DOSFALSE,ERROR_INVALID_COMPONENT_NAME);
  209.     CloseLibrary((struct Library *)IntuitionBase);
  210.     FreeMem(xarea,sizeof(struct things));
  211.     return;
  212.  }
  213.  mynode->dn_Task = &myproc->pr_MsgPort;    /* install handler taskid */
  214.  returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);  /* reply to initial packet */
  215.  
  216. /*======== Allocate the signal that TapeMon will
  217.   ======== use to acknowledge MPR requests.
  218. */
  219.  acksig = AllocSignal(-1);
  220.  if(acksig != -1) tpl.handsig = 1UL << acksig;
  221.  /* else { monitor will not attempt to signal us } */
  222.  
  223. /*======= Find the SCSI device type by INQUIRY.  Sequential or direct access?
  224. */
  225.  if(TapeIO(INQUIRY,0,CTLWAIT)) TapeIO(TSENSE,0,CTLWAIT);
  226.  inq[36] = 0;  /* null-terminate vendor info */
  227.  if(SEQ) {
  228.    reserved = 0;
  229.    fixedbit = varblk ^ 0x01;  /* fixed or variable block mode */
  230.    tranlen = (fixedbit) ? numblks : TBSize;
  231.  }
  232.  else /* DAC */ tranlen = numblks;
  233.  
  234. /* =========== The main packet processing loop =============== */
  235.  
  236.  for (;;)  {
  237.    mypkt = taskwait();          /* wait for a packet */
  238.    switch(mypkt->dp_Type) {
  239.  
  240.      case ACTION_FINDINPUT:  /*----------- Open() ------------*/
  241.      case ACTION_FINDOUTPUT:
  242.           if(opmode != CLOSED)  {
  243.              returnpkt(mypkt,DOSFALSE,ERROR_OBJECT_IN_USE);
  244.              break;
  245.           }
  246.           /* Allocate storage for buffers */
  247.           TapeBuff[0] = (UBYTE *) AllocMem(TBSize, bufmemtype | MEMF_CLEAR);
  248.           TapeBuff[1] = (UBYTE *) AllocMem(TBSize, bufmemtype | MEMF_CLEAR);
  249.           if (!TapeBuff[0] || !TapeBuff[1]) {
  250.                freestuff();
  251.                returnpkt(mypkt,DOSFALSE,ERROR_NO_FREE_STORE);
  252.                MPR0("Can't get memory for tape buffers\n");
  253.                break;
  254.           }
  255.  
  256.           /* Determine open mode */
  257.           z = (char *)BADDR(mypkt->dp_Arg3);
  258.           x = (UBYTE)(*z);
  259.           devname = (char *)memcpy(nbuf, z+1, x);
  260.           *(devname+x) = '\0';
  261.           toUPPER(devname);
  262.           for(z=devname; *(z++)!=':' ;);
  263.           if     (!strcmp(z,"RAWCMD"))  opmode=RAWMODE;
  264.           else if(!strcmp(z,"MODESEL")) opmode=UMODSEL;
  265.           else {    /* normal read/write */
  266.              opmode = (mypkt->dp_Type==ACTION_FINDINPUT) ? READING : WRITING;
  267.              if(!strcmp(z,"*")) gotopos=blknum;     /* current position */
  268.              else if(*z>='0' && *z<='9')     /* specific position */
  269.                    gotopos = (ULONG) strtoul (z,NULL,0);
  270.              else if(*z=='\0') gotopos=0;    /* beginning of tape */
  271.              else goto BADNAME;
  272.           }
  273.           if(opmode>=RAWMODE && mypkt->dp_Type==ACTION_FINDINPUT)  {
  274.             BADNAME:
  275.              freestuff();   /* can't read from raw/ms */
  276.              opmode=CLOSED;
  277.              returnpkt(mypkt,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  278.              break;
  279.           }
  280.  
  281.           /* Check device ready */
  282.           if(x=TapeIO(TREADY,0,CTLWAIT))  {
  283.              y=DoSense(x);
  284.              if     (y==UAT) blknum = reserved;
  285.              else if(y==NOS) ;
  286.              else {
  287.                freestuff();
  288.                opmode=CLOSED;
  289.                returnpkt(mypkt,DOSFALSE,ERROR_DEVICE_NOT_MOUNTED);
  290.                break;
  291.              }
  292.           }
  293.  
  294.           if(opmode<=WRITING) {
  295.  
  296.             /* Check write-prot, block length */
  297.             if(TapeIO(MDSNS,0,CTLWAIT))  TapeIO(TSENSE,0,CTLWAIT);
  298.             else {
  299.                if(opmode==WRITING && (sns[2] & 0x80)) {
  300.                  freestuff();
  301.                  opmode=CLOSED;
  302.                  returnpkt(mypkt,DOSFALSE,ERROR_DISK_WRITE_PROTECTED);
  303.                  break;
  304.                }
  305.                if(sns[3] >= 8) {
  306.                  x = *((long *) &sns[8]) & 0x00ffffff;  /* get block len */
  307.                  if(x != blksize) {  /* set block size with Mode Select */
  308.                    TapeIO(MDSET,(int)varblk,CTLWAIT);
  309.                    TapeIO(TSENSE,0,CTLWAIT);
  310.                  }
  311.                }
  312.             }
  313.  
  314.             /* Position tape */
  315.             if(gotopos==0) {    /* tape: */
  316.                TapeIO(TREWIND,0,CTLWAIT);
  317.                blknum = reserved;
  318.             }
  319.             else if(gotopos != blknum) {   /* tape:n */
  320.                if(DAC) blknum = gotopos;
  321.                else {
  322.                  TapeIO(TREWIND,0,CTLWAIT);
  323.                  if(x=TapeIO(TSKIP,(int)gotopos,CTLWAIT)) DoSense(x);
  324.                  blknum = 0;
  325.                }
  326.             }
  327.             else if(SEQ) blknum = 0;  /* tape:*  */
  328.  
  329.             /* Get capacity for 3M tape */
  330.             if(DAC) {
  331.                tpsize = 0x7fffffff;
  332.                if(TapeIO(RDCAP,0,CTLWAIT)) TapeIO(TSENSE,0,CTLWAIT);
  333.                else {
  334.                  tpsize = ((sns[2] << 8) | sns[3]) + 1;
  335.                  MPR1("Capacity: %u blocks\n", tpsize);
  336.                }
  337.             }
  338.           }
  339.  
  340.           dirty=FALSE; inprog=FALSE; Boff=0; pkcnt=0; tapenum=1;
  341.           MPR2("%s Opened at block %u\n",devname,blknum);
  342.  
  343.           if(opmode==READING) {  /* for reads, prefetch 1st buffer */
  344.              iostat = TapeIO(TREAD,0,CTLWAIT);
  345.              remain=0;  Bn=1;
  346.           }
  347.           else { remain=TBSize;  Bn=0;  iostat=0; }
  348.  
  349.           returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);
  350.           break;
  351.  
  352.  
  353.      case ACTION_END:        /*----------- Close() -----------*/
  354.           switch(opmode) {
  355.              case CLOSED:
  356.                 returnpkt(mypkt,DOSFALSE,ERROR_ACTION_NOT_KNOWN); break;
  357.              case RAWMODE:
  358.                 if(x=TapeIO(RAWCMD,Bn,CTLWAIT)) DoSense(x); break;
  359.              case UMODSEL:
  360.                 if(x=TapeIO(USRMODE,Bn,CTLWAIT)) DoSense(x); break;
  361.              case READING:
  362.                 if(inprog) iostat = TapeIO(TFINISH,0,CTLWAIT);
  363.                 if(iostat) DoSense(iostat);
  364.                 break;
  365.              case WRITING:
  366.                 if(inprog) iostat = TapeIO(TFINISH,0,CTLWAIT);
  367.                 if(iostat) iostat = wrteot(Bn^1,1,iostat);
  368.                 if(iostat==0) {
  369.                    if(dirty) {
  370.                       memset(&TapeBuff[Bn][Boff],0,remain);
  371.                       iostat = TapeIO(TWRITE,Bn,CTLWAIT);
  372.                    }
  373.                    if(iostat) iostat = wrteot(Bn,0,iostat);
  374.                 }
  375.                 if(iostat) { MPR0("Error writing final block\n"); }
  376.                 else if(pkcnt) {
  377.                    blknum += numblks;  x=0;
  378.                    if(SEQ) x=TapeIO(WFMARK,0,CTLWAIT);
  379.                    if(x) DoSense(x);
  380.                 }
  381.           }
  382.           returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);
  383.           opmode=CLOSED;
  384.           freestuff();
  385.           MPR1("Closed at block %u\n",blknum);
  386.           break;
  387.  
  388.      case ACTION_READ:       /*----------- Read() ------------*/
  389.           if(opmode != READING) {
  390.             MPR0("Function/mode error\n");
  391.             mypkt->dp_Arg3 = -1;
  392.             goto RDEND;
  393.           }
  394.           dptr = (UBYTE *) mypkt->dp_Arg2;
  395.           dcnt =           mypkt->dp_Arg3;
  396.           while(dcnt)   {
  397.             if(remain==0)   {
  398.                if(inprog) iostat = TapeIO(TFINISH,0,CTLWAIT);
  399.                if(iostat) {  /* check status of previous read */
  400.                   y=DoSense(iostat);  iostat=0;
  401.                   switch(y) {
  402.                     case RCV:
  403.                        y=0; break;
  404.                     case FMK:
  405.                        mypkt->dp_Arg3 = 0;  break;
  406.                     case VOF:
  407.                     case EOM:  /* End of Tape: (sequential) */
  408.                        if(NewTape())  {   /* ask for new tape */
  409.                           y=0;            /* and reread buffer */
  410.                           iostat=TapeIO(TREAD,(Bn^1),CTLWAIT);
  411.                           if(iostat) y=DoSense(iostat); /* and fall thru */
  412.                           else break;
  413.                        }
  414.                     default:
  415.                        MPR0("Error during read\n");
  416.                        mypkt->dp_Arg3 = -1;
  417.                   }
  418.                   if(y) goto RDEND;
  419.                }
  420.                blknum += numblks;
  421.                iostat = TapeIO(TREAD,Bn,Ctl); /* start refilling this buffer */
  422.                Bn ^= 1;      /* switch to other (full) buffer */
  423.                remain = TBSize;
  424.                Boff = 0;
  425.             }
  426.             mcnt = (dcnt>remain) ? remain : dcnt;
  427.             memcpy (dptr, &TapeBuff[Bn][Boff], mcnt);
  428.             dcnt -= mcnt ;
  429.             Boff += mcnt ;
  430.             dptr += mcnt ;
  431.             remain -= mcnt ;
  432.           }
  433.           RDEND:
  434.           returnpkt(mypkt,mypkt->dp_Arg3,mypkt->dp_Arg2);
  435.           break;
  436.  
  437.  
  438.      case ACTION_WRITE:      /*----------- Write() -----------*/
  439.           if(opmode < WRITING) {
  440.             MPR0("Function/mode error\n");
  441.             mypkt->dp_Arg3 = -1;
  442.             goto WRTEND;
  443.           }
  444.           pkcnt++;
  445.           dptr = (UBYTE *) mypkt->dp_Arg2;
  446.           dcnt =           mypkt->dp_Arg3;
  447.           while (dcnt)  {
  448.             if(dcnt >= remain) {
  449.                memcpy (&TapeBuff[Bn][Boff], dptr, remain);
  450.                if(inprog) iostat = TapeIO(TFINISH,0,CTLWAIT);
  451.                if(iostat) {  /* check status of previous write */
  452.                  if(iostat = wrteot(Bn^1,1,iostat)) {  /* possible EOT */
  453.                     mypkt->dp_Arg3 = -1;
  454.                     MPR0("Error during write\n");
  455.                     iostat=0;  dirty=FALSE;  pkcnt=0;
  456.                     goto WRTEND;
  457.                  }
  458.                }
  459.                iostat = TapeIO(TWRITE,Bn,Ctl); /* start writing full buffer */
  460.                blknum += numblks;
  461.                dcnt -= remain;
  462.                dptr += remain;
  463.                Boff  = 0;
  464.                remain= TBSize;
  465.                Bn   ^= 1;      /* switch to other (empty) buffer */
  466.                dirty = FALSE;
  467.             }
  468.             else {
  469.                memcpy (&TapeBuff[Bn][Boff], dptr, dcnt);
  470.                remain -= dcnt;
  471.                Boff += dcnt;
  472.                dcnt  = 0;
  473.                dirty = TRUE;
  474.             }
  475.           }
  476.           WRTEND:
  477.           returnpkt(mypkt,mypkt->dp_Arg3,mypkt->dp_Res2);
  478.           break;
  479.  
  480.  
  481.      case ACTION_CURRENT_VOLUME:  /* info not supported */
  482.           returnpkt(mypkt,dvnode,DOSFALSE);
  483.           break;
  484.  
  485.      case ACTION_LOCATE_OBJECT:  /* lock */
  486.           returnpkt(mypkt,mypkt->dp_Arg1,mypkt->dp_Res2);
  487.           break;
  488.  
  489.      case ACTION_FREE_LOCK:      /* unlock */
  490.           returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);
  491.           break;
  492.  
  493.      case ACTION_FLUSH:   /* flush buffers, NOOP */
  494.           returnpkt(mypkt,DOSTRUE,mypkt->dp_Res2);
  495.           break;
  496.  
  497.      default:  /* others not supported */
  498.           returnpkt(mypkt,DOSFALSE,ERROR_ACTION_NOT_KNOWN);
  499.           MPR1("Unsupported_Pkt=%d\n",mypkt->dp_Type);
  500.  
  501.      } /* end of switch */
  502.  } /* end of loop */
  503. } /* end of _main() */
  504.  
  505. /**************************************************************************/
  506.  
  507. int DoSense(long iocode)
  508. {
  509.    /* iocode is (ioerr<<8 + cmdstatus) */
  510.    UBYTE snskey;
  511.    static char *snstext[] = {
  512.        "NONE" , "RECOVERED ERROR", "NOT READY", "MEDIUM ERROR",
  513.        "HARDWARE ERROR", "ILLEGAL REQUEST", "UNIT ATTENTION", "DATA PROTECT",
  514.        "BLANK CHECK", "KEY=9", "COPY ABORTED", "ABORTED COMMAND", "KEY=C",
  515.        "VOLUME OVERFLOW", "KEY=E", "KEY=F", "FILEMARK", "END-OF-MEDIUM",
  516.        "INCORRECT BLOCK LENGTH"
  517.    };
  518.    static char *sderror[] = {
  519.        "SELF-UNIT", "DMA", "PHASE", "PARITY", "SELECT-TIMEOUT"
  520.    };
  521.    iocode=iocode>>8;
  522.  
  523.    if(iocode==0 || iocode==HFERR_BadStatus)  {
  524.        TapeIO(TSENSE,0,CTLWAIT);
  525.        if((sns[0] & 0x70)==0x70) {  /* extended */
  526.           if     (sns[2] & 0x80) snskey = FMK;  /* pseudo sense keys */
  527.           else if(sns[2] & 0x40) snskey = EOM;
  528.           else if(sns[2] & 0x20) snskey = ILI;
  529.           else                   snskey = sns[2] & 0x0f;  /* real sense key */
  530.        }
  531.        else snskey = sns[0] & 0x0f; /* non-extended */
  532.        linktp->sense = snstext[snskey];  /* keep last error info */
  533.        linktp->xsns1 = sns[12];
  534.        linktp->xsns2 = sns[13];
  535.        linktp->sns = sns;  /* flag for tapemon to print all data */
  536.        MPR3("Sense: %s, other= %02X,%02X\n", snstext[snskey], sns[12],sns[13]);
  537.        linktp->sns = NULL;
  538.        return((int)snskey);
  539.    }
  540.    else { MPR1("SCSI %s ERROR\n",sderror[iocode-40]);
  541.        return(SERR);
  542.    }
  543. }
  544.  
  545. /**************************************************************************/
  546. /* wrteot:  handle messiness that happens when writing at end of tape.
  547.       Returns non-zero status if not EOT or tape swap unsuccessful. */
  548.  
  549. long wrteot(int bfn, int dec, long stat)
  550. {
  551.    long ios = stat;
  552.    int  s = DoSense(ios);
  553.    if(s==EOM || s==VOF) {   /* EOT? */
  554.       if(NewTape()) {       /* ask for new tape */
  555.          if(dec) blknum -= numblks;  /* and rewrite old buffer */
  556.          ios=TapeIO(TWRITE,bfn,CTLWAIT);
  557.          if(ios) s=DoSense(ios);
  558.          if(dec) blknum += numblks;
  559.       }
  560.    }
  561.    if(s==RCV) ios=0;  /* ignore recoveries */
  562.    return(ios);
  563. }
  564.  
  565. /**************************************************************************/
  566.  
  567. void freestuff(void)
  568. {
  569.   if(TapeBuff[0]) FreeMem(TapeBuff[0],TBSize);
  570.   if(TapeBuff[1]) FreeMem(TapeBuff[1],TBSize);
  571.   TapeBuff[0] = TapeBuff[1] = NULL;
  572.   return;
  573. }
  574.  
  575. /**************************************************************************/
  576. /* getstart:
  577.     Given pointer (z) to a string of the form "SS-nn/..."
  578.     returns a number corresponding to SS, the binary value of nn,
  579.     and the pointer is updated to point after the slash.
  580. */
  581. int getstart(long *num)
  582. {
  583.   extern char *z;
  584.   #define NOTFND 99
  585.   #define ENDLST 100
  586.   #define NKEYS  12  /* number of keywords */
  587.   static char *keys[NKEYS] =
  588.       { "UN","LU","BS","NB","RB","BT","FM","VB","OV","DF","SU","C9" };
  589.      /*  0    1    2    3    4    5    6    7    8    9    10   11 */
  590.   char *ii, *jj;  int kk;
  591.  
  592.   if (*z == '\0') return(ENDLST);      /* return if end of string */
  593.   for (ii=z;  *ii != '-'; ii++);       /* find the dash */
  594.   for (jj=z;  *jj != '/' && *jj !='\0'; jj++); /* find the slash */
  595.   *ii = '\0'; *jj = '\0';              /* null-terminate name & number */
  596.   *num = (long) strtoul (++ii,NULL,0); /* return converted number */
  597.   ii = z;     z = ++jj;                /* update ptr to next item */
  598.   for (kk=0; kk <= NKEYS; kk++)  {     /* search for keyword */
  599.      if (*ii == *keys[kk] && *(ii+1) == *(keys[kk]+1) )
  600.         return(kk);                    /* return index of keyword if found */
  601.   }
  602.   return(NOTFND);                      /* didn't find keyword */
  603. }
  604.  
  605. /**************************************************************************
  606.    MonPrint requests that the TapeMon program print the message in 'dbb'.
  607.     Since this handler cannot do DOS I/O, it must beg the TapeMon program,
  608.     possibly running in a CLI somewhere, to do the printf for it.  If the
  609.     TapeMon is running, it will have installed a pointer to its task in
  610.     the link structure, and we can Signal() it.
  611. */
  612.  
  613. void MonPrint(void)
  614. {
  615.    if(linktp->montask)  {
  616.       Signal(linktp->montask, linktp->monsig);
  617.       Wait  (linktp->handsig);
  618.       Signal(linktp->montask, linktp->monsig);
  619.       Wait  (linktp->handsig);
  620.    }
  621.    return;
  622. }
  623.  
  624. /**************************************************************************/
  625. /* toUPPER: convert string to upper case */
  626.  
  627. void toUPPER(char *zz)
  628. {
  629.   for(; *zz != '\0'; zz++)  if(*zz >= 'a') *zz -= 0x20;
  630.   return;
  631. }
  632.  
  633. /**************************************************************************
  634. *  NewTape()   Displays a requester asking user to insert a new tape.
  635. */
  636.  
  637. long NewTape(void)
  638. {
  639.  long choice;
  640.  static char rqm[40];
  641.  static struct IntuiText rtxt[] = {
  642.     { AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,AUTOLEFTEDGE,AUTOTOPEDGE,
  643.        AUTOITEXTFONT, (UBYTE *) &rqm[0], AUTONEXTTEXT },
  644.     { AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,AUTOLEFTEDGE,AUTOTOPEDGE,
  645.        AUTOITEXTFONT, (UBYTE *) "Continue", AUTONEXTTEXT },
  646.     { AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,AUTOLEFTEDGE,AUTOTOPEDGE,
  647.        AUTOITEXTFONT, (UBYTE *) "Abort", AUTONEXTTEXT }
  648.  };
  649.  
  650.  MPR1("Time to insert tape# %d\n",++tapenum);
  651.  sprintf(rqm," Insert tape %d for %s",tapenum,devname);
  652.  choice=AutoRequest(NULL,&rtxt[0],&rtxt[1],&rtxt[2],NULL,NULL,250,50);
  653.  if(choice) {
  654.      DoSense(TapeIO(TREADY,0,CTLWAIT));  /* eat unit-atten status */
  655.      if(TapeIO(TREWIND,0,CTLWAIT)) TapeIO(TSENSE,0,CTLWAIT);
  656.      if(DAC) blknum=reserved;  /* reset block number */
  657.  }
  658.  return(choice);
  659. }
  660.  
  661.