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