Removed all patch kit headers, sccsid and rcsid strings, put $Id$ in, some
[unix-history] / sys / i386 / isa / wt.c
CommitLineData
df9b2252
RG
1/*
2 * Streamer tape driver for 386bsd and FreeBSD.
3 * Supports Archive QIC-02 and Wangtek QIC-02/QIC-36 boards.
4 *
5 * Copyright (C) 1993 by:
6 * Sergey Ryzhkov <sir@kiae.su>
7 * Serge Vakulenko <vak@zebub.msk.su>
8 *
df9b2252
RG
9 * Placed in the public domain with NO WARRANTIES, not even the implied
10 * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15637ed4 11 *
df9b2252
RG
12 * Authors grant any other persons or organisations permission to use
13 * or modify this software as long as this message is kept with the software,
14 * all derivative works or modified versions.
15637ed4 15 *
df9b2252
RG
16 * This driver is derived from the old 386bsd Wangtek streamer tape driver,
17 * made by Robert Baron at CMU, based on Intel sources.
18 * Authors thank Robert Baron, CMU and Intel and retain here
19 * the original CMU copyright notice.
d7136515
RG
20 *
21 * from: Version 1.1, Fri Sep 24 02:14:31 MSD 1993
22 * $Id$
15637ed4
RG
23 */
24
25/*
15637ed4
RG
26 * Copyright (c) 1989 Carnegie-Mellon University.
27 * All rights reserved.
28 *
29 * Authors: Robert Baron
30 *
31 * Permission to use, copy, modify and distribute this software and
32 * its documentation is hereby granted, provided that both the copyright
33 * notice and this permission notice appear in all copies of the
34 * software, derivative works or modified versions, and any portions
35 * thereof, and that both notices appear in supporting documentation.
36 *
37 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
38 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
39 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 *
41 * Carnegie Mellon requests users of this software to return to
42 *
43 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
44 * School of Computer Science
45 * Carnegie Mellon University
46 * Pittsburgh PA 15213-3890
47 *
48 * any improvements or extensions that they make and grant Carnegie the
49 * rights to redistribute these changes.
50 */
51
52#include "wt.h"
53#if NWT > 0
15637ed4 54
15637ed4
RG
55#include "sys/param.h"
56#include "sys/buf.h"
df9b2252
RG
57#include "sys/fcntl.h"
58#include "sys/malloc.h"
59#include "sys/ioctl.h"
60#include "sys/mtio.h"
61#include "vm/vm_param.h"
62#include "i386/include/pio.h"
63#include "i386/isa/isa_device.h"
15637ed4
RG
64#include "i386/isa/wtreg.h"
65
df9b2252
RG
66#define WTPRI (PZERO+10) /* sleep priority */
67#define BLKSIZE 512 /* streamer tape block size */
15637ed4
RG
68
69/*
df9b2252 70 * Wangtek controller ports
15637ed4 71 */
df9b2252
RG
72#define WT_CTLPORT(base) ((base)+0) /* control, write only */
73#define WT_STATPORT(base) ((base)+0) /* status, read only */
74#define WT_CMDPORT(base) ((base)+1) /* command, write only */
75#define WT_DATAPORT(base) ((base)+1) /* data, read only */
76#define WT_NPORT 2 /* 2 i/o ports */
77
78/* status port bits */
79#define WT_BUSY 0x01 /* not ready bit define */
80#define WT_NOEXCEP 0x02 /* no exception bit define */
81#define WT_RESETMASK 0x07 /* to check after reset */
82#define WT_RESETVAL 0x05 /* state after reset */
83
84/* control port bits */
85#define WT_ONLINE 0x01 /* device selected */
86#define WT_RESET 0x02 /* reset command */
87#define WT_REQUEST 0x04 /* request command */
88#define WT_IEN(chan) ((chan)>2 ? 0x10 : 0x8) /* enable intr */
15637ed4 89
df9b2252
RG
90/*
91 * Archive controller ports
92 */
93#define AV_DATAPORT(base) ((base)+0) /* data, read only */
94#define AV_CMDPORT(base) ((base)+0) /* command, write only */
95#define AV_STATPORT(base) ((base)+1) /* status, read only */
96#define AV_CTLPORT(base) ((base)+1) /* control, write only */
97#define AV_SDMAPORT(base) ((base)+2) /* start dma */
98#define AV_RDMAPORT(base) ((base)+3) /* reset dma */
99#define AV_NPORT 4 /* 4 i/o ports */
100
101/* status port bits */
102#define AV_BUSY 0x40 /* not ready bit define */
103#define AV_NOEXCEP 0x20 /* no exception bit define */
104#define AV_RESETMASK 0xf8 /* to check after reset */
105#define AV_RESETVAL 0x50 /* state after reset */
106
107/* control port bits */
108#define AV_RESET 0x80 /* reset command */
109#define AV_REQUEST 0x40 /* request command */
110#define AV_IEN 0x20 /* enable interrupts */
111
112#define DMA_STATUSREG 0x8
113#define DMA_DONE(chan) (1 << (chan))
114
115typedef struct {
116 unsigned short err; /* code for error encountered */
117 unsigned short ercnt; /* number of error blocks */
118 unsigned short urcnt; /* number of underruns */
119} wtstatus_t;
120
121typedef struct {
122 unsigned unit; /* unit number */
123 unsigned port; /* base i/o port */
124 unsigned chan; /* dma channel number, 1..3 */
125 unsigned flags; /* state of tape drive */
126 unsigned dens; /* tape density */
127 void *buf; /* internal i/o buffer */
128
129 void *dmavaddr; /* virtual address of dma i/o buffer */
130 unsigned dmatotal; /* size of i/o buffer */
131 unsigned dmaflags; /* i/o direction, B_READ or B_WRITE */
132 unsigned dmacount; /* resulting length of dma i/o */
133
134 wtstatus_t error; /* status of controller */
135
136 unsigned short DATAPORT, CMDPORT, STATPORT, CTLPORT, SDMAPORT, RDMAPORT;
137 unsigned char BUSY, NOEXCEP, RESETMASK, RESETVAL;
138 unsigned char ONLINE, RESET, REQUEST, IEN;
139} wtinfo_t;
140
141wtinfo_t wttab[NWT]; /* tape info by unit number */
142
143extern int hz; /* number of ticks per second */
144
145static int wtwait (wtinfo_t *t, int catch, char *msg);
146static int wtcmd (wtinfo_t *t, int cmd);
147static int wtstart (wtinfo_t *t, unsigned mode, void *vaddr, unsigned len);
148static void wtdma (wtinfo_t *t);
149static void wtimer (wtinfo_t *t);
150static void wtclock (wtinfo_t *t);
151static int wtreset (wtinfo_t *t);
152static int wtsense (wtinfo_t *t, int ignor);
153static int wtstatus (wtinfo_t *t);
154static void wtrewind (wtinfo_t *t);
155static int wtreadfm (wtinfo_t *t);
156static int wtwritefm (wtinfo_t *t);
157static int wtpoll (wtinfo_t *t);
158
159extern void DELAY (int usec);
160extern void bcopy (void *from, void *to, unsigned len);
161extern void isa_dmastart (int flags, void *addr, unsigned len, unsigned chan);
162extern void isa_dmadone (int flags, void *addr, unsigned len, int chan);
163extern void printf (char *str, ...);
164extern int splbio (void);
165extern int splx (int level);
166extern void timeout (void (*func) (), void *arg, int timo);
167extern int tsleep (void *chan, int priority, char *msg, int timo);
168extern void wakeup (void *chan);
15637ed4 169
df9b2252
RG
170/*
171 * Probe for the presence of the device.
172 */
173int wtprobe (struct isa_device *id)
174{
175 wtinfo_t *t = wttab + id->id_unit;
176
177 t->unit = id->id_unit;
178 t->chan = id->id_drq;
179 t->port = 0; /* Mark it as not configured. */
180 if (t->chan<1 || t->chan>3) {
181 printf ("wt%d: Bad drq=%d, should be 1..3\n", t->unit, t->chan);
182 return (0);
183 }
184 t->port = id->id_iobase;
185
186 /* Try Wangtek. */
187 t->CTLPORT = WT_CTLPORT (t->port); t->STATPORT = WT_STATPORT (t->port);
188 t->CMDPORT = WT_CMDPORT (t->port); t->DATAPORT = WT_DATAPORT (t->port);
189 t->SDMAPORT = 0; t->RDMAPORT = 0;
190 t->BUSY = WT_BUSY; t->NOEXCEP = WT_NOEXCEP;
191 t->RESETMASK = WT_RESETMASK; t->RESETVAL = WT_RESETVAL;
192 t->ONLINE = WT_ONLINE; t->RESET = WT_RESET;
193 t->REQUEST = WT_REQUEST; t->IEN = WT_IEN (t->chan);
194 if (wtreset (t))
195 return (WT_NPORT);
196
197 /* Try Archive. */
198 t->CTLPORT = AV_CTLPORT (t->port); t->STATPORT = AV_STATPORT (t->port);
199 t->CMDPORT = AV_CMDPORT (t->port); t->DATAPORT = AV_DATAPORT (t->port);
200 t->SDMAPORT = AV_SDMAPORT (t->port); t->RDMAPORT = AV_RDMAPORT (t->port);
201 t->BUSY = AV_BUSY; t->NOEXCEP = AV_NOEXCEP;
202 t->RESETMASK = AV_RESETMASK; t->RESETVAL = AV_RESETVAL;
203 t->ONLINE = 0; t->RESET = AV_RESET;
204 t->REQUEST = AV_REQUEST; t->IEN = AV_IEN;
205 if (wtreset (t))
206 return (AV_NPORT);
207
208 /* Tape controller not found. */
209 t->port = 0;
210 return (0);
15637ed4
RG
211}
212
213/*
df9b2252 214 * Device is found, configure it.
15637ed4 215 */
df9b2252 216int wtattach (struct isa_device *id)
15637ed4 217{
df9b2252 218 wtinfo_t *t = wttab + id->id_unit;
15637ed4 219
df9b2252
RG
220 if (t->RDMAPORT) {
221 printf ("wt%d: type <Archive>\n", t->unit);
222 outb (t->RDMAPORT, 0); /* reset dma */
223 } else
224 printf ("wt%d: type <Wangtek>\n", t->unit);
225 t->flags = TPSTART; /* tape is rewound */
226 t->dens = -1; /* unknown density */
227 t->buf = malloc (BLKSIZE, M_TEMP, M_NOWAIT);
228 return (1);
15637ed4
RG
229}
230
df9b2252 231struct isa_driver wtdriver = { wtprobe, wtattach, "wt", };
15637ed4 232
df9b2252 233int wtdump (int dev)
15637ed4 234{
df9b2252
RG
235 /* Not implemented */
236 return (EINVAL);
15637ed4
RG
237}
238
df9b2252 239int wtsize (int dev)
15637ed4 240{
df9b2252
RG
241 /* Not implemented */
242 return (-1);
15637ed4
RG
243}
244
245/*
df9b2252 246 * Open routine, called on every device open.
15637ed4 247 */
df9b2252
RG
248int wtopen (int dev, int flag)
249{
250 int u = minor (dev) & T_UNIT;
251 wtinfo_t *t = wttab + u;
252 int error;
253
254 if (u >= NWT || !t->port)
255 return (ENXIO);
256
257 /* Check that device is not in use */
258 if (t->flags & TPINUSE)
259 return (EBUSY);
260
261 /* If the tape is in rewound state, check the status and set density. */
262 if (t->flags & TPSTART) {
263 /* If rewind is going on, wait */
264 error = wtwait (t, PCATCH, "wtrew");
265 if (error)
266 return (error);
267
268 if (! wtsense (t, (flag & FWRITE) ? 0 : TP_WRP)) {
269 /* Bad status. Reset the controller. */
270 if (! wtreset (t))
271 return (ENXIO);
272 if (! wtsense (t, (flag & FWRITE) ? 0 : TP_WRP))
273 return (ENXIO);
15637ed4 274 }
df9b2252
RG
275
276 /* Set up tape density. */
277 if (t->dens != (minor (dev) & T_DENSEL)) {
278 int d;
279
280 switch (minor (dev) & T_DENSEL) {
281 default:
282 case T_800BPI: d = QIC_FMT150; break; /* minor 000 */
283 case T_1600BPI: d = QIC_FMT120; break; /* minor 010 */
284 case T_6250BPI: d = QIC_FMT24; break; /* minor 020 */
285 case T_BADBPI: d = QIC_FMT11; break; /* minor 030 */
286 }
287 if (! wtcmd (t, d))
288 return (ENXIO);
289
290 /* Check the status of the controller. */
291 if (! wtsense (t, (flag & FWRITE) ? 0 : TP_WRP))
292 return (ENXIO);
293
294 t->dens = minor (dev) & T_DENSEL;
15637ed4 295 }
df9b2252
RG
296 t->flags &= ~TPSTART;
297 } else if (t->dens != (minor (dev) & T_DENSEL))
298 return (ENXIO);
15637ed4 299
df9b2252 300 t->flags = TPINUSE;
15637ed4 301 if (flag & FREAD)
df9b2252 302 t->flags |= TPREAD;
15637ed4 303 if (flag & FWRITE)
df9b2252
RG
304 t->flags |= TPWRITE;
305 return (0);
15637ed4
RG
306}
307
308/*
df9b2252 309 * Close routine, called on last device close.
15637ed4 310 */
df9b2252 311int wtclose (int dev)
15637ed4 312{
df9b2252
RG
313 int u = minor (dev) & T_UNIT;
314 wtinfo_t *t = wttab + u;
15637ed4 315
df9b2252
RG
316 if (u >= NWT || !t->port)
317 return (ENXIO);
15637ed4 318
df9b2252
RG
319 /* If rewind is pending, do nothing */
320 if (t->flags & TPREW)
321 goto done;
15637ed4 322
df9b2252
RG
323 /* If seek forward is pending and no rewind on close, do nothing */
324 if ((t->flags & TPRMARK) && (minor (dev) & T_NOREWIND))
325 goto done;
15637ed4 326
df9b2252
RG
327 /* If file mark read is going on, wait */
328 wtwait (t, 0, "wtrfm");
15637ed4 329
df9b2252
RG
330 if (t->flags & TPWANY)
331 /* Tape was written. Write file mark. */
332 wtwritefm (t);
15637ed4 333
df9b2252
RG
334 if (! (minor (dev) & T_NOREWIND)) {
335 /* Rewind tape to beginning of tape. */
336 /* Don't wait until rewind, though. */
337 wtrewind (t);
338 goto done;
15637ed4 339 }
df9b2252
RG
340 if ((t->flags & TPRANY) && ! (t->flags & (TPVOL | TPWANY)))
341 /* Space forward to after next file mark if no writing done. */
342 /* Don't wait for completion. */
343 wtreadfm (t);
344done:
345 t->flags &= TPREW | TPRMARK | TPSTART | TPTIMER;
346 return (0);
15637ed4
RG
347}
348
df9b2252
RG
349/*
350 * Ioctl routine. Compatible with BSD ioctls.
351 * Direct QIC-02 commands ERASE and RETENSION added.
352 * There are three possible ioctls:
353 * ioctl (int fd, MTIOCGET, struct mtget *buf) -- get status
354 * ioctl (int fd, MTIOCTOP, struct mtop *buf) -- do BSD-like op
355 * ioctl (int fd, WTQICMD, int qicop) -- do QIC op
356 */
357int wtioctl (int dev, int cmd, void *arg, int mode)
358{
359 int u = minor (dev) & T_UNIT;
360 wtinfo_t *t = wttab + u;
361 int error, count, op;
362
363 if (u >= NWT || !t->port)
364 return (ENXIO);
365
366 switch (cmd) {
367 default:
368 return (EINVAL);
369 case WTQICMD: /* direct QIC command */
370 op = (int) *(void**)arg;
371 switch (op) {
372 default:
373 return (EINVAL);
374 case QIC_ERASE: /* erase the whole tape */
375 if (! (t->flags & TPWRITE) || (t->flags & TPWP))
376 return (EACCES);
377 if (error = wtwait (t, PCATCH, "wterase"))
378 return (error);
15637ed4 379 break;
df9b2252
RG
380 case QIC_RETENS: /* retension the tape */
381 if (error = wtwait (t, PCATCH, "wtretens"))
382 return (error);
15637ed4 383 break;
df9b2252
RG
384 }
385 /* Both ERASE and RETENS operations work like REWIND. */
386 /* Simulate the rewind operation here. */
387 t->flags &= ~(TPRO | TPWO | TPVOL);
388 if (! wtcmd (t, op))
389 return (EIO);
390 t->flags |= TPSTART | TPREW;
391 if (op == QIC_ERASE)
392 t->flags |= TPWANY;
393 wtclock (t);
394 return (0);
395 case MTIOCIEOT: /* ignore EOT errors */
396 case MTIOCEEOT: /* enable EOT errors */
397 return (0);
398 case MTIOCGET:
399 ((struct mtget*)arg)->mt_type = t->RDMAPORT ? MT_ISVIPER1 : 0x11;
400 ((struct mtget*)arg)->mt_dsreg = t->flags; /* status */
401 ((struct mtget*)arg)->mt_erreg = t->error.err; /* errors */
402 ((struct mtget*)arg)->mt_resid = 0;
403 ((struct mtget*)arg)->mt_fileno = 0; /* file */
404 ((struct mtget*)arg)->mt_blkno = 0; /* block */
405 return (0);
406 case MTIOCTOP:
407 break;
15637ed4 408 }
df9b2252
RG
409 switch ((short) ((struct mtop*)arg)->mt_op) {
410 default:
411 case MTFSR: /* forward space record */
412 case MTBSR: /* backward space record */
413 case MTBSF: /* backward space file */
414 break;
415 case MTNOP: /* no operation, sets status only */
416 case MTCACHE: /* enable controller cache */
417 case MTNOCACHE: /* disable controller cache */
418 return (0);
419 case MTREW: /* rewind */
420 case MTOFFL: /* rewind and put the drive offline */
421 if (t->flags & TPREW) /* rewind is running */
422 return (0);
423 if (error = wtwait (t, PCATCH, "wtorew"))
424 return (error);
425 wtrewind (t);
426 return (0);
427 case MTFSF: /* forward space file */
428 for (count=((struct mtop*)arg)->mt_count; count>0; --count) {
429 if (error = wtwait (t, PCATCH, "wtorfm"))
430 return (error);
431 if (error = wtreadfm (t))
432 return (error);
15637ed4 433 }
df9b2252
RG
434 return (0);
435 case MTWEOF: /* write an end-of-file record */
436 if (! (t->flags & TPWRITE) || (t->flags & TPWP))
437 return (EACCES);
438 if (error = wtwait (t, PCATCH, "wtowfm"))
439 return (error);
440 if (error = wtwritefm (t))
441 return (error);
442 return (0);
15637ed4 443 }
df9b2252 444 return (EINVAL);
15637ed4
RG
445}
446
df9b2252
RG
447/*
448 * Strategy routine.
449 */
450void wtstrategy (struct buf *bp)
15637ed4 451{
df9b2252
RG
452 int u = minor (bp->b_dev) & T_UNIT;
453 wtinfo_t *t = wttab + u;
454 int s;
15637ed4 455
df9b2252
RG
456 bp->b_resid = bp->b_bcount;
457 if (u >= NWT || !t->port)
458 goto errxit;
15637ed4 459
df9b2252
RG
460 /* at file marks and end of tape, we just return '0 bytes available' */
461 if (t->flags & TPVOL)
462 goto xit;
15637ed4 463
df9b2252
RG
464 if (bp->b_flags & B_READ) {
465 /* Check read access and no previous write to this tape. */
466 if (! (t->flags & TPREAD) || (t->flags & TPWANY))
467 goto errxit;
15637ed4 468
df9b2252
RG
469 /* For now, we assume that all data will be copied out */
470 /* If read command outstanding, just skip down */
471 if (! (t->flags & TPRO)) {
472 if (! wtsense (t, TP_WRP)) /* clear status */
473 goto errxit;
474 if (! wtcmd (t, QIC_RDDATA)) { /* sed read mode */
475 wtsense (t, TP_WRP);
476 goto errxit;
477 }
478 t->flags |= TPRO | TPRANY;
479 }
480 } else {
481 /* Check write access and write protection. */
482 /* No previous read from this tape allowed. */
483 if (! (t->flags & TPWRITE) || (t->flags & (TPWP | TPRANY)))
484 goto errxit;
15637ed4 485
df9b2252
RG
486 /* If write command outstanding, just skip down */
487 if (! (t->flags & TPWO)) {
488 if (! wtsense (t, 0)) /* clear status */
489 goto errxit;
490 if (! wtcmd (t, QIC_WRTDATA)) { /* set write mode */
491 wtsense (t, 0);
492 goto errxit;
493 }
494 t->flags |= TPWO | TPWANY;
495 }
496 }
15637ed4 497
df9b2252
RG
498 if (! bp->b_bcount)
499 goto xit;
15637ed4 500
df9b2252
RG
501 t->flags &= ~TPEXCEP;
502 s = splbio ();
503 if (wtstart (t, bp->b_flags, bp->b_un.b_addr, bp->b_bcount)) {
504 wtwait (t, 0, (bp->b_flags & B_READ) ? "wtread" : "wtwrite");
505 bp->b_resid -= t->dmacount;
506 }
507 splx (s);
15637ed4 508
df9b2252
RG
509 if (t->flags & TPEXCEP) {
510errxit: bp->b_flags |= B_ERROR;
511 bp->b_error = EIO;
512 }
513xit: biodone (bp);
514 return;
15637ed4
RG
515}
516
df9b2252
RG
517/*
518 * Interrupt routine.
519 */
520void wtintr (int u)
15637ed4 521{
df9b2252
RG
522 wtinfo_t *t = wttab + u;
523 unsigned char s;
15637ed4 524
df9b2252
RG
525 if (u >= NWT || !t->port)
526 return;
15637ed4 527
df9b2252
RG
528 s = inb (t->STATPORT); /* get status */
529 if ((s & (t->BUSY | t->NOEXCEP)) == (t->BUSY | t->NOEXCEP))
530 return; /* device is busy */
531 outb (t->CTLPORT, t->ONLINE); /* stop controller */
15637ed4 532
df9b2252
RG
533 /*
534 * Check if rewind finished.
535 */
536 if (t->flags & TPREW) {
537 t->flags &= ~TPREW; /* Rewind finished. */
538 wtsense (t, TP_WRP);
539 wakeup (t);
540 return;
541 }
15637ed4 542
df9b2252
RG
543 /*
544 * Check if writing/reading of file mark finished.
545 */
546 if (t->flags & (TPRMARK | TPWMARK)) {
547 if (! (s & t->NOEXCEP)) /* Operation failed. */
548 wtsense (t, (t->flags & TPRMARK) ? TP_WRP : 0);
549 t->flags &= ~(TPRMARK | TPWMARK); /* Operation finished. */
550 wakeup (t);
551 return;
552 }
15637ed4 553
df9b2252
RG
554 /*
555 * Do we started any i/o? If no, just return.
556 */
557 if (! (t->flags & TPACTIVE))
558 return;
559 t->flags &= ~TPACTIVE;
15637ed4 560
df9b2252
RG
561 if (inb (DMA_STATUSREG) & DMA_DONE (t->chan)) /* if dma finished */
562 t->dmacount += BLKSIZE; /* increment counter */
15637ed4 563
df9b2252
RG
564 /*
565 * Clean up dma.
566 */
567 if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < BLKSIZE) {
568 /* If the address crosses 64-k boundary, or reading short block,
569 * copy the internal buffer to the user memory. */
570 isa_dmadone (t->dmaflags, t->buf, BLKSIZE, t->chan);
571 bcopy (t->buf, t->dmavaddr, t->dmatotal - t->dmacount);
572 } else
573 isa_dmadone (t->dmaflags, t->dmavaddr, BLKSIZE, t->chan);
574
575 /*
576 * On exception, check for end of file and end of volume.
577 */
578 if (! (s & t->NOEXCEP)) {
579 wtsense (t, (t->dmaflags & B_READ) ? TP_WRP : 0);
580 if (t->error.err & (TP_EOM | TP_FIL))
581 t->flags |= TPVOL; /* end of file */
582 else
583 t->flags |= TPEXCEP; /* i/o error */
584 wakeup (t);
585 return;
586 }
15637ed4 587
df9b2252
RG
588 if (t->dmacount < t->dmatotal) { /* continue i/o */
589 t->dmavaddr += BLKSIZE;
590 wtdma (t);
591 return;
592 }
593 if (t->dmacount > t->dmatotal) /* short last block */
594 t->dmacount = t->dmatotal;
595 wakeup (t); /* wake up user level */
15637ed4
RG
596}
597
df9b2252
RG
598/* start the rewind operation */
599static void wtrewind (wtinfo_t *t)
15637ed4 600{
df9b2252
RG
601 t->flags &= ~(TPRO | TPWO | TPVOL);
602 if (! wtcmd (t, QIC_REWIND))
603 return;
604 t->flags |= TPSTART | TPREW;
605 wtclock (t);
15637ed4
RG
606}
607
df9b2252
RG
608/* start the `read marker' operation */
609static int wtreadfm (wtinfo_t *t)
15637ed4 610{
df9b2252
RG
611 t->flags &= ~(TPRO | TPWO | TPVOL);
612 if (! wtcmd (t, QIC_READFM)) {
613 wtsense (t, TP_WRP);
614 return (EIO);
615 }
616 t->flags |= TPRMARK | TPRANY;
617 wtclock (t);
618 /* Don't wait for completion here. */
619 return (0);
15637ed4
RG
620}
621
df9b2252
RG
622/* write marker to the tape */
623static int wtwritefm (wtinfo_t *t)
15637ed4 624{
df9b2252
RG
625 tsleep (wtwritefm, WTPRI, "wtwfm", hz); /* timeout: 1 second */
626 t->flags &= ~(TPRO | TPWO);
627 if (! wtcmd (t, QIC_WRITEFM)) {
628 wtsense (t, 0);
629 return (EIO);
15637ed4 630 }
df9b2252
RG
631 t->flags |= TPWMARK | TPWANY;
632 wtclock (t);
633 return (wtwait (t, 0, "wtwfm"));
15637ed4
RG
634}
635
df9b2252
RG
636/* wait for controller ready or exception */
637static int wtpoll (wtinfo_t *t)
15637ed4 638{
df9b2252 639 int s, NOTREADY = t->BUSY | t->NOEXCEP;
15637ed4 640
df9b2252
RG
641 /* Poll status port, waiting for ready or exception. */
642 do s = inb (t->STATPORT);
643 while ((s & NOTREADY) == NOTREADY);
644 return (s);
15637ed4
RG
645}
646
df9b2252
RG
647/* execute QIC command */
648static int wtcmd (wtinfo_t *t, int cmd)
15637ed4 649{
df9b2252
RG
650 if (! (wtpoll (t) & t->NOEXCEP)) /* wait for ready */
651 return (0); /* error */
652
653 outb (t->CMDPORT, cmd); /* output the command */
15637ed4 654
df9b2252
RG
655 outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
656 while (inb (t->STATPORT) & t->BUSY) /* wait for ready */
657 continue;
658 outb (t->CTLPORT, t->IEN | t->ONLINE); /* reset request */
659 while (! (inb (t->STATPORT) & t->BUSY)) /* wait for not ready */
660 continue;
15637ed4 661
df9b2252 662 return (1);
15637ed4
RG
663}
664
df9b2252
RG
665/* wait for the end of i/o, seeking marker or rewind operation */
666static int wtwait (wtinfo_t *t, int catch, char *msg)
15637ed4 667{
df9b2252 668 int error;
15637ed4 669
df9b2252
RG
670 while (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))
671 if (error = tsleep (t, WTPRI | catch, msg, 0))
672 return (error);
673 return (0);
15637ed4
RG
674}
675
df9b2252
RG
676/* initialize dma for the i/o operation */
677static void wtdma (wtinfo_t *t)
15637ed4 678{
df9b2252
RG
679 t->flags |= TPACTIVE;
680 wtclock (t);
681
682 if (t->SDMAPORT)
683 outb (t->SDMAPORT, 0); /* set dma */
684
685 if ((t->dmaflags & B_READ) && (t->dmatotal - t->dmacount) < BLKSIZE)
686 /* Reading short block. Do it through the internal buffer. */
687 isa_dmastart (t->dmaflags, t->buf, BLKSIZE, t->chan);
15637ed4 688 else
df9b2252 689 isa_dmastart (t->dmaflags, t->dmavaddr, BLKSIZE, t->chan);
15637ed4 690
df9b2252 691 outb (t->CTLPORT, t->IEN | t->ONLINE);
15637ed4
RG
692}
693
df9b2252
RG
694/* start i/o operation */
695static int wtstart (wtinfo_t *t, unsigned flags, void *vaddr, unsigned len)
15637ed4 696{
df9b2252
RG
697 if (! (wtpoll (t) & t->NOEXCEP)) { /* wait for ready or error */
698 t->flags |= TPEXCEP; /* error */
699 return (0);
700 }
701 t->flags &= ~TPEXCEP; /* clear exception flag */
702 t->dmavaddr = vaddr;
703 t->dmatotal = len;
704 t->dmacount = 0;
705 t->dmaflags = flags;
706 wtdma (t);
707 return (1);
15637ed4
RG
708}
709
df9b2252
RG
710/* start timer */
711static void wtclock (wtinfo_t *t)
15637ed4 712{
df9b2252
RG
713 if (! (t->flags & TPTIMER)) {
714 t->flags |= TPTIMER;
715 timeout (wtimer, t, hz);
716 }
15637ed4
RG
717}
718
df9b2252
RG
719/*
720 * Simulate an interrupt periodically while i/o is going.
721 * This is necessary in case interrupts get eaten due to
722 * multiple devices on a single IRQ line.
723 */
724static void wtimer (wtinfo_t *t)
15637ed4 725{
df9b2252 726 int s;
15637ed4 727
df9b2252
RG
728 t->flags &= ~TPTIMER;
729 if (! (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK)))
730 return;
15637ed4 731
df9b2252
RG
732 /* If i/o going, simulate interrupt. */
733 s = splbio ();
734 wtintr (t->unit);
735 splx (s);
736
737 /* Restart timer if i/o pending. */
738 if (t->flags & (TPACTIVE | TPREW | TPRMARK | TPWMARK))
739 wtclock (t);
740}
741
742/* reset the controller */
743static int wtreset (wtinfo_t *t)
744{
745 outb (t->CTLPORT, t->RESET); /* send reset */
746 DELAY (25);
747 outb (t->CTLPORT, 0); /* turn off reset */
748 if ((inb (t->STATPORT) & t->RESETMASK) != t->RESETVAL)
749 return (0);
750 return (1);
751}
752
753/* get controller status information */
754/* return 0 if user i/o request should receive an i/o error code */
755static int wtsense (wtinfo_t *t, int ignor)
756{
757 char *msg = 0;
758 int err;
759
760 t->flags &= ~(TPRO | TPWO);
761 if (! wtstatus (t))
762 return (0);
763 if (! (t->error.err & TP_ST0))
764 t->error.err &= ~TP_ST0MASK;
765 if (! (t->error.err & TP_ST1))
766 t->error.err &= ~TP_ST1MASK;
767 t->error.err &= ~ignor; /* ignore certain errors */
768 err = t->error.err & (TP_FIL | TP_BNL | TP_UDA | TP_EOM | TP_WRP |
769 TP_USL | TP_CNI | TP_MBD | TP_NDT | TP_ILL);
770 if (! err)
771 return (1);
772
773 /* lifted from tdriver.c from Wangtek */
774 if (err & TP_USL) msg = "Drive not online";
775 else if (err & TP_CNI) msg = "No cartridge";
776 else if ((err & TP_WRP) && !(t->flags & TPWP)) {
777 msg = "Tape is write protected";
778 t->flags |= TPWP;
779 }
780 else if (err & TP_FIL) msg = 0 /*"Filemark detected"*/;
781 else if (err & TP_EOM) msg = 0 /*"End of tape"*/;
782 else if (err & TP_BNL) msg = "Block not located";
783 else if (err & TP_UDA) msg = "Unrecoverable data error";
784 else if (err & TP_NDT) msg = "No data detected";
785 else if (err & TP_ILL) msg = "Illegal command";
786 if (msg)
787 printf ("wt%d: %s\n", t->unit, msg);
788 return (0);
789}
790
791/* get controller status information */
792static int wtstatus (wtinfo_t *t)
793{
794 char *p;
795
796 wtpoll (t); /* wait for ready or exception */
797 outb (t->CMDPORT, QIC_RDSTAT); /* send `read status' command */
798
799 outb (t->CTLPORT, t->REQUEST | t->ONLINE); /* set request */
800 while (inb (t->STATPORT) & t->BUSY) /* wait for ready */
801 continue;
802 outb (t->CTLPORT, t->ONLINE); /* reset request */
803 while (! (inb (t->STATPORT) & t->BUSY)) /* wait for not ready */
804 continue;
805
806 p = (char*) &t->error;
807 while (p < (char*)&t->error + 6) {
808 if (! (wtpoll (t) & t->NOEXCEP)) /* wait for ready */
809 return (0); /* error */
810
811 *p++ = inb (t->DATAPORT); /* read status byte */
812
813 outb (t->CTLPORT, t->REQUEST); /* set request */
814 while (! (inb (t->STATPORT) & t->BUSY)) /* wait for not ready */
815 continue;
816 /* DELAY (50); */ /* wait 50 usec */
817 outb (t->CTLPORT, 0); /* unset request */
818 }
819 return (1);
820}
821#endif /* NWT */