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