add PHYSU* for standalone drivers
[unix-history] / usr / src / sys / vax / uba / tm.c
CommitLineData
66b4fb09 1/* tm.c 4.3 %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;
235
236loop:
237 if ((bp = tmtab.b_actf) == 0)
238 return;
239 t_dsreg = TMADDR->tmcs;
240 t_erreg = TMADDR->tmer;
241 t_resid = TMADDR->tmbc;
242 t_flags &= ~LASTIOW;
243 if (t_openf < 0 || (TMADDR->tmcs&CUR) == 0) {
244 /* t_openf = -1; ??? */
245 bp->b_flags |= B_ERROR; /* hard error'ed or !SELR */
246 goto next;
247 }
248 cmd = IENABLE | GO;
249 if ((minor(bp->b_dev) & T_1600BPI) == 0)
250 cmd |= D800;
251 if (bp == &ctmbuf) {
252 if (bp->b_command == NOP)
253 goto next; /* just get status */
254 else {
255 cmd |= bp->b_command;
256 tmtab.b_active = SCOM;
257 if (bp->b_command == SFORW || bp->b_command == SREV)
258 TMADDR->tmbc = bp->b_repcnt;
259 TMADDR->tmcs = cmd;
260 return;
261 }
262 }
263 if ((blkno = t_blkno) == dbtofsb(bp->b_blkno)) {
264 TMADDR->tmbc = -bp->b_bcount;
265 if (tm_ubinfo == 0)
266 tm_ubinfo = ubasetup(bp,1);
267 if ((bp->b_flags&B_READ) == 0) {
268 if (tmtab.b_errcnt)
269 cmd |= WIRG;
270 else
271 cmd |= WCOM;
272 } else
273 cmd |= RCOM;
274 cmd |= (tm_ubinfo >> 12) & 0x30;
275 tmtab.b_active = SIO;
276 TMADDR->tmba = tm_ubinfo;
277 TMADDR->tmcs = cmd;
278 return;
279 }
280 tmtab.b_active = SSEEK;
281 if (blkno < dbtofsb(bp->b_blkno)) {
282 cmd |= SFORW;
283 TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno);
284 } else {
285 cmd |= SREV;
286 TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno;
287 }
288 TMADDR->tmcs = cmd;
289 return;
290
291next:
292 if (tm_ubinfo != 0) {
293 ubafree(tm_ubinfo);
294 tm_ubinfo = 0;
295 }
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; /* ???????? */
d75e5c3e
BJ
336 if (tm_ubinfo) {
337 ubafree(tm_ubinfo);
338 tm_ubinfo = 0;
339 }
340 tmstart();
341 return;
342 }
343 } else if (t_openf>0 && bp != &rtmbuf)
344 t_openf = -1;
0a51498e 345 deverror(bp, t_erreg, t_dsreg);
d75e5c3e
BJ
346 bp->b_flags |= B_ERROR;
347 state = SIO;
348 }
349out:
350 switch (state) {
351
352 case SIO:
353 t_blkno++;
354 /* fall into ... */
355
356 case SCOM:
357 if (bp == &ctmbuf) {
358 switch (bp->b_command) {
359 case SFORW:
360 t_blkno -= bp->b_repcnt;
361 break;
362
363 case SREV:
364 t_blkno += bp->b_repcnt;
365 break;
366
367 default:
368 if (++bp->b_repcnt < 0) {
369 tmstart(); /* continue */
370 return;
371 }
372 }
373 }
374errout:
375 tmtab.b_errcnt = 0;
376 tmtab.b_actf = bp->av_forw;
377 bp->b_resid = -TMADDR->tmbc;
378 if (tm_ubinfo != 0) {
379 ubafree(tm_ubinfo);
380 tm_ubinfo = 0;
381 }
382 iodone(bp);
383 break;
384
385 case SSEEK:
386 t_blkno = dbtofsb(bp->b_blkno);
387 break;
388
389 default:
390 return;
391 }
392 tmstart();
393}
394
395tmseteof(bp)
396 register struct buf *bp;
397{
398
399 if (bp == &ctmbuf) {
400 if (t_blkno > dbtofsb(bp->b_blkno)) {
401 /* reversing */
402 t_nxrec = dbtofsb(bp->b_blkno) - TMADDR->tmbc;
403 t_blkno = t_nxrec;
404 } else {
405 /* spacing forward */
406 t_blkno = dbtofsb(bp->b_blkno) + TMADDR->tmbc;
407 t_nxrec = t_blkno - 1;
408 }
409 return;
410 }
411 /* eof on read */
412 t_nxrec = dbtofsb(bp->b_blkno);
413}
414
415tmread(dev)
416{
417
418 tmphys(dev);
419 physio(tmstrategy, &rtmbuf, dev, B_READ, minphys);
420}
421
422tmwrite(dev)
423{
424
425 tmphys(dev);
426 physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys);
427}
428
429tmphys(dev)
430{
431 register daddr_t a;
432
433 a = dbtofsb(u.u_offset >> 9);
434 t_blkno = a;
435 t_nxrec = a + 1;
436}
437
438/*ARGSUSED*/
439tmioctl(dev, cmd, addr, flag)
440 caddr_t addr;
441 dev_t dev;
442{
443 register callcount;
444 int fcount;
445 struct mtop mtop;
446 struct mtget mtget;
447 /* we depend of the values and order of the MT codes here */
448 static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL};
449
450 switch(cmd) {
451 case MTIOCTOP: /* tape operation */
452 if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
453 u.u_error = EFAULT;
454 return;
455 }
456 switch(mtop.mt_op) {
457 case MTWEOF: case MTFSF: case MTBSF:
458 callcount = mtop.mt_count;
459 fcount = INF;
460 break;
461 case MTFSR: case MTBSR:
462 callcount = 1;
463 fcount = mtop.mt_count;
464 break;
465 case MTREW: case MTOFFL:
466 callcount = 1;
467 fcount = 1;
468 break;
469 default:
470 u.u_error = ENXIO;
471 return;
472 }
473 if (callcount <= 0 || fcount <= 0)
474 u.u_error = ENXIO;
475 else while (--callcount >= 0) {
476 tcommand(dev, tmops[mtop.mt_op], fcount);
477 if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
478 ctmbuf.b_resid) {
479 u.u_error = EIO;
480 break;
481 }
482 if ((ctmbuf.b_flags&B_ERROR) || t_erreg&BOT)
483 break;
484 }
485 geterror(&ctmbuf);
486 return;
487 case MTIOCGET:
488 mtget.mt_dsreg = t_dsreg;
489 mtget.mt_erreg = t_erreg;
490 mtget.mt_resid = t_resid;
491 if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
492 u.u_error = EFAULT;
493 return;
494 default:
495 u.u_error = ENXIO;
496 }
497}
498
499#define DBSIZE 20
500
501twall(start, num)
502 int start, num;
503{
504#if VAX==780
505 register struct uba_regs *up = (struct uba_regs *)PHYSUBA0;
506#endif
507 int blk;
508
509 TMPHYS->tmcs = DCLR | GO;
510#if VAX==780
511 up->uba_cr = ADINIT;
512 up->uba_cr = IFS|BRIE|USEFIE|SUEFIE;
513 while ((up->uba_cnfgr & UBIC) == 0)
514 ;
515#endif
516 while (num > 0) {
517 blk = num > DBSIZE ? DBSIZE : num;
518 tmdwrite(start, blk);
519 start += blk;
520 num -= blk;
521 }
0a51498e 522 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE;
d75e5c3e
BJ
523}
524
525tmdwrite(buf, num)
526register buf, num;
527{
528 register int *io, npf;
0a51498e 529
d75e5c3e 530 tmwait();
0a51498e 531 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE;
d75e5c3e
BJ
532 io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map;
533 npf = num+1;
0a51498e 534 while (--npf != 0)
d75e5c3e
BJ
535 *io++ = (int)(buf++ | (1<<21) | MRV);
536 *io = 0;
537 TMPHYS->tmbc = -(num*NBPG);
538 TMPHYS->tmba = 0;
539 TMPHYS->tmcs = WCOM | GO | D800;
540}
541
542tmwait()
543{
0a51498e 544 register s;
d75e5c3e
BJ
545
546 do
547 s = TMPHYS->tmcs;
548 while ((s & CUR) == 0);
549}
550
551tmrewind()
552{
553
554 tmwait();
555 TMPHYS->tmcs = REW | GO;
556}
557
558tmeof()
559{
560
561 tmwait();
562 TMPHYS->tmcs = WEOF | GO | D800;
563}
564#endif