[comp.unix.amiga] A3070 Tape Drive programming

lesle@NCoast.ORG (David A. Lesle) (06/19/91)

Is there any way to program the A3070 tape drive to read tapes
of lower density than 150M?  I have several tape cartridges with
tar files from a Sun system circa 1989 that I would like to read.

I remember that the Sun had several different devices depending
on which density you wanted to read, but I can't find anything
like that in the UNIX documentation.  I'd like to do this under
either AmigaDOS or UNIX so any help would be appreciated.

-- 
------------------------------------------------------------------------------
David Lesle                uucp: ncoast!lesle
CLEVELAND AREA-AMIGA USERS' GROUP (CA-AUG)     (216) 642-3344 (BBS)
------------------------------------------------------------------------------

masaru@media-lab.media.mit.edu (Masaru Sugai) (06/20/91)

In article <1991Jun19.100002.26682@NCoast.ORG> lesle@NCoast.ORG (David A. Lesle) writes:
>Is there any way to program the A3070 tape drive to read tapes
>of lower density than 150M?  I have several tape cartridges with
>tar files from a Sun system circa 1989 that I would like to read.
>
>I remember that the Sun had several different devices depending
>on which density you wanted to read, but I can't find anything
>like that in the UNIX documentation.  I'd like to do this under
>either AmigaDOS or UNIX so any help would be appreciated.

  This is a sort of gripe on A3070. I bought mine in April, but it turned
out that there is few programming info in the accompanied booklet. I asked
around on several nets when I came across several problems on trying to
use it as a tape drive for other platform including AmigaDOS. I'm partly
successful to use it as 150MB streamer, but I'm not sure if I really take
advantage of maximum performance.

  Some guy suggested me a possibility of undocumented dip switches and
vendor specific SCSI commands, but I couldn't find anybody who had
experience with CALIPER 150. I have no idea who OEMs this drive even though
it's made in Japan! 

  If AmigaUX is to be release as a software product and A3070 is the only
officially supported tape driver, many users would be no choice but to buy
this drive, even though there are no support for AmigaDOS. Methinks the 
advantage of Amiga is powerful hardware and rich PDS, and it's quite
wasteful for both us and CBM not to release programming info at large.
Or should I have opted for WangTek or Archive ? But I might have hassle 
in case of AmigaUX as well.  I would like additional doc for my A3070 too.

>David Lesle                uucp: ncoast!lesle
-- 
-- Masaru Sugai:Use disclaimer. CIS 72050,2141:NeXT + A3000 = money-eater
NEC Corporation:sugai@ccs.mt.nec.co.jp DORMANT:hardwired logic,machine language
MIT R.Affiliate:masaru@media-lab.media.mit.edu:  "Silicon on Sapphire" by CLASH

mscritsm@isis.cs.du.edu (Milton Scritsmier) (06/20/91)

In article <1991Jun19.171335.4227@news.media.mit.edu> masaru@media-lab.media.mit.edu (Masaru Sugai) writes:
>
>  This is a sort of gripe on A3070. I bought mine in April, but it turned
>out that there is few programming info in the accompanied booklet. I asked
>around on several nets when I came across several problems on trying to
>use it as a tape drive for other platform including AmigaDOS. I'm partly
>successful to use it as 150MB streamer, but I'm not sure if I really take
>advantage of maximum performance.
>
>  Some guy suggested me a possibility of undocumented dip switches and
>vendor specific SCSI commands, but I couldn't find anybody who had
>experience with CALIPER 150. I have no idea who OEMs this drive even though
>it's made in Japan! 

If the Caliper drive is truly QIC 150 compatible, it should be able to read
lower density QIC tapes automatically.  The drive itself does this by
various tricks.  The only problem might be with the mode select command,
which probably defaults to the QIC 150 density on power-up.  Even though
the drive can read the tape, it may not pass the data along until you
choose the proper density via the mode select command.  Unfortunately, I
don't have my SCSI spec handy, so I can't tell you what the correct value
would be.  Also, I believe Caliper is owned by Sanyo or Sankyo or a company
of a similar name in Japan.

crash@ckctpa.UUCP (Frank J. Edwards) (06/20/91)

Where should this have been posted to?  alt.sources?  c.s.a.programmer?
I'm listening ...

In article <1991Jun19.100002.26682@NCoast.ORG> lesle@NCoast.ORG (David A. Lesle) writes:
>Is there any way to program the A3070 tape drive to read tapes
>of lower density than 150M?  I have several tape cartridges with
>tar files from a Sun system circa 1989 that I would like to read.
>
>I remember that the Sun had several different devices depending
>on which density you wanted to read, but I can't find anything
>like that in the UNIX documentation.  I'd like to do this under
>either AmigaDOS or UNIX so any help would be appreciated.

Well, here are a couple of general purpose programs to manipulate the
tape drive directly using SCSIDirect, ie. talking to the scsi.device .

Don't complain about the coding style or I'll never again write another
piece of code!  ;-)  Seriously, though, I've since added more options than
what is given here, but they're still useful.  As soon as I pull out
a more recent backup I'll post the newer ones if anyone's interested.

>------------------------------------------------------------------------------
>David Lesle                uucp: ncoast!lesle
>CLEVELAND AREA-AMIGA USERS' GROUP (CA-AUG)     (216) 642-3344 (BBS)
>------------------------------------------------------------------------------
[Hey! say hello to Brandon@NCoast, huh?  He won't remember me but I do him!]


Here's how I tend to use these things:

1.System2.0:> tctl rewind		; rewind the tape
1.System2.0:> tctl reqblk		; request current block address
1
1.System2.0:> tctl fsf 1		; forward space to next (1) filemark
1.System2.0:> tctl fsb -200		; move backward 200 blocks
1.System2.0:> tctl mselect 1 60		; buffered,    60MB mode
1.System2.0:> tctl mselect 0 120	; unbuffered, 120MB mode
1.System2.0:> tctl mselect 1 150	; buffered,   150MB mode
					; normally the drive auto-syncs on read
1.System2.0:> tctl msense		; what is the current mode?
1.System2.0:> tctl seek 94300		; seek to...
1.System2.0:> tctl reqblk
94300
1.System2.0:> 

There are other options as well; play around a little...  This next
one is handy when you've accidentally blown away your BTN tape-handler
(nice program, huh?) and you need something to read your tapes.  Now that
I've started using BRU for everything, this isn't as necessary...

1.System2.0:> run scsird -o pipe:tar	; send tape data to PIPE:
[CLI 4]
1.System2.0:> tar -xvf pipe:tar		; extract files

I have similar programs for Amix, but everytime you re-open the tape
device (/dev/rmt/4*) the drive gets re-initialized (unfortunate, but
necessary) so you can make these changes or position the tape, but when
you again access the tape the only thing that remains is the tape position.

------ cut here ------ cut here ------ cut here ------ cut here ------
#!/bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# This archive contains:
#	Makefile	scsird.c	tctl.c
#

echo x - Makefile
sed -e 's/^X//' >Makefile <<'@EOF'
X#  Copyright (c) 1991 by Frank J. Edwards
X#  All Rights Reserved.
X#
XCC = cc
XCFLAGS = -bs -wl -DFJE
XLD = ln
XLDFLAGS = -g -w
XLIBS = -lc
X
Xtctl: tctl.o getopt.o
X	ln -o $@ tctl.o getopt.o $(LDFLAGS) $(LIBS)
X
Xscsird: scsird.o getopt.o
X	ln -o $@ scsird.o getopt.o $(LDFLAGS) $(LIBS)
@EOF

chmod 666 Makefile

echo x - scsird.c
sed -e 's/^X//' >scsird.c <<'@EOF'
X/* Copyright (c) 1991 by Frank J. Edwards
X * All Rights Reserved.
X */
X#include <stdio.h>
X#include <fcntl.h>
X#include <string.h>
X#include <devices/scsidisk.h>
X#include <proto/exec.h>
X
Xstruct reqsense {
X	UBYTE	bits[3];
X	UBYTE	rlen[4];
X	UBYTE	addlen;
X	UBYTE	srcptr, destptr;
X	UBYTE	recerrs[4];
X} rs;
X#define REQ_SIZE	(UBYTE) sizeof(struct reqsense)
X#define CLASS		0x70
X#define ERRCODE		0x0F
X#define SEGMENT		0xFF
X#define FILEMARK	0x80
X#define EOM			0x40
X#define SENSEKEY	0x0F
X#define LONG(x)		((x[0]<<24) | (x[1]<<16) | (x[2]<<8) | (x[3]))
X
Xtypedef UBYTE Block[512];
Xchar *sensekey(int sense);
Xint DoSCSI(struct IOStdReq *ior);
X
Xextern int optind;
Xextern char *optarg;
Xchar *prog;
X
XUBYTE readcmd[]   = {  8, 1, 0, 0, 0, 0 };
XUBYTE rewindcmd[] = {  1, 1, 0, 0, 0, 0 };
Xstruct SCSICmd sc;
Xstruct reqsense sensedata;
Xstruct MsgPort *port;
Xstruct IOStdReq *ior;
X
Xvoid cleanup(void)
X{
X	if (ior->io_Device)
X		CloseDevice((struct IORequest *) ior), ior->io_Device = 0;
X	if (ior)
X		DeleteStdIO(ior), ior = 0;
X	if (port)
X		DeletePort(port), port = 0;
X}
X
Xvoid usage(int ier, char *fmt, ...)
X{
X	va_list args;
X
X	if (fmt) {
X		va_start(args, fmt);
X		vfprintf(stderr, fmt, args);
X		va_end(args);
X	}
X	fprintf(stderr, "Usage:  %s [-b #] [-r] [-t] -o outfile\n", prog);
X	exit( ier );
X}
X
Xmain(int argc, char **argv)
X{
X	char *fname;
X	int err, out, ch, rewind, reten;
X	Block *buffer;
X	ULONG nblks = 100, bufsiz;
X
X	if ((prog = strrchr(*argv,'/')) || (prog = strrchr(*argv,':')))
X		prog++;
X	else
X		prog = *argv;
X	fname = NULL;
X	rewind = FALSE;
X	reten = FALSE;
X
X	while ((ch = getopt(argc, argv, "b:rto:")) != EOF) {
X		switch (ch) {
X		case 'b' :
X			nblks = atol(optarg);
X			break;
X		case 'r' :
X			rewind = TRUE;
X			break;
X		case 't' :
X			fprintf(stderr, "Retensioning is unimplemented.\n");
X			/* reten = TRUE; */
X			break;
X		case 'o' :
X			if (fname)
X				usage(1, "Specified output file twice!\n");
X			fname = optarg;
X			break;
X		default  :
X			usage(1, "Illegal option -%c\n", ch);
X		}
X	}
X	buffer = (Block *) malloc(bufsiz = sizeof(Block) * nblks);
X	if (!buffer) {
X		fputs("Couldn't allocate buffer!\n", stderr);
X		exit( 10 );
X	}
X	init_io( &port, &ior );
X	ior->io_Command = HD_SCSICMD;
X	ior->io_Data    = (APTR) &sc;
X	ior->io_Length  = sizeof(sc);
X
X	sc.scsi_SenseData   = (UBYTE *) &sensedata;
X	sc.scsi_SenseLength = (UWORD)   sizeof(sensedata);
X	sc.scsi_Data        = (UWORD *) buffer;
X	sc.scsi_Length      = (ULONG)   bufsiz;
X
X	if (rewind) {
X		sc.scsi_Command     = (UBYTE *) rewindcmd;
X		sc.scsi_CmdLength   = (UWORD)   sizeof(rewindcmd);
X		sc.scsi_Flags       = (UBYTE)   SCSIF_READ | SCSIF_AUTOSENSE;
X		if (err = DoSCSI(ior))
X			exit( 20 );
X	}
X#if 0
X	if (reten) {
X		sc.scsi_Command     = (UBYTE *) retencmd;
X		sc.scsi_CmdLength   = (UWORD)   sizeof(retencmd);
X		sc.scsi_Flags       = (UBYTE)   SCSIF_READ | SCSIF_AUTOSENSE;
X		if (err = DoSCSI(ior))
X			exit( 20 );
X	}
X#endif
X	sc.scsi_Command     = (UBYTE *) readcmd;
X	sc.scsi_CmdLength   = (UWORD)   sizeof(readcmd);
X	sc.scsi_Flags       = (UBYTE)   SCSIF_READ | SCSIF_AUTOSENSE;
X
X	readcmd[2] = (bufsiz >> 25) & 0xFF;		/* ((siz/512) >> 16) */
X	readcmd[3] = (bufsiz >> 17) & 0xFF;		/* ((siz/512) >>  8) */
X	readcmd[4] = (bufsiz >>  9) & 0xFF;
X
X	if (!fname)
X		usage(10, "Must specify an output filename!\n");
X	out = open(fname, O_WRONLY | O_CREAT | O_TRUNC);
X	ior->io_Error = 0;
X	while (!ior->io_Error) {
X		if (err = DoSCSI(ior)) {
X			fprintf(stderr, "Error %d during DoSCSI()!\n", err);
X			break;
X		} else if (sc.scsi_Actual) {
X			if (sc.scsi_Actual != bufsiz)
X				fprintf(stderr, "Short block (%ld bytes)\n", sc.scsi_Actual);
X			if (write(out, buffer, sc.scsi_Actual) != sc.scsi_Actual)
X				perror(fname);
X		} else
X			fprintf(stderr, "No data transferred.\n");
X	}
X	close(out);
X	if (rewind) {
X		sc.scsi_Command     = (UBYTE *) rewindcmd;
X		sc.scsi_CmdLength   = (UWORD)   sizeof(rewindcmd);
X		sc.scsi_Flags       = (UBYTE)   SCSIF_READ | SCSIF_AUTOSENSE;
X		(void) DoSCSI(ior);
X	}
X	return( err );
X}
X
Xinit_io(struct MsgPort **Port, struct IOStdReq **Ior)
X{
X	int err;
X
X	atexit(cleanup);
X	if (! (*Port = CreatePort(0L, 0L)) ) {
X		fputs("Couldn't CreatePort()!\n", stderr);
X		exit( 10 );
X	}
X	if (! (*Ior = CreateStdIO(*Port)) ) {
X		fputs("Couldn't CreateStdIO()!\n", stderr);
X		exit( 10 );
X	}
X	err = 2;
X	if (err = OpenDevice("scsi.device", err, (struct IORequest *) *Ior, 0)) {
X		fprintf(stderr, "Error %d from OpenDevice()!\n", err);
X		exit( 10 );
X	}
X	return( 0 );
X}
X
Xchar *sensekey(int sense)
X{
X	static char *SenseKey[] = {
X		"FM/EOM or no status available",
X		"Recovered from error; command successful",
X		"Not Ready",
X		"Medium Error",
X		"Hardware Error",
X		"Illegal Request (illegal parameter in CDB)",
X		"Unit Attention (cartridge changed or Viper reset)",
X		"Data Protect (cartridge is write-portected)",
X		"Blank Check (no-data condition found on tape)",
X		"Vendor Unique Code -- not used on Viper",
X		"-- undocumented error --",
X		"Aborted Command (may retry)",
X		"-- undocumented error --",
X		"Volume Overflow (internal buffer may contain data)",
X	};
X#define KEY_SIZE	sizeof(SenseKey)
X	return( SenseKey[sense] );
X}
X
Xint DoSCSI(struct IOStdReq *ior)
X{
X	int err;
X
X	while (err = DoIO( (struct IORequest *)ior )) {
X		struct SCSICmd *scsicmd = (struct SCSICmd *) ior->io_Data;
X		struct reqsense *rs;
X
X		if (err!=HFERR_BadStatus || !(scsicmd->scsi_Flags&SCSIF_AUTOSENSE)) {
X			fprintf(stderr, "Got error %d from DoIO()!\n", err);
X			return( err );
X		}
X		rs = (struct reqsense *) scsicmd->scsi_SenseData;
X		if (err = rs->bits[2]) {
X			if (err & FILEMARK) {
X				fputs("Filemark.\n", stderr);
X				return( err );
X			} else if (err & EOM) {
X				fputs("End-of-Media.\n", stderr);
X				return( err );
X			} else {
X				err &= SENSEKEY;
X				fprintf(stderr, "sense key = %d (%s)\n", err, sensekey(err));
X				if (err == 1)			/* Recovered Error */
X					break;
X				else if (err != 6)		/* Unit Attention */
X					return( err );
X			}
X		}
X	}
X	return( 0 );
X}
@EOF

chmod 666 scsird.c

echo x - tctl.c
sed -e 's/^X//' >tctl.c <<'@EOF'
X/* Copyright (c) 1991 by Frank J. Edwards
X * All Rights Reserved.
X */
X#include <stdio.h>
X#include <fcntl.h>
X#include <string.h>
X#include <stdarg.h>
X#include <exec/types.h>
X#include <exec/io.h>
X#include <devices/scsidisk.h>
X#include <clib/exec_protos.h>
X
Xextern struct MsgPort *CreatePort(char *, long);
Xextern struct IOStdReq *CreateStdIO(struct MsgPort *);
X
Xstruct reqsense {
X	UBYTE	bits[3];
X	UBYTE	rlen[4];
X	UBYTE	addlen;
X	UBYTE	srcptr, destptr;
X	UBYTE	recerrs[4];
X} rs;
X#define REQ_SIZE	(UBYTE) sizeof(struct reqsense)
X#define CLASS		0x70
X#define ERRCODE		0x0F
X#define SEGMENT		0xFF
X#define FILEMARK	0x80
X#define EOM			0x40
X#define SENSEKEY	0x0F
X#define LONG(x)		((x[0]<<24) | (x[1]<<16) | (x[2]<<8) | (x[3]))
X
Xchar *sensekey(int sense);
Xint DoSCSI(struct IOStdReq *ior);
X
Xextern int optind;
Xextern char *optarg;
Xchar *prog;
X
XUBYTE trewind[]  = {  1, 0, 0, 0, 0, 0 };
XUBYTE treqblk[]  = {  2, 0, 0, 0, 0, 0 };	/* blockaddr returned in [2..4] */
XUBYTE tseekblk[] = { 12, 0, 0, 0, 0, 0 };	/* blockaddr into [2..4] */
XUBYTE twritefm[] = { 16, 0, 0, 0, 0, 0 };	/* count into [2..4] */
XUBYTE tspace[]   = { 17, 0, 0, 0, 0, 0 };	/* (tspace[1] & 03) == SPACE_TYPE */
XUBYTE tverify[]  = { 19, 1, 0, 0, 0, 0 };	/* length into [2..4] */
XUBYTE terase[]   = { 25, 1, 0, 0, 0, 0 };
X
Xstruct SCSICmd sc;
Xstruct reqsense sensedata;
Xstruct MsgPort *port;
Xstruct IOStdReq *ior;
X
Xvoid cleanup(void)
X{
X	if (ior->io_Device)
X		CloseDevice((struct IORequest *) ior), ior->io_Device = 0;
X	if (ior)
X		DeleteStdIO(ior), ior = 0;
X	if (port)
X		DeletePort(port), port = 0;
X}
X
Xchar *cmdlist[] = {
X#define REWIND 0
X	"rewind",		/* Rewind the tape */
X/*	"reset",		/* Reset the controller */
X/*	"sense",		/* Print out request sense data */
X#define REQBLK 1
X#define SEEK 2
X#define FSB 3
X#define FSF 4
X#define FSSF 5
X#define EOD 6
X	"reqblk",		/* Print out current block position */
X	"seek",			/* Seek to given block */
X	"fsb",			/* Forward Space Blocks */
X	"fsf",			/* Forward Space Filemarks */
X	"fssf",			/* Forward Space Sequential Filemarks */
X	"eod",			/* Forward to EOD */
X#define ERASE 7
X#define WRITEFM 8
X	"erase",		/* Erase the tape */
X	"writefm",		/* Write filemarks on tape */
X#define VERIFY 9
X	"verify",		/* Run CRC verification on # blocks */
X	NULL };
Xchar **cmdp;
X
Xvoid usage(int ier, char *fmt, ...)
X{
X	if (fmt) {
X		va_list args;
X
X		va_start(args, fmt);
X		vfprintf(stderr, fmt, args);
X		va_end(args);
X	}
X	fprintf(stderr, "Usage:  %s [-s #] { command }\n", prog);
X	fputs("  -s specifies the SCSI ID of the tape drive, and\n", stderr);
X	fputs("  the rest are:  rewind, eod, reqblk, verify, and\n", stderr);
X	fputs("  erase don't take parameters;  seek, fsb, fsf, fssf,\n", stderr);
X	fputs("  and writefm do.\n", stderr);
X
X	exit( ier );
X}
X
Xvoid encode_size(register UBYTE *cmd, register int offset, register long pos)
X{
X	cmd[offset++] = (pos >> 16) & 0xFF;
X	cmd[offset++] = (pos >>  8) & 0xFF;
X	cmd[offset]   = (   pos   ) & 0xFF;
X}
X
Xmain(int argc, char **argv)
X{
X	int err, cmd, scsi_id = 2;		/* My tape drive is at "2" */
X	long value;
X
X	if ((prog = strrchr(*argv,'/')) || (prog = strrchr(*argv,':')))
X		prog++;
X	else
X		prog = *argv;
X
X	if (argc > 1 && !strcmp(argv[1], "-s")) {
X		if (argc > 2)
X			scsi_id = atoi(argv[2]);
X		argc -= 2;
X		argv += 2;
X	}
X	if (argc < 2)
X		usage(5, NULL);
X
X	init_io( scsi_id, &port, &ior );
X	ior->io_Command = HD_SCSICMD;
X	ior->io_Data    = (APTR) &sc;
X	ior->io_Length  = sizeof(sc);
X
X	sc.scsi_SenseData   = (UBYTE *) &sensedata;
X	sc.scsi_SenseLength = (UWORD)   sizeof(sensedata);
X	sc.scsi_Data        = (UWORD *) 0;
X	sc.scsi_Length      = (ULONG)   0;
X
X	while (argc-- > 1) {
X		++argv;
X		for (cmdp = cmdlist; *cmdp; cmdp++)
X			if (!strcmp(*cmdp, *argv))
X				break;
X		if (!*cmdp)
X			usage(5, "Unknown option `%s'\n", *argv);
X		cmd = cmdp - cmdlist;
X		if (cmd == FSB || cmd == FSF || cmd == FSSF ||
X										cmd == SEEK || cmd == WRITEFM) {
X			if (argc-- > 1)
X				value = atol(*++argv);
X			else
X				usage(5, "Required value for `%s' missing\n", *argv);
X		}
X		if (err = doit(cmd, value))
X			break;
X	}
X	return( err );
X}
X
Xint doit(int cmd, long value)
X{
X	int err;
X	unsigned char reqblkd[3];
X
X	sc.scsi_Flags = (UBYTE) SCSIF_READ | SCSIF_AUTOSENSE;
X	switch (cmd) {
X	case REWIND  :
X		sc.scsi_Command   = (UBYTE *) trewind;
X		sc.scsi_CmdLength = (ULONG)   sizeof(trewind);
X		break;
X#if 0
X	case RESET   :
X		sc.scsi_Command   = (UBYTE *) treset;
X		sc.scsi_CmdLength = (ULONG)   sizeof(treset);
X		break;
X	case SENSE   :
X		sc.scsi_Command   = (UBYTE *) treqsen;
X		sc.scsi_CmdLength = (ULONG)   sizeof(treqsen);
X		break;
X#endif
X	case REQBLK  :
X		sc.scsi_Command   = (UBYTE *) treqblk;
X		sc.scsi_CmdLength = (ULONG)   sizeof(treqblk);
X		sc.scsi_Data      = (UWORD *) reqblkd;
X		sc.scsi_Length    = (ULONG)   3;
X		break;
X	case SEEK    :
X		sc.scsi_Command   = (UBYTE *) tseekblk;
X		sc.scsi_CmdLength = (ULONG)   sizeof(tseekblk);
X		encode_size(tseekblk, 2, value);
X		break;
X	case FSB     :
X		sc.scsi_Command   = (UBYTE *) tspace;
X		sc.scsi_CmdLength = (ULONG)   sizeof(tspace);
X		tspace[1] = 0;
X		encode_size(tspace, 2, value);
X		break;
X	case FSF     :
X		sc.scsi_Command   = (UBYTE *) tspace;
X		sc.scsi_CmdLength = (ULONG)   sizeof(tspace);
X		tspace[1] = 1;
X		encode_size(tspace, 2, value);
X		break;
X	case FSSF    :
X		sc.scsi_Command   = (UBYTE *) tspace;
X		sc.scsi_CmdLength = (ULONG)   sizeof(tspace);
X		tspace[1] = 2;
X		encode_size(tspace, 2, value);
X		break;
X	case EOD     :
X		sc.scsi_Command   = (UBYTE *) tspace;
X		sc.scsi_CmdLength = (ULONG)   sizeof(tspace);
X		tspace[1] = 3;
X		break;
X	case ERASE   :
X		sc.scsi_Command   = (UBYTE *) terase;
X		sc.scsi_CmdLength = (ULONG)   sizeof(terase);
X		break;
X	case WRITEFM :
X		sc.scsi_Command   = (UBYTE *) twritefm;
X		sc.scsi_CmdLength = (ULONG)   sizeof(twritefm);
X		encode_size(twritefm, 2, value);
X		break;
X	case VERIFY  :
X		sc.scsi_Command   = (UBYTE *) tverify;
X		sc.scsi_CmdLength = (ULONG)   sizeof(tverify);
X		encode_size(tverify, 2, value);
X		break;
X	}
X	ior->io_Error = 0;
X	if (err = DoSCSI(ior))
X		fprintf(stderr, "Error %d during DoSCSI()!\n", err);
X	if (cmd == REQBLK)
X		printf("%ld\n", (reqblkd[0] << 16) | (reqblkd[1] << 8) | reqblkd[2]);
X	return( err ? err : ior->io_Error );
X}
X
Xinit_io(int scsi_id, struct MsgPort **Port, struct IOStdReq **Ior)
X{
X	int err;
X
X	atexit(cleanup);
X	if (! (*Port = CreatePort(0L, 0L)) ) {
X		fputs("Couldn't CreatePort()!\n", stderr);
X		exit( 10 );
X	}
X	if (! (*Ior = CreateStdIO(*Port)) ) {
X		fputs("Couldn't CreateStdIO()!\n", stderr);
X		exit( 10 );
X	}
X	if (err = OpenDevice("scsi.device", scsi_id, (struct IORequest *) *Ior, 0)) {
X		fprintf(stderr, "Error %d from OpenDevice()!\n", err);
X		exit( 10 );
X	}
X	return( 0 );
X}
X
Xchar *sensekey(int sense)
X{
X	static char *SenseKey[] = {
X		"FM/EOM or no status available",
X		"Recovered from error; command successful",
X		"Not Ready",
X		"Medium Error",
X		"Hardware Error",
X		"Illegal Request (illegal parameter in CDB)",
X		"Unit Attention (cartridge changed or Viper reset)",
X		"Data Protect (cartridge is write-portected)",
X		"Blank Check (no-data condition found on tape)",
X		"Vendor Unique Code -- not used on Viper",
X		"-- undocumented error --",
X		"Aborted Command (may retry)",
X		"-- undocumented error --",
X		"Volume Overflow (internal buffer may contain data)",
X	};
X#define KEY_SIZE	sizeof(SenseKey)
X	return( SenseKey[sense] );
X}
X
Xint DoSCSI(struct IOStdReq *ior)
X{
X	register int err, retry = 4;
X
X	while ((err = DoIO((struct IORequest *)ior)) && (retry-- > 0)) {
X		struct SCSICmd *scsicmd = (struct SCSICmd *) ior->io_Data;
X		struct reqsense *rs;
X
X		if (err != HFERR_BadStatus) {
X			fprintf(stderr, "Got error %d from DoIO()!\n", err);
X			return( err );
X		}
X		rs = (struct reqsense *) scsicmd->scsi_SenseData;
X		if (err = rs->bits[2]) {
X			if (err & FILEMARK) {
X				fputs("Filemark encountered.\n", stderr);
X				return( err );
X			} else if (err & EOM) {
X				fputs("End-Of-Media encountered.\n", stderr);
X				return( err );
X			} else {
X				err &= SENSEKEY;
X				fprintf(stderr, "sense key = %d (%s)\n", err, sensekey(err));
X				if (err == 1)			/* Recovered Error */
X					break;
X				else if (err != 6)		/* Unit Attention */
X					return( err );
X			}
X		}
X	}
X	return( 0 );
X}
@EOF

chmod 666 tctl.c

exit 0
------ cut here ------ cut here ------ cut here ------ cut here ------
-- 
Frank J. Edwards		|  "I did make up my own mind -- there
2677 Arjay Court		|   simply WASN'T ANY OTHER choice!"
Palm Harbor, FL  34684-4504	|		-- Me
Phone (813) 786-3675 (voice)	|    Only Amiga Makes It Possible...

jmpor@dynam.UUCP (Jean-MarcPorchet) (06/21/91)

In article <1991Jun19.171335.4227@news.media.mit.edu>, Masaru Sugai writes:

> 
>   If AmigaUX is to be release as a software product and A3070 is the only
> officially supported tape driver, many users would be no choice but to buy
> this drive, even though there are no support for AmigaDOS. Methinks the 
> advantage of Amiga is powerful hardware and rich PDS, and it's quite
> wasteful for both us and CBM not to release programming info at large.
> Or should I have opted for WangTek or Archive ? But I might have hassle 
> in case of AmigaUX as well.  I would like additional doc for my A3070 too.

  I think you can use the drive you want at long it can read and write
QIC 150 cartridges. At the moment I use a WANGTEK 5150ES and it work
perfectly well under unix and AmigaDos. 

Under Amigados I use the TapeStore Program from GVP, latest version work
on the A3000 and with the A3070.

> 
> >David Lesle                uucp: ncoast!lesle
> -- 
> -- Masaru Sugai:Use disclaimer. CIS 72050,2141:NeXT + A3000 = money-eater
> NEC Corporation:sugai@ccs.mt.nec.co.jp DORMANT:hardwired logic,machine language
> MIT R.Affiliate:masaru@media-lab.media.mit.edu:  "Silicon on Sapphire" by CLASH

--

PS : forget my bad English, I'm still trying to learn it
-----------------------------------------------------------------------------
Jean-Marc PORCHET                                    Phone : 41 22-754-1733
301 Mandement Road                                   ORG   : DYNAMIC COMPUTER
1281 RUSSIN
SWITZERLAND      UUCP :   ...{uunet,rutgers}!cbmvax!cbmehq!cbmswi!dynam!jmpor
					  or try   mcsun!cbmswi!dynam!jmpor		 
-----------------------------------------------------------------------------
'Simple things should be simple & complex things should be possible' Alan key

rhealey@kas.helios.mn.org (Rob Healey) (06/23/91)

In article <1991Jun19.171335.4227@news.media.mit.edu> masaru@media-lab.media.mit.edu (Masaru Sugai) writes:
>  If AmigaUX is to be release as a software product and A3070 is the only
>officially supported tape driver, many users would be no choice but to buy
>this drive, even though there are no support for AmigaDOS. Methinks the 
	
	Huh? The 3070 works great under AmigaDOS 2.0, and if you have
	Amiga UNIX you should have AmigaDOS 2.0. Look at BRU...

	OK, so you don't like BRU. Well, BRU is using the scsi.device
	driver to do the dirty work. If BRU can do it then other packages
	should be able to do it too.

	Maybe C= could comment officially if the SCSI driver under UNIX
	can handle generic 150M SCSI tape drives? Not neccessarily optimally,
	but will they work at all? How about support for other SCSI
	devices? Is the main SCSI driver written so that subdrivers can
	hook right into it? For Tapes, CD-ROM's, foo and bar SCSI gadgets etc...

		-Rob

bdb@becker.UUCP (Bruce D. Becker) (06/25/91)

In article <1991Jun19.171335.4227@news.media.mit.edu> masaru@media-lab.media.mit.edu (Masaru Sugai) writes:
|
|In article <1991Jun19.100002.26682@NCoast.ORG> lesle@NCoast.ORG (David A. Lesle) writes:
|>Is there any way to program the A3070 tape drive to read tapes
|>of lower density than 150M?  I have several tape cartridges with
|>tar files from a Sun system circa 1989 that I would like to read.
|>
|>I remember that the Sun had several different devices depending
|>on which density you wanted to read, but I can't find anything
|>like that in the UNIX documentation.  I'd like to do this under
|>either AmigaDOS or UNIX so any help would be appreciated.

	I wonder how to read 60 MB tapes under either
	AmigaDos or Unix also. I need to read one now
	as well, so it's not an idle question, sigh

|  If AmigaUX is to be release as a software product and A3070 is the only
|officially supported tape driver, many users would be no choice but to buy
|this drive, even though there are no support for AmigaDOS. Methinks the 
|advantage of Amiga is powerful hardware and rich PDS, and it's quite
|wasteful for both us and CBM not to release programming info at large.
|Or should I have opted for WangTek or Archive ? But I might have hassle 
|in case of AmigaUX as well.  I would like additional doc for my A3070 too.

	Early versions of Amiga Unix were on A2500 hardware,
	and came with Archive or Wangtek tape drives.  Both
	functioned without obvious problems, altho I'm not
	aware of which jumpers were different from normal
	factory settings (other than SCSI i.d., which is
	usually 4 for Amiga Unix tape streamers).

-- 
  ,u,	 Bruce Becker	Toronto, Ontario
a /i/	 Internet: bdb@becker.UUCP, bruce@gpu.utcs.toronto.edu
 `\o\-e	 UUCP: ...!utai!mnetor!becker!bdb
 _< /_	 "Ferget yer humanity, do the poot" - devo