/*
 * Magtape driver
 */

#include <sys/local.h>
#include <sys/param.h>
#include <sys/inode.h>
#include "../saio.h"

#define CDISARM  0xc0
#define CENABLE  0x40
#define CCLEAR   0x20
#define CREAD    0x21
#define CWRITE   0x22
#define CWF      0x30
#define CRW      0x38
#define CFF      0x23
#define CBF      0x13
#define CBR      0x11

#define	ERR	0x80
#define	EOF	0x40
#define	EOT	0x20
#define	NMTN	0x10
#define	BSY	0x04
#define	DU	0x01

#define	STOP	0x48
#define	GO	0x50
#define	READ_GO	0x70
#define SELCHBSY	0x08

char    mtaddr[]        = { 0x85 };
char    mtselch         = 0xf0;

mtclose(io)
register struct iob *io;
{
	mtstrategy(io, CRW);
}

mtopen(io)
register struct iob *io;
{
	register mt, skip;

	if ((mt = io->i_deva) == 0) mt = mtaddr[io->i_unit];
	oc(mt, CCLEAR);
	oc(mt, CDISARM);
	mtstrategy(io, CRW);
	skip = io->i_boff;
	while (skip--)
		mtstrategy(io, CFF);
}
mtstrategy(io, func)
register struct iob *io;
{
	register int mt, selch, errcnt, stat;

	if ((mt = io->i_deva) == 0) mt = mtaddr[io->i_unit];
	errcnt = 0;
retry:
	if (ss(mt) & DU) {
		printf("Tape offline ad=%x\n", mt);
		return(-1);
	}
	switch (func) {
		case CRW:       /* rewind */
		case CFF:       /* forward space file */
			oc(mt, func);
			mtquiet(mt);
			break;
		case READ:      /* read record */
		case WRITE:     /* write record */
			if ((selch = io->i_selch) == 0) selch = mtselch;
			oc(selch, STOP);
			wdh(selch, io->i_ma);
			wdh(selch, io->i_ma + io->i_cc - 1);
			if (func == READ) {
				oc(mt, CREAD);
				oc(selch, READ_GO);
			} else {
				oc(mt, CWRITE);
				oc(selch, GO);
			}
			while (ss(selch) & SELCHBSY) ;
			oc(selch, STOP);
			mtquiet(mt);
			if ((stat = ss(mt)) & (EOF|EOT))
				return(0);
			if (stat & ERR) {
				if (errcnt == 0)
					printf("Tape error: er=%x ad=%x", stat, mt);
				if (errcnt==10) {
					printf("\n");
					return(-1);
				}
				errcnt++;
				oc(mt, CBR);
				mtquiet(mt);
				goto retry;
			}
			if (errcnt)
				printf(" recovered by retry\n");
			return(((rdh(selch)+1) & ~01) - io->i_ma);
	}
}

mtquiet(addr)
{
	while ((ss(addr) & NMTN) == 0)
		;
}
