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