home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / i386 / isa / wt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-05-09  |  25.9 KB  |  1,197 lines

  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  Software.Distribution@CS.CMU.EDU
  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
  1197.