/*
**  TapeIO: performs operations to the tape unit via SCSI-direct for BTNtape
**     Version 1.0  09/10/90
**
**   (c) Copyright 1990 Robert Rethemeyer.
**     This code is freely distributable and redistributable,
**     for non-commercial purposes, provided this notice is included.
**
**   This code was derived from programs written by Robert Mitchell.
*/

#include <exec/types.h>
#include <exec/io.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <devices/scsidisk.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include <string.h>

#if defined AZTEC_C
  #include <functions.h>
#elif defined LATTICE
  #include <proto/exec.h>
  #include <proto/intuition.h>
#endif

#include "tape.h"
#include "tplink.h"

/* the following SCSI commands are defined for the 3M MCD-403 tape unit */
#define CMD_TEST_UNIT_READY         0x00
#define CMD_REZERO                  0x01
#define CMD_REQUEST_SENSE           0x03
#define CMD_FORMAT_UNIT             0x04
#define CMD_SEND_SYSTEM_DATA        0x05
#define CMD_RECEIVE_SYSTEM_DATA     0x06
#define CMD_REASSIGN_BLOCKS         0x07
#define CMD_SCSI_READ               0x08
#define CMD_VERIFY_UNIT             0x09
#define CMD_SCSI_WRITE              0x0a
#define CMD_SEEK                    0x0b
#define CMD_READ_SCSI_DEFECT        0x0d
#define CMD_READ_CONTROLLER_INFO    0x0e
#define CMD_WRITE_CONTROLLER_INFO   0x0f
#define CMD_DRIVE_PASS_THRU         0x10
#define CMD_READ_DRIVE_LINES        0x11
#define CMD_INQUIRY                 0x12
#define CMD_READ_QIC100_INFO        0x13
#define CMD_WRITE_QIC100_INFO       0x14
#define CMD_MODE_SELECT             0x15
#define CMD_RESERVE                 0x16
#define CMD_RELEASE                 0x17
#define CMD_READ_QIC100_DEFECT      0x19
#define CMD_MODE_SENSE              0x1a
#define CMD_LOAD_UNLOAD             0x1b
#define CMD_READ_DIAG_RESULT        0x1c
#define CMD_SEND_DIAG               0x1d
#define CMD_READ_CAPACITY           0x25
#define CMD_READ_EXTENDED           0x28
#define CMD_WRITE_EXTENDED          0x2a
#define CMD_SEEK_EXTENDED           0x2b
#define CMD_READ_SCSI_DEFECT_DATA   0x37
#define CMD_WRITE_BUFFER            0x3b
#define CMD_READ_BUFFER             0x3c

#define CBLEN 6
extern          UBYTE  *cdb;
extern          UBYTE  *sns;
extern struct SCSICmd  *cmd;
extern          UBYTE  *TapeBuff[2];
extern struct IOStdReq *ior;
extern          ULONG  blknum;
extern          ULONG  numblks;
extern          ULONG  rwlen;
extern          ULONG  bugmask;
extern          long   tpsize;
extern struct tplink   *linktp;
extern          short  inprog;
extern          char   dbb[80];


long TapeIO(int toper, int bn, UBYTE ctl)
{
 char *z;
 short i;

  if(inprog) { WaitIO((struct IORequest *)ior);
               inprog = FALSE;
               if(ior->io_Error)
                 return((long)((ior->io_Error << 8) + cmd->scsi_Status));
             }
  if(toper == TFINISH) return(0L);
  cmd->scsi_Command = cdb;
  cmd->scsi_CmdLength = CBLEN;
  cmd->scsi_Status = 0;
  ior->io_Command = HD_SCSICMD;
  ior->io_Data = (APTR) cmd;
  ior->io_Length = sizeof(struct SCSICmd);
  ior->io_Error = 0;
  ior->io_Flags = IOF_QUICK;
  for (i=0 ; i<CBLEN; i++) cdb[i] = 0x00;

  switch(toper) {
  case TREAD:
    if((blknum+numblks)>=tpsize) NewTape();
    cdb[0] = CMD_SCSI_READ;
    cdb[2] = (UBYTE) ( (blknum >> 8) & 0x00ff);
    cdb[3] = (UBYTE) (blknum & 0x00ff);
    cdb[4] = (UBYTE) numblks ;
    cmd->scsi_Data = (UWORD *) TapeBuff[bn];
    cmd->scsi_Length = rwlen;
    cmd->scsi_Flags = SCSIF_READ;
    MPR2("Reading block %d * %d\n",blknum,numblks)
    break;

  case TWRITE:
    if((blknum+numblks)>=tpsize) NewTape();
    cdb[0] = CMD_SCSI_WRITE;
    cdb[2] = (UBYTE)(blknum >> 8) & 0x00ff;
    cdb[3] = (UBYTE)(blknum & 0x00ff);
    cdb[4] = (UBYTE) numblks ;
 /* cmd->scsi_Data = (UWORD *) TapeBuff[bn]; */      /* 2090A bug fix */
    cmd->scsi_Data = (UWORD *) ((ULONG) TapeBuff[bn] | bugmask);
    cmd->scsi_Length = rwlen;
    cmd->scsi_Flags = SCSIF_WRITE;
    MPR2("Writing block %d * %d\n",blknum,numblks)
    break;

  case TREWIND:
    cdb[0] = CMD_REZERO;
    cmd->scsi_Data = (UWORD *) TapeBuff[bn];
    cmd->scsi_Length = 0;
    cmd->scsi_Flags  = 0;
    MPR0("Rewinding\n")
    break;

  case TSENSE:
    cdb[0] = CMD_REQUEST_SENSE;
    cdb[4] = 28;  /* extended sense */
    cmd->scsi_Length = 28;
    cmd->scsi_Data = (UWORD *) sns;
    cmd->scsi_Flags = SCSIF_READ;
    MPR0("Sense:")
    break;

  case RDCAP:
    cdb[0] = CMD_READ_CAPACITY;
    cmd->scsi_Length = 8;
    cmd->scsi_Data = (UWORD *) sns;
    cmd->scsi_Flags = SCSIF_READ;
    MPR0("Capacity:")
    break;

  case RAWCMD:    /* Convert hex in tape buffer to bytes in command buffer. */
    i = 0;        /* Bytes are specified by hex digit pairs sep. by blanks  */
    z = (char *)TapeBuff[bn];   /* terminated by newline */
    while(z[0]!='\n' && i<32)  cdb[i++] = (UBYTE) 0xff & strtol(z,&z,16);
    cmd->scsi_Data = (UWORD *) sns;
    cmd->scsi_Length = 0;
    cmd->scsi_Flags  = 0;
    MPR0("Raw command\n")
    break;

  }
  if(ctl == CTLWAIT) {
         DoIO ((struct IORequest *)ior);    /* start sync io */
         return((long)((ior->io_Error << 8) + cmd->scsi_Status));
         }
  else               {
         BeginIO((struct IORequest *)ior);  /* start async io */
         if(ior->io_Error)
                  return((long)((ior->io_Error << 8) + cmd->scsi_Status));
         if( !(ior->io_Flags & IOF_QUICK) )  inprog = TRUE;
         return(0L);
         }
}

/**************************************************************************
*  NewTape()   Displays a requester asking user to insert a new tape.
*/

void NewTape(void)
{
 extern ULONG  blknum;
 extern short  reserved;
 extern void   DoSense();

 static struct IntuiText reqtext[] = {
     { AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,AUTOLEFTEDGE,AUTOTOPEDGE,AUTOITEXTFONT,
        "  EOT: Insert next tape", AUTONEXTTEXT },
     { AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,AUTOLEFTEDGE,AUTOTOPEDGE,AUTOITEXTFONT,
        "Continue", AUTONEXTTEXT },
     { AUTOFRONTPEN,AUTOBACKPEN,AUTODRAWMODE,AUTOLEFTEDGE,AUTOTOPEDGE,AUTOITEXTFONT,
        "Quit", AUTONEXTTEXT }
  };

 TapeIO(TFINISH,0,CTLWAIT);   /* yeeks, recursion! */
 MPR0("Time for a new tape\n")
 if( AutoRequest(NULL,&reqtext[0],&reqtext[1],&reqtext[2],NULL,NULL,250,50) ) {
      blknum=reserved;  /* reset block number for new tape */
      DoSense(0);      /* eat tape change status (recursion again) */
      }
 return;
}
