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