Commit | Line | Data |
---|---|---|
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 | ||
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 (;;) { | |
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 | ||
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 | ||
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 | ||
233 | tmstart() | |
234 | { | |
235 | register struct buf *bp; | |
236 | register cmd; | |
237 | register daddr_t blkno; | |
238 | ||
239 | loop: | |
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 | ||
294 | next: | |
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 | ||
304 | tmintr() | |
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 | } | |
353 | out: | |
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 | } | |
378 | errout: | |
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 | ||
399 | tmseteof(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 | ||
419 | tmread(dev) | |
420 | { | |
421 | ||
422 | tmphys(dev); | |
423 | physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); | |
424 | } | |
425 | ||
426 | tmwrite(dev) | |
427 | { | |
428 | ||
429 | tmphys(dev); | |
430 | physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); | |
431 | } | |
432 | ||
433 | tmphys(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*/ | |
443 | tmioctl(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 | ||
505 | twall(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 | ||
528 | tmdwrite(buf, num) | |
529 | register 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 | ||
547 | tmwait() | |
548 | { | |
549 | register short s; | |
550 | ||
551 | do | |
552 | s = TMPHYS->tmcs; | |
553 | while ((s & CUR) == 0); | |
554 | } | |
555 | ||
556 | tmrewind() | |
557 | { | |
558 | ||
559 | tmwait(); | |
560 | TMPHYS->tmcs = REW | GO; | |
561 | } | |
562 | ||
563 | tmeof() | |
564 | { | |
565 | ||
566 | tmwait(); | |
567 | TMPHYS->tmcs = WEOF | GO | D800; | |
568 | } | |
569 | #endif |