FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/wt.c
1
2 /*
3 * Streamer tape driver for 386bsd and FreeBSD.
4 * Supports Archive and Wangtek compatible QIC-02/QIC-36 boards.
5 *
6 * Copyright (C) 1993 by:
7 * Sergey Ryzhkov <sir@kiae.su>
8 * Serge Vakulenko <vak@zebub.msk.su>
9 *
10 * This software is distributed with NO WARRANTIES, not even the implied
11 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * Authors grant any other persons or organisations permission to use
14 * or modify this software as long as this message is kept with the software,
15 * all derivative works or modified versions.
16 *
17 * This driver is derived from the old 386bsd Wangtek streamer tape driver,
18 * made by Robert Baron at CMU, based on Intel sources.
19 * Authors thank Robert Baron, CMU and Intel and retain here
20 * the original CMU copyright notice.
21 *
22 * Version 1.3, Thu Nov 11 12:09:13 MSK 1993
23 * $FreeBSD: src/sys/i386/isa/wt.c,v 1.35.2.2 1999/09/05 08:13:45 peter Exp $
24 *
25 */
26
27 /*
28 * Code for MTERASE added by John Lind (john@starfire.mn.org) 95/09/02.
29 * This was very easy due to the excellent structure and clear coding
30 * of the original driver.
31 */
32
33 /*
34 * Copyright (c) 1989 Carnegie-Mellon University.
35 * All rights reserved.
36 *
37 * Authors: Robert Baron
38 *
39 * Permission to use, copy, modify and distribute this software and
40 * its documentation is hereby granted, provided that both the copyright
41 * notice and this permission notice appear in all copies of the
42 * software, derivative works or modified versions, and any portions
43 * thereof, and that both notices appear in supporting documentation.
44 *
45 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
46 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
47 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 *
49 * Carnegie Mellon requests users of this software to return to
50 *
51 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
52 * School of Computer Science
53 * Carnegie Mellon University
54 * Pittsburgh PA 15213-3890
55 *
56 * any improvements or extensions that they make and grant Carnegie the
57 * rights to redistribute these changes.
58 */
59
60 #include "wt.h"
61 #if NWT > 0
62
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/buf.h>
67 #include <sys/fcntl.h>
68 #include <sys/malloc.h>
69 #include <sys/ioctl.h>
70 #include <sys/mtio.h>
71 #include <sys/proc.h>
72 #include <sys/conf.h>
73 #ifdef DEVFS
74 #include <sys/devfsext.h>
75 #endif /*DEVFS*/
76 #include <vm/vm_param.h>
77
78 #include <machine/clock.h>
79 #include <machine/wtio.h>
80
81 #include <i386/isa/isa_device.h>
82 #include <i386/isa/wtreg.h>
83
84
85 /*
86 * Uncomment this to enable internal device tracing.
87 */
88 #define TRACE(s) /* printf s */
89
90 #define WTPRI (PZERO+10) /* sleep priority */
91
92 /*
93 * Wangtek controller ports
94 */
95 #define WT_CTLPORT(base) ((base)+0) /* control, write only */
96 #define WT_STATPORT(base) ((base)+0) /* status, read only */
97 #define WT_CMDPORT(base) ((base)+1) /* command, write only */
98 #define WT_DATAPORT(base) ((base)+1) /* data, read only */
99 #define WT_NPORT 2 /* 2 i/o ports */
100
101 /* status port bits */
102 #define WT_BUSY 0x01 /* not ready bit define */
103 #define WT_NOEXCEP 0x02 /* no exception bit define */
104 #define WT_RESETMASK 0x07 /* to check after reset */
105 #define WT_RESETVAL 0x05 /* state after reset */
106
107 /* control port bits */
108 #define WT_ONLINE 0x01 /* device selected */
109 #define WT_RESET 0x02 /* reset command */
110 #define WT_REQUEST 0x04 /* request command */
111 #define WT_IEN 0x08 /* enable dma */
112
113 /*
114 * Archive controller ports
115 */
116 #define AV_DATAPORT(base) ((base)+0) /* data, read only */
117 #define AV_CMDPORT(base) ((base)+0) /* command, write only */
118 #define AV_STATPORT(base) ((base)+1) /* status, read only */
119 #define AV_CTLPORT(base) ((base)+1) /* control, write only */
120 #define AV_SDMAPORT(base) ((base)+2) /* start dma */
121 #define AV_RDMAPORT(base) ((base)+3) /* reset dma */
122 #define AV_NPORT 4 /* 4 i/o ports */
123
124 /* status port bits */
125 #define AV_BUSY 0x40 /* not ready bit define */
126 #define AV_NOEXCEP 0x20 /* no exception bit define */
127 #define AV_RESETMASK 0xf8 /* to check after reset */
128 #define AV_RESETVAL 0x50 /* state after reset */
129
130 /* control port bits */
131 #define AV_RESET 0x80 /* reset command */
132 #define AV_REQUEST 0x40 /* request command */
133 #define AV_IEN 0x20 /* enable interrupts */
134
135 enum wttype {
136 UNKNOWN = 0, /* unknown type, driver disabled */
137 ARCHIVE, /* Archive Viper SC499, SC402 etc */
138 WANGTEK, /* Wangtek */
139 };
140
141 typedef struct {
142 unsigned short err; /* code for error encountered */
143 unsigned short ercnt; /* number of error blocks */
144 unsigned short urcnt; /* number of underruns */
145 } wtstatus_t;
146
147 typedef struct {
148 enum wttype type; /* type of controller */
149 unsigned unit; /* unit number */
150 unsigned port; /* base i/o port */
151 unsigned chan; /* dma channel number, 1..3 */
152 unsigned flags; /* state of tape drive */
153 unsigned dens; /* tape density */
154 int bsize; /* tape block size */
155 void *buf; /* internal i/o buffer */
156
157 void *dmavaddr; /* virtual address of dma i/o buffer */
158 unsigned dmatotal; /* size of i/o buffer */
159 unsigned dmaflags; /* i/o direction, B_READ or B_WRITE */
160 unsigned dmacount; /* resulting length of dma i/o */
161
162 wtstatus_t error; /* status of controller */
163
164 unsigned short DATAPORT, CMDPORT, STATPORT, CTLPORT, SDMAPORT, RDMAPORT;
165 unsigned char BUSY, NOEXCEP, RESETMASK, RESETVAL;
166 unsigned char ONLINE, RESET, REQUEST, IEN;
167 #ifdef DEVFS
168 void *devfs_token;
169 void *devfs_token_r;
170 #endif
171 } wtinfo_t;
172
173 static wtinfo_t wttab[NWT]; /* tape info by unit number */
174
175 static int wtwait (wtinfo_t *t, int catch, char *msg);
176 static int wtcmd (wtinfo_t *t, int cmd);
177 static int wtstart (wtinfo_t *t, unsigned mode, void *vaddr, unsigned len);
178 static void wtdma (wtinfo_t *t);
179 static timeout_t wtimer;
180 static void wtclock (wtinfo_t *t);
181 static int wtreset (wtinfo_t *t);
182 static int wtsense (wtinfo_t *t, int verb, int ignor);
183 static int wtstatus (wtinfo_t *t);
184 static void wtrewind (wtinfo_t *t);
185 static int wtreadfm (wtinfo_t *t);
186 static int wtwritefm (wtinfo_t *t);
187 static int wtpoll (wtinfo_t *t, int mask, int bits);
188
189 static d_open_t wtopen;
190 static d_close_t wtclose;
191 static d_ioctl_t wtioctl;
192 static d_dump_t wtdump;
193 static d_psize_t wtsize;
194 static d_strategy_t wtstrategy;
195
196 #define CDEV_MAJOR 10
197 #define BDEV_MAJOR 3
198
199 static struct cdevsw wt_cdevsw;
200 static struct bdevsw wt_bdevsw =
201 { wtopen, wtclose, wtstrategy, wtioctl, /*3*/
202 wtdump, wtsize, B_TAPE, "wt", &wt_cdevsw, -1 };
203
204
205 /*
206 * Probe for the presence of the device.
207 */
208 static int
209 wtprobe (struct isa_device *id)
210 {
211 wtinfo_t *t = wttab + id->id_unit;
212
213 t->unit = id->id_unit;
214 t->chan = id->id_drq;
215 t->port = id->id_iobase;
216 if (t->chan<1 || t->chan>3) {
217 printf ("wt%d: Bad drq=%d, should be 1..3\n", t->unit, t->chan);
218 return (0);
219 }
220
221 /* Try Wangtek. */
222 t->type = WANGTEK;
223 t->CTLPORT = WT_CTLPORT (t->port); t->STATPORT = WT_STATPORT (t->port);
224 t->CMDPORT = WT_CMDPORT (t->port); t->DATAPORT = WT_DATAPORT (t->port);
225 t->SDMAPORT = 0; t->RDMAPORT = 0;
226 t->BUSY = WT_BUSY; t->NOEXCEP = WT_NOEXCEP;
227 t->RESETMASK = WT_RESETMASK; t->RESETVAL = WT_RESETVAL;
228 t->ONLINE = WT_ONLINE; t->RESET = WT_RESET;
229 t->REQUEST = WT_REQUEST; t->IEN = WT_IEN;
230 if (wtreset (t))
231 return (WT_NPORT);
232
233 /* Try Archive. */
234 t->type = ARCHIVE;
235 t->CTLPORT = AV_CTLPORT (t->port); t->STATPORT = AV_STATPORT (t->port);
236 t->CMDPORT = AV_CMDPORT (t->port); t->DATAPORT = AV_DATAPORT (t->port);
237 t->SDMAPORT = AV_SDMAPORT (t->port); t->RDMAPORT = AV_RDMAPORT (t->port);
238 t->BUSY = AV_BUSY; t->NOEXCEP = AV_NOEXCEP;
239 t->RESETMASK = AV_RESETMASK; t->RESETVAL = AV_RESETVAL;
240 t->ONLINE = 0; t->RESET = AV_RESET;
241 t->REQUEST = AV_REQUEST; t->IEN = AV_IEN;
242 if (wtreset (t))
243 return (AV_NPORT);
244
245 /* Tape controller not found. */
246 t->type = UNKNOWN;
247 return (0);
248 }
249
250 /*
251 * Device is found, configure it.
252 */
253 static int
254 wtattach (struct isa_device *id)
255 {
256 wtinfo_t *t = wttab + id->id_unit;
257
258 if (t->type == ARCHIVE) {
259 printf ("wt%d: type <Archive>\n", t->unit);
260 outb (t->RDMAPORT, 0); /* reset dma */
261 } else
262 printf ("wt%d: type <Wangtek>\n", t->unit);
263 t->flags = TPSTART; /* tape is rewound */
264 t->dens = -1; /* unknown density */
265 isa_dmainit(t->chan, 1024);
266
267 #ifdef DEVFS
268 t->devfs_token_r =
269 devfs_add_devswf(&wt_cdevsw, id->id_unit, DV_CHR, 0, 0,
270 0600, "rwt%d", id->id_unit);
271 t->devfs_token =
272 devfs_add_devswf(&wt_bdevsw, id->id_unit, DV_BLK, 0, 0,
273 0600, "wt%d", id->id_unit);
274 #endif
275 return (1);
276 }
277
278 struct isa_driver wtdriver = { wtprobe, wtattach, "wt", };
279
280 int
281 wtdump (dev_t dev)
282 {
283 /* Not implemented */
284 return (EINVAL);
285 }
286
287 int
288 wtsize (dev_t dev)
289 {
290 /* Not implemented */
291 return (-1);
292 }
293
294 /*
295 * Open routine, called on every device open.
296 */
297 int
298 wtopen (dev_t dev, int flag, int fmt, struct proc *p)
299 {
300 int u = minor (dev) & T_UNIT;
301 wtinfo_t *t = wttab + u;
302 int error;
303
304 if (u >= NWT || t->type == UNKNOWN)
305 return (ENXIO);
306
307 /* Check that device is not in use */
308 if (t->flags & TPINUSE)
309 return (EBUSY);
310
311 /* If the tape is in rewound state, check the status and set density. */
312 if (t->flags & TPSTART) {
313 /* If rewind is going on, wait */
314 if (error = wtwait (t, PCATCH, "wtrew"))
315 return (error);
316
317 /* Check the controller status */
318 if (! wtsense (t, 0, (flag & FWRITE) ? 0 : TP_WRP)) {
319 /* Bad status, reset the controller */
320 if (! wtreset (t))
321 return (EIO);
322 if (! wtsense (t, 1, (flag & FWRITE) ? 0 : TP_WRP))
323 return (EIO);
324 }
325
326 /* Set up tape density. */
327 if (t->dens != (minor (dev) & WT_DENSEL)) {
328 int d = 0;
329
330 switch (minor (dev) & WT_DENSEL) {
331 case WT_DENSDFLT: default: break; /* default density */
332 case WT_QIC11: d = QIC_FMT11; break; /* minor 010 */
333 case WT_QIC24: d = QIC_FMT24; break; /* minor 020 */
334 case WT_QIC120: d = QIC_FMT120; break; /* minor 030 */
335 case WT_QIC150: d = QIC_FMT150; break; /* minor 040 */
336 case WT_QIC300: d = QIC_FMT300; break; /* minor 050 */
337 case WT_QIC600: d = QIC_FMT600; break; /* minor 060 */
338 }
339 if (d) {
340 /* Change tape density. */
341 if (! wtcmd (t, d))
342 return (EIO);
343 if (! wtsense (t, 1, TP_WRP | TP_ILL))
344 return (EIO);
345
346 /* Check the status of the controller. */
347 if (t->error.err & TP_ILL) {
348 printf ("wt%d: invalid tape density\n", t->unit);
349 return (ENODEV);
350 }
351 }
352 t->dens = minor (dev) & WT_DENSEL;
353 }
354 t->flags &= ~TPSTART;
355 } else if (t->dens != (minor (dev) & WT_DENSEL))
356 return (ENXIO);
357
358 t->bsize = (minor (dev) & WT_BSIZE) ? 1024 : 512;
359 t->buf = malloc (t->bsize, M_TEMP, M_WAITOK);
360 if (! t->buf)
361 return (EAGAIN);
362
363 if (isa_dma_acquire(t->chan))
364 return(EBUSY);
365
366 t->flags = TPINUSE;
367
368 if (flag & FREAD)
369 t->flags |= TPREAD;
370 if (flag & FWRITE)
371 t->flags |= TPWRITE;
372 return (0);
373 }
374
375 /*
376 * Close routine, called on last device close.
377 */
378 int
379 wtclose (dev_t dev, int flags, int fmt, struct proc *p)
380 {
381 int u = minor (dev) & T_UNIT;
382 wtinfo_t *t = wttab + u;
383
384 if (u >= NWT || t->type == UNKNOWN)
385 return (ENXIO);
386
387 /* If rewind is pending, do nothing */
388 if (t->flags & TPREW)
389 goto done;
390
391 /* If seek forward is pending and no rewind on close, do nothing */
392 if (t->flags & TPRMARK) {
393 if (minor (dev) & T_NOREWIND)
394 goto done;
395
396 /* If read file mark is going on, wait */
397 wtwait (t, 0, "wtrfm");
398 }
399
400 if (t->flags & TPWANY)
401 /* Tape was written. Write file mark. */
402 wtwritefm (t);
403
404 if (! (minor (dev) & T_NOREWIND)) {
405 /* Rewind tape to beginning of tape. */
406 /* Don't wait until rewind, though. */
407 wtrewind (t);
408 goto done;
409 }
410 if ((t->flags & TPRANY) && ! (t->flags & (TPVOL | TPWANY)))
411 /* Space forward to after next file mark if no writing done. */
412 /* Don't wait for completion. */
413 wtreadfm (t);
414 done:
415 t->flags &= TPREW | TPRMARK | TPSTART | TPTIMER;
416 free (t->buf, M_TEMP);
417 isa_dma_release(t->chan);
418 return (0);
419 }
420
421 /*
422 * Ioctl routine. Compatible with BSD ioctls.
423 * There are two possible ioctls:
424 * ioctl (int fd, MTIOCGET, struct mtget *buf) -- get status
425 * ioctl (int fd, MTIOCTOP, struct mtop *buf) -- do BSD-like op
426 */
427 int
428 wtioctl (dev_t dev, int cmd, caddr_t arg, int flags, struct proc *p)
429 {
430 int u = minor (dev) & T_UNIT;
431 wtinfo_t *t = wttab + u;
432 int error, count, op;
433
434 if (u >= NWT || t->type == UNKNOWN)
435 return (ENXIO);
436
437 switch (cmd) {
438 default:
439 return (EINVAL);
440 case MTIOCIEOT: /* ignore EOT errors */
441 case MTIOCEEOT: /* enable EOT errors */
442 return (0);
443 case MTIOCGET:
444 ((struct mtget*)arg)->mt_type =
445 t->type == ARCHIVE ? MT_ISVIPER1 : 0x11;
446 ((struct mtget*)arg)->mt_dsreg = t->flags; /* status */
447 ((struct mtget*)arg)->mt_erreg = t->error.err; /* errors */
448 ((struct mtget*)arg)->mt_resid = 0;
449 ((struct mtget*)arg)->mt_fileno = 0; /* file */
450 ((struct mtget*)arg)->mt_blkno = 0; /* block */
451 return (0);
452 case MTIOCTOP:
453 break;
454 }
455 switch ((short) ((struct mtop*)arg)->mt_op) {
456 default:
457 case MTFSR: /* forward space record */
458 case MTBSR: /* backward space record */
459 case MTBSF: /* backward space file */
460 break;
461 case MTNOP: /* no operation, sets status only */
462 case MTCACHE: /* enable controller cache */
463 case MTNOCACHE: /* disable controller cache */
464 return (0);
465 case MTREW: /* rewind */
466 case MTOFFL: /* rewind and put the drive offline */
467 if (t->flags & TPREW) /* rewind is running */
468 return (0);
469 if (error = wtwait (t, PCATCH, "wtorew"))
470 return (error);
471 wtrewind (t);
472 return (0);
473 case MTFSF: /* forward space file */
474 for (count=((struct mtop*)arg)->mt_count; count>0; --count) {
475 if (error = wtwait (t, PCATCH, "wtorfm"))
476 return (error);
477 if (error = wtreadfm (t))
478 return (error);
479 }
480 return (0);
481 case MTWEOF: /* write an end-of-file record */
482 if (! (t->flags & TPWRITE) || (t->flags & TPWP))
483 return (EACCES);
484 if (error = wtwait (t, PCATCH, "wtowfm"))
485 return (error);
486 if (error = wtwritefm (t))
487 return (error);
488 return (0);
489 case MTRETENS: /* re-tension tape */
490 if (error = wtwait (t, PCATCH, "wtretens"))
491 return (error);
492 op = QIC_RETENS;
493 goto erase_retens;
494
495 case MTERASE: /* erase to EOM */
496 if (! (t->flags & TPWRITE) || (t->flags & TPWP))
497 return (EACCES);
498 if (error = wtwait (t, PCATCH, "wterase"))
499 return (error);
500 op = QIC_ERASE;
501 erase_retens:
502 /* ERASE and RETENS operations work like REWIND. */
503 /* Simulate the rewind operation here. */
504 t->flags &= ~(TPRO | TPWO | TPVOL);
505 if (! wtcmd (t, op))
506 return (EIO);
507 t->flags |= TPSTART | TPREW;
508 t->flags |= TPWANY;
509 wtclock (t);
510 return (0);
511 }
512 return (EINVAL);
513 }
514
515 /*
516 * Strategy routine.
517 */
518 void
519 wtstrategy (struct buf *bp)
520 {
521 int u = minor (bp->b_dev) & T_UNIT;
522 wtinfo_t *t = wttab + u;
523 int s;
524
525 bp->b_resid = bp->b_bcount;
526 if (u >= NWT || t->type == UNKNOWN) {
527 bp->b_error = ENXIO;
528 goto err2xit;
529 }
530
531 /* at file marks and end of tape, we just return '0 bytes available' */
532 if (t->flags & TPVOL)
533 goto xit;
534
535 if (bp->b_bcount % t->bsize != 0) {
536 bp->b_error = EINVAL;
537 goto err2xit;
538 }
539
540 if (bp->b_flags & B_READ) {
541 /* Check read access and no previous write to this tape. */
542 if (! (t->flags & TPREAD) || (t->flags & TPWANY))
543 goto errxit;
544
545 /* For now, we assume that all data will be copied out */
546 /* If read command outstanding, just skip down */
547 if (! (t->flags & TPRO)) {
548 if (! wtsense (t, 1, TP_WRP)) /* clear status */
549 goto errxit;
550 if (! wtcmd (t, QIC_RDDATA)) { /* sed read mode */
551 wtsense (t, 1, TP_WRP);
552 goto errxit;
553 }
554 t->flags |= TPRO | TPRANY;
555 }
556 } else {
557 /* Check write access and write protection. */
558 /* No previous read from this tape allowed. */
559 if (! (t->flags & TPWRITE) || (t->flags & (TPWP | TPRANY)))
560 goto errxit;
561
562 /* If write command outstanding, just skip down */
563 if (! (t->flags & TPWO)) {
564 if (! wtsense (t, 1, 0)) /* clear status */
565 goto errxit;
566 if (! wtcmd (t, QIC_WRTDATA)) { /* set write mode */
567 wtsense (t, 1, 0);
568 goto errxit;
569 }
570 t->flags |= TPWO | TPWANY;
571 }
572 }
573
574 if (! bp->b_bcount)
575 goto xit;
576
577 t->flags &= ~TPEXCEP;
578 s = splbio ();
579 if (wtstart (t, bp->b_flags, bp->b_un.b_addr, bp->b_bcount)) {
580 wtwait (t, 0, (bp->b_flags & B_READ) ? "wtread" : "wtwrite");
581 bp->b_resid -= t->dmacount;
582 }
583 splx (s);
584
585 if (t->flags & TPEXCEP) {
586 errxit: bp->b_error = EIO;
587 err2xit: bp->b_flags |= B_ERROR;
588 }
589 xit: biodone (bp);
590 return;
591 }
592
593 /*
594 * Interrupt routine.
595 */
596 void
597 wtintr (int u)
598 {
599 wtinfo_t *t = wttab + u;
600 unsigned char s;
601
602 if (u >= NWT || t->type == UNKNOWN) {
603 TRACE (("wtintr() -- device not configured\n"));
604 return;
605 }
606
607 s = inb (t->STATPORT); /* get status */
608 TRACE (("wtintr() status=0x%x -- ", s));
609 if ((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP)) {
610 TRACE (("busy\n"));
611 return; /* device is busy */
612 }
613
614 /*
615 * Check if rewind finished.
616 */
617 if (t->flags & TPREW) {
618 TRACE (((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP) ?
619 "rewind busy?\n" : "rewind finished\n"));
620 t->flags &= ~TPREW; /* Rewind finished. */
621 wtsense (t, 1, TP_WRP);
622 wakeup ((caddr_t)t);
623 return;
624 }
625
626 /*
627 * Check if writing/reading of file mark finished.
628 */
629 if (t->flags & (TPRMARK | TPWMARK)) {
630 TRACE (((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP) ?
631 "marker r/w busy?\n" : "marker r/w finished\n"));
632 if (! (s & t->NOEXCEP)) /* operation failed */
633 wtsense (t, 1, (t->flags & TPRMARK) ? TP_WRP : 0);
634 t->flags &= ~(TPRMARK | TPWMARK); /* operation finished */
635 wakeup ((caddr_t)t);
636 return;
637 }
638
639 /*
640 * Do we started any i/o? If no, just return.
641 */
642 if (! (t->flags & TPACTIVE)) {
643 TRACE (("unexpected interrupt\n"));
644 return;
645 }
646
647 /*
648 * Clean up dma.
649 */
650 if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < t->bsize) {
651 /* If reading short block, copy the internal buffer
652 * to the user memory. */
653 isa_dmadone (t->dmaflags, t->buf, t->bsize, t->chan);
654 bcopy (t->buf, t->dmavaddr, t->dmatotal - t->dmacount);
655 } else
656 isa_dmadone (t->dmaflags, t->dmavaddr, t->bsize, t->chan);
657
658 t->flags &= ~TPACTIVE;
659 t->dmacount += t->bsize;
660 t->dmavaddr = (char *)t->dmavaddr + t->bsize;
661
662 /*
663 * On exception, check for end of file and end of volume.
664 */
665 if (! (s & t->NOEXCEP)) {
666 TRACE (("i/o exception\n"));
667 wtsense (t, 1, (t->dmaflags & B_READ) ? TP_WRP : 0);
668 if (t->error.err & (TP_EOM | TP_FIL))
669 t->flags |= TPVOL; /* end of file */
670 else
671 t->flags |= TPEXCEP; /* i/o error */
672 wakeup ((caddr_t)t);
673 return;
674 }
675
676 if (t->dmacount < t->dmatotal) { /* continue i/o */
677 wtdma (t);
678 TRACE (("continue i/o, %d\n", t->dmacount));
679 return;
680 }
681 if (t->dmacount > t->dmatotal) /* short last block */
682 t->dmacount = t->dmatotal;
683 wakeup ((caddr_t)t); /* wake up user level */
684 TRACE (("i/o finished, %d\n", t->dmacount));
685 }
686
687 /* start the rewind operation */
688 static void
689 wtrewind (wtinfo_t *t)
690 {
691 int rwmode = (t->flags & (TPRO | TPWO));
692
693 t->flags &= ~(TPRO | TPWO | TPVOL);
694 /*
695 * Wangtek strictly follows QIC-02 standard:
696 * clearing ONLINE in read/write modes causes rewind.
697 * REWIND command is not allowed in read/write mode
698 * and gives `illegal command' error.
699 */
700 if (t->type==WANGTEK && rwmode) {
701 outb (t->CTLPORT, 0);
702 } else if (! wtcmd (t, QIC_REWIND))
703 return;
704 t->flags |= TPSTART | TPREW;
705 wtclock (t);
706 }
707
708 /* start the `read marker' operation */
709 static int
710 wtreadfm (wtinfo_t *t)
711 {
712 t->flags &= ~(TPRO | TPWO | TPVOL);
713 if (! wtcmd (t, QIC_READFM)) {
714 wtsense (t, 1, TP_WRP);
715 return (EIO);
716 }
717 t->flags |= TPRMARK | TPRANY;
718 wtclock (t);
719 /* Don't wait for completion here. */
720 return (0);
721 }
722
723 /* write marker to the tape */
724 static int
725 wtwritefm (wtinfo_t *t)
726 {
727 tsleep ((caddr_t)wtwritefm, WTPRI, "wtwfm", hz); /* timeout: 1 second */
728 t->flags &= ~(TPRO | TPWO);
729 if (! wtcmd (t, QIC_WRITEFM)) {
730 wtsense (t, 1, 0);
731 return (EIO);
732 }
733 t->flags |= TPWMARK | TPWANY;
734 wtclock (t);
735 return (wtwait (t, 0, "wtwfm"));
736 }
737
738 /* while controller status & mask == bits continue waiting */
739 static int
740 wtpoll (wtinfo_t *t, int mask, int bits)
741 {
742 int s, i;
743
744 /* Poll status port, waiting for specified bits. */
745 for (i=0; i<1000; ++i) { /* up to 1 msec */
746 s = inb (t->STATPORT);
747 if ((s & mask) != bits)
748 return (s);
749 DELAY (1);
750 }
751 for (i=0; i<100; ++i) { /* up to 10 msec */
752 s = inb (t->STATPORT);
753 if ((s & mask) != bits)
754 return (s);
755 DELAY (100);
756 }
757 for (;;) { /* forever */
758 s = inb (t->STATPORT);
759 if ((s & mask) != bits)
760 return (s);
761 tsleep ((caddr_t)wtpoll, WTPRI, "wtpoll", 1); /* timeout: 1 tick */
762 }
763 }
764
765 /* execute QIC command */
766 static int
767 wtcmd (wtinfo_t *t, int cmd)
768 {
769 int s, x;
770
771 TRACE (("wtcmd() cmd=0x%x\n", cmd));
772 x = splbio();
773 s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
774 if (! (s & t->NOEXCEP)) { /* error */
775 splx(x);
776 return (0);
777 }
778
779 outb (t->CMDPORT, cmd); /* output the command */
780
781 outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
782 wtpoll (t, t->BUSY, t->BUSY); /* wait for ready */
783 outb (t->CTLPORT, t->IEN | t->ONLINE); /* reset request */
784 wtpoll (t, t->BUSY, 0); /* wait for not ready */
785 splx(x);
786 return (1);
787 }
788
789 /* wait for the end of i/o, seeking marker or rewind operation */
790 static int
791 wtwait (wtinfo_t *t, int catch, char *msg)
792 {
793 int error;
794
795 TRACE (("wtwait() `%s'\n", msg));
796 while (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))
797 if (error = tsleep ((caddr_t)t, WTPRI | catch, msg, 0))
798 return (error);
799 return (0);
800 }
801
802 /* initialize dma for the i/o operation */
803 static void
804 wtdma (wtinfo_t *t)
805 {
806 t->flags |= TPACTIVE;
807 wtclock (t);
808
809 if (t->type == ARCHIVE)
810 outb (t->SDMAPORT, 0); /* set dma */
811
812 if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < t->bsize)
813 /* Reading short block. Do it through the internal buffer. */
814 isa_dmastart (t->dmaflags, t->buf, t->bsize, t->chan);
815 else
816 isa_dmastart (t->dmaflags, t->dmavaddr, t->bsize, t->chan);
817 }
818
819 /* start i/o operation */
820 static int
821 wtstart (wtinfo_t *t, unsigned flags, void *vaddr, unsigned len)
822 {
823 int s, x;
824
825 TRACE (("wtstart()\n"));
826 x = splbio();
827 s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
828 if (! (s & t->NOEXCEP)) {
829 t->flags |= TPEXCEP; /* error */
830 splx(x);
831 return (0);
832 }
833 t->flags &= ~TPEXCEP; /* clear exception flag */
834 t->dmavaddr = vaddr;
835 t->dmatotal = len;
836 t->dmacount = 0;
837 t->dmaflags = flags;
838 wtdma (t);
839 splx(x);
840 return (1);
841 }
842
843 /* start timer */
844 static void
845 wtclock (wtinfo_t *t)
846 {
847 if (! (t->flags & TPTIMER)) {
848 t->flags |= TPTIMER;
849 /* Some controllers seem to lose dma interrupts too often.
850 * To make the tape stream we need 1 tick timeout. */
851 timeout (wtimer, (caddr_t)t, (t->flags & TPACTIVE) ? 1 : hz);
852 }
853 }
854
855 /*
856 * Simulate an interrupt periodically while i/o is going.
857 * This is necessary in case interrupts get eaten due to
858 * multiple devices on a single IRQ line.
859 */
860 static void
861 wtimer (void *xt)
862 {
863 wtinfo_t *t = (wtinfo_t *)xt;
864 int s;
865
866 t->flags &= ~TPTIMER;
867 if (! (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK)))
868 return;
869
870 /* If i/o going, simulate interrupt. */
871 s = splbio ();
872 if ((inb (t->STATPORT) & (t->BUSY | t->NOEXCEP)) != (t->BUSY | t->NOEXCEP)) {
873 TRACE (("wtimer() -- "));
874 wtintr (t->unit);
875 }
876 splx (s);
877
878 /* Restart timer if i/o pending. */
879 if (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))
880 wtclock (t);
881 }
882
883 /* reset the controller */
884 static int
885 wtreset (wtinfo_t *t)
886 {
887 /* Perform QIC-02 and QIC-36 compatible reset sequence. */
888 /* Thanks to Mikael Hybsch <micke@dynas.se>. */
889 int s, i;
890
891 outb (t->CTLPORT, t->RESET | t->ONLINE); /* send reset */
892 DELAY (30);
893 outb (t->CTLPORT, t->ONLINE); /* turn off reset */
894 DELAY (30);
895
896 /* Read the controller status. */
897 s = inb (t->STATPORT);
898 if (s == 0xff) /* no port at this address? */
899 return (0);
900
901 /* Wait 3 sec for reset to complete. Needed for QIC-36 boards? */
902 for (i=0; i<3000; ++i) {
903 if (! (s & t->BUSY) || ! (s & t->NOEXCEP))
904 break;
905 DELAY (1000);
906 s = inb (t->STATPORT);
907 }
908 return ((s & t->RESETMASK) == t->RESETVAL);
909 }
910
911 /* get controller status information */
912 /* return 0 if user i/o request should receive an i/o error code */
913 static int
914 wtsense (wtinfo_t *t, int verb, int ignor)
915 {
916 char *msg = 0;
917 int err;
918
919 TRACE (("wtsense() ignor=0x%x\n", ignor));
920 t->flags &= ~(TPRO | TPWO);
921 if (! wtstatus (t))
922 return (0);
923 if (! (t->error.err & TP_ST0))
924 t->error.err &= ~TP_ST0MASK;
925 if (! (t->error.err & TP_ST1))
926 t->error.err &= ~TP_ST1MASK;
927 t->error.err &= ~ignor; /* ignore certain errors */
928 err = t->error.err & (TP_FIL | TP_BNL | TP_UDA | TP_EOM | TP_WRP |
929 TP_USL | TP_CNI | TP_MBD | TP_NDT | TP_ILL);
930 if (! err)
931 return (1);
932 if (! verb)
933 return (0);
934
935 /* lifted from tdriver.c from Wangtek */
936 if (err & TP_USL) msg = "Drive not online";
937 else if (err & TP_CNI) msg = "No cartridge";
938 else if ((err & TP_WRP) && !(t->flags & TPWP)) {
939 msg = "Tape is write protected";
940 t->flags |= TPWP;
941 }
942 else if (err & TP_FIL) msg = 0 /*"Filemark detected"*/;
943 else if (err & TP_EOM) msg = 0 /*"End of tape"*/;
944 else if (err & TP_BNL) msg = "Block not located";
945 else if (err & TP_UDA) msg = "Unrecoverable data error";
946 else if (err & TP_NDT) msg = "No data detected";
947 else if (err & TP_ILL) msg = "Illegal command";
948 if (msg)
949 printf ("wt%d: %s\n", t->unit, msg);
950 return (0);
951 }
952
953 /* get controller status information */
954 static int
955 wtstatus (wtinfo_t *t)
956 {
957 char *p;
958 int x;
959
960 x = splbio();
961 wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP); /* ready? */
962 outb (t->CMDPORT, QIC_RDSTAT); /* send `read status' command */
963
964 outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
965 wtpoll (t, t->BUSY, t->BUSY); /* wait for ready */
966 outb (t->CTLPORT, t->ONLINE); /* reset request */
967 wtpoll (t, t->BUSY, 0); /* wait for not ready */
968
969 p = (char*) &t->error;
970 while (p < (char*)&t->error + 6) {
971 int s = wtpoll (t, t->BUSY | t->NOEXCEP, t->BUSY | t->NOEXCEP);
972 if (! (s & t->NOEXCEP)) { /* error */
973 splx(x);
974 return (0);
975 }
976
977 *p++ = inb (t->DATAPORT); /* read status byte */
978
979 outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
980 wtpoll (t, t->BUSY, 0); /* wait for not ready */
981 DELAY(20);
982 outb (t->CTLPORT, t->ONLINE); /* unset request */
983 }
984 splx(x);
985 return (1);
986 }
987
988
989 static wt_devsw_installed = 0;
990
991 static void
992 wt_drvinit(void *unused)
993 {
994
995 if( ! wt_devsw_installed ) {
996 bdevsw_add_generic(BDEV_MAJOR,CDEV_MAJOR, &wt_bdevsw);
997 wt_devsw_installed = 1;
998 }
999 }
1000
1001 SYSINIT(wtdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,wt_drvinit,NULL)
1002
1003
1004 #endif /* NWT */
Cache object: 26577171b878f4afae0a0897274730cc
|