|
|
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
1.1.1.3 ! root 305: ucnt1 = bp->b_bcount % NBPG;
1.1 root 306: ucnt2 = 0;
307: adr2 = 0;
308: #ifdef DEBUG
309: debug("WTstart: adr1 %lx cnt %x\n", adr1, ucnt1);
310: #endif
1.1.1.3 ! root 311: /* 64K boundary? (XXX) */
1.1 root 312: if (ftoseg(adr1) != ftoseg(adr1 + (unsigned) ucnt1 - 1))
313: {
314: adr2 = (adr1 & 0xffff0000L) + 0x10000L;
315: ucnt2 = (adr1 + ucnt1) - adr2;
316: ucnt1 -= ucnt2;
317: }
1.1.1.3 ! root 318: /* page boundary? */
! 319: if (trunc_page(adr1) != trunc_page(adr1 + (unsigned) ucnt1 - 1))
! 320: { unsigned u;
! 321: u = NBPG - ((unsigned)bp->b_un.b_addr & (NBPG-1));
! 322: adr2 = kvtop(bp->b_un.b_addr + u);
! 323: ucnt2 = ucnt1 - u;
! 324: ucnt1 = u;
! 325: }
1.1 root 326: /* at file marks and end of tape, we just return '0 bytes available' */
327: if (wtflags & TPVOL) {
328: bp->b_resid = bp->b_bcount;
329: goto xit;
330: }
331: if ((Hogproc == (struct proc *) 0) && TPHOG(bp->b_dev))
332: {
333: #ifdef DEBUG
334: printf("setting Hogproc\n");
335: #endif
336: Hogtime = 0;
337: Hogproc = myproc;
338: }
339: if (bp->b_flags & B_READ) {
340: bad = 0;
341:
342: /* For now, we assume that all data will be copied out */
343: /* If read command outstanding, just skip down */
344: if (!(wtflags & TPRO)) {
345: if (ERROR == wtsense(TP_WRP)) /* clear status */
346: goto errxit;
347: #ifdef DEBUG
348: debug("WTread: Start read\n");
349: #endif
350: if (!(wtflags & TPREAD) || (wtflags & TPWANY) ||
351: (rstart() == ERROR)) {
352: #ifdef DEBUG
353: debug("Tpstart: read init error\n"); /* */
354: #endif
355: goto errxit;
356: }
357: wtflags |= TPRO|TPRANY;
358: }
359:
360: finished = 0;
361: /* Take a deep breath */
362: if (ucnt1) {
363: if ((rtape(adr1, ucnt1) == ERROR) &&
364: (wtsense(TP_WRP) == ERROR))
365: goto endio;
366: /* wait for it */
367: bad = pollrdy();
368: finished = bytes;
369: if (bad)
370: goto endio;
371: }
372: /* if a second I/O region, start it */
373: if (ucnt2) {
374: if ((rtape(adr2, ucnt2) == ERROR) &&
375: (wtsense(TP_WRP) == ERROR))
376: ucnt2 = 0; /* don't poll for me */
377: }
378:
379: /* if second i/o pending wait for it */
380: if (ucnt2) {
381: pollrdy();
382: /* whether pollrdy is ok or not */
383: finished += bytes;
384: }
385: } else {
386: if (wtflags & TPWP) /* write protected */
387: goto errxit;
388:
389: /* If write command outstanding, just skip down */
390: if (!(wtflags & TPWO)) {
391: if (ERROR == wtsense(0)) /* clear status */
392: {
393: #ifdef DEBUG
394: debug("TPstart: sense 0\n");
395: #endif
396: goto errxit;
397: }
398: if (!(wtflags & TPWRITE) || (wtflags & TPRANY) ||
399: (wstart() == ERROR)) {
400: #ifdef DEBUG
401: debug("Tpstart: write init error\n"); /* */
402: #endif
403: wtsense(0);
404:
405: errxit: bp->b_flags |= B_ERROR;
406: bp->b_resid = bp->b_bcount;
407: goto xit;
408: }
409: wtflags |= TPWO|TPWANY;
410: }
411:
412: /* and hold your nose */
413: if (ucnt1 && ((wtape(adr1, ucnt1) == ERROR)
414: && (wtsense(0) == ERROR)))
415: finished = bytes;
416:
417: else if (ucnt2 &&
418: (((ucnt1 && pollrdy()) ||
419: (wtape(adr2, ucnt2) == ERROR)) &&
420: (wtsense(0) == ERROR)))
421: finished = ucnt1 + NBPS + bytes;
422: /* All writes and/or copyins were fine! */
423: else
424: finished = bp->b_bcount;
425: bad = pollrdy();
426: }
427:
428: endio:
429: if(bad == EIO) bad = 0;
430: wterror.wt_err = 0;
431: if (exflag && wtsense((bp->b_flags & B_READ) ? TP_WRP : 0)) {
432: if ((wterror.wt_err & TP_ST0)
433: && (wterror.wt_err & (TP_FIL|TP_EOM))) {
434: #ifdef DEBUG
435: debug("WTsta: Hit end of tape\n"); /* */
436: #endif
437: wtflags |= TPVOL;
438: if (wterror.wt_err & TP_FIL) {
439: if (wtflags & TPRO)
440: /* interrupter is bogus */
441: rstart(); /* restart read command */
442: else
443: wtflags &= ~TPWO;
444: finished += NBPS;
445: }
446: /* Reading file marks or writing end of tape return 0 bytes */
447: } else {
448: bp->b_flags |= B_ERROR;
449: wtflags &= ~(TPWO|TPRO);
450: }
451: }
452:
453: if(bad) {
454: bp->b_flags |= B_ERROR;
455: bp->b_error = bad;
456: }
457: bp->b_resid = bp->b_bcount - finished;
458: xit:
459: biodone(bp);
460: if (wtimeron)
461: Hogtime = lbolt;
462: else if (Hogproc == myproc)
463: Hogproc = (struct proc *) 0;
464: }
465:
466: /*
467: * simulate an interrupt periodically while I/O is going
468: * this is necessary in case interrupts get eaten due to
469: * multiple devices on a single IRQ line
470: */
471: wtimer()
472: {
473: /* If I/O going and not in isr(), simulate interrupt
474: * If no I/O for at least 1 second, stop being a Hog
475: * If I/O done and not a Hog, turn off wtimer()
476: */
477: if (wtio && !isrlock)
478: isr();
479:
480: if ((Hogproc == myproc) && Hogtime && (lbolt-Hogtime > HZ))
481: Hogproc = (struct proc *) 0;
482:
483: if (wtio || (Hogproc == myproc))
484: timeout(wtimer, (caddr_t) 0, HZ);
485: else
486: wtimeron = 0;
487: }
488:
489:
490: wtrawio(bp)
491: struct buf *bp;
492: {
493: wtstrategy(bp);
494: biowait(bp);
495: return(0);
496: }
497:
498: /*
499: * ioctl routine
500: * for user level QIC commands only
501: */
502: wtioctl(dev, cmd, arg, mode)
503: int dev, cmd;
504: unsigned long arg;
505: int mode;
506: {
507: if (cmd == WTQICMD)
508: {
509: if ((qicmd((int)arg) == ERROR) || (rdyexc(HZ) == ERROR))
510: {
511: wtsense(0);
512: return(EIO);
513: }
514: return(0);
515: }
516: return(EINVAL);
517: }
518:
519: /*
520: * open routine
521: * called on every device open
522: */
523: wtopen(dev, flag)
524: int dev, flag;
525: {
526: if (first_wtopen_ever) {
527: wtinit();
528: first_wtopen_ever = 0;
529: }
530: #ifdef DEBUG
531: printf("wtopen ...\n");
532: #endif
533: if (!pageaddr) {
534: return(ENXIO);
535: }
536: if (wtflags & (TPINUSE)) {
537: return(ENXIO);
538: }
539: if (wtflags & (TPDEAD)) {
540: return(EIO);
541: }
542: /* If a rewind from the last session is going on, wait */
543: while(wtflags & TPREW) {
544: #ifdef DEBUG
545: debug("Waiting for rew to finish\n");
546: #endif
1.1.1.3 ! root 547: DELAY(1000000); /* delay one second */
1.1 root 548: }
549: /* Only do reset and select when tape light is off, and tape is rewound.
550: * This allows multiple volumes. */
551: if (wtflags & TPSTART) {
552: if (t_reset() != SUCCESS) {
553: return(ENXIO);
554: }
555: #ifdef DEBUG
556: debug("reset done. calling wtsense\n");
557: #endif
558: if (wtsense(TP_WRP) == ERROR) {
559: return (EIO);
560: }
561: #ifdef DEBUG
562: debug("wtsense done\n");
563: #endif
564: wtflags &= ~TPSTART;
565: }
566:
567: wtflags = TPINUSE;
568: if (flag & FREAD)
569: wtflags |= TPREAD;
570: if (flag & FWRITE)
571: wtflags |= TPWRITE;
572: rwtbuf.b_flags = 0;
573: myproc = curproc; /* for comparison */
1.1.1.3 ! root 574: #ifdef not
1.1 root 575: switch(TP_DENS(dev)) {
576: case 0:
577: cmds(0x28);
578: break;
579: case 1:
580: cmds(0x29);
581: break;
582: case 2:
583: cmds(0x27);
584: break;
585: case 3:
586: cmds(0x24);
587: }
1.1.1.3 ! root 588: #endif
1.1 root 589: return(0);
590: }
591:
592: /*
593: * close routine
594: * called on last device close
595: * If not rewind-on-close, leave read or write command intact.
596: */
597: wtclose(dev)
598: {
599: int wtdsl2();
600:
601: #ifdef DEBUG
602: debug("WTclose:\n");
603: #endif
604: if (Hogproc == myproc)
605: Hogproc = (struct proc *) 0;
606: if (!exflag && (wtflags & TPWANY) && !(wtflags & (TPSESS|TPDEAD))) {
607: if (!(wtflags & TPWO))
608: wstart();
609: #ifdef DEBUG
610: debug("WT: Writing file mark\n");
611: #endif
612: wmark(); /* write file mark */
613: #ifdef DEBUG
614: debug("WT: Wrote file mark, going to wait\n");
615: #endif
616: if (rdyexc(HZ/10) == ERROR) {
617: wtsense(0);
618: }
619: }
620: if (TP_REWCLOSE(dev) || (wtflags & (TPSESS|TPDEAD))) {
621: /* rewind tape to beginning of tape, deselect tape, and make a note */
622: /* don't wait until rewind, though */
623: /* Ending read or write causes rewind to happen, if no error,
624: * and READY and EXCEPTION stay up until it finishes */
625: if (wtflags & (TPRO|TPWO))
626: {
627: #ifdef DEBUG
628: debug("End read or write\n");
629: #endif
630: rdyexc(HZ/10);
631: ioend();
632: wtflags &= ~(TPRO|TPWO);
633: }
634: else wtwind();
635: wtflags |= TPSTART | TPREW;
636: timeout(wtdsl2, 0, HZ);
637: }
638: else if (!(wtflags & (TPVOL|TPWANY)))
639: {
640: /* space forward to after next file mark no writing done */
641: /* This allows skipping data without reading it.*/
642: #ifdef DEBUG
643: debug("Reading past file mark\n");
644: #endif
645: if (!(wtflags & TPRO))
646: rstart();
647: rmark();
648: if (rdyexc(HZ/10))
649: {
650: wtsense(TP_WRP);
651: }
652: }
653: wtflags &= TPREW|TPDEAD|TPSTART|TPRO|TPWO;
654: return(0);
655: }
656:
657: /* return ERROR if user I/O request should receive an I/O error code */
658:
659: wtsense(ignor)
660: {
661: wtflags &= ~(TPRO|TPWO);
662: #ifdef DEBUGx
663: debug("WTsense: start ");
664: #endif
665: if (rdstatus(&wterror) == ERROR)
666: {
667: #ifdef DEBUG
668: debug("WTsense: Can't read status\n");
669: #endif
670: return(ERROR);
671: }
672: #ifdef DEBUG
673: if (wterror.wt_err & (TP_ST0|TP_ST1))
674: {
675: debug("Tperror: status %x error %d underruns %d\n",
676: wterror.wt_err, wterror.wt_ercnt, wterror.wt_urcnt);
677: }
678: else
679: debug("done. no error\n");
680: #endif
681: wterror.wt_err &= ~ignor; /* ignore certain errors */
682: reperr(wterror.wt_err);
683: if (((wterror.wt_err & TP_ST0) && (wterror.wt_err & TP_ERR0)) ||
684: ((wterror.wt_err & TP_ST1) && (wterror.wt_err & TP_ERR1)))
685: return ERROR;
686:
687: return SUCCESS;
688: }
689:
690: /* lifted from tdriver.c from Wangtek */
691: reperr(srb0)
692: int srb0;
693: {
694: int s0 = srb0 & (TP_ERR0|TP_ERR1); /* find out which exception to report */
695:
696: if (s0) {
697: if (s0 & TP_USL)
698: sterr("Drive not online");
699: else if (s0 & TP_CNI)
700: sterr("No cartridge");
701: else if ((s0 & TP_WRP) && !(wtflags & TPWP))
702: {
703: sterr("Tape is write protected");
704: wtflags |= TPWP;
705: }
706: /*
707: if (s0 & TP_FIL)
708: sterr("Filemark detected");
709: */
710: else if (s0 & TP_BNL)
711: sterr("Block in error not located");
712: else if (s0 & TP_UDA)
713: sterr("Unrecoverable data error");
714: /*
715: else if (s0 & TP_EOM)
716: sterr("End of tape");
717: */
718: else if (s0 & TP_NDT)
719: sterr("No data detected");
720: /*
721: if (s0 & TP_POR)
722: sterr("Reset occured");
723: */
724: else if (s0 & TP_BOM)
725: sterr("Beginning of tape");
726: else if (s0 & TP_ILL)
727: sterr("Illegal command");
728: }
729: }
730:
731: sterr(errstr)
732: char *errstr;
733: {
734: printf("Streamer: %s\n", errstr);
735: }
736:
737: /* Wait until rewind finishes, and deselect drive */
738: wtdsl2() {
739: int stat;
740:
741: stat = inb(wtport) & (READY|EXCEP);
742: #ifdef DEBUG
743: debug("Timeout: Waiting for rewind to finish: stat %x\n", stat);
744: #endif
745: switch (stat) {
746: /* They're active low, ya'know */
747: case READY|EXCEP:
748: timeout(wtdsl2, (caddr_t) 0, HZ);
749: return;
750: case EXCEP:
751: wtflags &= ~TPREW;
752: return;
753: case READY:
754: case 0:
755: wtflags &= ~TPREW;
756: sterr("Rewind failed");
757: wtsense(TP_WRP);
758: return;
759: }
760: }
761:
762: wtwind() {
763: #ifdef DEBUG
764: debug("WT: About to rewind\n");
765: #endif
766: rwind(); /* actually start rewind */
767: }
768:
769: wtintr(unit) {
770: if (wtflags & (TPWO|TPRO))
771: {
772: isrlock = 1;
773: if (wtio) isr();
774: isrlock = 0;
775: }
776: }
777:
778: wtinit() {
779: if (wtchan < 1 || wtchan > 3)
780: {
781: sterr("Bad DMA channel, cannot init driver");
782: return;
783: }
784: wtlinit(); /* init assembly language variables */
785: pageset();
786: }
787:
788: rdyexc(ticks)
789: {
790: int s;
791: #ifdef DEBUG
792: int os = 0xffff; /* force printout first time */
793: #endif
794: for (;;) { /* loop until ready or exception */
795: s=(inb(wtport) & 0xff); /* read the status register */
796: #ifdef DEBUG
797: if (os != s) {
798: debug("Status reg = %x\n", s); /* */
799: os = s;
800: }
801: #endif
802: if (!(s & EXCEP)) /* check if exception have occured */
803: break;
804: if (!(s & READY)) /* check if controller is ready */
805: break;
806: s = splbio();
1.1.1.3 ! root 807: DELAY((ticks/HZ)*1000000); /* */
1.1 root 808: splx(s);
809: }
810: #ifdef DEBUG
811: debug("Status reg = %x on return\n", s); /* */
812: #endif
813: return((s & EXCEP)?SUCCESS:ERROR); /* return exception if it occured */
814: }
815:
816: pollrdy()
817: {
818: int sps;
819: #ifdef DEBUG
820: debug("Pollrdy\n");
821: #endif
822: sps = splbio();
823: while (wtio) {
824: int error;
825:
826: if (error = tsleep((caddr_t)&wci, WTPRI | PCATCH,
827: "wtpoll", 0)) {
828: splx(sps);
829: return(error);
830: }
831: }
832: splx(sps);
833: #ifdef DEBUG
834: debug("Finish poll, wci %d exflag %d\n", wci, exflag);
835: #endif
836: return (EIO);
837: }
838:
839: wtdma() /* start up i/o operation, called from dma() in wtlib1.s */
840: {
841: wtio = 1;
842: if (!wtimeron)
843: {
844: wtimeron = 1;
845: timeout(wtimer, (caddr_t) 0, HZ/2);
846: }
847: }
848:
849: wtwake() /* end i/o operation, called from isr() in wtlib1.s */
850: {
851: wtio = 0;
852: wakeup(&wci);
853: }
854:
855: pageset()
856: {
857: unsigned long pp;
858:
859: pp = (unsigned long) pagebuf;
860: pageaddr = kvtop(pp);
861: #ifdef DEBUG
862: debug("pageset: addr %lx\n", pageaddr);
863: #endif
864: }
865:
866:
867:
868: #define near
869:
870: static near
871: sendcmd()
872: {
873: /* desired command in global mbits */
874:
875: outb(CTLPORT, mbits | REQUEST); /* set request */
876: while (inb(STATPORT) & READY); /* wait for ready */
877: outb(CTLPORT, mbits & ~REQUEST); /* reset request */
878: while ((inb(STATPORT) & READY) == 0); /* wait for not ready */
879: }
880:
881: static near /* execute command */
882: cmds(cmd)
883: {
884: register s;
885:
886: do s = inb(STATPORT);
887: while ((s & STAT) == STAT); /* wait for ready */
888:
889: if ((s & EXCEP) == 0) /* if exception */
890: return ERROR; /* error */
891:
892: outb(CMDPORT, cmd); /* output the command */
893:
894: outb(CTLPORT, mbits=ONLINE); /* set & send ONLINE */
895: sendcmd();
896:
897: return SUCCESS;
898: }
899:
900: qicmd(cmd)
901: {
902: return cmds(cmd);
903: }
904:
905: rstart()
906: {
907: return cmds(RDDATA);
908: }
909:
910: rmark()
911: {
912: return cmds(READFM);
913: }
914:
915: wstart()
916: {
917: return cmds(WRTDATA);
918: }
919:
920: ioend()
921: {
922: register s;
923: register rval = SUCCESS;
924:
925: do s = inb(STATPORT);
926: while ((s & STAT) == STAT); /* wait for ready */
927:
928: if ((s & EXCEP) == 0) /* if exception */
929: rval = ERROR; /* error */
930:
931: mbits &= ~ONLINE;
932: outb(CTLPORT, mbits); /* reset ONLINE */
933: outb(MASKREG, wtchan+4); /* turn off dma */
934: outb(CLEARFF, 0); /* reset direction flag */
935:
936: return rval;
937: }
938:
939: wmark()
940: {
941: register s;
942:
943: if (cmds(WRITEFM) == ERROR)
944: return ERROR;
945:
946: do s = inb(STATPORT);
947: while ((s & STAT) == STAT); /* wait for ready */
948:
949: if ((s & EXCEP) == 0) /* if exception */
950: return ERROR; /* error */
951:
952: return SUCCESS;
953: }
954:
955: rwind()
956: {
957: register s;
958:
959: mbits = CMDOFF;
960:
961: do s = inb(STATPORT);
962: while ((s & STAT) == STAT); /* wait for ready */
963:
964: outb(CMDPORT, REWIND);
965: sendcmd();
966:
967: return SUCCESS;
968: }
969:
970: rdstatus(stp)
971: char *stp; /* pointer to 6 byte buffer */
972: {
973: register s;
974: int n;
975:
976: do s = inb(STATPORT);
977: while ((s & STAT) == STAT); /* wait for ready or exception */
978:
979: outb(CMDPORT, RDSTAT);
980: sendcmd(); /* send read status command */
981:
982: for (n=0; n<6; n++)
983: {
984: #ifdef DEBUGx
985: debug("rdstatus: waiting, byte %d\n", n);
986: #endif
987: do s = inb(STATPORT);
988: while ((s & STAT) == STAT); /* wait for ready */
989: #ifdef DEBUGx
990: debug("rdstatus: done\n");
991: #endif
992: if ((s & EXCEP) == 0) /* if exception */
993: return ERROR; /* error */
994:
995: *stp++ = inb(DATAPORT); /* read status byte */
996:
997: outb(CTLPORT, mbits | REQUEST); /* set request */
998: #ifdef DEBUGx
999: debug("rdstatus: waiting after request, byte %d\n", n);
1000: #endif
1001: while ((inb(STATPORT)&READY) == 0); /* wait for not ready */
1002: for (s=100; s>0; s--); /* wait an additional time */
1003:
1004: outb(CTLPORT, mbits & ~REQUEST);/* unset request */
1005: #ifdef DEBUGx
1006: debug("rdstatus: done\n");
1007: #endif
1008: }
1009: return SUCCESS;
1010: }
1011:
1012: t_reset()
1013: {
1014: register i;
1015: mbits |= RESET;
1016: outb(CTLPORT, mbits); /* send reset */
1.1.1.3 ! root 1017: DELAY(20);
1.1 root 1018: mbits &= ~RESET;
1019: outb(CTLPORT, mbits); /* turn off reset */
1020: if ((inb(STATPORT) & RESETMASK) == RESETVAL)
1021: return SUCCESS;
1022: return ERROR;
1023: }
1024:
1025: static
1026: dma()
1027: {
1028: int x=splbio();
1029: wtdma();
1030: outb(CLEARFF, 0);
1031: outb(MODEREG, mode); /* set dma mode */
1032: outb(dmareg, bufptr & 0xFF);
1033: outb(dmareg, (bufptr>>8) & 0xFF);
1034: outb(pagereg, (bufptr>>16) & 0xFF);
1035: outb(dmareg+1, (BLKSIZE-1) & 0xFF);
1036: outb(dmareg+1, (BLKSIZE-1) >> 8);
1037: outb(wtport, eqdma+ONLINE);
1038: outb(MASKREG, wtchan); /* enable command to 8237, start dma */
1039: splx(x);
1040: }
1041:
1042: static near
1043: wtstart(buf, cnt)
1044: long buf;
1045: int cnt;
1046: {
1047: register s;
1048:
1049: bufptr = buf; /* init statics */
1050: numbytes = cnt;
1051: wci = 0; /* init flags */
1052: exflag = 0;
1053: bytes = 0; /* init counter */
1054:
1055: do s = inb(STATPORT) & STAT;
1056: while (s == STAT); /* wait for ready or error */
1057:
1058: if (s & EXCEP) /* no error */
1059: {
1060: dma();
1061: return SUCCESS;
1062: }
1063: return ERROR; /* error */
1064: }
1065:
1066: rtape(buf, cnt)
1067: long buf; /* physical address */
1068: int cnt; /* number of bytes */
1069: {
1070: mode = dma_read;
1071: return wtstart(buf,cnt);
1072: }
1073:
1074: wtape(buf, cnt)
1075: long buf; /* physical address */
1076: int cnt; /* number of bytes */
1077: {
1078: mode = dma_write;
1079: return wtstart(buf,cnt);
1080: }
1081:
1082: isr()
1083: {
1084: int stat = inb(wtport);
1085: if (!(stat & EXCEP)) /* exception during I/O */
1086: {
1087: if (bytes + BLKSIZE >= numbytes) wci = 1;
1088: exflag = 1;
1089: goto isrwake;
1090: }
1091: if ((stat & READY) || !(inb(STATUSREG) & dma_done))
1092: return;
1093: exflag = 0;
1094: outb(wtport, ONLINE);
1095: bytes += BLKSIZE;
1096: if (bytes >= numbytes) /* normal completion of I/O */
1097: {
1098: wci = 1;
1099: isrwake:
1100: outb(MASKREG, 4+wtchan); /* turn off dma */
1101: wtwake(); /* wake up user level */
1102: }
1103: else
1104: { /* continue I/O */
1105: bufptr += BLKSIZE;
1106: dma();
1107: }
1108: }
1109:
1110: wtlinit()
1111: {
1112: switch (wtchan) {
1113: case 1:
1114: return;
1115: case 2:
1116: pagereg = 0x81;
1117: dma_done = 4;
1118: break;
1119: case 3:
1120: eqdma = 0x10;
1121: pagereg = 0x82;
1122: dma_done = 8;
1123: break;
1124: }
1125: dma_write = wtchan+0x48;
1126: dma_read = wtchan+0x44;
1127: dmareg = wtchan+wtchan;
1128: }
1129:
1130: wtsize()
1131: {
1132: }
1133:
1134: wtdump()
1135: {
1136: }
1137:
1138: #include "i386/isa/isa_device.h"
1139: #include "i386/isa/icu.h"
1140:
1141: int wtprobe(), wtattach();
1142: struct isa_driver wtdriver = {
1143: wtprobe, wtattach, "wt",
1144: };
1145:
1146: wtprobe(dvp)
1147: struct isa_device *dvp;
1148: {
1149: int val,i,s;
1150:
1151: #ifdef lint
1152: wtintr(0);
1153: #endif
1154:
1155: wtport = dvp->id_iobase;
1156: if(t_reset() != SUCCESS) return(0);
1157: return(1);
1158: }
1159:
1160: wtattach() { }
1161:
1162: #endif NWT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.