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