cleanup with new soft interrupts and new ctlr scheme
[unix-history] / usr / src / sys / vax / uba / tm.c
CommitLineData
5aa9d5ea 1/* tm.c 4.10 %G% */
d75e5c3e 2
66b4fb09 3#include "tm.h"
d75e5c3e
BJ
4#if NTM > 0
5/*
6 * TM tape driver
7 */
77115c00 8#define DELAY(N) { register int d; d = N; while (--d > 0); }
d75e5c3e
BJ
9#include "../h/param.h"
10#include "../h/buf.h"
11#include "../h/dir.h"
12#include "../h/conf.h"
13#include "../h/user.h"
14#include "../h/file.h"
15#include "../h/map.h"
16#include "../h/pte.h"
17#include "../h/uba.h"
18#include "../h/mtio.h"
19#include "../h/ioctl.h"
20#include "../h/vm.h"
7455bf3e 21#include "../h/cmap.h"
3f3a34c3 22#include "../h/cpu.h"
d75e5c3e 23
3f3a34c3 24#include "../h/tmreg.h"
d75e5c3e
BJ
25
26struct buf tmtab;
27struct buf ctmbuf;
28struct buf rtmbuf;
29
3f3a34c3
BJ
30int tmcntrlr(), tmslave(), tmdgo(), tmintr();
31struct uba_dinfo *tminfo[NTM];
5aa9d5ea 32extern u_short tmstd[];
3f3a34c3 33struct uba_driver tmdriver =
5aa9d5ea 34 { tmcntrlr, tmslave, tmdgo, 4, 0, tmstd, "tm", tminfo };
d75e5c3e
BJ
35int tm_ubinfo;
36
37/* bits in minor device */
38#define T_NOREWIND 04
39#define T_1600BPI 08
40
41#define INF (daddr_t)1000000L
42
43/*
44 * Really only handle one tape drive... if you have more than one,
3f3a34c3
BJ
45 * you can put all these (and some of the above) in a structure,
46 * change the obvious things, and make tmslave smarter, but
d75e5c3e
BJ
47 * it is not clear what happens when some drives are transferring while
48 * others rewind, so we don't pretend that this driver handles multiple
49 * tape drives.
50 */
51char t_openf;
52daddr_t t_blkno;
53char t_flags;
54daddr_t t_nxrec;
55u_short t_erreg;
56u_short t_dsreg;
57short t_resid;
58
d75e5c3e
BJ
59#define SSEEK 1 /* seeking */
60#define SIO 2 /* doing seq i/o */
61#define SCOM 3 /* sending control command */
62
63#define LASTIOW 1 /* last op was a write */
64#define WAITREW 2 /* someone is waiting for a rewind */
65
5aa9d5ea
RE
66/*
67 * Determine if there is a controller for
68 * a tm at address reg. Our goal is to make the
69 * device interrupt.
70 * THE ARGUMENT UI IS OBSOLETE
71 */
3f3a34c3
BJ
72tmcntrlr(ui, reg)
73 struct uba_dinfo *ui;
74 caddr_t reg;
75{
5aa9d5ea 76
3f3a34c3
BJ
77 ((struct device *)reg)->tmcs = IENABLE;
78 /*
79 * If this is a tm03/tc11, it ought to have interrupted
80 * by now, if it isn't (ie: it is a ts04) then we just
81 * pray that it didn't interrupt, so autoconf will ignore it
82 * - just in case out prayers fail, we will reference one
83 * of the more distant registers, and hope for a machine
84 * check, or similar disaster
85 */
86 if (badaddr(&((struct device *)reg)->tmrd, 2))
87 return(0);
88 return(1);
89}
90
91tmslave(ui, reg, slaveno)
92 struct uba_dinfo *ui;
93 caddr_t reg;
94{
95 /*
96 * Due to a design flaw, we cannot ascertain if the tape
97 * exists or not unless it is on line - ie: unless a tape is
98 * mounted. This is too servere a restriction to bear.
99 * As we can only handle one tape, we might just as well insist
100 * that it be slave #0, and just assume that it exists.
101 * Something better will have to be done if you have two
102 * tapes on one controller, or two controllers
103 */
5aa9d5ea 104 printf("tm: sl %d - tmi %x\n", slaveno, tminfo[0]);
3f3a34c3
BJ
105 if (slaveno != 0 || tminfo[0])
106 return(0);
107 return(1);
108}
109
d75e5c3e
BJ
110tmopen(dev, flag)
111 dev_t dev;
112 int flag;
113{
114 register ds, unit;
3f3a34c3 115 register struct uba_dinfo *ui;
d75e5c3e
BJ
116
117 tmtab.b_flags |= B_TAPE;
118 unit = minor(dev)&03;
5aa9d5ea 119 if (unit>=NTM || t_openf || !(ui = tminfo[minor(dev)&03])->ui_alive) {
d75e5c3e
BJ
120 u.u_error = ENXIO; /* out of range or open */
121 return;
122 }
123 tcommand(dev, NOP, 1);
124 if ((t_erreg&SELR) == 0) {
125 u.u_error = EIO; /* offline */
126 return;
127 }
128 t_openf = 1;
129 if (t_erreg&RWS)
130 tmwaitrws(dev); /* wait for rewind complete */
131 while (t_erreg&SDWN)
132 tcommand(dev, NOP, 1); /* await settle down */
133 if ((t_erreg&TUR)==0 ||
134 ((flag&(FREAD|FWRITE)) == FWRITE && (t_erreg&WRL))) {
3f3a34c3 135 ((struct device *)ui->ui_addr)->tmcs = DCLR|GO;
d75e5c3e
BJ
136 u.u_error = EIO; /* offline or write protect */
137 }
138 if (u.u_error != 0) {
139 t_openf = 0;
140 return;
141 }
142 t_blkno = (daddr_t)0;
143 t_nxrec = INF;
144 t_flags = 0;
145 t_openf = 1;
146}
147
148tmwaitrws(dev)
149 register dev;
150{
3f3a34c3 151 register struct device *addr =
5aa9d5ea 152 (struct device *)tminfo[minor(dev)&03]->ui_addr;
d75e5c3e
BJ
153
154 spl5();
155 for (;;) {
3f3a34c3 156 if ((addr->tmer&RWS) == 0) {
d75e5c3e
BJ
157 spl0(); /* rewind complete */
158 return;
159 }
160 t_flags |= WAITREW;
161 sleep((caddr_t)&t_flags, PRIBIO);
162 }
163}
164
165tmclose(dev, flag)
166 register dev_t dev;
167 register flag;
168{
169
170 if (flag == FWRITE || ((flag&FWRITE) && (t_flags&LASTIOW))) {
171 tcommand(dev, WEOF, 1);
172 tcommand(dev, WEOF, 1);
173 tcommand(dev, SREV, 1);
174 }
175 if ((minor(dev)&T_NOREWIND) == 0)
176 tcommand(dev, REW, 1);
177 t_openf = 0;
178}
179
180tcommand(dev, com, count)
181 dev_t dev;
182 int com, count;
183{
184 register struct buf *bp;
185
186 bp = &ctmbuf;
187 (void) spl5();
188 while (bp->b_flags&B_BUSY) {
189 bp->b_flags |= B_WANTED;
190 sleep((caddr_t)bp, PRIBIO);
191 }
192 bp->b_flags = B_BUSY|B_READ;
193 (void) spl0();
194 bp->b_dev = dev;
195 bp->b_repcnt = -count;
196 bp->b_command = com;
197 bp->b_blkno = 0;
198 tmstrategy(bp);
199 iowait(bp);
200 if (bp->b_flags&B_WANTED)
201 wakeup((caddr_t)bp);
202 bp->b_flags &= B_ERROR;
203}
204
205tmstrategy(bp)
206 register struct buf *bp;
207{
208 register daddr_t *p;
209
0a51498e 210 tmwaitrws(bp->b_dev);
d75e5c3e
BJ
211 if (bp != &ctmbuf) {
212 p = &t_nxrec;
213 if (dbtofsb(bp->b_blkno) > *p) {
214 bp->b_flags |= B_ERROR;
215 bp->b_error = ENXIO; /* past EOF */
216 iodone(bp);
217 return;
218 } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
219 bp->b_resid = bp->b_bcount;
220 clrbuf(bp); /* at EOF */
221 iodone(bp);
222 return;
223 } else if ((bp->b_flags&B_READ) == 0)
224 *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */
225 }
226 bp->av_forw = NULL;
227 (void) spl5();
228 if (tmtab.b_actf == NULL)
229 tmtab.b_actf = bp;
230 else
231 tmtab.b_actl->av_forw = bp;
232 tmtab.b_actl = bp;
233 if (tmtab.b_active == 0)
234 tmstart();
235 (void) spl0();
236}
237
238tmstart()
239{
240 register struct buf *bp;
3f3a34c3
BJ
241 register struct uba_dinfo *ui;
242 register struct device *addr;
d75e5c3e
BJ
243 register cmd;
244 register daddr_t blkno;
b28deaf8 245 int s;
d75e5c3e
BJ
246
247loop:
248 if ((bp = tmtab.b_actf) == 0)
249 return;
5aa9d5ea 250 ui = tminfo[minor(bp->b_dev)&03];
3f3a34c3
BJ
251 addr = (struct device *)ui->ui_addr;
252 t_dsreg = addr->tmcs;
253 t_erreg = addr->tmer;
254 t_resid = addr->tmbc;
d75e5c3e 255 t_flags &= ~LASTIOW;
3f3a34c3 256 if (t_openf < 0 || (addr->tmcs&CUR) == 0) {
d75e5c3e
BJ
257 /* t_openf = -1; ??? */
258 bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */
259 goto next;
260 }
261 cmd = IENABLE | GO;
262 if ((minor(bp->b_dev) & T_1600BPI) == 0)
263 cmd |= D800;
264 if (bp == &ctmbuf) {
265 if (bp->b_command == NOP)
266 goto next; /* just get status */
267 else {
268 cmd |= bp->b_command;
269 tmtab.b_active = SCOM;
270 if (bp->b_command == SFORW || bp->b_command == SREV)
3f3a34c3
BJ
271 addr->tmbc = bp->b_repcnt;
272 addr->tmcs = cmd;
d75e5c3e
BJ
273 return;
274 }
275 }
276 if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) {
3f3a34c3 277 addr->tmbc = -bp->b_bcount;
b28deaf8 278 s = spl6();
d75e5c3e 279 if (tm_ubinfo == 0)
3f3a34c3 280 tm_ubinfo = ubasetup(ui->ui_ubanum, bp, 1);
b28deaf8 281 splx(s);
d75e5c3e
BJ
282 if ((bp->b_flags&B_READ) == 0) {
283 if (tmtab.b_errcnt)
284 cmd |= WIRG;
285 else
286 cmd |= WCOM;
287 } else
288 cmd |= RCOM;
289 cmd |= (tm_ubinfo >> 12) & 0x30;
290 tmtab.b_active = SIO;
3f3a34c3
BJ
291 addr->tmba = tm_ubinfo;
292 addr->tmcs = cmd;
d75e5c3e
BJ
293 return;
294 }
295 tmtab.b_active = SSEEK;
296 if (blkno < dbtofsb(bp->b_blkno)) {
297 cmd |= SFORW;
3f3a34c3 298 addr->tmbc = blkno - dbtofsb(bp->b_blkno);
d75e5c3e
BJ
299 } else {
300 cmd |= SREV;
3f3a34c3 301 addr->tmbc = dbtofsb(bp->b_blkno) - blkno;
d75e5c3e 302 }
3f3a34c3 303 addr->tmcs = cmd;
d75e5c3e
BJ
304 return;
305
306next:
3f3a34c3 307 ubarelse(ui->ui_ubanum, &tm_ubinfo);
d75e5c3e
BJ
308 tmtab.b_actf = bp->av_forw;
309 iodone(bp);
310 goto loop;
311}
312
3f3a34c3
BJ
313tmdgo()
314{
315}
316
317tmintr(d)
d75e5c3e
BJ
318{
319 register struct buf *bp;
3f3a34c3 320 register struct device *addr = (struct device *)tminfo[d]->ui_addr;
d75e5c3e
BJ
321 register state;
322
3f3a34c3 323 if (t_flags&WAITREW && (addr->tmer&RWS) == 0) {
d75e5c3e
BJ
324 t_flags &= ~WAITREW;
325 wakeup((caddr_t)&t_flags);
326 }
327 if ((bp = tmtab.b_actf) == NULL)
328 return;
3f3a34c3
BJ
329 t_dsreg = addr->tmcs;
330 t_erreg = addr->tmer;
331 t_resid = addr->tmbc;
d75e5c3e
BJ
332 if ((bp->b_flags & B_READ) == 0)
333 t_flags |= LASTIOW;
334 state = tmtab.b_active;
335 tmtab.b_active = 0;
3f3a34c3
BJ
336 if (addr->tmcs&ERROR) {
337 while(addr->tmer & SDWN)
d75e5c3e 338 ; /* await settle down */
3f3a34c3 339 if (addr->tmer&EOF) {
d75e5c3e
BJ
340 tmseteof(bp); /* set blkno and nxrec */
341 state = SCOM;
3f3a34c3 342 addr->tmbc = -bp->b_bcount;
d75e5c3e
BJ
343 goto errout;
344 }
3f3a34c3 345 if ((bp->b_flags&B_READ) && (addr->tmer&(HARD|SOFT)) == RLE)
d75e5c3e 346 goto out;
3f3a34c3 347 if ((addr->tmer&HARD)==0 && state==SIO) {
0a51498e 348 if (++tmtab.b_errcnt < 7) {
3f3a34c3 349 if((addr->tmer&SOFT) == NXM)
d75e5c3e 350 printf("TM UBA late error\n");
5aa9d5ea 351 t_blkno++;
3f3a34c3 352 ubarelse(tminfo[d]->ui_ubanum, &tm_ubinfo);
d75e5c3e
BJ
353 tmstart();
354 return;
355 }
356 } else if (t_openf>0 && bp != &rtmbuf)
357 t_openf = -1;
0a51498e 358 deverror(bp, t_erreg, t_dsreg);
d75e5c3e
BJ
359 bp->b_flags |= B_ERROR;
360 state = SIO;
361 }
362out:
363 switch (state) {
364
365 case SIO:
366 t_blkno++;
367 /* fall into ... */
368
369 case SCOM:
370 if (bp == &ctmbuf) {
371 switch (bp->b_command) {
372 case SFORW:
373 t_blkno -= bp->b_repcnt;
374 break;
375
376 case SREV:
377 t_blkno += bp->b_repcnt;
378 break;
379
380 default:
381 if (++bp->b_repcnt < 0) {
382 tmstart(); /* continue */
383 return;
384 }
385 }
386 }
387errout:
388 tmtab.b_errcnt = 0;
389 tmtab.b_actf = bp->av_forw;
3f3a34c3
BJ
390 bp->b_resid = -addr->tmbc;
391 ubarelse(tminfo[d]->ui_ubanum, &tm_ubinfo);
d75e5c3e
BJ
392 iodone(bp);
393 break;
394
395 case SSEEK:
396 t_blkno = dbtofsb(bp->b_blkno);
397 break;
398
399 default:
400 return;
401 }
402 tmstart();
403}
404
405tmseteof(bp)
406 register struct buf *bp;
407{
3f3a34c3 408 register struct device *addr =
5aa9d5ea 409 (struct device *)tminfo[minor(bp->b_dev)&03]->ui_addr;
d75e5c3e
BJ
410
411 if (bp == &ctmbuf) {
412 if (t_blkno > dbtofsb(bp->b_blkno)) {
413 /* reversing */
3f3a34c3 414 t_nxrec = dbtofsb(bp->b_blkno) - addr->tmbc;
d75e5c3e
BJ
415 t_blkno = t_nxrec;
416 } else {
417 /* spacing forward */
3f3a34c3 418 t_blkno = dbtofsb(bp->b_blkno) + addr->tmbc;
d75e5c3e
BJ
419 t_nxrec = t_blkno - 1;
420 }
421 return;
422 }
423 /* eof on read */
424 t_nxrec = dbtofsb(bp->b_blkno);
425}
426
427tmread(dev)
428{
429
430 tmphys(dev);
431 physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
432}
433
434tmwrite(dev)
435{
436
437 tmphys(dev);
438 physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
439}
440
441tmphys(dev)
442{
443 register daddr_t a;
444
445 a = dbtofsb(u.u_offset >> 9);
446 t_blkno = a;
447 t_nxrec = a + 1;
448}
449
450/*ARGSUSED*/
451tmioctl(dev, cmd, addr, flag)
452 caddr_t addr;
453 dev_t dev;
454{
455 register callcount;
456 int fcount;
457 struct mtop mtop;
458 struct mtget mtget;
459 /* we depend of the values and order of the MT codes here */
77115c00 460 static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP};
d75e5c3e
BJ
461
462 switch(cmd) {
463 case MTIOCTOP: /* tape operation */
464 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
465 u.u_error = EFAULT;
466 return;
467 }
468 switch(mtop.mt_op) {
469 case MTWEOF: case MTFSF: case MTBSF:
470 callcount = mtop.mt_count;
471 fcount = INF;
472 break;
473 case MTFSR: case MTBSR:
474 callcount = 1;
475 fcount = mtop.mt_count;
476 break;
77115c00 477 case MTREW: case MTOFFL: case MTNOP:
d75e5c3e
BJ
478 callcount = 1;
479 fcount = 1;
480 break;
481 default:
482 u.u_error = ENXIO;
483 return;
484 }
485 if (callcount <= 0 || fcount <= 0)
486 u.u_error = ENXIO;
487 else while (--callcount >= 0) {
488 tcommand(dev, tmops[mtop.mt_op], fcount);
489 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
490 ctmbuf.b_resid) {
491 u.u_error = EIO;
492 break;
493 }
494 if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT)
495 break;
496 }
497 geterror(&ctmbuf);
498 return;
499 case MTIOCGET:
500 mtget.mt_dsreg = t_dsreg;
501 mtget.mt_erreg = t_erreg;
502 mtget.mt_resid = t_resid;
503 if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
504 u.u_error = EFAULT;
505 return;
506 default:
507 u.u_error = ENXIO;
508 }
509}
510
511#define DBSIZE 20
512
7455bf3e 513tmdump()
d75e5c3e 514{
3f3a34c3
BJ
515 register struct uba_dinfo *ui;
516 register struct uba_regs *up;
517 register struct device *addr;
5aa9d5ea
RE
518 int blk, num;
519 int start;
d75e5c3e 520
5aa9d5ea
RE
521 start = 0;
522 num = maxfree;
523#define phys(a,b) ((b)((int)(a)&0x7fffffff))
3f3a34c3
BJ
524 if (tminfo[0] == 0) {
525 printf("dna\n");
526 return (-1);
527 }
528 ui = phys(tminfo[0], struct uba_dinfo *);
529 up = phys(ui->ui_hd, struct uba_hd *)->uh_physuba;
530#if VAX780
531 if (cpu == VAX_780)
532 ubainit(up);
d75e5c3e 533#endif
77115c00 534 DELAY(1000000);
3f3a34c3
BJ
535 addr = (struct device *)ui->ui_physaddr;
536 tmwait(addr);
537 addr->tmcs = DCLR | GO;
d75e5c3e
BJ
538 while (num > 0) {
539 blk = num > DBSIZE ? DBSIZE : num;
3f3a34c3 540 tmdwrite(start, blk, addr, up);
d75e5c3e
BJ
541 start += blk;
542 num -= blk;
543 }
5aa9d5ea
RE
544 tmwait(addr);
545 tmeof(addr);
546 tmeof(addr);
547 tmrewind(addr);
548 tmwait(addr);
7455bf3e 549 return (0);
d75e5c3e
BJ
550}
551
3f3a34c3
BJ
552tmdwrite(buf, num, addr, up)
553 register buf, num;
554 register struct device *addr;
555 struct uba_regs *up;
d75e5c3e 556{
3f3a34c3
BJ
557 register struct pte *io;
558 register int npf;
0a51498e 559
3f3a34c3 560 tmwait(addr);
3f3a34c3 561 io = up->uba_map;
d75e5c3e 562 npf = num+1;
0a51498e 563 while (--npf != 0)
3f3a34c3
BJ
564 *(int *)io++ = (buf++ | (1<<UBA_DPSHIFT) | UBA_MRV);
565 *(int *)io = 0;
566 addr->tmbc = -(num*NBPG);
567 addr->tmba = 0;
568 addr->tmcs = WCOM | GO;
d75e5c3e
BJ
569}
570
3f3a34c3
BJ
571tmwait(addr)
572 register struct device *addr;
d75e5c3e 573{
0a51498e 574 register s;
d75e5c3e
BJ
575
576 do
3f3a34c3 577 s = addr->tmcs;
d75e5c3e
BJ
578 while ((s & CUR) == 0);
579}
580
3f3a34c3
BJ
581tmrewind(addr)
582 struct device *addr;
d75e5c3e
BJ
583{
584
3f3a34c3
BJ
585 tmwait(addr);
586 addr->tmcs = REW | GO;
d75e5c3e
BJ
587}
588
3f3a34c3
BJ
589tmeof(addr)
590 struct device *addr;
d75e5c3e
BJ
591{
592
3f3a34c3
BJ
593 tmwait(addr);
594 addr->tmcs = WEOF | GO;
d75e5c3e
BJ
595}
596#endif