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