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