|
|
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: /*
490: * ioctl routine
491: * for user level QIC commands only
492: */
493: wtioctl(dev, cmd, arg, mode)
494: int dev, cmd;
495: unsigned long arg;
496: int mode;
497: {
498: if (cmd == WTQICMD)
499: {
500: if ((qicmd((int)arg) == ERROR) || (rdyexc(HZ) == ERROR))
501: {
502: wtsense(0);
503: return(EIO);
504: }
505: return(0);
506: }
507: return(EINVAL);
508: }
509:
510: /*
511: * open routine
512: * called on every device open
513: */
514: wtopen(dev, flag)
515: int dev, flag;
516: {
517: if (first_wtopen_ever) {
518: wtinit();
519: first_wtopen_ever = 0;
520: }
521: #ifdef DEBUG
522: printf("wtopen ...\n");
523: #endif
524: if (!pageaddr) {
525: return(ENXIO);
526: }
527: if (wtflags & (TPINUSE)) {
528: return(ENXIO);
529: }
530: if (wtflags & (TPDEAD)) {
531: return(EIO);
532: }
533: /* If a rewind from the last session is going on, wait */
534: while(wtflags & TPREW) {
535: #ifdef DEBUG
536: debug("Waiting for rew to finish\n");
537: #endif
538: delay(1000000); /* delay one second */
539: }
540: /* Only do reset and select when tape light is off, and tape is rewound.
541: * This allows multiple volumes. */
542: if (wtflags & TPSTART) {
543: if (t_reset() != SUCCESS) {
544: return(ENXIO);
545: }
546: #ifdef DEBUG
547: debug("reset done. calling wtsense\n");
548: #endif
549: if (wtsense(TP_WRP) == ERROR) {
550: return (EIO);
551: }
552: #ifdef DEBUG
553: debug("wtsense done\n");
554: #endif
555: wtflags &= ~TPSTART;
556: }
557:
558: wtflags = TPINUSE;
559: if (flag & FREAD)
560: wtflags |= TPREAD;
561: if (flag & FWRITE)
562: wtflags |= TPWRITE;
563: rwtbuf.b_flags = 0;
564: myproc = curproc; /* for comparison */
565: switch(TP_DENS(dev)) {
566: case 0:
567: cmds(0x28);
568: break;
569: case 1:
570: cmds(0x29);
571: break;
572: case 2:
573: cmds(0x27);
574: break;
575: case 3:
576: cmds(0x24);
577: }
578: return(0);
579: }
580:
581: /*
582: * close routine
583: * called on last device close
584: * If not rewind-on-close, leave read or write command intact.
585: */
586: wtclose(dev)
587: {
588: int wtdsl2();
589:
590: #ifdef DEBUG
591: debug("WTclose:\n");
592: #endif
593: if (Hogproc == myproc)
594: Hogproc = (struct proc *) 0;
595: if (!exflag && (wtflags & TPWANY) && !(wtflags & (TPSESS|TPDEAD))) {
596: if (!(wtflags & TPWO))
597: wstart();
598: #ifdef DEBUG
599: debug("WT: Writing file mark\n");
600: #endif
601: wmark(); /* write file mark */
602: #ifdef DEBUG
603: debug("WT: Wrote file mark, going to wait\n");
604: #endif
605: if (rdyexc(HZ/10) == ERROR) {
606: wtsense(0);
607: }
608: }
609: if (TP_REWCLOSE(dev) || (wtflags & (TPSESS|TPDEAD))) {
610: /* rewind tape to beginning of tape, deselect tape, and make a note */
611: /* don't wait until rewind, though */
612: /* Ending read or write causes rewind to happen, if no error,
613: * and READY and EXCEPTION stay up until it finishes */
614: if (wtflags & (TPRO|TPWO))
615: {
616: #ifdef DEBUG
617: debug("End read or write\n");
618: #endif
619: rdyexc(HZ/10);
620: ioend();
621: wtflags &= ~(TPRO|TPWO);
622: }
623: else wtwind();
624: wtflags |= TPSTART | TPREW;
625: timeout(wtdsl2, 0, HZ);
626: }
627: else if (!(wtflags & (TPVOL|TPWANY)))
628: {
629: /* space forward to after next file mark no writing done */
630: /* This allows skipping data without reading it.*/
631: #ifdef DEBUG
632: debug("Reading past file mark\n");
633: #endif
634: if (!(wtflags & TPRO))
635: rstart();
636: rmark();
637: if (rdyexc(HZ/10))
638: {
639: wtsense(TP_WRP);
640: }
641: }
642: wtflags &= TPREW|TPDEAD|TPSTART|TPRO|TPWO;
643: return(0);
644: }
645:
646: /* return ERROR if user I/O request should receive an I/O error code */
647:
648: wtsense(ignor)
649: {
650: wtflags &= ~(TPRO|TPWO);
651: #ifdef DEBUGx
652: debug("WTsense: start ");
653: #endif
654: if (rdstatus(&wterror) == ERROR)
655: {
656: #ifdef DEBUG
657: debug("WTsense: Can't read status\n");
658: #endif
659: return(ERROR);
660: }
661: #ifdef DEBUG
662: if (wterror.wt_err & (TP_ST0|TP_ST1))
663: {
664: debug("Tperror: status %x error %d underruns %d\n",
665: wterror.wt_err, wterror.wt_ercnt, wterror.wt_urcnt);
666: }
667: else
668: debug("done. no error\n");
669: #endif
670: wterror.wt_err &= ~ignor; /* ignore certain errors */
671: reperr(wterror.wt_err);
672: if (((wterror.wt_err & TP_ST0) && (wterror.wt_err & TP_ERR0)) ||
673: ((wterror.wt_err & TP_ST1) && (wterror.wt_err & TP_ERR1)))
674: return ERROR;
675:
676: return SUCCESS;
677: }
678:
679: /* lifted from tdriver.c from Wangtek */
680: reperr(srb0)
681: int srb0;
682: {
683: int s0 = srb0 & (TP_ERR0|TP_ERR1); /* find out which exception to report */
684:
685: if (s0) {
686: if (s0 & TP_USL)
687: sterr("Drive not online");
688: else if (s0 & TP_CNI)
689: sterr("No cartridge");
690: else if ((s0 & TP_WRP) && !(wtflags & TPWP))
691: {
692: sterr("Tape is write protected");
693: wtflags |= TPWP;
694: }
695: /*
696: if (s0 & TP_FIL)
697: sterr("Filemark detected");
698: */
699: else if (s0 & TP_BNL)
700: sterr("Block in error not located");
701: else if (s0 & TP_UDA)
702: sterr("Unrecoverable data error");
703: /*
704: else if (s0 & TP_EOM)
705: sterr("End of tape");
706: */
707: else if (s0 & TP_NDT)
708: sterr("No data detected");
709: /*
710: if (s0 & TP_POR)
711: sterr("Reset occured");
712: */
713: else if (s0 & TP_BOM)
714: sterr("Beginning of tape");
715: else if (s0 & TP_ILL)
716: sterr("Illegal command");
717: }
718: }
719:
720: sterr(errstr)
721: char *errstr;
722: {
723: printf("Streamer: %s\n", errstr);
724: }
725:
726: /* Wait until rewind finishes, and deselect drive */
727: wtdsl2() {
728: int stat;
729:
730: stat = inb(wtport) & (READY|EXCEP);
731: #ifdef DEBUG
732: debug("Timeout: Waiting for rewind to finish: stat %x\n", stat);
733: #endif
734: switch (stat) {
735: /* They're active low, ya'know */
736: case READY|EXCEP:
737: timeout(wtdsl2, (caddr_t) 0, HZ);
738: return;
739: case EXCEP:
740: wtflags &= ~TPREW;
741: return;
742: case READY:
743: case 0:
744: wtflags &= ~TPREW;
745: sterr("Rewind failed");
746: wtsense(TP_WRP);
747: return;
748: }
749: }
750:
751: wtwind() {
752: #ifdef DEBUG
753: debug("WT: About to rewind\n");
754: #endif
755: rwind(); /* actually start rewind */
756: }
757:
758: wtintr(unit) {
759: if (wtflags & (TPWO|TPRO))
760: {
761: isrlock = 1;
762: if (wtio) isr();
763: isrlock = 0;
764: }
765: }
766:
767: wtinit() {
768: if (wtchan < 1 || wtchan > 3)
769: {
770: sterr("Bad DMA channel, cannot init driver");
771: return;
772: }
773: wtlinit(); /* init assembly language variables */
774: pageset();
775: }
776:
777: rdyexc(ticks)
778: {
779: int s;
780: #ifdef DEBUG
781: int os = 0xffff; /* force printout first time */
782: #endif
783: for (;;) { /* loop until ready or exception */
784: s=(inb(wtport) & 0xff); /* read the status register */
785: #ifdef DEBUG
786: if (os != s) {
787: debug("Status reg = %x\n", s); /* */
788: os = s;
789: }
790: #endif
791: if (!(s & EXCEP)) /* check if exception have occured */
792: break;
793: if (!(s & READY)) /* check if controller is ready */
794: break;
795: s = splbio();
796: delay((ticks/HZ)*1000000); /* */
797: splx(s);
798: }
799: #ifdef DEBUG
800: debug("Status reg = %x on return\n", s); /* */
801: #endif
802: return((s & EXCEP)?SUCCESS:ERROR); /* return exception if it occured */
803: }
804:
805: pollrdy()
806: {
807: int sps;
808: #ifdef DEBUG
809: debug("Pollrdy\n");
810: #endif
811: sps = splbio();
812: while (wtio) {
813: int error;
814:
815: if (error = tsleep((caddr_t)&wci, WTPRI | PCATCH,
816: "wtpoll", 0)) {
817: splx(sps);
818: return(error);
819: }
820: }
821: splx(sps);
822: #ifdef DEBUG
823: debug("Finish poll, wci %d exflag %d\n", wci, exflag);
824: #endif
825: return (EIO);
826: }
827:
828: wtdma() /* start up i/o operation, called from dma() in wtlib1.s */
829: {
830: wtio = 1;
831: if (!wtimeron)
832: {
833: wtimeron = 1;
834: timeout(wtimer, (caddr_t) 0, HZ/2);
835: }
836: }
837:
838: wtwake() /* end i/o operation, called from isr() in wtlib1.s */
839: {
840: wtio = 0;
841: wakeup(&wci);
842: }
843:
844: pageset()
845: {
846: unsigned long pp;
847:
848: pp = (unsigned long) pagebuf;
849: pageaddr = kvtop(pp);
850: #ifdef DEBUG
851: debug("pageset: addr %lx\n", pageaddr);
852: #endif
853: }
854:
855:
856:
857: #define near
858:
859: static near
860: sendcmd()
861: {
862: /* desired command in global mbits */
863:
864: outb(CTLPORT, mbits | REQUEST); /* set request */
865: while (inb(STATPORT) & READY); /* wait for ready */
866: outb(CTLPORT, mbits & ~REQUEST); /* reset request */
867: while ((inb(STATPORT) & READY) == 0); /* wait for not ready */
868: }
869:
870: static near /* execute command */
871: cmds(cmd)
872: {
873: register s;
874:
875: do s = inb(STATPORT);
876: while ((s & STAT) == STAT); /* wait for ready */
877:
878: if ((s & EXCEP) == 0) /* if exception */
879: return ERROR; /* error */
880:
881: outb(CMDPORT, cmd); /* output the command */
882:
883: outb(CTLPORT, mbits=ONLINE); /* set & send ONLINE */
884: sendcmd();
885:
886: return SUCCESS;
887: }
888:
889: qicmd(cmd)
890: {
891: return cmds(cmd);
892: }
893:
894: rstart()
895: {
896: return cmds(RDDATA);
897: }
898:
899: rmark()
900: {
901: return cmds(READFM);
902: }
903:
904: wstart()
905: {
906: return cmds(WRTDATA);
907: }
908:
909: ioend()
910: {
911: register s;
912: register rval = SUCCESS;
913:
914: do s = inb(STATPORT);
915: while ((s & STAT) == STAT); /* wait for ready */
916:
917: if ((s & EXCEP) == 0) /* if exception */
918: rval = ERROR; /* error */
919:
920: mbits &= ~ONLINE;
921: outb(CTLPORT, mbits); /* reset ONLINE */
922: outb(MASKREG, wtchan+4); /* turn off dma */
923: outb(CLEARFF, 0); /* reset direction flag */
924:
925: return rval;
926: }
927:
928: wmark()
929: {
930: register s;
931:
932: if (cmds(WRITEFM) == ERROR)
933: return ERROR;
934:
935: do s = inb(STATPORT);
936: while ((s & STAT) == STAT); /* wait for ready */
937:
938: if ((s & EXCEP) == 0) /* if exception */
939: return ERROR; /* error */
940:
941: return SUCCESS;
942: }
943:
944: rwind()
945: {
946: register s;
947:
948: mbits = CMDOFF;
949:
950: do s = inb(STATPORT);
951: while ((s & STAT) == STAT); /* wait for ready */
952:
953: outb(CMDPORT, REWIND);
954: sendcmd();
955:
956: return SUCCESS;
957: }
958:
959: rdstatus(stp)
960: char *stp; /* pointer to 6 byte buffer */
961: {
962: register s;
963: int n;
964:
965: do s = inb(STATPORT);
966: while ((s & STAT) == STAT); /* wait for ready or exception */
967:
968: outb(CMDPORT, RDSTAT);
969: sendcmd(); /* send read status command */
970:
971: for (n=0; n<6; n++)
972: {
973: #ifdef DEBUGx
974: debug("rdstatus: waiting, byte %d\n", n);
975: #endif
976: do s = inb(STATPORT);
977: while ((s & STAT) == STAT); /* wait for ready */
978: #ifdef DEBUGx
979: debug("rdstatus: done\n");
980: #endif
981: if ((s & EXCEP) == 0) /* if exception */
982: return ERROR; /* error */
983:
984: *stp++ = inb(DATAPORT); /* read status byte */
985:
986: outb(CTLPORT, mbits | REQUEST); /* set request */
987: #ifdef DEBUGx
988: debug("rdstatus: waiting after request, byte %d\n", n);
989: #endif
990: while ((inb(STATPORT)&READY) == 0); /* wait for not ready */
991: for (s=100; s>0; s--); /* wait an additional time */
992:
993: outb(CTLPORT, mbits & ~REQUEST);/* unset request */
994: #ifdef DEBUGx
995: debug("rdstatus: done\n");
996: #endif
997: }
998: return SUCCESS;
999: }
1000:
1001: t_reset()
1002: {
1003: register i;
1004: mbits |= RESET;
1005: outb(CTLPORT, mbits); /* send reset */
1006: delay(20);
1007: mbits &= ~RESET;
1008: outb(CTLPORT, mbits); /* turn off reset */
1009: if ((inb(STATPORT) & RESETMASK) == RESETVAL)
1010: return SUCCESS;
1011: return ERROR;
1012: }
1013:
1014: static
1015: dma()
1016: {
1017: int x=splbio();
1018: wtdma();
1019: outb(CLEARFF, 0);
1020: outb(MODEREG, mode); /* set dma mode */
1021: outb(dmareg, bufptr & 0xFF);
1022: outb(dmareg, (bufptr>>8) & 0xFF);
1023: outb(pagereg, (bufptr>>16) & 0xFF);
1024: outb(dmareg+1, (BLKSIZE-1) & 0xFF);
1025: outb(dmareg+1, (BLKSIZE-1) >> 8);
1026: outb(wtport, eqdma+ONLINE);
1027: outb(MASKREG, wtchan); /* enable command to 8237, start dma */
1028: splx(x);
1029: }
1030:
1031: static near
1032: wtstart(buf, cnt)
1033: long buf;
1034: int cnt;
1035: {
1036: register s;
1037:
1038: bufptr = buf; /* init statics */
1039: numbytes = cnt;
1040: wci = 0; /* init flags */
1041: exflag = 0;
1042: bytes = 0; /* init counter */
1043:
1044: do s = inb(STATPORT) & STAT;
1045: while (s == STAT); /* wait for ready or error */
1046:
1047: if (s & EXCEP) /* no error */
1048: {
1049: dma();
1050: return SUCCESS;
1051: }
1052: return ERROR; /* error */
1053: }
1054:
1055: rtape(buf, cnt)
1056: long buf; /* physical address */
1057: int cnt; /* number of bytes */
1058: {
1059: mode = dma_read;
1060: return wtstart(buf,cnt);
1061: }
1062:
1063: wtape(buf, cnt)
1064: long buf; /* physical address */
1065: int cnt; /* number of bytes */
1066: {
1067: mode = dma_write;
1068: return wtstart(buf,cnt);
1069: }
1070:
1071: isr()
1072: {
1073: int stat = inb(wtport);
1074: if (!(stat & EXCEP)) /* exception during I/O */
1075: {
1076: if (bytes + BLKSIZE >= numbytes) wci = 1;
1077: exflag = 1;
1078: goto isrwake;
1079: }
1080: if ((stat & READY) || !(inb(STATUSREG) & dma_done))
1081: return;
1082: exflag = 0;
1083: outb(wtport, ONLINE);
1084: bytes += BLKSIZE;
1085: if (bytes >= numbytes) /* normal completion of I/O */
1086: {
1087: wci = 1;
1088: isrwake:
1089: outb(MASKREG, 4+wtchan); /* turn off dma */
1090: wtwake(); /* wake up user level */
1091: }
1092: else
1093: { /* continue I/O */
1094: bufptr += BLKSIZE;
1095: dma();
1096: }
1097: }
1098:
1099: wtlinit()
1100: {
1101: switch (wtchan) {
1102: case 1:
1103: return;
1104: case 2:
1105: pagereg = 0x81;
1106: dma_done = 4;
1107: break;
1108: case 3:
1109: eqdma = 0x10;
1110: pagereg = 0x82;
1111: dma_done = 8;
1112: break;
1113: }
1114: dma_write = wtchan+0x48;
1115: dma_read = wtchan+0x44;
1116: dmareg = wtchan+wtchan;
1117: }
1118:
1119: /*
1120: * delay i microseconds
1121: */
1122: delay(i)
1123: register int i;
1124: {
1125: while (i-- > 0)
1126: DELAY(1000);
1127: }
1128:
1129: wtsize()
1130: {
1131: }
1132:
1133: wtdump()
1134: {
1135: }
1136:
1137: #include "i386/isa/isa_device.h"
1138: #include "i386/isa/icu.h"
1139:
1140: int wtprobe(), wtattach();
1141: struct isa_driver wtdriver = {
1142: wtprobe, wtattach, "wt",
1143: };
1144:
1145: wtprobe(dvp)
1146: struct isa_device *dvp;
1147: {
1148: int val,i,s;
1149:
1150: #ifdef lint
1151: wtintr(0);
1152: #endif
1153:
1154: wtport = dvp->id_iobase;
1155: if(t_reset() != SUCCESS) return(0);
1156: return(1);
1157: }
1158:
1159: wtattach() { }
1160:
1161: #endif NWT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.