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