xref: /csrg-svn/sys/i386/isa/wt.c (revision 63364)
149617Sbostic /*-
2*63364Sbostic  * Copyright (c) 1991, 1993
3*63364Sbostic  *	The Regents of the University of California.  All rights reserved.
449617Sbostic  *
549617Sbostic  * %sccs.include.redist.c%
649617Sbostic  *
7*63364Sbostic  *	@(#)wt.c	8.1 (Berkeley) 06/11/93
849617Sbostic  */
949617Sbostic 
1049617Sbostic /*
1149617Sbostic  *
1249617Sbostic  * Copyright (c) 1989 Carnegie-Mellon University.
1349617Sbostic  * All rights reserved.
1449617Sbostic  *
1549617Sbostic  * Authors: Robert Baron
1649617Sbostic  *
1749617Sbostic  * Permission to use, copy, modify and distribute this software and
1849617Sbostic  * its documentation is hereby granted, provided that both the copyright
1949617Sbostic  * notice and this permission notice appear in all copies of the
2049617Sbostic  * software, derivative works or modified versions, and any portions
2149617Sbostic  * thereof, and that both notices appear in supporting documentation.
2249617Sbostic  *
2349617Sbostic  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
2449617Sbostic  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
2549617Sbostic  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
2649617Sbostic  *
2749617Sbostic  * Carnegie Mellon requests users of this software to return to
2849617Sbostic  *
2949617Sbostic  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
3049617Sbostic  *  School of Computer Science
3149617Sbostic  *  Carnegie Mellon University
3249617Sbostic  *  Pittsburgh PA 15213-3890
3349617Sbostic  *
3449617Sbostic  * any improvements or extensions that they make and grant Carnegie the
3549617Sbostic  * rights to redistribute these changes.
3649617Sbostic  */
3749617Sbostic 
3845553Sbill #include "wt.h"
3945553Sbill #if NWT > 0
4045553Sbill /*
4145553Sbill  * HISTORY
4245553Sbill  * $Log:	wt.c,v $
4345553Sbill  * Revision 2.2.1.3  90/01/08  13:29:38  rvb
4445553Sbill  * 	Add Intel copyright.
4545553Sbill  * 	[90/01/08            rvb]
4645553Sbill  *
4745553Sbill  * Revision 2.2.1.2  89/12/21  18:00:09  rvb
4845553Sbill  * 	Change WTPRI to make the streamer tape read/write
4945553Sbill  * 	interruptible. 		[lin]
5045553Sbill  *
5145553Sbill  * Revision 2.2.1.1  89/11/10  09:49:49  rvb
5245553Sbill  * 	ORC likes their streamer port at 0x288.
5345553Sbill  * 	[89/11/08            rvb]
5445553Sbill  *
5545553Sbill  * Revision 2.2  89/09/25  12:33:02  rvb
5645553Sbill  * 	Driver was provided by Intel 9/18/89.
5745553Sbill  * 	[89/09/23            rvb]
5845553Sbill  *
5945553Sbill  */
6045553Sbill 
6145553Sbill /*
6245553Sbill  *
6345553Sbill  *  Copyright 1988, 1989 by Intel Corporation
6445553Sbill  *
6545553Sbill  *	Support Bell Tech QIC-02 and WANGTEK QIC-36 or QIC-02
6645553Sbill  */
6745553Sbill 
6856513Sbostic #include <sys/param.h>
6956513Sbostic #include <sys/buf.h>
7056513Sbostic #include <sys/file.h>
7156513Sbostic #include <sys/proc.h>
7256513Sbostic #include <sys/user.h>
7345553Sbill 
7456513Sbostic #include <i386/isa/wtreg.h>
7556513Sbostic 
7645553Sbill #ifdef	ORC
7745553Sbill unsigned wtport = 0x288;	/* base I/O port of controller	*/
7845553Sbill #else	ORC
7945553Sbill unsigned wtport = 0x300;	/* base I/O port of controller	*/
8045553Sbill #endif	ORC
8145553Sbill 				/* standard = 0x300		*/
8245553Sbill 				/* alternate = 0x338		*/
8345553Sbill 
8445553Sbill unsigned wtchan = 1;		/* DMA channel number		*/
8545553Sbill 				/* stardard = 1			*/
8645553Sbill 				/* hardware permits 1, 2 or 3.	*/
8745553Sbill 		                /* (Avoid DMA 2: used by disks) */
8845553Sbill 
8945553Sbill int	first_wtopen_ever = 1;
9045553Sbill 
9145553Sbill 
9245553Sbill #define	ERROR 		1	/* return from tape routines */
9345553Sbill #define	SUCCESS		0	/* return from tape routines */
9445553Sbill 
9545553Sbill int	wci = 0;
9645553Sbill int	exflag = 0;
9745553Sbill int	bytes = 0;
9845553Sbill 
9945553Sbill static	unsigned char eqdma = 0x8;
10045553Sbill static	unsigned char pagereg = 0x83;
10145553Sbill static	unsigned char dmareg = 2;
10245553Sbill static	unsigned char dma_write = 0x49;
10345553Sbill static	unsigned char dma_read = 0x45;
10445553Sbill static	unsigned char dma_done = 2;
10545553Sbill static	unsigned char mode = 0;
10645553Sbill static	unsigned char mbits;	/* map bits into each other */
10745553Sbill static	long bufptr;
10845553Sbill static	unsigned numbytes;
10945553Sbill /*
11045553Sbill _wci		dw	0	; interrupt chain finished normally
11145553Sbill _exflag		dw	0	; exception variable
11245553Sbill _bytes		dw	0	; current bytes
11345553Sbill 
11445553Sbill eqdma		db	8h	; enable dma command: ch1,ch2=8h, ch3=10h
11545553Sbill pagereg		db	83h	; ch1=83h, ch2=81h, ch3=82h
11645553Sbill dmareg		db	2	; ch1=2, ch2=4, ch3=6
11745553Sbill dma_write	db	49h	; write dma command: 48h+_wtchan
11845553Sbill dma_read	db	45h	; read dma command: 44h+_wtchan
11945553Sbill dma_done	db	2	; dma done flag: 1<<_wtchan
12045553Sbill mode		db	0	; dma operation mode
12145553Sbill lbufptr		dw	0	; buffer pointer to data buffers, low word
12245553Sbill hbufptr		dw	0	; buffer pointer to data buffers, high word
12345553Sbill numbytes	dw	0	; number of bytes to read or write (new)
12445553Sbill */
12545553Sbill 
12645553Sbill #define PAGESIZ		4096
12745553Sbill #define HZ		60
12845553Sbill 
12945553Sbill /* tape controller ports */
13045553Sbill #define STATPORT	wtport
13145553Sbill #define CTLPORT		STATPORT
13245553Sbill #define CMDPORT		(wtport+1)
13345553Sbill #define DATAPORT	CMDPORT
13445553Sbill 
13545553Sbill /* defines for reading out status from wangtek tape controller */
13645553Sbill #define READY   	0x01    /* ready bit define        */
13745553Sbill #define EXCEP		0x02	/* exception bit define    */
13845553Sbill #define STAT		(READY|EXCEP)
13945553Sbill #define	RESETMASK	0x7
14045553Sbill #define	RESETVAL	(RESETMASK & ~EXCEP)
14145553Sbill 
14245553Sbill /* tape controller control bits (CTLPORT) */
14345553Sbill #define	ONLINE	0x01
14445553Sbill #define	RESET	0x02
14545553Sbill #define	REQUEST	0x04		/* request command */
14645553Sbill #define	CMDOFF	0xC0
14745553Sbill 
14845553Sbill /* QIC-02 commands (CMDPORT) */
14945553Sbill #define	RDDATA	0x80		/* read data */
15045553Sbill #define	READFM	0xA0		/* read file mark */
15145553Sbill #define	WRTDATA	0x40		/* write data */
15245553Sbill #define	WRITEFM	0x60		/* write file mark */
15345553Sbill #define	RDSTAT	0xC0		/* read status command */
15445553Sbill #define	REWIND	0x21		/* rewind command (position+bot) */
15545553Sbill 
15645553Sbill /* 8237 DMA controller regs */
15745553Sbill #define	STATUSREG	0x8
15845553Sbill #define MASKREG		0xA
15945553Sbill #define MODEREG		0xB
16045553Sbill #define CLEARFF		0xC
16145553Sbill 
16245553Sbill /* streamer tape block size */
16345553Sbill #define BLKSIZE	512
16445553Sbill 
16545553Sbill /* Tape characteristics */
16645553Sbill #define	NBPS		512	/* 512-byte blocks */
16745553Sbill #define	ERROR 		1	/* return from tape routines */
16845553Sbill #define	SUCCESS		0	/* return from tape routines */
16945553Sbill 
17045553Sbill /* Minor devs */
17145553Sbill #define	TP_REWCLOSE(d)	((minor(d)&04) == 0) /* Rewind tape on close if read/write */
17245553Sbill #define	TP_DENS(dev)	((minor(dev) >> 3) & 03) /* set density */
17345553Sbill #define TPHOG(d)	0	/* use Hogproc during tape I/O	*/
17445553Sbill 
17545553Sbill /* defines for wtflags */
17645553Sbill #define	TPINUSE	0x0001		/* tape is already open */
17745553Sbill #define	TPREAD	0x0002		/* tape is only open for reading */
17845553Sbill #define	TPWRITE	0x0004		/* tape is only open for writing */
17945553Sbill #define	TPSTART 0x0008		/* tape must be rewound and reset */
18045553Sbill #define	TPDEAD	0x0010		/* tape drive does not work or driver error */
18145553Sbill #define	TPSESS	0x0020		/* no more reads or writes allowed in session */
18245553Sbill 				/* for example, when tape has to be changed */
18345553Sbill #define	TPSTOP	0x0040		/* Stop command outstanding */
18445553Sbill #define	TPREW	0x0080		/* Rewind command outstanding, see wtdsl2() */
18545553Sbill #define	TPVOL	0x0100		/* Read file mark, or hit end of tape */
18645553Sbill #define	TPWO	0x0200		/* write command outstanding */
18745553Sbill #define	TPRO	0x0400		/* read command outstanding */
18845553Sbill #define TPWANY	0x0800		/* write command requested */
18945553Sbill #define TPRANY	0x1000		/* read command requested */
19045553Sbill #define	TPWP	0x2000		/* write protect error seen */
19145553Sbill 
19245553Sbill unsigned int	wtflags = TPSTART;	/* state of tape drive */
19345553Sbill 
19445553Sbill struct	buf	rwtbuf;		/* header for raw i/o */
19545553Sbill struct  proc	*myproc;	/* process which opened tape driver */
19645553Sbill 
19745553Sbill char wtimeron;			/* wtimer() active flag */
19845553Sbill char wtio;			/* dma (i/o) active flag */
19945553Sbill char isrlock;			/* isr() flag */
20045553Sbill 
20145553Sbill struct proc * Hogproc;	/* no Hogproc on Microport */
20245553Sbill #define	ftoseg(x)	((unsigned) (x >> 16))
20345553Sbill 
20445553Sbill struct	wtstatus {
20545553Sbill 	ushort	wt_err;		/* code for error encountered */
20645553Sbill 	ushort	wt_ercnt;	/* number of error blocks */
20745553Sbill 	ushort	wt_urcnt;	/* number of underruns */
20845553Sbill }	wterror;
20945553Sbill 
21045553Sbill /* defines for wtstatus.wt_err */
21145553Sbill #define	TP_POR		0x100	/* Power on/reset occurred */
21245553Sbill #define	TP_RES1		0x200	/* Reserved for end of media */
21345553Sbill #define	TP_RES2		0x400	/* Reserved for bus parity */
21445553Sbill #define	TP_BOM		0x800	/* Beginning of media */
21545553Sbill #define	TP_MBD		0x1000	/* Marginal block detected */
21645553Sbill #define	TP_NDT		0x2000	/* No data detected */
21745553Sbill #define	TP_ILL		0x4000	/* Illegal command */
21845553Sbill #define	TP_ST1		0x8000	/* Status byte 1 bits */
21945553Sbill #define	TP_FIL		0x01	/* File mark detected */
22045553Sbill #define	TP_BNL		0x02	/* Bad block not located */
22145553Sbill #define	TP_UDA		0x04	/* Unrecoverable data error */
22245553Sbill #define	TP_EOM		0x08	/* End of media */
22345553Sbill #define	TP_WRP		0x10	/* Write protected cartridge */
22445553Sbill #define	TP_USL		0x20	/* Unselected drive */
22545553Sbill #define	TP_CNI		0x40	/* Cartridge not in place */
22645553Sbill #define	TP_ST0		0x80	/* Status byte 0 bits */
22745553Sbill 
22845553Sbill /* Grounds for reporting I/O error to user */
22945553Sbill #define	TP_ERR0		(TP_BNL|TP_UDA|TP_WRP|TP_CNI|TP_FIL|TP_EOM|TP_USL)
23045553Sbill #define	TP_ERR1		(TP_MBD|TP_NDT|TP_ILL)
23145553Sbill /* TP_ILL should never happen! */
23245553Sbill /*
23345553Sbill #define	TP_ERR0		0x7f
23445553Sbill #define	TP_ERR1		0x7700
23545553Sbill */
23645553Sbill 
23745553Sbill /* defines for reading out status from wangtek tape controller */
23845553Sbill #define READY   	0x01    /* ready bit define        */
23945553Sbill #define EXCEP		0x02	/* exception bit define    */
24045553Sbill 
24145553Sbill /* sleep priority */
24245553Sbill #define WTPRI	(PZERO+10)
24345553Sbill 
24445553Sbill char	pagebuf[NBPS];		/* buffer of size NBPS */
24545553Sbill unsigned long	pageaddr;	/* physical addr of pagebuf */
24645553Sbill 				/* pageaddr is used with DMA controller */
24745553Sbill time_t Hogtime;			/* lbolt when Hog timer started */
24845553Sbill extern time_t	lbolt;
24945553Sbill 
25045553Sbill #define	debug	printf
25145553Sbill 
25245553Sbill /*
25345553Sbill  * Strategy routine.
25445553Sbill  *
25545553Sbill  * Arguments:
25645553Sbill  *  Pointer to buffer structure
25745553Sbill  * Function:
25845553Sbill  *  Start transfer.
25945553Sbill  *
26045553Sbill  * It would be nice to have this multiple-threaded.
26145553Sbill  * There is a version of dump from Berkeley that works with multiple processes
26245553Sbill  * trading off with disk & tape I/O.
26345553Sbill  */
26445553Sbill 
26545553Sbill int
wtstrategy(bp)26645553Sbill wtstrategy(bp)
26745553Sbill register struct buf *bp;
26845553Sbill {
26945553Sbill 	unsigned ucnt1, ucnt2, finished;
27045553Sbill 	unsigned long adr1, adr2;
27149573Swilliam 	int	bad;
27245553Sbill 
27345553Sbill 	adr1 = kvtop(bp->b_un.b_addr);
27445553Sbill #ifdef DEBUG
27545553Sbill 	debug("bpaddr %x\n", adr1);
27645553Sbill #endif
27745553Sbill 	ucnt1 = bp->b_bcount;
27845553Sbill 	ucnt2 = 0;
27945553Sbill 	adr2 = 0;
28045553Sbill #ifdef DEBUG
28145553Sbill 	debug("WTstart: adr1 %lx cnt %x\n", adr1, ucnt1);
28245553Sbill #endif
28345553Sbill 	if (ftoseg(adr1) != ftoseg(adr1 + (unsigned) ucnt1 - 1))
28445553Sbill 	{
28545553Sbill 		adr2 = (adr1 & 0xffff0000L) + 0x10000L;
28645553Sbill 		ucnt2 = (adr1 + ucnt1) - adr2;
28745553Sbill 		ucnt1 -= ucnt2;
28845553Sbill 	}
28945553Sbill 	/* at file marks and end of tape, we just return '0 bytes available' */
29045553Sbill 	if (wtflags & TPVOL) {
29145553Sbill 		bp->b_resid = bp->b_bcount;
29245553Sbill 		goto xit;
29345553Sbill 	}
29445553Sbill 	if ((Hogproc == (struct proc *) 0) && TPHOG(bp->b_dev))
29545553Sbill 	{
29645553Sbill #ifdef DEBUG
29745553Sbill 		printf("setting Hogproc\n");
29845553Sbill #endif
29945553Sbill 		Hogtime = 0;
30045553Sbill 		Hogproc = myproc;
30145553Sbill 	}
30245553Sbill 	if (bp->b_flags & B_READ) {
30349573Swilliam 		bad = 0;
30445553Sbill 
30545553Sbill 		/* For now, we assume that all data will be copied out */
30645553Sbill 		/* If read command outstanding, just skip down */
30745553Sbill 		if (!(wtflags & TPRO)) {
30845553Sbill 			if (ERROR == wtsense(TP_WRP))	/* clear status */
30945553Sbill 				goto errxit;
31045553Sbill #ifdef DEBUG
31145553Sbill 			debug("WTread: Start read\n");
31245553Sbill #endif
31345553Sbill 			if (!(wtflags & TPREAD) || (wtflags & TPWANY) ||
31445553Sbill 			    (rstart() == ERROR))  {
31545553Sbill #ifdef DEBUG
31645553Sbill 				debug("Tpstart: read init error\n"); /* */
31745553Sbill #endif
31845553Sbill 				goto errxit;
31945553Sbill 			}
32045553Sbill 			wtflags |= TPRO|TPRANY;
32145553Sbill 		}
32245553Sbill 
32345553Sbill 		finished = 0;
32445553Sbill 		/* Take a deep breath */
32545553Sbill 		if (ucnt1) {
32645553Sbill 			if ((rtape(adr1, ucnt1) == ERROR) &&
32745553Sbill 					(wtsense(TP_WRP) == ERROR))
32845553Sbill 				goto endio;
32945553Sbill 			/* wait for it */
33045553Sbill 			bad = pollrdy();
33145553Sbill 			finished = bytes;
33245553Sbill 			if (bad)
33345553Sbill 				goto endio;
33445553Sbill 		}
33545553Sbill 		/* if a second I/O region, start it */
33645553Sbill 		if (ucnt2) {
33745553Sbill 			if ((rtape(adr2, ucnt2) == ERROR) &&
33845553Sbill 					(wtsense(TP_WRP) == ERROR))
33945553Sbill 				ucnt2 = 0;	/* don't poll for me */
34045553Sbill 			}
34145553Sbill 
34245553Sbill 		/* if second i/o pending wait for it */
34345553Sbill 		if (ucnt2) {
34445553Sbill 			pollrdy();
34545553Sbill 			/* whether pollrdy is ok or not */
34645553Sbill 			finished += bytes;
34745553Sbill 		}
34845553Sbill 	} else {
34945553Sbill 		if (wtflags & TPWP)	/* write protected */
35045553Sbill 			goto errxit;
35145553Sbill 
35245553Sbill 		/* If write command outstanding, just skip down */
35345553Sbill 		if (!(wtflags & TPWO)) {
35445553Sbill 			if (ERROR == wtsense(0))	/* clear status */
35545553Sbill 			{
35645553Sbill #ifdef DEBUG
35745553Sbill 				debug("TPstart: sense 0\n");
35845553Sbill #endif
35945553Sbill 				goto errxit;
36045553Sbill 			}
36145553Sbill 			if (!(wtflags & TPWRITE) || (wtflags & TPRANY) ||
36245553Sbill 			    (wstart() == ERROR))  {
36345553Sbill #ifdef DEBUG
36445553Sbill 				debug("Tpstart: write init error\n"); /* */
36545553Sbill #endif
36645553Sbill 				wtsense(0);
36745553Sbill 
36845553Sbill errxit:				bp->b_flags |= B_ERROR;
36945553Sbill 				bp->b_resid = bp->b_bcount;
37045553Sbill 				goto xit;
37145553Sbill 			}
37245553Sbill 			wtflags |= TPWO|TPWANY;
37345553Sbill 		}
37445553Sbill 
37545553Sbill 		/* and hold your nose */
37645553Sbill 		if (ucnt1 && ((wtape(adr1, ucnt1) == ERROR)
37745553Sbill 				&& (wtsense(0) == ERROR)))
37845553Sbill 			finished = bytes;
37945553Sbill 
38045553Sbill 		else if (ucnt2 &&
38145553Sbill 			(((ucnt1 && pollrdy()) ||
38245553Sbill 				(wtape(adr2, ucnt2) == ERROR)) &&
38345553Sbill 				(wtsense(0) == ERROR)))
38445553Sbill 			finished = ucnt1 + NBPS + bytes;
38545553Sbill 		/* All writes and/or copyins were fine! */
38645553Sbill 		else
38745553Sbill 			finished = bp->b_bcount;
38849573Swilliam 		bad = pollrdy();
38945553Sbill 	}
39045553Sbill 
39145553Sbill 	endio:
39249573Swilliam 	if(bad == EIO) bad = 0;
39345553Sbill 	wterror.wt_err = 0;
39445553Sbill 	if (exflag && wtsense((bp->b_flags & B_READ) ? TP_WRP : 0)) {
39545553Sbill 		if ((wterror.wt_err & TP_ST0)
39645553Sbill 			&& (wterror.wt_err & (TP_FIL|TP_EOM))) {
39745553Sbill #ifdef DEBUG
39845553Sbill 			debug("WTsta: Hit end of tape\n"); /* */
39945553Sbill #endif
40045553Sbill 			wtflags |= TPVOL;
40145553Sbill 			if (wterror.wt_err & TP_FIL) {
40245553Sbill 				if (wtflags & TPRO)
40345553Sbill 					/* interrupter is bogus */
40445553Sbill 					rstart();  /* restart read command */
40545553Sbill 				else
40645553Sbill 					wtflags &= ~TPWO;
40745553Sbill 				finished += NBPS;
40845553Sbill 			}
40945553Sbill 		/* Reading file marks or writing end of tape return 0 bytes */
41045553Sbill 		} else	{
41145553Sbill 			bp->b_flags |= B_ERROR;
41245553Sbill 			wtflags &= ~(TPWO|TPRO);
41345553Sbill 		}
41445553Sbill 	}
41545553Sbill 
41649573Swilliam 	if(bad) {
41749573Swilliam 		bp->b_flags |= B_ERROR;
41849573Swilliam 		bp->b_error = bad;
41949573Swilliam 	}
42045553Sbill 	bp->b_resid = bp->b_bcount - finished;
42145553Sbill xit:
42245553Sbill 	biodone(bp);
42345553Sbill 	if (wtimeron)
42445553Sbill 		Hogtime = lbolt;
42545553Sbill 	else if (Hogproc == myproc)
42645553Sbill 		Hogproc = (struct proc *) 0;
42745553Sbill }
42845553Sbill 
42945553Sbill /*
43045553Sbill  * simulate an interrupt periodically while I/O is going
43145553Sbill  * this is necessary in case interrupts get eaten due to
43245553Sbill  * multiple devices on a single IRQ line
43345553Sbill  */
wtimer()43445553Sbill wtimer()
43545553Sbill {
43645553Sbill 	/* If I/O going and not in isr(), simulate interrupt
43745553Sbill 	 * If no I/O for at least 1 second, stop being a Hog
43845553Sbill 	 * If I/O done and not a Hog, turn off wtimer()
43945553Sbill 	 */
44045553Sbill 	if (wtio && !isrlock)
44145553Sbill 		isr();
44245553Sbill 
44345553Sbill 	if ((Hogproc == myproc) && Hogtime && (lbolt-Hogtime > HZ))
44445553Sbill 		Hogproc = (struct proc *) 0;
44545553Sbill 
44645553Sbill 	if (wtio || (Hogproc == myproc))
44745553Sbill 		timeout(wtimer, (caddr_t) 0, HZ);
44845553Sbill 	else
44945553Sbill 		wtimeron = 0;
45045553Sbill }
45145553Sbill 
45245553Sbill 
45345553Sbill wtrawio(bp)
45445553Sbill struct buf	*bp;
45545553Sbill {
45645553Sbill 	wtstrategy(bp);
45745553Sbill 	biowait(bp);
45845553Sbill 	return(0);
45945553Sbill }
46045553Sbill 
46145553Sbill wt_minphys(bp)
46245553Sbill struct buf	*bp;
46345553Sbill {
46445553Sbill 	if (bp->b_bcount > PAGESIZ)
46545553Sbill 		bp->b_bcount = PAGESIZ;
46645553Sbill }
46745553Sbill 
46845553Sbill /*
46945553Sbill  * raw read routine
47045553Sbill  */
47145553Sbill wtread(dev, uio)
47245553Sbill struct uio	*uio;
47345553Sbill {
47445553Sbill 	if (wtflags & TPSESS) {
47545553Sbill 		return(EIO);
47645553Sbill 	}
47745553Sbill 	physio(wtrawio, &rwtbuf, dev, B_READ, wt_minphys, uio);
47845553Sbill 	return(0);
47945553Sbill }
48045553Sbill 
48145553Sbill /*
48245553Sbill  * raw write routine
48345553Sbill  */
48445553Sbill wtwrite(dev, uio)
48545553Sbill struct uio	*uio;
48645553Sbill {
48745553Sbill 	if (wtflags & TPSESS) {
48845553Sbill 		return(EIO);
48945553Sbill 	}
49045553Sbill 	physio(wtrawio, &rwtbuf, dev, B_WRITE, wt_minphys, uio);
49145553Sbill 	return(0);
49245553Sbill }
49345553Sbill 
49445553Sbill 
49545553Sbill 
49645553Sbill /*
49745553Sbill  * ioctl routine
49845553Sbill  *  for user level QIC commands only
49945553Sbill  */
wtioctl(dev,cmd,arg,mode)50045553Sbill wtioctl(dev, cmd, arg, mode)
50145553Sbill int dev, cmd;
50245553Sbill unsigned long arg;
50345553Sbill int mode;
50445553Sbill {
50545553Sbill 	if (cmd == WTQICMD)
50645553Sbill 	{
50745553Sbill 		if ((qicmd((int)arg) == ERROR) || (rdyexc(HZ) == ERROR))
50845553Sbill 		{
50945553Sbill 			wtsense(0);
51049573Swilliam 			return(EIO);
51145553Sbill 		}
51249573Swilliam 		return(0);
51345553Sbill 	}
51449573Swilliam 	return(EINVAL);
51545553Sbill }
51645553Sbill 
51745553Sbill /*
51845553Sbill  * open routine
51945553Sbill  * called on every device open
52045553Sbill  */
wtopen(dev,flag)52145553Sbill wtopen(dev, flag)
52245553Sbill int	dev, flag;
52345553Sbill {
52445553Sbill 	if (first_wtopen_ever) {
52545553Sbill 		wtinit();
52645553Sbill 		first_wtopen_ever = 0;
52745553Sbill 	}
52845553Sbill #ifdef DEBUG
52945553Sbill 	printf("wtopen ...\n");
53045553Sbill #endif
53145553Sbill 	if (!pageaddr) {
53245553Sbill 		return(ENXIO);
53345553Sbill 	}
53445553Sbill 	if (wtflags & (TPINUSE)) {
53545553Sbill 		return(ENXIO);
53645553Sbill 	}
53745553Sbill 	if (wtflags & (TPDEAD)) {
53845553Sbill 		return(EIO);
53945553Sbill 	}
54045553Sbill 	/* If a rewind from the last session is going on, wait */
54145553Sbill 	while(wtflags & TPREW) {
54245553Sbill #ifdef DEBUG
54345553Sbill 		debug("Waiting for rew to finish\n");
54445553Sbill #endif
54545553Sbill 		delay(1000000);	/* delay one second */
54645553Sbill 	}
54745553Sbill 	/* Only do reset and select when tape light is off, and tape is rewound.
54845553Sbill 	 * This allows multiple volumes. */
54945553Sbill 	if (wtflags & TPSTART) {
55045553Sbill 		if (t_reset() != SUCCESS) {
55145553Sbill 			return(ENXIO);
55245553Sbill 		}
55345553Sbill #ifdef DEBUG
55445553Sbill 		debug("reset done. calling wtsense\n");
55545553Sbill #endif
55645553Sbill 		if (wtsense(TP_WRP) == ERROR) {
55745553Sbill 			return (EIO);
55845553Sbill 		}
55945553Sbill #ifdef DEBUG
56045553Sbill 		debug("wtsense done\n");
56145553Sbill #endif
56245553Sbill 		wtflags &= ~TPSTART;
56345553Sbill 	}
56445553Sbill 
56545553Sbill 	wtflags = TPINUSE;
56645553Sbill 	if (flag & FREAD)
56745553Sbill 		wtflags |= TPREAD;
56845553Sbill 	if (flag & FWRITE)
56945553Sbill 		wtflags |= TPWRITE;
57045553Sbill 	rwtbuf.b_flags = 0;
57149573Swilliam 	myproc = curproc;		/* for comparison */
57245553Sbill 	switch(TP_DENS(dev)) {
57345553Sbill case 0:
57445553Sbill cmds(0x28);
57545553Sbill break;
57645553Sbill case 1:
57745553Sbill cmds(0x29);
57845553Sbill break;
57945553Sbill case 2:
58045553Sbill cmds(0x27);
58145553Sbill break;
58245553Sbill case 3:
58345553Sbill cmds(0x24);
58445553Sbill 	}
58545553Sbill 	return(0);
58645553Sbill }
58745553Sbill 
58845553Sbill /*
58945553Sbill  * close routine
59045553Sbill  * called on last device close
59145553Sbill  * If not rewind-on-close, leave read or write command intact.
59245553Sbill  */
wtclose(dev)59345553Sbill wtclose(dev)
59445553Sbill {
59545553Sbill 	int wtdsl2();
59645553Sbill 
59745553Sbill #ifdef DEBUG
59845553Sbill 	debug("WTclose:\n");
59945553Sbill #endif
60045553Sbill 	if (Hogproc == myproc)
60145553Sbill 		Hogproc = (struct proc *) 0;
60245553Sbill 	if (!exflag && (wtflags & TPWANY) && !(wtflags & (TPSESS|TPDEAD))) {
60345553Sbill 		if (!(wtflags & TPWO))
60445553Sbill 			wstart();
60545553Sbill #ifdef DEBUG
60645553Sbill 		debug("WT: Writing file mark\n");
60745553Sbill #endif
60845553Sbill 		wmark();	/* write file mark */
60945553Sbill #ifdef DEBUG
61045553Sbill 		debug("WT: Wrote file mark, going to wait\n");
61145553Sbill #endif
61245553Sbill 		if (rdyexc(HZ/10) == ERROR) {
61345553Sbill 			wtsense(0);
61445553Sbill 			}
61545553Sbill 		}
61645553Sbill 	if (TP_REWCLOSE(dev) || (wtflags & (TPSESS|TPDEAD))) {
61745553Sbill 	/* rewind tape to beginning of tape, deselect tape, and make a note */
61845553Sbill 	/* don't wait until rewind, though */
61945553Sbill 		/* Ending read or write causes rewind to happen, if no error,
62045553Sbill 		 * and READY and EXCEPTION stay up until it finishes */
62145553Sbill 		if (wtflags & (TPRO|TPWO))
62245553Sbill 		{
62345553Sbill #ifdef DEBUG
62445553Sbill 			debug("End read or write\n");
62545553Sbill #endif
62645553Sbill 			rdyexc(HZ/10);
62745553Sbill 			ioend();
62845553Sbill 			wtflags &= ~(TPRO|TPWO);
62945553Sbill 		}
63045553Sbill 		else	wtwind();
63145553Sbill 		wtflags |= TPSTART | TPREW;
63245553Sbill 		timeout(wtdsl2, 0, HZ);
63345553Sbill 	}
63445553Sbill 	else if (!(wtflags & (TPVOL|TPWANY)))
63545553Sbill 	{
63645553Sbill 		/* space forward to after next file mark no writing done */
63745553Sbill 		/* This allows skipping data without reading it.*/
63845553Sbill #ifdef DEBUG
63945553Sbill 		debug("Reading past file mark\n");
64045553Sbill #endif
64145553Sbill 		if (!(wtflags & TPRO))
64245553Sbill 			rstart();
64345553Sbill 		rmark();
64445553Sbill 		if (rdyexc(HZ/10))
64545553Sbill 		{
64645553Sbill 			wtsense(TP_WRP);
64745553Sbill 		}
64845553Sbill 	}
64945553Sbill 	wtflags &= TPREW|TPDEAD|TPSTART|TPRO|TPWO;
65045553Sbill 	return(0);
65145553Sbill }
65245553Sbill 
65345553Sbill /* return ERROR if user I/O request should receive an I/O error code */
65445553Sbill 
wtsense(ignor)65545553Sbill wtsense(ignor)
65645553Sbill {
65745553Sbill 	wtflags &= ~(TPRO|TPWO);
65845553Sbill #ifdef DEBUGx
65945553Sbill 	debug("WTsense: start ");
66045553Sbill #endif
66145553Sbill 	if (rdstatus(&wterror) == ERROR)
66245553Sbill 	{
66345553Sbill #ifdef DEBUG
66445553Sbill 		debug("WTsense: Can't read status\n");
66545553Sbill #endif
66645553Sbill 		return(ERROR);
66745553Sbill 	}
66845553Sbill #ifdef DEBUG
66945553Sbill 	if (wterror.wt_err & (TP_ST0|TP_ST1))
67045553Sbill 	{
67145553Sbill 		debug("Tperror: status %x error %d underruns %d\n",
67245553Sbill 			wterror.wt_err, wterror.wt_ercnt, wterror.wt_urcnt);
67345553Sbill 	}
67445553Sbill 	else
67545553Sbill 		debug("done. no error\n");
67645553Sbill #endif
67745553Sbill 	wterror.wt_err &= ~ignor;	/* ignore certain errors */
67845553Sbill 	reperr(wterror.wt_err);
67945553Sbill 	if (((wterror.wt_err & TP_ST0) && (wterror.wt_err & TP_ERR0)) ||
68045553Sbill 		    ((wterror.wt_err & TP_ST1) && (wterror.wt_err & TP_ERR1)))
68145553Sbill 			return	ERROR;
68245553Sbill 
68345553Sbill 	return SUCCESS;
68445553Sbill }
68545553Sbill 
68645553Sbill /* lifted from tdriver.c from Wangtek */
reperr(srb0)68745553Sbill reperr(srb0)
68845553Sbill int srb0;
68945553Sbill {
69045553Sbill 	int s0 = srb0 & (TP_ERR0|TP_ERR1);	/* find out which exception to report */
69145553Sbill 
69245553Sbill 	if (s0) {
69345553Sbill 		if (s0 & TP_USL)
69445553Sbill 			sterr("Drive not online");
69545553Sbill 		else if (s0 & TP_CNI)
69645553Sbill 			sterr("No cartridge");
69745553Sbill 		else if ((s0 & TP_WRP) && !(wtflags & TPWP))
69845553Sbill 		{
69945553Sbill 			sterr("Tape is write protected");
70045553Sbill 			wtflags |= TPWP;
70145553Sbill 		}
70245553Sbill 		/*
70345553Sbill 		if (s0 & TP_FIL)
70445553Sbill 			sterr("Filemark detected");
70545553Sbill 		*/
70645553Sbill 		else if (s0 & TP_BNL)
70745553Sbill 			sterr("Block in error not located");
70845553Sbill 		else if (s0 & TP_UDA)
70945553Sbill 			sterr("Unrecoverable data error");
71045553Sbill 		/*
71145553Sbill 		else if (s0 & TP_EOM)
71245553Sbill 			sterr("End of tape");
71345553Sbill 		*/
71445553Sbill 		else if (s0 & TP_NDT)
71545553Sbill 			sterr("No data detected");
71645553Sbill 		/*
71745553Sbill 		if (s0 & TP_POR)
71845553Sbill 			sterr("Reset occured");
71945553Sbill 		*/
72045553Sbill 		else if (s0 & TP_BOM)
72145553Sbill 			sterr("Beginning of tape");
72245553Sbill 		else if (s0 & TP_ILL)
72345553Sbill 			sterr("Illegal command");
72445553Sbill 	}
72545553Sbill }
72645553Sbill 
sterr(errstr)72745553Sbill sterr(errstr)
72845553Sbill char	*errstr;
72945553Sbill {
73045553Sbill 	printf("Streamer: %s\n", errstr);
73145553Sbill }
73245553Sbill 
73345553Sbill /* Wait until rewind finishes, and deselect drive */
wtdsl2()73445553Sbill wtdsl2() {
73545553Sbill 	int	stat;
73645553Sbill 
73745553Sbill 	stat = inb(wtport) & (READY|EXCEP);
73845553Sbill #ifdef DEBUG
73945553Sbill 	debug("Timeout: Waiting for rewind to finish: stat %x\n", stat);
74045553Sbill #endif
74145553Sbill 	switch (stat) {
74245553Sbill 		/* They're active low, ya'know */
74345553Sbill 		case READY|EXCEP:
74445553Sbill 			timeout(wtdsl2, (caddr_t) 0, HZ);
74545553Sbill 			return;
74645553Sbill 		case EXCEP:
74745553Sbill 			wtflags &= ~TPREW;
74845553Sbill 			return;
74945553Sbill 		case READY:
75045553Sbill 		case	0:
75145553Sbill 			wtflags &= ~TPREW;
75245553Sbill 			sterr("Rewind failed");
75345553Sbill 			wtsense(TP_WRP);
75445553Sbill 			return;
75545553Sbill 			}
75645553Sbill 	}
75745553Sbill 
wtwind()75845553Sbill wtwind() {
75945553Sbill #ifdef DEBUG
76045553Sbill 	debug("WT: About to rewind\n");
76145553Sbill #endif
76245553Sbill 	rwind();	/* actually start rewind */
76345553Sbill }
76445553Sbill 
wtintr(unit)76549573Swilliam wtintr(unit) {
76645553Sbill 	if (wtflags & (TPWO|TPRO))
76745553Sbill 	{
76845553Sbill 		isrlock = 1;
76945553Sbill 		if (wtio) isr();
77045553Sbill 		isrlock = 0;
77145553Sbill 	}
77245553Sbill }
77345553Sbill 
wtinit()77445553Sbill wtinit() {
77545553Sbill 	if (wtchan < 1 || wtchan > 3)
77645553Sbill 	{
77745553Sbill 		sterr("Bad DMA channel, cannot init driver");
77845553Sbill 		return;
77945553Sbill 	}
78045553Sbill 	wtlinit();	/* init assembly language variables */
78145553Sbill 	pageset();
78245553Sbill }
78345553Sbill 
rdyexc(ticks)78445553Sbill rdyexc(ticks)
78545553Sbill {
78645553Sbill 	int s;
78745553Sbill #ifdef DEBUG
78845553Sbill 	int os = 0xffff;		/* force printout first time */
78945553Sbill #endif
79045553Sbill 	for (;;) {			/* loop until ready or exception */
79145553Sbill 		s=(inb(wtport) & 0xff);	/* read the status register */
79245553Sbill #ifdef DEBUG
79345553Sbill 		if (os != s) {
79445553Sbill 			debug("Status reg = %x\n", s); /* */
79545553Sbill 			os = s;
79645553Sbill 			}
79745553Sbill #endif
79845553Sbill 		if (!(s & EXCEP))	/* check if exception have occured */
79945553Sbill 			break;
80045553Sbill 		if (!(s & READY))	/* check if controller is ready */
80145553Sbill 			break;
80245553Sbill 		s = splbio();
80345553Sbill 		delay((ticks/HZ)*1000000); /* */
80445553Sbill 		splx(s);
80545553Sbill 	}
80645553Sbill #ifdef DEBUG
80745553Sbill 	debug("Status reg = %x on return\n", s); /* */
80845553Sbill #endif
80945553Sbill 	return((s & EXCEP)?SUCCESS:ERROR);  /* return exception if it occured */
81045553Sbill }
81145553Sbill 
pollrdy()81245553Sbill pollrdy()
81345553Sbill {
81445553Sbill 	int	 sps;
81545553Sbill #ifdef DEBUG
81645553Sbill 	debug("Pollrdy\n");
81745553Sbill #endif
81845553Sbill 	sps = splbio();
81949573Swilliam 	while (wtio) {
82049573Swilliam 		int error;
82149573Swilliam 
82249573Swilliam 		if (error = tsleep((caddr_t)&wci, WTPRI | PCATCH,
82349573Swilliam 			"wtpoll", 0)) {
82449573Swilliam 			splx(sps);
82549573Swilliam 			return(error);
82649573Swilliam 		}
82749573Swilliam 	}
82845553Sbill 	splx(sps);
82945553Sbill #ifdef DEBUG
83045553Sbill 	debug("Finish poll, wci %d exflag %d\n", wci, exflag);
83145553Sbill #endif
83249573Swilliam 	return (EIO);
83345553Sbill }
83445553Sbill 
wtdma()83545553Sbill wtdma()		/* start up i/o operation, called from dma() in wtlib1.s */
83645553Sbill {
83745553Sbill 	wtio = 1;
83845553Sbill 	if (!wtimeron)
83945553Sbill 	{
84045553Sbill 		wtimeron = 1;
84145553Sbill 		timeout(wtimer, (caddr_t) 0, HZ/2);
84245553Sbill 	}
84345553Sbill }
84445553Sbill 
wtwake()84545553Sbill wtwake()	/* end i/o operation, called from isr() in wtlib1.s */
84645553Sbill {
84745553Sbill 	wtio = 0;
84845553Sbill 	wakeup(&wci);
84945553Sbill }
85045553Sbill 
pageset()85145553Sbill pageset()
85245553Sbill {
85345553Sbill 	unsigned long pp;
85445553Sbill 
85545553Sbill 	pp = (unsigned long) pagebuf;
85645553Sbill 	pageaddr = kvtop(pp);
85745553Sbill #ifdef DEBUG
85845553Sbill 	debug("pageset: addr %lx\n", pageaddr);
85945553Sbill #endif
86045553Sbill }
86145553Sbill 
86245553Sbill 
86345553Sbill 
86445553Sbill #define near
86545553Sbill 
86645553Sbill static near
sendcmd()86745553Sbill sendcmd()
86845553Sbill {
86945553Sbill 	/* desired command in global mbits */
87045553Sbill 
87145553Sbill 	outb(CTLPORT, mbits | REQUEST);		/* set request */
87245553Sbill 	while (inb(STATPORT) & READY);		/* wait for ready */
87345553Sbill 	outb(CTLPORT, mbits & ~REQUEST);	/* reset request */
87445553Sbill 	while ((inb(STATPORT) & READY) == 0);	/* wait for not ready */
87545553Sbill }
87645553Sbill 
87745553Sbill static near		/* execute command */
cmds(cmd)87845553Sbill cmds(cmd)
87945553Sbill {
88045553Sbill 	register s;
88145553Sbill 
88245553Sbill 	do s = inb(STATPORT);
88345553Sbill 	while ((s & STAT) == STAT);	/* wait for ready */
88445553Sbill 
88545553Sbill 	if ((s & EXCEP) == 0)		/* if exception */
88645553Sbill 		return ERROR;		/* error */
88745553Sbill 
88845553Sbill 	outb(CMDPORT, cmd);		/* output the command	*/
88945553Sbill 
89045553Sbill 	outb(CTLPORT, mbits=ONLINE);	/* set & send ONLINE	*/
89145553Sbill 	sendcmd();
89245553Sbill 
89345553Sbill 	return SUCCESS;
89445553Sbill }
89545553Sbill 
qicmd(cmd)89645553Sbill qicmd(cmd)
89745553Sbill {
89845553Sbill 	return cmds(cmd);
89945553Sbill }
90045553Sbill 
rstart()90145553Sbill rstart()
90245553Sbill {
90345553Sbill 	return cmds(RDDATA);
90445553Sbill }
90545553Sbill 
rmark()90645553Sbill rmark()
90745553Sbill {
90845553Sbill 	return cmds(READFM);
90945553Sbill }
91045553Sbill 
wstart()91145553Sbill wstart()
91245553Sbill {
91345553Sbill 	return cmds(WRTDATA);
91445553Sbill }
91545553Sbill 
ioend()91645553Sbill ioend()
91745553Sbill {
91845553Sbill 	register s;
91945553Sbill 	register rval = SUCCESS;
92045553Sbill 
92145553Sbill 	do s = inb(STATPORT);
92245553Sbill 	while ((s & STAT) == STAT);	/* wait for ready */
92345553Sbill 
92445553Sbill 	if ((s & EXCEP) == 0)		/* if exception */
92545553Sbill 		rval = ERROR;		/* error */
92645553Sbill 
92745553Sbill 	mbits &= ~ONLINE;
92845553Sbill 	outb(CTLPORT, mbits);		/* reset ONLINE */
92945553Sbill 	outb(MASKREG, wtchan+4);	/* turn off dma */
93045553Sbill 	outb(CLEARFF, 0);		/* reset direction flag */
93145553Sbill 
93245553Sbill 	return rval;
93345553Sbill }
93445553Sbill 
wmark()93545553Sbill wmark()
93645553Sbill {
93745553Sbill 	register s;
93845553Sbill 
93945553Sbill 	if (cmds(WRITEFM) == ERROR)
94045553Sbill 		return ERROR;
94145553Sbill 
94245553Sbill 	do s = inb(STATPORT);
94345553Sbill 	while ((s & STAT) == STAT);	/* wait for ready */
94445553Sbill 
94545553Sbill 	if ((s & EXCEP) == 0)		/* if exception */
94645553Sbill 		return ERROR;		/* error */
94745553Sbill 
94845553Sbill 	return SUCCESS;
94945553Sbill }
95045553Sbill 
rwind()95145553Sbill rwind()
95245553Sbill {
95345553Sbill 	register s;
95445553Sbill 
95545553Sbill 	mbits = CMDOFF;
95645553Sbill 
95745553Sbill 	do s = inb(STATPORT);
95845553Sbill 	while ((s & STAT) == STAT);	/* wait for ready */
95945553Sbill 
96045553Sbill 	outb(CMDPORT, REWIND);
96145553Sbill 	sendcmd();
96245553Sbill 
96345553Sbill 	return SUCCESS;
96445553Sbill }
96545553Sbill 
rdstatus(stp)96645553Sbill rdstatus(stp)
96745553Sbill char *stp;		/* pointer to 6 byte buffer */
96845553Sbill {
96945553Sbill 	register s;
97045553Sbill 	int n;
97145553Sbill 
97245553Sbill 	do s = inb(STATPORT);
97345553Sbill 	while ((s & STAT) == STAT);	/* wait for ready or exception */
97445553Sbill 
97545553Sbill 	outb(CMDPORT, RDSTAT);
97645553Sbill 	sendcmd();			/* send read status command */
97745553Sbill 
97845553Sbill 	for (n=0; n<6; n++)
97945553Sbill 	{
98045553Sbill #ifdef DEBUGx
98145553Sbill 		debug("rdstatus: waiting, byte %d\n", n);
98245553Sbill #endif
98345553Sbill 		do s = inb(STATPORT);
98445553Sbill 		while ((s & STAT) == STAT);	/* wait for ready */
98545553Sbill #ifdef DEBUGx
98645553Sbill 		debug("rdstatus: done\n");
98745553Sbill #endif
98845553Sbill 		if ((s & EXCEP) == 0)		/* if exception */
98945553Sbill 			return ERROR;		/* error */
99045553Sbill 
99145553Sbill 		*stp++ = inb(DATAPORT);		/* read status byte */
99245553Sbill 
99345553Sbill 		outb(CTLPORT, mbits | REQUEST);	/* set request */
99445553Sbill #ifdef DEBUGx
99545553Sbill 		debug("rdstatus: waiting after request, byte %d\n", n);
99645553Sbill #endif
99745553Sbill 		while ((inb(STATPORT)&READY) == 0);	/* wait for not ready */
99845553Sbill 		for (s=100; s>0; s--);		/* wait an additional time */
99945553Sbill 
100045553Sbill 		outb(CTLPORT, mbits & ~REQUEST);/* unset request */
100145553Sbill #ifdef DEBUGx
100245553Sbill 		debug("rdstatus: done\n");
100345553Sbill #endif
100445553Sbill 	}
100545553Sbill 	return SUCCESS;
100645553Sbill }
100745553Sbill 
t_reset()100845553Sbill t_reset()
100945553Sbill {
101045553Sbill 	register i;
101145553Sbill 	mbits |= RESET;
101245553Sbill 	outb(CTLPORT, mbits);		/* send reset */
101345553Sbill 	delay(20);
101445553Sbill 	mbits &= ~RESET;
101545553Sbill 	outb(CTLPORT, mbits);		/* turn off reset */
101645553Sbill 	if ((inb(STATPORT) & RESETMASK) == RESETVAL)
101745553Sbill 		return SUCCESS;
101845553Sbill 	return ERROR;
101945553Sbill }
102045553Sbill 
102145553Sbill static
dma()102245553Sbill dma()
102345553Sbill {
102445553Sbill 	int x=splbio();
102545553Sbill 	wtdma();
102645553Sbill 	outb(CLEARFF, 0);
102745553Sbill 	outb(MODEREG, mode);	/* set dma mode */
102845553Sbill 	outb(dmareg, bufptr & 0xFF);
102945553Sbill 	outb(dmareg, (bufptr>>8) & 0xFF);
103045553Sbill 	outb(pagereg, (bufptr>>16) & 0xFF);
103145553Sbill 	outb(dmareg+1, (BLKSIZE-1) & 0xFF);
103245553Sbill 	outb(dmareg+1, (BLKSIZE-1) >> 8);
103345553Sbill 	outb(wtport, eqdma+ONLINE);
103445553Sbill 	outb(MASKREG, wtchan);	/* enable command to 8237, start dma */
103545553Sbill 	splx(x);
103645553Sbill }
103745553Sbill 
103845553Sbill static near
wtstart(buf,cnt)103945553Sbill wtstart(buf, cnt)
104045553Sbill long buf;
104145553Sbill int cnt;
104245553Sbill {
104345553Sbill 	register s;
104445553Sbill 
104545553Sbill 	bufptr = buf;		/* init statics */
104645553Sbill 	numbytes = cnt;
104745553Sbill 	wci = 0;		/* init flags */
104845553Sbill 	exflag = 0;
104945553Sbill 	bytes = 0;		/* init counter */
105045553Sbill 
105145553Sbill 	do s = inb(STATPORT) & STAT;
105245553Sbill 	while (s == STAT);	/* wait for ready or error */
105345553Sbill 
105445553Sbill 	if (s & EXCEP)		/* no error */
105545553Sbill 	{
105645553Sbill 		dma();
105745553Sbill 		return SUCCESS;
105845553Sbill 	}
105945553Sbill 	return ERROR;		/* error */
106045553Sbill }
106145553Sbill 
rtape(buf,cnt)106245553Sbill rtape(buf, cnt)
106345553Sbill long buf;			/* physical address */
106445553Sbill int cnt;			/* number of bytes */
106545553Sbill {
106645553Sbill 	mode = dma_read;
106745553Sbill 	return wtstart(buf,cnt);
106845553Sbill }
106945553Sbill 
wtape(buf,cnt)107045553Sbill wtape(buf, cnt)
107145553Sbill long buf;			/* physical address */
107245553Sbill int cnt;			/* number of bytes */
107345553Sbill {
107445553Sbill 	mode = dma_write;
107545553Sbill 	return wtstart(buf,cnt);
107645553Sbill }
107745553Sbill 
isr()107845553Sbill isr()
107945553Sbill {
108045553Sbill 	int stat = inb(wtport);
108145553Sbill 	if (!(stat & EXCEP))	/* exception during I/O */
108245553Sbill 	{
108345553Sbill 		if (bytes + BLKSIZE >= numbytes) wci = 1;
108445553Sbill 		exflag = 1;
108545553Sbill 		goto isrwake;
108645553Sbill 	}
108745553Sbill 	if ((stat & READY) || !(inb(STATUSREG) & dma_done))
108845553Sbill 		return;
108945553Sbill 	exflag = 0;
109045553Sbill 	outb(wtport, ONLINE);
109145553Sbill 	bytes += BLKSIZE;
109245553Sbill 	if (bytes >= numbytes)	/* normal completion of I/O */
109345553Sbill 	{
109445553Sbill 		wci = 1;
109545553Sbill isrwake:
109645553Sbill 		outb(MASKREG, 4+wtchan);	/* turn off dma */
109745553Sbill 		wtwake();			/* wake up user level */
109845553Sbill 	}
109945553Sbill 	else
110045553Sbill 	{			/* continue I/O */
110145553Sbill 		bufptr += BLKSIZE;
110245553Sbill 		dma();
110345553Sbill 	}
110445553Sbill }
110545553Sbill 
wtlinit()110645553Sbill wtlinit()
110745553Sbill {
110845553Sbill 	switch (wtchan) {
110945553Sbill 	case 1:
111045553Sbill 		return;
111145553Sbill 	case 2:
111245553Sbill 		pagereg = 0x81;
111345553Sbill 		dma_done = 4;
111445553Sbill 		break;
111545553Sbill 	case 3:
111645553Sbill 		eqdma = 0x10;
111745553Sbill 		pagereg = 0x82;
111845553Sbill 		dma_done = 8;
111945553Sbill 		break;
112045553Sbill 	}
112145553Sbill 	dma_write = wtchan+0x48;
112245553Sbill 	dma_read = wtchan+0x44;
112345553Sbill 	dmareg = wtchan+wtchan;
112445553Sbill }
112545553Sbill 
112645553Sbill /*
112745553Sbill  * delay i microseconds
112845553Sbill  */
delay(i)112945553Sbill delay(i)
113045553Sbill register int i;
113145553Sbill {
113245553Sbill 	while (i-- > 0)
113345553Sbill 		DELAY(1000);
113445553Sbill }
113545553Sbill 
wtsize()113645553Sbill wtsize()
113745553Sbill {
113845553Sbill }
113945553Sbill 
wtdump()114045553Sbill wtdump()
114145553Sbill {
114245553Sbill }
114345553Sbill 
114456513Sbostic #include <i386/isa/isa_device.h>
114556513Sbostic #include <i386/isa/icu.h>
114645553Sbill 
114745553Sbill int	wtprobe(), wtattach();
114845553Sbill struct	isa_driver wtdriver = {
114945553Sbill 	wtprobe, wtattach, "wt",
115045553Sbill };
115145553Sbill 
115245553Sbill wtprobe(dvp)
115345553Sbill 	struct isa_device *dvp;
115445553Sbill {
115545553Sbill 	int val,i,s;
115645553Sbill 
115745553Sbill #ifdef lint
115845553Sbill 	wtintr(0);
115945553Sbill #endif
116045553Sbill 
116145553Sbill 	wtport = dvp->id_iobase;
116245553Sbill 	if(t_reset() != SUCCESS) return(0);
116345553Sbill 	return(1);
116445553Sbill }
116545553Sbill 
wtattach()116645553Sbill wtattach() { }
116745553Sbill 
116845553Sbill #endif NWT
1169