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