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