date and time created 80/12/17 18:35:38 by wnj
[unix-history] / usr / src / sys / vax / uba / tm.c
CommitLineData
d75e5c3e
BJ
1/* tm.c 4.1 %G% */
2
3#include "../conf/tm.h"
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 (;;) {
148 tcommand(dev, NOP, 1);
149 if ((t_erreg&RWS) == 0) {
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
203 tcommand(bp->b_dev, NOP, 1);
204 if (t_erreg&RWS)
205 tmwaitrws(bp->b_dev);
206 if (bp != &ctmbuf) {
207 p = &t_nxrec;
208 if (dbtofsb(bp->b_blkno) > *p) {
209 bp->b_flags |= B_ERROR;
210 bp->b_error = ENXIO; /* past EOF */
211 iodone(bp);
212 return;
213 } else if (dbtofsb(bp->b_blkno) == *p && bp->b_flags&B_READ) {
214 bp->b_resid = bp->b_bcount;
215 clrbuf(bp); /* at EOF */
216 iodone(bp);
217 return;
218 } else if ((bp->b_flags&B_READ) == 0)
219 *p = dbtofsb(bp->b_blkno) + 1; /* write sets EOF */
220 }
221 bp->av_forw = NULL;
222 (void) spl5();
223 if (tmtab.b_actf == NULL)
224 tmtab.b_actf = bp;
225 else
226 tmtab.b_actl->av_forw = bp;
227 tmtab.b_actl = bp;
228 if (tmtab.b_active == 0)
229 tmstart();
230 (void) spl0();
231}
232
233tmstart()
234{
235 register struct buf *bp;
236 register cmd;
237 register daddr_t blkno;
238
239loop:
240 if ((bp = tmtab.b_actf) == 0)
241 return;
242 t_dsreg = TMADDR->tmcs;
243 t_erreg = TMADDR->tmer;
244 t_resid = TMADDR->tmbc;
245 t_flags &= ~LASTIOW;
246 if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) {
247 /* t_openf = -1; ??? */
248 bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */
249 goto next;
250 }
251 cmd = IENABLE | GO;
252 if ((minor(bp->b_dev) & T_1600BPI) == 0)
253 cmd |= D800;
254 if (bp == &ctmbuf) {
255 if (bp->b_command == NOP)
256 goto next; /* just get status */
257 else {
258 cmd |= bp->b_command;
259 tmtab.b_active = SCOM;
260 if (bp->b_command == SFORW || bp->b_command == SREV)
261 TMADDR->tmbc = bp->b_repcnt;
262 TMADDR->tmcs = cmd;
263 return;
264 }
265 }
266 if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) {
267 TMADDR->tmbc = -bp->b_bcount;
268 if (tm_ubinfo == 0)
269 tm_ubinfo = ubasetup(bp,1);
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:
295 if (tm_ubinfo != 0) {
296 ubafree(tm_ubinfo);
297 tm_ubinfo = 0;
298 }
299 tmtab.b_actf = bp->av_forw;
300 iodone(bp);
301 goto loop;
302}
303
304tmintr()
305{
306 register struct buf *bp;
307 register state;
308
309 if (t_flags&WAITREW && (TMADDR->tmer&RWS) == 0) {
310 t_flags &= ~WAITREW;
311 wakeup((caddr_t)&t_flags);
312 }
313 if ((bp = tmtab.b_actf) == NULL)
314 return;
315 t_dsreg = TMADDR->tmcs;
316 TMADDR->tmcs = IENABLE;
317 t_erreg = TMADDR->tmer;
318 t_resid = TMADDR->tmbc;
319 if ((bp->b_flags & B_READ) == 0)
320 t_flags |= LASTIOW;
321 state = tmtab.b_active;
322 tmtab.b_active = 0;
323 if (TMADDR->tmcs&ERROR) {
324 while(TMADDR->tmer & SDWN)
325 ; /* await settle down */
326 if (TMADDR->tmer&EOF) {
327 tmseteof(bp); /* set blkno and nxrec */
328 state = SCOM;
329 TMADDR->tmbc = -bp->b_bcount;
330 goto errout;
331 }
332 if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|SOFT)) == RLE)
333 goto out;
334 if ((TMADDR->tmer&HARD)==0 && state==SIO) {
335 if (++tmtab.b_errcnt < 3) {
336 if((TMADDR->tmer&SOFT) == NXM)
337 printf("TM UBA late error\n");
338 else
339 t_blkno++;
340 if (tm_ubinfo) {
341 ubafree(tm_ubinfo);
342 tm_ubinfo = 0;
343 }
344 tmstart();
345 return;
346 }
347 } else if (t_openf>0 && bp != &rtmbuf)
348 t_openf = -1;
349 deverror(bp, t_erreg, 0);
350 bp->b_flags |= B_ERROR;
351 state = SIO;
352 }
353out:
354 switch (state) {
355
356 case SIO:
357 t_blkno++;
358 /* fall into ... */
359
360 case SCOM:
361 if (bp == &ctmbuf) {
362 switch (bp->b_command) {
363 case SFORW:
364 t_blkno -= bp->b_repcnt;
365 break;
366
367 case SREV:
368 t_blkno += bp->b_repcnt;
369 break;
370
371 default:
372 if (++bp->b_repcnt < 0) {
373 tmstart(); /* continue */
374 return;
375 }
376 }
377 }
378errout:
379 tmtab.b_errcnt = 0;
380 tmtab.b_actf = bp->av_forw;
381 bp->b_resid = -TMADDR->tmbc;
382 if (tm_ubinfo != 0) {
383 ubafree(tm_ubinfo);
384 tm_ubinfo = 0;
385 }
386 iodone(bp);
387 break;
388
389 case SSEEK:
390 t_blkno = dbtofsb(bp->b_blkno);
391 break;
392
393 default:
394 return;
395 }
396 tmstart();
397}
398
399tmseteof(bp)
400 register struct buf *bp;
401{
402
403 if (bp == &ctmbuf) {
404 if (t_blkno > dbtofsb(bp->b_blkno)) {
405 /* reversing */
406 t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc;
407 t_blkno = t_nxrec;
408 } else {
409 /* spacing forward */
410 t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc;
411 t_nxrec = t_blkno - 1;
412 }
413 return;
414 }
415 /* eof on read */
416 t_nxrec = dbtofsb(bp->b_blkno);
417}
418
419tmread(dev)
420{
421
422 tmphys(dev);
423 physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
424}
425
426tmwrite(dev)
427{
428
429 tmphys(dev);
430 physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
431}
432
433tmphys(dev)
434{
435 register daddr_t a;
436
437 a = dbtofsb(u.u_offset >> 9);
438 t_blkno = a;
439 t_nxrec = a + 1;
440}
441
442/*ARGSUSED*/
443tmioctl(dev, cmd, addr, flag)
444 caddr_t addr;
445 dev_t dev;
446{
447 register callcount;
448 int fcount;
449 struct mtop mtop;
450 struct mtget mtget;
451 /* we depend of the values and order of the MT codes here */
452 static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL};
453
454 switch(cmd) {
455 case MTIOCTOP: /* tape operation */
456 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
457 u.u_error = EFAULT;
458 return;
459 }
460 switch(mtop.mt_op) {
461 case MTWEOF: case MTFSF: case MTBSF:
462 callcount = mtop.mt_count;
463 fcount = INF;
464 break;
465 case MTFSR: case MTBSR:
466 callcount = 1;
467 fcount = mtop.mt_count;
468 break;
469 case MTREW: case MTOFFL:
470 callcount = 1;
471 fcount = 1;
472 break;
473 default:
474 u.u_error = ENXIO;
475 return;
476 }
477 if (callcount <= 0 || fcount <= 0)
478 u.u_error = ENXIO;
479 else while (--callcount >= 0) {
480 tcommand(dev, tmops[mtop.mt_op], fcount);
481 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
482 ctmbuf.b_resid) {
483 u.u_error = EIO;
484 break;
485 }
486 if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT)
487 break;
488 }
489 geterror(&ctmbuf);
490 return;
491 case MTIOCGET:
492 mtget.mt_dsreg = t_dsreg;
493 mtget.mt_erreg = t_erreg;
494 mtget.mt_resid = t_resid;
495 if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
496 u.u_error = EFAULT;
497 return;
498 default:
499 u.u_error = ENXIO;
500 }
501}
502
503#define DBSIZE 20
504
505twall(start, num)
506 int start, num;
507{
508#if VAX==780
509 register struct uba_regs *up = (struct uba_regs *)PHYSUBA0;
510#endif
511 int blk;
512
513 TMPHYS->tmcs = DCLR | GO;
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
520 while (num > 0) {
521 blk = num > DBSIZE ? DBSIZE : num;
522 tmdwrite(start, blk);
523 start += blk;
524 num -= blk;
525 }
526}
527
528tmdwrite(buf, num)
529register buf, num;
530{
531 register int *io, npf;
532 tmwait();
533 /* Flush buffered data path 0 */
534 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] = 0;
535 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] = BNE;
536 /* Map unibus address 0 to section of interest */
537 io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map;
538 npf = num+1;
539 while(--npf != 0)
540 *io++ = (int)(buf++ | (1<<21) | MRV);
541 *io = 0;
542 TMPHYS->tmbc = -(num*NBPG);
543 TMPHYS->tmba = 0;
544 TMPHYS->tmcs = WCOM | GO | D800;
545}
546
547tmwait()
548{
549 register short s;
550
551 do
552 s = TMPHYS->tmcs;
553 while ((s & CUR) == 0);
554}
555
556tmrewind()
557{
558
559 tmwait();
560 TMPHYS->tmcs = REW | GO;
561}
562
563tmeof()
564{
565
566 tmwait();
567 TMPHYS->tmcs = WEOF | GO | D800;
568}
569#endif