1 /* tm.c 4.8 02/07/81 */ 2 3 #include "tm.h" 4 #if NTM > 0 5 /* 6 * TM tape driver 7 */ 8 #define DELAY(N) { register int d; d = N; while (--d > 0); } 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 #include "../h/cmap.h" 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 (;;) { 149 if ((TMADDR->tmer&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 tmwaitrws(bp->b_dev); 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; 236 int s; 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; 267 s = spl6(); 268 if (tm_ubinfo == 0) 269 tm_ubinfo = ubasetup(bp,1); 270 splx(s); 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: 296 ubarelse(&tm_ubinfo); 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; 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) { 332 if (++tmtab.b_errcnt < 7) { 333 if((TMADDR->tmer&SOFT) == NXM) 334 printf("TM UBA late error\n"); 335 else 336 t_blkno += 2; /* ???????? */ 337 ubarelse(&tm_ubinfo); 338 tmstart(); 339 return; 340 } 341 } else if (t_openf>0 && bp != &rtmbuf) 342 t_openf = -1; 343 deverror(bp, t_erreg, t_dsreg); 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; 376 ubarelse(&tm_ubinfo); 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 */ 443 static tmops[] = {WEOF, SFORW, SREV, SFORW, SREV, REW, OFFL, NOP}; 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; 460 case MTREW: case MTOFFL: case MTNOP: 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 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) 507 int start, num; 508 { 509 #if VAX==780 510 register struct uba_regs *up = (struct uba_regs *)PHYSUBA0; 511 #endif 512 int blk, bdp; 513 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 DELAY(1000000); 521 tmwait(); 522 TMPHYS->tmcs = DCLR | GO; 523 while (num > 0) { 524 blk = num > DBSIZE ? DBSIZE : num; 525 tmdwrite(start, blk); 526 start += blk; 527 num -= blk; 528 } 529 bdp = 1; /* crud to fool c compiler */ 530 ((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE; 531 return (0); 532 } 533 534 tmdwrite(buf, num) 535 register buf, num; 536 { 537 register int *io, npf; 538 int bdp; 539 540 tmwait(); 541 bdp = 1; /* more dastardly tricks on pcc */ 542 ((struct uba_regs *)PHYSUBA0)->uba_dpr[bdp] |= BNE; 543 io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map; 544 npf = num+1; 545 while (--npf != 0) 546 *io++ = (int)(buf++ | (1<<21) | MRV); 547 *io = 0; 548 TMPHYS->tmbc = -(num*NBPG); 549 TMPHYS->tmba = 0; 550 TMPHYS->tmcs = WCOM | GO; 551 } 552 553 tmwait() 554 { 555 register s; 556 557 do 558 s = TMPHYS->tmcs; 559 while ((s & CUR) == 0); 560 } 561 562 tmrewind() 563 { 564 565 tmwait(); 566 TMPHYS->tmcs = REW | GO; 567 } 568 569 tmeof() 570 { 571 572 tmwait(); 573 TMPHYS->tmcs = WEOF | GO; 574 } 575 #endif 576