/* ** TapeIO: performs operations to the tape unit via SCSI-direct for BTNtape ** Version 2.1 10/22/91 ** ** (c) Copyright 1990, 1991 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 #include #include #include #include #include #include #define DBUG 0 #if defined AZTEC_C #include /*#define strtoul strtol */ #elif defined LATTICE #include #endif #include "tape.h" #include "tplink.h" /* SCSI commands used by handler */ #define CMD_TEST_UNIT_READY 0x00 #define CMD_REWIND 0x01 #define CMD_REQUEST_SENSE 0x03 #define CMD_SCSI_READ 0x08 #define CMD_SCSI_WRITE 0x0a #define CMD_FILEMARK 0x10 #define CMD_SPACE 0x11 #define CMD_INQUIRY 0x12 #define CMD_MODE_SELECT 0x15 #define CMD_MODE_SENSE 0x1a #define CMD_LOAD_UNLOAD 0x1b #define CMD_READ_CAPACITY 0x25 extern UBYTE *cdb; extern UBYTE *sns; extern UBYTE *inq; extern struct SCSICmd *cmd; extern UBYTE *TapeBuff[2]; extern struct IOStdReq *ior; extern ULONG blknum; extern ULONG blksize; extern ULONG numblks; extern ULONG TBSize; extern ULONG rwlen; extern ULONG tranlen; extern ULONG bugmask; extern long reserved; extern long tpsize; extern struct tplink *linktp; extern int inprog; extern char dbb[80]; extern UBYTE Lun; extern UBYTE fixedbit; extern long NewTape(); long TapeIO(int toper, int bn, int ctl) { char *z; int i; if(inprog) { WaitIO((struct IORequest *)ior); inprog = FALSE; if(ior->io_Error) return((long)(ior->io_Error)); } if(toper == TFINISH) return(0L); cmd->scsi_Command = cdb; cmd->scsi_CmdLength = 6; cmd->scsi_Status = 0; cmd->scsi_Length = 0; cmd->scsi_Flags = 0; ior->io_Command = HD_SCSICMD; ior->io_Data = (APTR) cmd; ior->io_Length = sizeof(struct SCSICmd); ior->io_Error = 0; for (i=0 ; i<10; i++) cdb[i] = 0x00; switch(toper) { case TWRITE: if(DAC && ((blknum+numblks)>tpsize)) return(FAKEOM); cdb[0] = CMD_SCSI_WRITE; cdb[1] = Lun | fixedbit; *((UWORD *)&cdb[2]) = (SEQ) ? (UWORD)(tranlen>>8) : (UWORD) blknum; cdb[4] = (UBYTE) tranlen & 0xff; /* 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 %u x %d\n",blknum,tranlen); break; case TREAD: if(DAC && ((blknum+numblks)>tpsize)) return(FAKEOM); cdb[0] = CMD_SCSI_READ; cdb[1] = Lun | fixedbit; *((UWORD *)&cdb[2]) = (SEQ) ? (UWORD)(tranlen>>8) : (UWORD) blknum; cdb[4] = (UBYTE) tranlen & 0xff; cmd->scsi_Data = (UWORD *) TapeBuff[bn]; cmd->scsi_Length = rwlen; cmd->scsi_Flags = SCSIF_READ; MPR2("Reading block %u x %d\n",blknum,tranlen); break; case TSENSE: for (i=0 ; i<32; i++) sns[i] = 0; cdb[0] = CMD_REQUEST_SENSE; cdb[1] = Lun; cdb[4] = 32; /* extended sense */ cmd->scsi_Length = 32; cmd->scsi_Data = (UWORD *) sns; cmd->scsi_Flags = SCSIF_READ; break; case TREWIND: cdb[0] = CMD_REWIND; cdb[1] = Lun; MPR0("Rewinding\n"); break; case INQUIRY: /* read drive information */ cdb[0] = CMD_INQUIRY; cdb[1] = Lun; cdb[4] = 36; cmd->scsi_Length = 36; cmd->scsi_Data = (UWORD *) inq; cmd->scsi_Flags = SCSIF_READ; break; case TREADY: /* test unit ready */ cdb[0] = CMD_TEST_UNIT_READY; cdb[1] = Lun; break; case MDSNS: for (i=0 ; i<12; i++) sns[i] = 0; cdb[0] = CMD_MODE_SENSE; cdb[1] = Lun; cdb[4] = 12; cmd->scsi_Length = 12; cmd->scsi_Data = (UWORD *) sns; cmd->scsi_Flags = SCSIF_READ; break; case WFMARK: /* write file mark */ cdb[0] = CMD_FILEMARK; cdb[1] = Lun; cdb[4] = (UBYTE) bn & 0xff; MPR0("Writing filemark\n"); break; case TSKIPF: /* skip over filemarks */ cdb[0] = CMD_SPACE; cdb[1] = Lun | 0x01; cdb[3] = (UBYTE) bn >> 8; cdb[4] = (UBYTE) bn & 0xff; break; case TSKIPE: /* skip to end-of-data */ cdb[0] = CMD_SPACE; cdb[1] = Lun | 0x03; MPR0("Skipping to end of data\n"); break; case TRETEN: /* retension tape */ cdb[0] = CMD_LOAD_UNLOAD; cdb[1] = Lun; cdb[4] = 0x03; MPR0("Retensioning\n"); break; case RDCAP: /* read tape capacity. 3M drive only */ cdb[0] = CMD_READ_CAPACITY; cdb[1] = Lun; cmd->scsi_CmdLength = 10; cmd->scsi_Length = 8; cmd->scsi_Data = (UWORD *) sns; cmd->scsi_Flags = SCSIF_READ; break; case RAWCMD: /* write user-provided control command */ i = 0; z = (char *)TapeBuff[bn]; while(*z!='\n' && i<10) cdb[i++] = (UBYTE) 0xff & strtoul (z,&z,16); cdb[1] |= Lun; if(cdb[0] == CMD_REWIND) blknum = reserved; if(cdb[0] >= 0x20) cmd->scsi_CmdLength = 10; if(cdb[0] >= 0xa0) cmd->scsi_CmdLength = 12; cmd->scsi_Data = (UWORD *) sns; MPR1("Raw command %02X\n",cdb[0]); break; case MDSET: /* set fixed-mode block length */ cdb[0] = CMD_MODE_SELECT; cdb[1] = Lun; cdb[4] = 12; for (i=0 ; i<12; i++) sns[i] = 0x00; sns[2] = 0x10; /* buffered mode */ sns[3] = 8; if(!bn) *((ULONG *)&sns[8]) = blksize & 0x00ffffff; /* block length */ cmd->scsi_Length = 12; cmd->scsi_Data = (UWORD *) sns; cmd->scsi_Flags = SCSIF_WRITE; MPR1("Mode Select block size %d\n",blksize); break; case USRMODE: /* write user-provided mode-select data */ for (i=0 ; i<64; i++) sns[i] = 0x00; i = 0; z = (char *)TapeBuff[bn]; while(*z!='\n' && i<64) sns[i++] = (UBYTE) 0xff & strtoul (z,&z,16); cdb[0] = CMD_MODE_SELECT; cdb[1] = Lun; cdb[4] = i; cmd->scsi_Length = i; cmd->scsi_Data = (UWORD *) sns; cmd->scsi_Flags = SCSIF_WRITE; MPR0("User Mode-Select\n"); break; } #if DBUG MPR3("CDB = %02x %02x %02x",cdb[0],cdb[1],cdb[2]); MPR3("%02x %02x %02x\n",cdb[3],cdb[4],cdb[5]); MPR1("ADDR = %X\n", cmd->scsi_Data ); MPR1("LENG = %X\n\n", cmd->scsi_Length ); return(0L); #endif if(ctl == CTLWAIT) { DoIO ((struct IORequest *)ior); /* start sync io */ return((long)(ior->io_Error)); } else { SendIO((struct IORequest *)ior); /* start async io */ inprog = TRUE; return(0L); } }