xref: /csrg-svn/sys/i386/isa/wt.c (revision 45553)
1*45553Sbill #include "wt.h"
2*45553Sbill #if NWT > 0
3*45553Sbill /*
4*45553Sbill  * Mach Operating System
5*45553Sbill  * Copyright (c) 1989 Carnegie-Mellon University
6*45553Sbill  * All rights reserved.  The CMU software License Agreement specifies
7*45553Sbill  * the terms and conditions for use and redistribution.
8*45553Sbill  *	@(#)wt.c	1.1 (Berkeley) 11/08/90
9*45553Sbill  */
10*45553Sbill /*
11*45553Sbill  * HISTORY
12*45553Sbill  * $Log:	wt.c,v $
13*45553Sbill  * Revision 2.2.1.3  90/01/08  13:29:38  rvb
14*45553Sbill  * 	Add Intel copyright.
15*45553Sbill  * 	[90/01/08            rvb]
16*45553Sbill  *
17*45553Sbill  * Revision 2.2.1.2  89/12/21  18:00:09  rvb
18*45553Sbill  * 	Change WTPRI to make the streamer tape read/write
19*45553Sbill  * 	interruptible. 		[lin]
20*45553Sbill  *
21*45553Sbill  * Revision 2.2.1.1  89/11/10  09:49:49  rvb
22*45553Sbill  * 	ORC likes their streamer port at 0x288.
23*45553Sbill  * 	[89/11/08            rvb]
24*45553Sbill  *
25*45553Sbill  * Revision 2.2  89/09/25  12:33:02  rvb
26*45553Sbill  * 	Driver was provided by Intel 9/18/89.
27*45553Sbill  * 	[89/09/23            rvb]
28*45553Sbill  *
29*45553Sbill  */
30*45553Sbill 
31*45553Sbill /*
32*45553Sbill  *
33*45553Sbill  *  Copyright 1988, 1989 by Intel Corporation
34*45553Sbill  *
35*45553Sbill  *	Support Bell Tech QIC-02 and WANGTEK QIC-36 or QIC-02
36*45553Sbill  */
37*45553Sbill 
38*45553Sbill #include <sys/errno.h>
39*45553Sbill #include <sys/signal.h>
40*45553Sbill #include <sys/types.h>
41*45553Sbill #include <sys/param.h>
42*45553Sbill #include <sys/buf.h>
43*45553Sbill #include <sys/dir.h>
44*45553Sbill #include <sys/user.h>
45*45553Sbill #include <sys/file.h>
46*45553Sbill #include <sys/proc.h>
47*45553Sbill #include <machine/isa/wtreg.h>
48*45553Sbill 
49*45553Sbill #ifdef	ORC
50*45553Sbill unsigned wtport = 0x288;	/* base I/O port of controller	*/
51*45553Sbill #else	ORC
52*45553Sbill unsigned wtport = 0x300;	/* base I/O port of controller	*/
53*45553Sbill #endif	ORC
54*45553Sbill 				/* standard = 0x300		*/
55*45553Sbill 				/* alternate = 0x338		*/
56*45553Sbill 
57*45553Sbill unsigned wtchan = 1;		/* DMA channel number		*/
58*45553Sbill 				/* stardard = 1			*/
59*45553Sbill 				/* hardware permits 1, 2 or 3.	*/
60*45553Sbill 		                /* (Avoid DMA 2: used by disks) */
61*45553Sbill 
62*45553Sbill int	first_wtopen_ever = 1;
63*45553Sbill 
64*45553Sbill 
65*45553Sbill #define	ERROR 		1	/* return from tape routines */
66*45553Sbill #define	SUCCESS		0	/* return from tape routines */
67*45553Sbill 
68*45553Sbill int	wci = 0;
69*45553Sbill int	exflag = 0;
70*45553Sbill int	bytes = 0;
71*45553Sbill 
72*45553Sbill static	unsigned char eqdma = 0x8;
73*45553Sbill static	unsigned char pagereg = 0x83;
74*45553Sbill static	unsigned char dmareg = 2;
75*45553Sbill static	unsigned char dma_write = 0x49;
76*45553Sbill static	unsigned char dma_read = 0x45;
77*45553Sbill static	unsigned char dma_done = 2;
78*45553Sbill static	unsigned char mode = 0;
79*45553Sbill static	unsigned char mbits;	/* map bits into each other */
80*45553Sbill static	long bufptr;
81*45553Sbill static	unsigned numbytes;
82*45553Sbill /*
83*45553Sbill _wci		dw	0	; interrupt chain finished normally
84*45553Sbill _exflag		dw	0	; exception variable
85*45553Sbill _bytes		dw	0	; current bytes
86*45553Sbill 
87*45553Sbill eqdma		db	8h	; enable dma command: ch1,ch2=8h, ch3=10h
88*45553Sbill pagereg		db	83h	; ch1=83h, ch2=81h, ch3=82h
89*45553Sbill dmareg		db	2	; ch1=2, ch2=4, ch3=6
90*45553Sbill dma_write	db	49h	; write dma command: 48h+_wtchan
91*45553Sbill dma_read	db	45h	; read dma command: 44h+_wtchan
92*45553Sbill dma_done	db	2	; dma done flag: 1<<_wtchan
93*45553Sbill mode		db	0	; dma operation mode
94*45553Sbill lbufptr		dw	0	; buffer pointer to data buffers, low word
95*45553Sbill hbufptr		dw	0	; buffer pointer to data buffers, high word
96*45553Sbill numbytes	dw	0	; number of bytes to read or write (new)
97*45553Sbill */
98*45553Sbill 
99*45553Sbill #define PAGESIZ		4096
100*45553Sbill #define HZ		60
101*45553Sbill 
102*45553Sbill /* tape controller ports */
103*45553Sbill #define STATPORT	wtport
104*45553Sbill #define CTLPORT		STATPORT
105*45553Sbill #define CMDPORT		(wtport+1)
106*45553Sbill #define DATAPORT	CMDPORT
107*45553Sbill 
108*45553Sbill /* defines for reading out status from wangtek tape controller */
109*45553Sbill #define READY   	0x01    /* ready bit define        */
110*45553Sbill #define EXCEP		0x02	/* exception bit define    */
111*45553Sbill #define STAT		(READY|EXCEP)
112*45553Sbill #define	RESETMASK	0x7
113*45553Sbill #define	RESETVAL	(RESETMASK & ~EXCEP)
114*45553Sbill 
115*45553Sbill /* tape controller control bits (CTLPORT) */
116*45553Sbill #define	ONLINE	0x01
117*45553Sbill #define	RESET	0x02
118*45553Sbill #define	REQUEST	0x04		/* request command */
119*45553Sbill #define	CMDOFF	0xC0
120*45553Sbill 
121*45553Sbill /* QIC-02 commands (CMDPORT) */
122*45553Sbill #define	RDDATA	0x80		/* read data */
123*45553Sbill #define	READFM	0xA0		/* read file mark */
124*45553Sbill #define	WRTDATA	0x40		/* write data */
125*45553Sbill #define	WRITEFM	0x60		/* write file mark */
126*45553Sbill #define	RDSTAT	0xC0		/* read status command */
127*45553Sbill #define	REWIND	0x21		/* rewind command (position+bot) */
128*45553Sbill 
129*45553Sbill /* 8237 DMA controller regs */
130*45553Sbill #define	STATUSREG	0x8
131*45553Sbill #define MASKREG		0xA
132*45553Sbill #define MODEREG		0xB
133*45553Sbill #define CLEARFF		0xC
134*45553Sbill 
135*45553Sbill /* streamer tape block size */
136*45553Sbill #define BLKSIZE	512
137*45553Sbill 
138*45553Sbill /* Tape characteristics */
139*45553Sbill #define	NBPS		512	/* 512-byte blocks */
140*45553Sbill #define	ERROR 		1	/* return from tape routines */
141*45553Sbill #define	SUCCESS		0	/* return from tape routines */
142*45553Sbill 
143*45553Sbill /* Minor devs */
144*45553Sbill #define	TP_REWCLOSE(d)	((minor(d)&04) == 0) /* Rewind tape on close if read/write */
145*45553Sbill #define	TP_DENS(dev)	((minor(dev) >> 3) & 03) /* set density */
146*45553Sbill #define TPHOG(d)	0	/* use Hogproc during tape I/O	*/
147*45553Sbill 
148*45553Sbill /* defines for wtflags */
149*45553Sbill #define	TPINUSE	0x0001		/* tape is already open */
150*45553Sbill #define	TPREAD	0x0002		/* tape is only open for reading */
151*45553Sbill #define	TPWRITE	0x0004		/* tape is only open for writing */
152*45553Sbill #define	TPSTART 0x0008		/* tape must be rewound and reset */
153*45553Sbill #define	TPDEAD	0x0010		/* tape drive does not work or driver error */
154*45553Sbill #define	TPSESS	0x0020		/* no more reads or writes allowed in session */
155*45553Sbill 				/* for example, when tape has to be changed */
156*45553Sbill #define	TPSTOP	0x0040		/* Stop command outstanding */
157*45553Sbill #define	TPREW	0x0080		/* Rewind command outstanding, see wtdsl2() */
158*45553Sbill #define	TPVOL	0x0100		/* Read file mark, or hit end of tape */
159*45553Sbill #define	TPWO	0x0200		/* write command outstanding */
160*45553Sbill #define	TPRO	0x0400		/* read command outstanding */
161*45553Sbill #define TPWANY	0x0800		/* write command requested */
162*45553Sbill #define TPRANY	0x1000		/* read command requested */
163*45553Sbill #define	TPWP	0x2000		/* write protect error seen */
164*45553Sbill 
165*45553Sbill unsigned int	wtflags = TPSTART;	/* state of tape drive */
166*45553Sbill 
167*45553Sbill struct	buf	rwtbuf;		/* header for raw i/o */
168*45553Sbill struct  proc	*myproc;	/* process which opened tape driver */
169*45553Sbill 
170*45553Sbill char wtimeron;			/* wtimer() active flag */
171*45553Sbill char wtio;			/* dma (i/o) active flag */
172*45553Sbill char isrlock;			/* isr() flag */
173*45553Sbill 
174*45553Sbill struct proc * Hogproc;	/* no Hogproc on Microport */
175*45553Sbill #define	ftoseg(x)	((unsigned) (x >> 16))
176*45553Sbill #define	seterror(err)	u.u_error = err
177*45553Sbill 
178*45553Sbill struct	wtstatus {
179*45553Sbill 	ushort	wt_err;		/* code for error encountered */
180*45553Sbill 	ushort	wt_ercnt;	/* number of error blocks */
181*45553Sbill 	ushort	wt_urcnt;	/* number of underruns */
182*45553Sbill }	wterror;
183*45553Sbill 
184*45553Sbill /* defines for wtstatus.wt_err */
185*45553Sbill #define	TP_POR		0x100	/* Power on/reset occurred */
186*45553Sbill #define	TP_RES1		0x200	/* Reserved for end of media */
187*45553Sbill #define	TP_RES2		0x400	/* Reserved for bus parity */
188*45553Sbill #define	TP_BOM		0x800	/* Beginning of media */
189*45553Sbill #define	TP_MBD		0x1000	/* Marginal block detected */
190*45553Sbill #define	TP_NDT		0x2000	/* No data detected */
191*45553Sbill #define	TP_ILL		0x4000	/* Illegal command */
192*45553Sbill #define	TP_ST1		0x8000	/* Status byte 1 bits */
193*45553Sbill #define	TP_FIL		0x01	/* File mark detected */
194*45553Sbill #define	TP_BNL		0x02	/* Bad block not located */
195*45553Sbill #define	TP_UDA		0x04	/* Unrecoverable data error */
196*45553Sbill #define	TP_EOM		0x08	/* End of media */
197*45553Sbill #define	TP_WRP		0x10	/* Write protected cartridge */
198*45553Sbill #define	TP_USL		0x20	/* Unselected drive */
199*45553Sbill #define	TP_CNI		0x40	/* Cartridge not in place */
200*45553Sbill #define	TP_ST0		0x80	/* Status byte 0 bits */
201*45553Sbill 
202*45553Sbill /* Grounds for reporting I/O error to user */
203*45553Sbill #define	TP_ERR0		(TP_BNL|TP_UDA|TP_WRP|TP_CNI|TP_FIL|TP_EOM|TP_USL)
204*45553Sbill #define	TP_ERR1		(TP_MBD|TP_NDT|TP_ILL)
205*45553Sbill /* TP_ILL should never happen! */
206*45553Sbill /*
207*45553Sbill #define	TP_ERR0		0x7f
208*45553Sbill #define	TP_ERR1		0x7700
209*45553Sbill */
210*45553Sbill 
211*45553Sbill /* defines for reading out status from wangtek tape controller */
212*45553Sbill #define READY   	0x01    /* ready bit define        */
213*45553Sbill #define EXCEP		0x02	/* exception bit define    */
214*45553Sbill 
215*45553Sbill /* sleep priority */
216*45553Sbill #define WTPRI	(PZERO+10)
217*45553Sbill 
218*45553Sbill char	pagebuf[NBPS];		/* buffer of size NBPS */
219*45553Sbill unsigned long	pageaddr;	/* physical addr of pagebuf */
220*45553Sbill 				/* pageaddr is used with DMA controller */
221*45553Sbill time_t Hogtime;			/* lbolt when Hog timer started */
222*45553Sbill extern time_t	lbolt;
223*45553Sbill 
224*45553Sbill #define	debug	printf
225*45553Sbill 
226*45553Sbill /*
227*45553Sbill  * Strategy routine.
228*45553Sbill  *
229*45553Sbill  * Arguments:
230*45553Sbill  *  Pointer to buffer structure
231*45553Sbill  * Function:
232*45553Sbill  *  Start transfer.
233*45553Sbill  *
234*45553Sbill  * It would be nice to have this multiple-threaded.
235*45553Sbill  * There is a version of dump from Berkeley that works with multiple processes
236*45553Sbill  * trading off with disk & tape I/O.
237*45553Sbill  */
238*45553Sbill 
239*45553Sbill int
240*45553Sbill wtstrategy(bp)
241*45553Sbill register struct buf *bp;
242*45553Sbill {
243*45553Sbill 	unsigned ucnt1, ucnt2, finished;
244*45553Sbill 	unsigned long adr1, adr2;
245*45553Sbill 
246*45553Sbill 	adr1 = kvtop(bp->b_un.b_addr);
247*45553Sbill #ifdef DEBUG
248*45553Sbill 	debug("bpaddr %x\n", adr1);
249*45553Sbill #endif
250*45553Sbill 	ucnt1 = bp->b_bcount;
251*45553Sbill 	ucnt2 = 0;
252*45553Sbill 	adr2 = 0;
253*45553Sbill #ifdef DEBUG
254*45553Sbill 	debug("WTstart: adr1 %lx cnt %x\n", adr1, ucnt1);
255*45553Sbill #endif
256*45553Sbill 	if (ftoseg(adr1) != ftoseg(adr1 + (unsigned) ucnt1 - 1))
257*45553Sbill 	{
258*45553Sbill 		adr2 = (adr1 & 0xffff0000L) + 0x10000L;
259*45553Sbill 		ucnt2 = (adr1 + ucnt1) - adr2;
260*45553Sbill 		ucnt1 -= ucnt2;
261*45553Sbill 	}
262*45553Sbill 	/* at file marks and end of tape, we just return '0 bytes available' */
263*45553Sbill 	if (wtflags & TPVOL) {
264*45553Sbill 		bp->b_resid = bp->b_bcount;
265*45553Sbill 		goto xit;
266*45553Sbill 	}
267*45553Sbill 	if ((Hogproc == (struct proc *) 0) && TPHOG(bp->b_dev))
268*45553Sbill 	{
269*45553Sbill #ifdef DEBUG
270*45553Sbill 		printf("setting Hogproc\n");
271*45553Sbill #endif
272*45553Sbill 		Hogtime = 0;
273*45553Sbill 		Hogproc = myproc;
274*45553Sbill 	}
275*45553Sbill 	if (bp->b_flags & B_READ) {
276*45553Sbill 		int	bad = 0;
277*45553Sbill 
278*45553Sbill 		/* For now, we assume that all data will be copied out */
279*45553Sbill 		/* If read command outstanding, just skip down */
280*45553Sbill 		if (!(wtflags & TPRO)) {
281*45553Sbill 			if (ERROR == wtsense(TP_WRP))	/* clear status */
282*45553Sbill 				goto errxit;
283*45553Sbill #ifdef DEBUG
284*45553Sbill 			debug("WTread: Start read\n");
285*45553Sbill #endif
286*45553Sbill 			if (!(wtflags & TPREAD) || (wtflags & TPWANY) ||
287*45553Sbill 			    (rstart() == ERROR))  {
288*45553Sbill #ifdef DEBUG
289*45553Sbill 				debug("Tpstart: read init error\n"); /* */
290*45553Sbill #endif
291*45553Sbill 				goto errxit;
292*45553Sbill 			}
293*45553Sbill 			wtflags |= TPRO|TPRANY;
294*45553Sbill 		}
295*45553Sbill 
296*45553Sbill 		finished = 0;
297*45553Sbill 		/* Take a deep breath */
298*45553Sbill 		if (ucnt1) {
299*45553Sbill 			if ((rtape(adr1, ucnt1) == ERROR) &&
300*45553Sbill 					(wtsense(TP_WRP) == ERROR))
301*45553Sbill 				goto endio;
302*45553Sbill 			/* wait for it */
303*45553Sbill 			bad = pollrdy();
304*45553Sbill 			finished = bytes;
305*45553Sbill 			if (bad)
306*45553Sbill 				goto endio;
307*45553Sbill 		}
308*45553Sbill 		/* if a second I/O region, start it */
309*45553Sbill 		if (ucnt2) {
310*45553Sbill 			if ((rtape(adr2, ucnt2) == ERROR) &&
311*45553Sbill 					(wtsense(TP_WRP) == ERROR))
312*45553Sbill 				ucnt2 = 0;	/* don't poll for me */
313*45553Sbill 			}
314*45553Sbill 
315*45553Sbill 		/* if second i/o pending wait for it */
316*45553Sbill 		if (ucnt2) {
317*45553Sbill 			pollrdy();
318*45553Sbill 			/* whether pollrdy is ok or not */
319*45553Sbill 			finished += bytes;
320*45553Sbill 		}
321*45553Sbill 	} else {
322*45553Sbill 		if (wtflags & TPWP)	/* write protected */
323*45553Sbill 			goto errxit;
324*45553Sbill 
325*45553Sbill 		/* If write command outstanding, just skip down */
326*45553Sbill 		if (!(wtflags & TPWO)) {
327*45553Sbill 			if (ERROR == wtsense(0))	/* clear status */
328*45553Sbill 			{
329*45553Sbill #ifdef DEBUG
330*45553Sbill 				debug("TPstart: sense 0\n");
331*45553Sbill #endif
332*45553Sbill 				goto errxit;
333*45553Sbill 			}
334*45553Sbill 			if (!(wtflags & TPWRITE) || (wtflags & TPRANY) ||
335*45553Sbill 			    (wstart() == ERROR))  {
336*45553Sbill #ifdef DEBUG
337*45553Sbill 				debug("Tpstart: write init error\n"); /* */
338*45553Sbill #endif
339*45553Sbill 				wtsense(0);
340*45553Sbill 
341*45553Sbill errxit:				bp->b_flags |= B_ERROR;
342*45553Sbill 				bp->b_resid = bp->b_bcount;
343*45553Sbill 				goto xit;
344*45553Sbill 			}
345*45553Sbill 			wtflags |= TPWO|TPWANY;
346*45553Sbill 		}
347*45553Sbill 
348*45553Sbill 		/* and hold your nose */
349*45553Sbill 		if (ucnt1 && ((wtape(adr1, ucnt1) == ERROR)
350*45553Sbill 				&& (wtsense(0) == ERROR)))
351*45553Sbill 			finished = bytes;
352*45553Sbill 
353*45553Sbill 		else if (ucnt2 &&
354*45553Sbill 			(((ucnt1 && pollrdy()) ||
355*45553Sbill 				(wtape(adr2, ucnt2) == ERROR)) &&
356*45553Sbill 				(wtsense(0) == ERROR)))
357*45553Sbill 			finished = ucnt1 + NBPS + bytes;
358*45553Sbill 		/* All writes and/or copyins were fine! */
359*45553Sbill 		else
360*45553Sbill 			finished = bp->b_bcount;
361*45553Sbill 		pollrdy();
362*45553Sbill 	}
363*45553Sbill 
364*45553Sbill 	endio:
365*45553Sbill 	wterror.wt_err = 0;
366*45553Sbill 	if (exflag && wtsense((bp->b_flags & B_READ) ? TP_WRP : 0)) {
367*45553Sbill 		if ((wterror.wt_err & TP_ST0)
368*45553Sbill 			&& (wterror.wt_err & (TP_FIL|TP_EOM))) {
369*45553Sbill #ifdef DEBUG
370*45553Sbill 			debug("WTsta: Hit end of tape\n"); /* */
371*45553Sbill #endif
372*45553Sbill 			wtflags |= TPVOL;
373*45553Sbill 			if (wterror.wt_err & TP_FIL) {
374*45553Sbill 				if (wtflags & TPRO)
375*45553Sbill 					/* interrupter is bogus */
376*45553Sbill 					rstart();  /* restart read command */
377*45553Sbill 				else
378*45553Sbill 					wtflags &= ~TPWO;
379*45553Sbill 				finished += NBPS;
380*45553Sbill 			}
381*45553Sbill 		/* Reading file marks or writing end of tape return 0 bytes */
382*45553Sbill 		} else	{
383*45553Sbill 			bp->b_flags |= B_ERROR;
384*45553Sbill 			wtflags &= ~(TPWO|TPRO);
385*45553Sbill 		}
386*45553Sbill 	}
387*45553Sbill 
388*45553Sbill 	bp->b_resid = bp->b_bcount - finished;
389*45553Sbill xit:
390*45553Sbill 	biodone(bp);
391*45553Sbill 	if (wtimeron)
392*45553Sbill 		Hogtime = lbolt;
393*45553Sbill 	else if (Hogproc == myproc)
394*45553Sbill 		Hogproc = (struct proc *) 0;
395*45553Sbill }
396*45553Sbill 
397*45553Sbill /*
398*45553Sbill  * simulate an interrupt periodically while I/O is going
399*45553Sbill  * this is necessary in case interrupts get eaten due to
400*45553Sbill  * multiple devices on a single IRQ line
401*45553Sbill  */
402*45553Sbill wtimer()
403*45553Sbill {
404*45553Sbill 	/* If I/O going and not in isr(), simulate interrupt
405*45553Sbill 	 * If no I/O for at least 1 second, stop being a Hog
406*45553Sbill 	 * If I/O done and not a Hog, turn off wtimer()
407*45553Sbill 	 */
408*45553Sbill 	if (wtio && !isrlock)
409*45553Sbill 		isr();
410*45553Sbill 
411*45553Sbill 	if ((Hogproc == myproc) && Hogtime && (lbolt-Hogtime > HZ))
412*45553Sbill 		Hogproc = (struct proc *) 0;
413*45553Sbill 
414*45553Sbill 	if (wtio || (Hogproc == myproc))
415*45553Sbill 		timeout(wtimer, (caddr_t) 0, HZ);
416*45553Sbill 	else
417*45553Sbill 		wtimeron = 0;
418*45553Sbill }
419*45553Sbill 
420*45553Sbill 
421*45553Sbill wtrawio(bp)
422*45553Sbill struct buf	*bp;
423*45553Sbill {
424*45553Sbill 	wtstrategy(bp);
425*45553Sbill 	biowait(bp);
426*45553Sbill 	return(0);
427*45553Sbill }
428*45553Sbill 
429*45553Sbill wt_minphys(bp)
430*45553Sbill struct buf	*bp;
431*45553Sbill {
432*45553Sbill 	if (bp->b_bcount > PAGESIZ)
433*45553Sbill 		bp->b_bcount = PAGESIZ;
434*45553Sbill }
435*45553Sbill 
436*45553Sbill /*
437*45553Sbill  * raw read routine
438*45553Sbill  */
439*45553Sbill wtread(dev, uio)
440*45553Sbill struct uio	*uio;
441*45553Sbill {
442*45553Sbill 	if (wtflags & TPSESS) {
443*45553Sbill 		seterror(EIO);
444*45553Sbill 		return(EIO);
445*45553Sbill 	}
446*45553Sbill 	physio(wtrawio, &rwtbuf, dev, B_READ, wt_minphys, uio);
447*45553Sbill 	return(0);
448*45553Sbill }
449*45553Sbill 
450*45553Sbill /*
451*45553Sbill  * raw write routine
452*45553Sbill  */
453*45553Sbill wtwrite(dev, uio)
454*45553Sbill struct uio	*uio;
455*45553Sbill {
456*45553Sbill 	if (wtflags & TPSESS) {
457*45553Sbill 		seterror(EIO);
458*45553Sbill 		return(EIO);
459*45553Sbill 	}
460*45553Sbill 	physio(wtrawio, &rwtbuf, dev, B_WRITE, wt_minphys, uio);
461*45553Sbill 	return(0);
462*45553Sbill }
463*45553Sbill 
464*45553Sbill 
465*45553Sbill 
466*45553Sbill /*
467*45553Sbill  * ioctl routine
468*45553Sbill  *  for user level QIC commands only
469*45553Sbill  */
470*45553Sbill wtioctl(dev, cmd, arg, mode)
471*45553Sbill int dev, cmd;
472*45553Sbill unsigned long arg;
473*45553Sbill int mode;
474*45553Sbill {
475*45553Sbill 	if (cmd == WTQICMD)
476*45553Sbill 	{
477*45553Sbill 		if ((qicmd((int)arg) == ERROR) || (rdyexc(HZ) == ERROR))
478*45553Sbill 		{
479*45553Sbill 			wtsense(0);
480*45553Sbill 			seterror(EIO);
481*45553Sbill 		}
482*45553Sbill 		return;
483*45553Sbill 	}
484*45553Sbill 	seterror(EINVAL);
485*45553Sbill }
486*45553Sbill 
487*45553Sbill /*
488*45553Sbill  * open routine
489*45553Sbill  * called on every device open
490*45553Sbill  */
491*45553Sbill wtopen(dev, flag)
492*45553Sbill int	dev, flag;
493*45553Sbill {
494*45553Sbill 	if (first_wtopen_ever) {
495*45553Sbill 		wtinit();
496*45553Sbill 		first_wtopen_ever = 0;
497*45553Sbill 	}
498*45553Sbill #ifdef DEBUG
499*45553Sbill 	printf("wtopen ...\n");
500*45553Sbill #endif
501*45553Sbill 	if (!pageaddr) {
502*45553Sbill 		nodev();
503*45553Sbill 		return(ENXIO);
504*45553Sbill 	}
505*45553Sbill 	if (wtflags & (TPINUSE)) {
506*45553Sbill 		seterror(ENXIO);
507*45553Sbill 		return(ENXIO);
508*45553Sbill 	}
509*45553Sbill 	if (wtflags & (TPDEAD)) {
510*45553Sbill 		seterror(EIO);
511*45553Sbill 		return(EIO);
512*45553Sbill 	}
513*45553Sbill 	/* If a rewind from the last session is going on, wait */
514*45553Sbill 	while(wtflags & TPREW) {
515*45553Sbill #ifdef DEBUG
516*45553Sbill 		debug("Waiting for rew to finish\n");
517*45553Sbill #endif
518*45553Sbill 		delay(1000000);	/* delay one second */
519*45553Sbill 	}
520*45553Sbill 	/* Only do reset and select when tape light is off, and tape is rewound.
521*45553Sbill 	 * This allows multiple volumes. */
522*45553Sbill 	if (wtflags & TPSTART) {
523*45553Sbill 		if (t_reset() != SUCCESS) {
524*45553Sbill 			nodev();
525*45553Sbill 			return(ENXIO);
526*45553Sbill 		}
527*45553Sbill #ifdef DEBUG
528*45553Sbill 		debug("reset done. calling wtsense\n");
529*45553Sbill #endif
530*45553Sbill 		if (wtsense(TP_WRP) == ERROR) {
531*45553Sbill 			seterror(EIO);
532*45553Sbill 			return (EIO);
533*45553Sbill 		}
534*45553Sbill #ifdef DEBUG
535*45553Sbill 		debug("wtsense done\n");
536*45553Sbill #endif
537*45553Sbill 		wtflags &= ~TPSTART;
538*45553Sbill 	}
539*45553Sbill 
540*45553Sbill 	wtflags = TPINUSE;
541*45553Sbill 	if (flag & FREAD)
542*45553Sbill 		wtflags |= TPREAD;
543*45553Sbill 	if (flag & FWRITE)
544*45553Sbill 		wtflags |= TPWRITE;
545*45553Sbill 	rwtbuf.b_flags = 0;
546*45553Sbill 	myproc = u.u_procp;		/* for comparison */
547*45553Sbill 	switch(TP_DENS(dev)) {
548*45553Sbill case 0:
549*45553Sbill cmds(0x28);
550*45553Sbill break;
551*45553Sbill case 1:
552*45553Sbill cmds(0x29);
553*45553Sbill break;
554*45553Sbill case 2:
555*45553Sbill cmds(0x27);
556*45553Sbill break;
557*45553Sbill case 3:
558*45553Sbill cmds(0x24);
559*45553Sbill 	}
560*45553Sbill 	return(0);
561*45553Sbill }
562*45553Sbill 
563*45553Sbill /*
564*45553Sbill  * close routine
565*45553Sbill  * called on last device close
566*45553Sbill  * If not rewind-on-close, leave read or write command intact.
567*45553Sbill  */
568*45553Sbill wtclose(dev)
569*45553Sbill {
570*45553Sbill 	int wtdsl2();
571*45553Sbill 
572*45553Sbill #ifdef DEBUG
573*45553Sbill 	debug("WTclose:\n");
574*45553Sbill #endif
575*45553Sbill 	if (Hogproc == myproc)
576*45553Sbill 		Hogproc = (struct proc *) 0;
577*45553Sbill 	if (!exflag && (wtflags & TPWANY) && !(wtflags & (TPSESS|TPDEAD))) {
578*45553Sbill 		if (!(wtflags & TPWO))
579*45553Sbill 			wstart();
580*45553Sbill #ifdef DEBUG
581*45553Sbill 		debug("WT: Writing file mark\n");
582*45553Sbill #endif
583*45553Sbill 		wmark();	/* write file mark */
584*45553Sbill #ifdef DEBUG
585*45553Sbill 		debug("WT: Wrote file mark, going to wait\n");
586*45553Sbill #endif
587*45553Sbill 		if (rdyexc(HZ/10) == ERROR) {
588*45553Sbill 			wtsense(0);
589*45553Sbill 			}
590*45553Sbill 		}
591*45553Sbill 	if (TP_REWCLOSE(dev) || (wtflags & (TPSESS|TPDEAD))) {
592*45553Sbill 	/* rewind tape to beginning of tape, deselect tape, and make a note */
593*45553Sbill 	/* don't wait until rewind, though */
594*45553Sbill 		/* Ending read or write causes rewind to happen, if no error,
595*45553Sbill 		 * and READY and EXCEPTION stay up until it finishes */
596*45553Sbill 		if (wtflags & (TPRO|TPWO))
597*45553Sbill 		{
598*45553Sbill #ifdef DEBUG
599*45553Sbill 			debug("End read or write\n");
600*45553Sbill #endif
601*45553Sbill 			rdyexc(HZ/10);
602*45553Sbill 			ioend();
603*45553Sbill 			wtflags &= ~(TPRO|TPWO);
604*45553Sbill 		}
605*45553Sbill 		else	wtwind();
606*45553Sbill 		wtflags |= TPSTART | TPREW;
607*45553Sbill 		timeout(wtdsl2, 0, HZ);
608*45553Sbill 	}
609*45553Sbill 	else if (!(wtflags & (TPVOL|TPWANY)))
610*45553Sbill 	{
611*45553Sbill 		/* space forward to after next file mark no writing done */
612*45553Sbill 		/* This allows skipping data without reading it.*/
613*45553Sbill #ifdef DEBUG
614*45553Sbill 		debug("Reading past file mark\n");
615*45553Sbill #endif
616*45553Sbill 		if (!(wtflags & TPRO))
617*45553Sbill 			rstart();
618*45553Sbill 		rmark();
619*45553Sbill 		if (rdyexc(HZ/10))
620*45553Sbill 		{
621*45553Sbill 			wtsense(TP_WRP);
622*45553Sbill 		}
623*45553Sbill 	}
624*45553Sbill 	wtflags &= TPREW|TPDEAD|TPSTART|TPRO|TPWO;
625*45553Sbill 	return(0);
626*45553Sbill }
627*45553Sbill 
628*45553Sbill /* return ERROR if user I/O request should receive an I/O error code */
629*45553Sbill 
630*45553Sbill wtsense(ignor)
631*45553Sbill {
632*45553Sbill 	wtflags &= ~(TPRO|TPWO);
633*45553Sbill #ifdef DEBUGx
634*45553Sbill 	debug("WTsense: start ");
635*45553Sbill #endif
636*45553Sbill 	if (rdstatus(&wterror) == ERROR)
637*45553Sbill 	{
638*45553Sbill #ifdef DEBUG
639*45553Sbill 		debug("WTsense: Can't read status\n");
640*45553Sbill #endif
641*45553Sbill 		return(ERROR);
642*45553Sbill 	}
643*45553Sbill #ifdef DEBUG
644*45553Sbill 	if (wterror.wt_err & (TP_ST0|TP_ST1))
645*45553Sbill 	{
646*45553Sbill 		debug("Tperror: status %x error %d underruns %d\n",
647*45553Sbill 			wterror.wt_err, wterror.wt_ercnt, wterror.wt_urcnt);
648*45553Sbill 	}
649*45553Sbill 	else
650*45553Sbill 		debug("done. no error\n");
651*45553Sbill #endif
652*45553Sbill 	wterror.wt_err &= ~ignor;	/* ignore certain errors */
653*45553Sbill 	reperr(wterror.wt_err);
654*45553Sbill 	if (((wterror.wt_err & TP_ST0) && (wterror.wt_err & TP_ERR0)) ||
655*45553Sbill 		    ((wterror.wt_err & TP_ST1) && (wterror.wt_err & TP_ERR1)))
656*45553Sbill 			return	ERROR;
657*45553Sbill 
658*45553Sbill 	return SUCCESS;
659*45553Sbill }
660*45553Sbill 
661*45553Sbill /* lifted from tdriver.c from Wangtek */
662*45553Sbill reperr(srb0)
663*45553Sbill int srb0;
664*45553Sbill {
665*45553Sbill 	int s0 = srb0 & (TP_ERR0|TP_ERR1);	/* find out which exception to report */
666*45553Sbill 
667*45553Sbill 	if (s0) {
668*45553Sbill 		if (s0 & TP_USL)
669*45553Sbill 			sterr("Drive not online");
670*45553Sbill 		else if (s0 & TP_CNI)
671*45553Sbill 			sterr("No cartridge");
672*45553Sbill 		else if ((s0 & TP_WRP) && !(wtflags & TPWP))
673*45553Sbill 		{
674*45553Sbill 			sterr("Tape is write protected");
675*45553Sbill 			wtflags |= TPWP;
676*45553Sbill 		}
677*45553Sbill 		/*
678*45553Sbill 		if (s0 & TP_FIL)
679*45553Sbill 			sterr("Filemark detected");
680*45553Sbill 		*/
681*45553Sbill 		else if (s0 & TP_BNL)
682*45553Sbill 			sterr("Block in error not located");
683*45553Sbill 		else if (s0 & TP_UDA)
684*45553Sbill 			sterr("Unrecoverable data error");
685*45553Sbill 		/*
686*45553Sbill 		else if (s0 & TP_EOM)
687*45553Sbill 			sterr("End of tape");
688*45553Sbill 		*/
689*45553Sbill 		else if (s0 & TP_NDT)
690*45553Sbill 			sterr("No data detected");
691*45553Sbill 		/*
692*45553Sbill 		if (s0 & TP_POR)
693*45553Sbill 			sterr("Reset occured");
694*45553Sbill 		*/
695*45553Sbill 		else if (s0 & TP_BOM)
696*45553Sbill 			sterr("Beginning of tape");
697*45553Sbill 		else if (s0 & TP_ILL)
698*45553Sbill 			sterr("Illegal command");
699*45553Sbill 	}
700*45553Sbill }
701*45553Sbill 
702*45553Sbill sterr(errstr)
703*45553Sbill char	*errstr;
704*45553Sbill {
705*45553Sbill 	printf("Streamer: %s\n", errstr);
706*45553Sbill }
707*45553Sbill 
708*45553Sbill /* Wait until rewind finishes, and deselect drive */
709*45553Sbill wtdsl2() {
710*45553Sbill 	int	stat;
711*45553Sbill 
712*45553Sbill 	stat = inb(wtport) & (READY|EXCEP);
713*45553Sbill #ifdef DEBUG
714*45553Sbill 	debug("Timeout: Waiting for rewind to finish: stat %x\n", stat);
715*45553Sbill #endif
716*45553Sbill 	switch (stat) {
717*45553Sbill 		/* They're active low, ya'know */
718*45553Sbill 		case READY|EXCEP:
719*45553Sbill 			timeout(wtdsl2, (caddr_t) 0, HZ);
720*45553Sbill 			return;
721*45553Sbill 		case EXCEP:
722*45553Sbill 			wtflags &= ~TPREW;
723*45553Sbill 			return;
724*45553Sbill 		case READY:
725*45553Sbill 		case	0:
726*45553Sbill 			wtflags &= ~TPREW;
727*45553Sbill 			sterr("Rewind failed");
728*45553Sbill 			wtsense(TP_WRP);
729*45553Sbill 			return;
730*45553Sbill 			}
731*45553Sbill 	}
732*45553Sbill 
733*45553Sbill wtwind() {
734*45553Sbill #ifdef DEBUG
735*45553Sbill 	debug("WT: About to rewind\n");
736*45553Sbill #endif
737*45553Sbill 	rwind();	/* actually start rewind */
738*45553Sbill }
739*45553Sbill 
740*45553Sbill wtintr(vec) {
741*45553Sbill 	if (wtflags & (TPWO|TPRO))
742*45553Sbill 	{
743*45553Sbill 		isrlock = 1;
744*45553Sbill 		if (wtio) isr();
745*45553Sbill 		isrlock = 0;
746*45553Sbill 	}
747*45553Sbill }
748*45553Sbill 
749*45553Sbill wtinit() {
750*45553Sbill 	if (wtchan < 1 || wtchan > 3)
751*45553Sbill 	{
752*45553Sbill 		sterr("Bad DMA channel, cannot init driver");
753*45553Sbill 		return;
754*45553Sbill 	}
755*45553Sbill 	wtlinit();	/* init assembly language variables */
756*45553Sbill 	pageset();
757*45553Sbill }
758*45553Sbill 
759*45553Sbill rdyexc(ticks)
760*45553Sbill {
761*45553Sbill 	int s;
762*45553Sbill #ifdef DEBUG
763*45553Sbill 	int os = 0xffff;		/* force printout first time */
764*45553Sbill #endif
765*45553Sbill 	for (;;) {			/* loop until ready or exception */
766*45553Sbill 		s=(inb(wtport) & 0xff);	/* read the status register */
767*45553Sbill #ifdef DEBUG
768*45553Sbill 		if (os != s) {
769*45553Sbill 			debug("Status reg = %x\n", s); /* */
770*45553Sbill 			os = s;
771*45553Sbill 			}
772*45553Sbill #endif
773*45553Sbill 		if (!(s & EXCEP))	/* check if exception have occured */
774*45553Sbill 			break;
775*45553Sbill 		if (!(s & READY))	/* check if controller is ready */
776*45553Sbill 			break;
777*45553Sbill 		s = splbio();
778*45553Sbill 		delay((ticks/HZ)*1000000); /* */
779*45553Sbill 		splx(s);
780*45553Sbill 	}
781*45553Sbill #ifdef DEBUG
782*45553Sbill 	debug("Status reg = %x on return\n", s); /* */
783*45553Sbill #endif
784*45553Sbill 	return((s & EXCEP)?SUCCESS:ERROR);  /* return exception if it occured */
785*45553Sbill }
786*45553Sbill 
787*45553Sbill pollrdy()
788*45553Sbill {
789*45553Sbill 	int	 sps;
790*45553Sbill #ifdef DEBUG
791*45553Sbill 	debug("Pollrdy\n");
792*45553Sbill #endif
793*45553Sbill 	sps = splbio();
794*45553Sbill 	while (wtio)
795*45553Sbill 		sleep(&wci, WTPRI);
796*45553Sbill 	splx(sps);
797*45553Sbill #ifdef DEBUG
798*45553Sbill 	debug("Finish poll, wci %d exflag %d\n", wci, exflag);
799*45553Sbill #endif
800*45553Sbill 	return exflag;
801*45553Sbill }
802*45553Sbill 
803*45553Sbill wtdma()		/* start up i/o operation, called from dma() in wtlib1.s */
804*45553Sbill {
805*45553Sbill 	wtio = 1;
806*45553Sbill 	if (!wtimeron)
807*45553Sbill 	{
808*45553Sbill 		wtimeron = 1;
809*45553Sbill 		timeout(wtimer, (caddr_t) 0, HZ/2);
810*45553Sbill 	}
811*45553Sbill }
812*45553Sbill 
813*45553Sbill wtwake()	/* end i/o operation, called from isr() in wtlib1.s */
814*45553Sbill {
815*45553Sbill 	wtio = 0;
816*45553Sbill 	wakeup(&wci);
817*45553Sbill }
818*45553Sbill 
819*45553Sbill pageset()
820*45553Sbill {
821*45553Sbill 	unsigned long pp;
822*45553Sbill 
823*45553Sbill 	pp = (unsigned long) pagebuf;
824*45553Sbill 	pageaddr = kvtop(pp);
825*45553Sbill #ifdef DEBUG
826*45553Sbill 	debug("pageset: addr %lx\n", pageaddr);
827*45553Sbill #endif
828*45553Sbill }
829*45553Sbill 
830*45553Sbill 
831*45553Sbill 
832*45553Sbill #define near
833*45553Sbill 
834*45553Sbill static near
835*45553Sbill sendcmd()
836*45553Sbill {
837*45553Sbill 	/* desired command in global mbits */
838*45553Sbill 
839*45553Sbill 	outb(CTLPORT, mbits | REQUEST);		/* set request */
840*45553Sbill 	while (inb(STATPORT) & READY);		/* wait for ready */
841*45553Sbill 	outb(CTLPORT, mbits & ~REQUEST);	/* reset request */
842*45553Sbill 	while ((inb(STATPORT) & READY) == 0);	/* wait for not ready */
843*45553Sbill }
844*45553Sbill 
845*45553Sbill static near		/* execute command */
846*45553Sbill cmds(cmd)
847*45553Sbill {
848*45553Sbill 	register s;
849*45553Sbill 
850*45553Sbill 	do s = inb(STATPORT);
851*45553Sbill 	while ((s & STAT) == STAT);	/* wait for ready */
852*45553Sbill 
853*45553Sbill 	if ((s & EXCEP) == 0)		/* if exception */
854*45553Sbill 		return ERROR;		/* error */
855*45553Sbill 
856*45553Sbill 	outb(CMDPORT, cmd);		/* output the command	*/
857*45553Sbill 
858*45553Sbill 	outb(CTLPORT, mbits=ONLINE);	/* set & send ONLINE	*/
859*45553Sbill 	sendcmd();
860*45553Sbill 
861*45553Sbill 	return SUCCESS;
862*45553Sbill }
863*45553Sbill 
864*45553Sbill qicmd(cmd)
865*45553Sbill {
866*45553Sbill 	return cmds(cmd);
867*45553Sbill }
868*45553Sbill 
869*45553Sbill rstart()
870*45553Sbill {
871*45553Sbill 	return cmds(RDDATA);
872*45553Sbill }
873*45553Sbill 
874*45553Sbill rmark()
875*45553Sbill {
876*45553Sbill 	return cmds(READFM);
877*45553Sbill }
878*45553Sbill 
879*45553Sbill wstart()
880*45553Sbill {
881*45553Sbill 	return cmds(WRTDATA);
882*45553Sbill }
883*45553Sbill 
884*45553Sbill ioend()
885*45553Sbill {
886*45553Sbill 	register s;
887*45553Sbill 	register rval = SUCCESS;
888*45553Sbill 
889*45553Sbill 	do s = inb(STATPORT);
890*45553Sbill 	while ((s & STAT) == STAT);	/* wait for ready */
891*45553Sbill 
892*45553Sbill 	if ((s & EXCEP) == 0)		/* if exception */
893*45553Sbill 		rval = ERROR;		/* error */
894*45553Sbill 
895*45553Sbill 	mbits &= ~ONLINE;
896*45553Sbill 	outb(CTLPORT, mbits);		/* reset ONLINE */
897*45553Sbill 	outb(MASKREG, wtchan+4);	/* turn off dma */
898*45553Sbill 	outb(CLEARFF, 0);		/* reset direction flag */
899*45553Sbill 
900*45553Sbill 	return rval;
901*45553Sbill }
902*45553Sbill 
903*45553Sbill wmark()
904*45553Sbill {
905*45553Sbill 	register s;
906*45553Sbill 
907*45553Sbill 	if (cmds(WRITEFM) == ERROR)
908*45553Sbill 		return ERROR;
909*45553Sbill 
910*45553Sbill 	do s = inb(STATPORT);
911*45553Sbill 	while ((s & STAT) == STAT);	/* wait for ready */
912*45553Sbill 
913*45553Sbill 	if ((s & EXCEP) == 0)		/* if exception */
914*45553Sbill 		return ERROR;		/* error */
915*45553Sbill 
916*45553Sbill 	return SUCCESS;
917*45553Sbill }
918*45553Sbill 
919*45553Sbill rwind()
920*45553Sbill {
921*45553Sbill 	register s;
922*45553Sbill 
923*45553Sbill 	mbits = CMDOFF;
924*45553Sbill 
925*45553Sbill 	do s = inb(STATPORT);
926*45553Sbill 	while ((s & STAT) == STAT);	/* wait for ready */
927*45553Sbill 
928*45553Sbill 	outb(CMDPORT, REWIND);
929*45553Sbill 	sendcmd();
930*45553Sbill 
931*45553Sbill 	return SUCCESS;
932*45553Sbill }
933*45553Sbill 
934*45553Sbill rdstatus(stp)
935*45553Sbill char *stp;		/* pointer to 6 byte buffer */
936*45553Sbill {
937*45553Sbill 	register s;
938*45553Sbill 	int n;
939*45553Sbill 
940*45553Sbill 	do s = inb(STATPORT);
941*45553Sbill 	while ((s & STAT) == STAT);	/* wait for ready or exception */
942*45553Sbill 
943*45553Sbill 	outb(CMDPORT, RDSTAT);
944*45553Sbill 	sendcmd();			/* send read status command */
945*45553Sbill 
946*45553Sbill 	for (n=0; n<6; n++)
947*45553Sbill 	{
948*45553Sbill #ifdef DEBUGx
949*45553Sbill 		debug("rdstatus: waiting, byte %d\n", n);
950*45553Sbill #endif
951*45553Sbill 		do s = inb(STATPORT);
952*45553Sbill 		while ((s & STAT) == STAT);	/* wait for ready */
953*45553Sbill #ifdef DEBUGx
954*45553Sbill 		debug("rdstatus: done\n");
955*45553Sbill #endif
956*45553Sbill 		if ((s & EXCEP) == 0)		/* if exception */
957*45553Sbill 			return ERROR;		/* error */
958*45553Sbill 
959*45553Sbill 		*stp++ = inb(DATAPORT);		/* read status byte */
960*45553Sbill 
961*45553Sbill 		outb(CTLPORT, mbits | REQUEST);	/* set request */
962*45553Sbill #ifdef DEBUGx
963*45553Sbill 		debug("rdstatus: waiting after request, byte %d\n", n);
964*45553Sbill #endif
965*45553Sbill 		while ((inb(STATPORT)&READY) == 0);	/* wait for not ready */
966*45553Sbill 		for (s=100; s>0; s--);		/* wait an additional time */
967*45553Sbill 
968*45553Sbill 		outb(CTLPORT, mbits & ~REQUEST);/* unset request */
969*45553Sbill #ifdef DEBUGx
970*45553Sbill 		debug("rdstatus: done\n");
971*45553Sbill #endif
972*45553Sbill 	}
973*45553Sbill 	return SUCCESS;
974*45553Sbill }
975*45553Sbill 
976*45553Sbill t_reset()
977*45553Sbill {
978*45553Sbill 	register i;
979*45553Sbill 	mbits |= RESET;
980*45553Sbill 	outb(CTLPORT, mbits);		/* send reset */
981*45553Sbill 	delay(20);
982*45553Sbill 	mbits &= ~RESET;
983*45553Sbill 	outb(CTLPORT, mbits);		/* turn off reset */
984*45553Sbill 	if ((inb(STATPORT) & RESETMASK) == RESETVAL)
985*45553Sbill 		return SUCCESS;
986*45553Sbill 	return ERROR;
987*45553Sbill }
988*45553Sbill 
989*45553Sbill static
990*45553Sbill dma()
991*45553Sbill {
992*45553Sbill 	int x=splbio();
993*45553Sbill 	wtdma();
994*45553Sbill 	outb(CLEARFF, 0);
995*45553Sbill 	outb(MODEREG, mode);	/* set dma mode */
996*45553Sbill 	outb(dmareg, bufptr & 0xFF);
997*45553Sbill 	outb(dmareg, (bufptr>>8) & 0xFF);
998*45553Sbill 	outb(pagereg, (bufptr>>16) & 0xFF);
999*45553Sbill 	outb(dmareg+1, (BLKSIZE-1) & 0xFF);
1000*45553Sbill 	outb(dmareg+1, (BLKSIZE-1) >> 8);
1001*45553Sbill 	outb(wtport, eqdma+ONLINE);
1002*45553Sbill 	outb(MASKREG, wtchan);	/* enable command to 8237, start dma */
1003*45553Sbill 	splx(x);
1004*45553Sbill }
1005*45553Sbill 
1006*45553Sbill static near
1007*45553Sbill wtstart(buf, cnt)
1008*45553Sbill long buf;
1009*45553Sbill int cnt;
1010*45553Sbill {
1011*45553Sbill 	register s;
1012*45553Sbill 
1013*45553Sbill 	bufptr = buf;		/* init statics */
1014*45553Sbill 	numbytes = cnt;
1015*45553Sbill 	wci = 0;		/* init flags */
1016*45553Sbill 	exflag = 0;
1017*45553Sbill 	bytes = 0;		/* init counter */
1018*45553Sbill 
1019*45553Sbill 	do s = inb(STATPORT) & STAT;
1020*45553Sbill 	while (s == STAT);	/* wait for ready or error */
1021*45553Sbill 
1022*45553Sbill 	if (s & EXCEP)		/* no error */
1023*45553Sbill 	{
1024*45553Sbill 		dma();
1025*45553Sbill 		return SUCCESS;
1026*45553Sbill 	}
1027*45553Sbill 	return ERROR;		/* error */
1028*45553Sbill }
1029*45553Sbill 
1030*45553Sbill rtape(buf, cnt)
1031*45553Sbill long buf;			/* physical address */
1032*45553Sbill int cnt;			/* number of bytes */
1033*45553Sbill {
1034*45553Sbill 	mode = dma_read;
1035*45553Sbill 	return wtstart(buf,cnt);
1036*45553Sbill }
1037*45553Sbill 
1038*45553Sbill wtape(buf, cnt)
1039*45553Sbill long buf;			/* physical address */
1040*45553Sbill int cnt;			/* number of bytes */
1041*45553Sbill {
1042*45553Sbill 	mode = dma_write;
1043*45553Sbill 	return wtstart(buf,cnt);
1044*45553Sbill }
1045*45553Sbill 
1046*45553Sbill isr()
1047*45553Sbill {
1048*45553Sbill 	int stat = inb(wtport);
1049*45553Sbill 	if (!(stat & EXCEP))	/* exception during I/O */
1050*45553Sbill 	{
1051*45553Sbill 		if (bytes + BLKSIZE >= numbytes) wci = 1;
1052*45553Sbill 		exflag = 1;
1053*45553Sbill 		goto isrwake;
1054*45553Sbill 	}
1055*45553Sbill 	if ((stat & READY) || !(inb(STATUSREG) & dma_done))
1056*45553Sbill 		return;
1057*45553Sbill 	exflag = 0;
1058*45553Sbill 	outb(wtport, ONLINE);
1059*45553Sbill 	bytes += BLKSIZE;
1060*45553Sbill 	if (bytes >= numbytes)	/* normal completion of I/O */
1061*45553Sbill 	{
1062*45553Sbill 		wci = 1;
1063*45553Sbill isrwake:
1064*45553Sbill 		outb(MASKREG, 4+wtchan);	/* turn off dma */
1065*45553Sbill 		wtwake();			/* wake up user level */
1066*45553Sbill 	}
1067*45553Sbill 	else
1068*45553Sbill 	{			/* continue I/O */
1069*45553Sbill 		bufptr += BLKSIZE;
1070*45553Sbill 		dma();
1071*45553Sbill 	}
1072*45553Sbill }
1073*45553Sbill 
1074*45553Sbill wtlinit()
1075*45553Sbill {
1076*45553Sbill 	switch (wtchan) {
1077*45553Sbill 	case 1:
1078*45553Sbill 		return;
1079*45553Sbill 	case 2:
1080*45553Sbill 		pagereg = 0x81;
1081*45553Sbill 		dma_done = 4;
1082*45553Sbill 		break;
1083*45553Sbill 	case 3:
1084*45553Sbill 		eqdma = 0x10;
1085*45553Sbill 		pagereg = 0x82;
1086*45553Sbill 		dma_done = 8;
1087*45553Sbill 		break;
1088*45553Sbill 	}
1089*45553Sbill 	dma_write = wtchan+0x48;
1090*45553Sbill 	dma_read = wtchan+0x44;
1091*45553Sbill 	dmareg = wtchan+wtchan;
1092*45553Sbill }
1093*45553Sbill 
1094*45553Sbill /*
1095*45553Sbill  * delay i microseconds
1096*45553Sbill  */
1097*45553Sbill delay(i)
1098*45553Sbill register int i;
1099*45553Sbill {
1100*45553Sbill 	while (i-- > 0)
1101*45553Sbill 		DELAY(1000);
1102*45553Sbill }
1103*45553Sbill 
1104*45553Sbill wtsize()
1105*45553Sbill {
1106*45553Sbill }
1107*45553Sbill 
1108*45553Sbill wtdump()
1109*45553Sbill {
1110*45553Sbill }
1111*45553Sbill 
1112*45553Sbill #include "machine/isa/device.h"
1113*45553Sbill #include "machine/isa/icu.h"
1114*45553Sbill 
1115*45553Sbill int	wtprobe(), wtattach();
1116*45553Sbill struct	isa_driver wtdriver = {
1117*45553Sbill 	wtprobe, wtattach, "wt",
1118*45553Sbill };
1119*45553Sbill 
1120*45553Sbill wtprobe(dvp)
1121*45553Sbill 	struct isa_device *dvp;
1122*45553Sbill {
1123*45553Sbill 	int val,i,s;
1124*45553Sbill 
1125*45553Sbill #ifdef lint
1126*45553Sbill 	wtintr(0);
1127*45553Sbill #endif
1128*45553Sbill 
1129*45553Sbill 	wtport = dvp->id_iobase;
1130*45553Sbill 	if(t_reset() != SUCCESS) return(0);
1131*45553Sbill 	return(1);
1132*45553Sbill }
1133*45553Sbill 
1134*45553Sbill wtattach() { }
1135*45553Sbill 
1136*45553Sbill #endif NWT
1137