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