Commit | Line | Data |
---|---|---|
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 | ||
22 | struct 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 | ||
34 | struct buf tmtab; | |
35 | struct buf ctmbuf; | |
36 | struct buf rtmbuf; | |
37 | ||
38 | int 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 | */ | |
53 | char t_openf; | |
54 | daddr_t t_blkno; | |
55 | char t_flags; | |
56 | daddr_t t_nxrec; | |
57 | u_short t_erreg; | |
58 | u_short t_dsreg; | |
59 | short 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 | ||
105 | tmopen(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 | ||
142 | tmwaitrws(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 | ||
157 | tmclose(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 | ||
172 | tcommand(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 | ||
197 | tmstrategy(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 | ||
230 | tmstart() | |
231 | { | |
232 | register struct buf *bp; | |
233 | register cmd; | |
234 | register daddr_t blkno; | |
235 | ||
236 | loop: | |
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 | ||
291 | next: | |
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 | ||
301 | tmintr() | |
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 | } | |
349 | out: | |
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 | } | |
374 | errout: | |
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 | ||
395 | tmseteof(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 | ||
415 | tmread(dev) | |
416 | { | |
417 | ||
418 | tmphys(dev); | |
419 | physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); | |
420 | } | |
421 | ||
422 | tmwrite(dev) | |
423 | { | |
424 | ||
425 | tmphys(dev); | |
426 | physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); | |
427 | } | |
428 | ||
429 | tmphys(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*/ | |
439 | tmioctl(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 | ||
501 | twall(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 | ||
525 | tmdwrite(buf, num) | |
526 | register 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 | ||
542 | tmwait() | |
543 | { | |
0a51498e | 544 | register s; |
d75e5c3e BJ |
545 | |
546 | do | |
547 | s = TMPHYS->tmcs; | |
548 | while ((s & CUR) == 0); | |
549 | } | |
550 | ||
551 | tmrewind() | |
552 | { | |
553 | ||
554 | tmwait(); | |
555 | TMPHYS->tmcs = REW | GO; | |
556 | } | |
557 | ||
558 | tmeof() | |
559 | { | |
560 | ||
561 | tmwait(); | |
562 | TMPHYS->tmcs = WEOF | GO | D800; | |
563 | } | |
564 | #endif |