1 /* tm.c 4.3 12/19/80 */ 2 3 #include "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 if ((TMADDR->tmer&RWS) == 0) { 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 202 tmwaitrws(bp->b_dev); 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; 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) { 331 if (++tmtab.b_errcnt < 7) { 332 if((TMADDR->tmer&SOFT) == NXM) 333 printf("TM UBA late error\n"); 334 else 335 t_blkno += 2; /* ???????? */ 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; 345 deverror(bp, t_erreg, t_dsreg); 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 } 522 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE; 523 } 524 525 tmdwrite(buf, num) 526 register buf, num; 527 { 528 register int *io, npf; 529 530 tmwait(); 531 ((struct uba_regs *)PHYSUBA0)->uba_dpr[1] |= BNE; 532 io = (int *)((struct uba_regs *)PHYSUBA0)->uba_map; 533 npf = num+1; 534 while (--npf != 0) 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 { 544 register s; 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 565