|
|
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.