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