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