Commit | Line | Data |
---|---|---|
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 | |
23 | struct 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 | ||
35 | struct buf tmtab; | |
36 | struct buf ctmbuf; | |
37 | struct buf rtmbuf; | |
38 | ||
39 | int 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 | */ | |
54 | char t_openf; | |
55 | daddr_t t_blkno; | |
56 | char t_flags; | |
57 | daddr_t t_nxrec; | |
58 | u_short t_erreg; | |
59 | u_short t_dsreg; | |
60 | short 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 | ||
106 | tmopen(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 | ||
143 | tmwaitrws(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 | ||
158 | tmclose(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 | ||
173 | tcommand(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 | ||
198 | tmstrategy(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 | ||
231 | tmstart() | |
232 | { | |
233 | register struct buf *bp; | |
234 | register cmd; | |
235 | register daddr_t blkno; | |
b28deaf8 | 236 | int s; |
d75e5c3e BJ |
237 | |
238 | loop: | |
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 | ||
295 | next: | |
b28deaf8 | 296 | ubarelse(&tm_ubinfo); |
d75e5c3e BJ |
297 | tmtab.b_actf = bp->av_forw; |
298 | iodone(bp); | |
299 | goto loop; | |
300 | } | |
301 | ||
302 | tmintr() | |
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 | } | |
347 | out: | |
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 | } | |
372 | errout: | |
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 | ||
390 | tmseteof(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 | ||
410 | tmread(dev) | |
411 | { | |
412 | ||
413 | tmphys(dev); | |
414 | physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); | |
415 | } | |
416 | ||
417 | tmwrite(dev) | |
418 | { | |
419 | ||
420 | tmphys(dev); | |
421 | physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); | |
422 | } | |
423 | ||
424 | tmphys(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*/ | |
434 | tmioctl(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 |
496 | tmdump() |
497 | { | |
498 | ||
499 | tmwall((char *)0, maxfree); /* write out memory */ | |
500 | tmeof(); | |
501 | tmeof(); | |
502 | tmrewind(); | |
503 | tmwait(); | |
504 | } | |
505 | ||
506 | tmwall(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 | ||
534 | tmdwrite(buf, num) | |
535 | register 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 | 553 | tmwait() |
d75e5c3e | 554 | { |
0a51498e | 555 | register s; |
d75e5c3e BJ |
556 | |
557 | do | |
558 | s = TMPHYS->tmcs; | |
559 | while ((s & CUR) == 0); | |
560 | } | |
561 | ||
7455bf3e | 562 | tmrewind() |
d75e5c3e BJ |
563 | { |
564 | ||
7455bf3e | 565 | tmwait(); |
d75e5c3e BJ |
566 | TMPHYS->tmcs = REW | GO; |
567 | } | |
568 | ||
7455bf3e | 569 | tmeof() |
d75e5c3e BJ |
570 | { |
571 | ||
7455bf3e | 572 | tmwait(); |
77115c00 | 573 | TMPHYS->tmcs = WEOF | GO; |
d75e5c3e BJ |
574 | } |
575 | #endif |