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