|
|
1.1 ! root 1: ! 2: # ! 3: ! 4: /* ! 5: * TM tape driver ! 6: * Modified by Margie Murphy 9/1/80 ! 7: */ ! 8: ! 9: #include "../ch/param.h" ! 10: #include "../ch/buf.h" ! 11: #include "../ch/dir.h" ! 12: #include "../ch/conf.h" ! 13: #include "../ch/user.h" ! 14: #include "../ch/file.h" ! 15: #include "../ch/map.h" ! 16: #include "../ch/pte.h" ! 17: #include "../ch/uba.h" ! 18: ! 19: struct device { ! 20: short tmer; /* status register*/ ! 21: short tmcs; /* command register */ ! 22: short tmbc; /* byte (read/write) record (space) counter */ ! 23: unsigned short tmba; /* current memory address counter */ ! 24: short tmdb; /* data buffer register */ ! 25: short tmrd; /* tu10 read lines */ ! 26: }; ! 27: ! 28: #define b_repcnt b_bcount /* Command repetition counter */ ! 29: #define b_command b_resid /* Command to do */ ! 30: #define b_status b_resid /* Status after a tcommand */ ! 31: ! 32: struct buf tmtab; /* block device list header */ ! 33: struct buf ctmbuf; /* control semaphore*/ ! 34: struct buf rtmbuf; /* raw i/o device list header */ ! 35: ! 36: #define NUNIT 1 /* number of units on controller*/ ! 37: ! 38: #define U_REWD 04 /* Rewind on close */ ! 39: #define U_DUALD 08 /* Dual density */ ! 40: ! 41: char t_flags[NUNIT]; /* used for T_WRITTEN flag */ ! 42: char t_openf[NUNIT]; /* open flag for device */ ! 43: daddr_t t_blkno[NUNIT]; /* pointer to current block on tape */ ! 44: daddr_t t_nxrec[NUNIT]; /* pointer to end of file on tape */ ! 45: ! 46: #define TMADDR ((struct device *)(UBA0_DEV + 0172520)) /* unibus address of tm device*/ ! 47: /* CONTROL FLAGS */ ! 48: ! 49: #define GO 01 /* initiate command and reset CU RDY */ ! 50: #define RCOM 02 /* read */ ! 51: #define WCOM 04 /* write */ ! 52: #define WEOF 06 /* write eof mark */ ! 53: #define SFORW 010 /* space forward */ ! 54: #define SREV 012 /* space reverse */ ! 55: #define WIRG 014 /* write with extended irg -- for write errors */ ! 56: #define REW 016 /* rewind */ ! 57: #define NOP 0100 /* nop = interrupt enable */ ! 58: #define IENABLE 0100 /* enable interrupts */ ! 59: #define DCLR 010000 /* Drive clear -- reset any hard error bits */ ! 60: #define D800 060000 /* 9-channel, 800 bpi density */ ! 61: #define D1600 0117777 /* 9-channel, 1600 bpi density*/ ! 62: ! 63: /* STATUS FLAGS */ ! 64: #define TUR 1 /* tape unit ready */ ! 65: #define RWS 02 /* rewind in progress--set on first rewind int*/ ! 66: #define WL 04 /* write lock bit -- read ring off tape */ ! 67: #define GAPSD 010 /* gap settle down bit */ ! 68: #define RLE 0100 /* record length error on read */ ! 69: #define CRDY 0200 /* control unit ready */ ! 70: #define EOF 040000 /* end of file */ ! 71: #define HARD 0100000 /* ILC (could be a stronger test if we trusted the UNIBUS) */ ! 72: ! 73: /* DRIVER MODES */ ! 74: #define SSEEK 1 /* seek mode */ ! 75: #define SIO 2 /* sequential i/o mode */ ! 76: #define SCOM 3 /* command mode */ ! 77: ! 78: #define T_WRITTEN 1 /* device flag for eof writes */ ! 79: #define T_WANTED 02 /* wait for rewind flag*/ ! 80: ! 81: tmopen(dev, flag) ! 82: dev_t dev; ! 83: int flag; ! 84: { ! 85: register unit, ds; ! 86: ! 87: unit = minor(dev) & 03; ! 88: if (t_openf[unit]) ! 89: { ! 90: u.u_error = ENXIO; ! 91: return; ! 92: } ! 93: t_blkno[unit] = 0; ! 94: t_flags[unit] = 0; ! 95: t_nxrec[unit] = 65535; ! 96: ! 97: tmtab.b_flags |= B_TAPE; ! 98: ! 99: ds = tcommand(dev, NOP, 1); ! 100: ! 101: if ((ds & TUR) == 0) ! 102: { ! 103: while (ds = tcommand(dev, NOP, 1) & RWS) ! 104: { ! 105: /* sleep during rewind initiated during prior IO */ ! 106: t_flags[NUNIT] |= T_WANTED; ! 107: sleep((caddr_t)&t_flags[NUNIT],PRIBIO); ! 108: } ! 109: } ! 110: ! 111: while ((ds = tcommand(dev, NOP, 1)) & GAPSD); ! 112: ! 113: if ((ds&TUR)==0 || (flag && ds&WL)) ! 114: { ! 115: /* Offline or needs a write ring */ ! 116: TMADDR->tmcs = DCLR|GO; ! 117: u.u_error = EIO; ! 118: } ! 119: /* t_openf may have value -1 if certain hardware conditions came up */ ! 120: t_openf[unit] = (u.u_error == 0); ! 121: } ! 122: ! 123: tmclose(dev, flag) ! 124: register dev_t dev; ! 125: register flag; ! 126: { ! 127: register unit; ! 128: ! 129: unit = minor(dev)&03; ! 130: t_openf[unit]++; ! 131: if( ! 132: flag == FWRITE || ! 133: ((flag&FWRITE) && (t_flags[minor(dev)&03] & T_WRITTEN)) ! 134: ) { ! 135: (void) tcommand(dev, WEOF, 2); ! 136: (void) tcommand(dev, SREV, 1); ! 137: } ! 138: if ((minor(dev)&U_REWD) == 0) ! 139: /* rewind if bit 2 is set in minor */ ! 140: (void) tcommand(dev, REW, 1); ! 141: ! 142: t_openf[minor(dev)&03] = 0; ! 143: } ! 144: ! 145: ! 146: tcommand(dev, com, cnt) ! 147: register dev_t dev; ! 148: register com, cnt; ! 149: { ! 150: register struct buf *bp; ! 151: ! 152: bp = &ctmbuf; ! 153: (void) spl5(); ! 154: while (bp->b_flags&B_BUSY) ! 155: { ! 156: bp->b_flags |= B_WANTED; ! 157: sleep((caddr_t)bp, PRIBIO); ! 158: } ! 159: bp->b_flags = B_BUSY|B_READ; ! 160: (void) spl0(); ! 161: ! 162: bp->b_dev = dev; ! 163: bp->b_repcnt = -cnt; ! 164: bp->b_command = com; ! 165: bp->b_blkno = 0; ! 166: ! 167: tmstrategy(bp); ! 168: ! 169: iowait(bp); ! 170: if (bp->b_flags&B_WANTED) ! 171: wakeup((caddr_t)bp); ! 172: bp->b_flags = 0; ! 173: return(bp->b_status); ! 174: } ! 175: ! 176: tmstrategy(bp) ! 177: register struct buf *bp; ! 178: { ! 179: register daddr_t *p; ! 180: ! 181: if (bp != &ctmbuf) ! 182: { ! 183: p = &t_nxrec[minor(bp->b_dev)&03]; ! 184: if (*p <= dbtofsb(bp->b_blkno)) ! 185: { ! 186: if (*p < dbtofsb(bp->b_blkno)) ! 187: { ! 188: /* Blkno past EOF */ ! 189: bp->b_flags |= B_ERROR; ! 190: iodone(bp); ! 191: return; ! 192: } ! 193: if (bp->b_flags&B_READ) ! 194: { ! 195: /* Reading at EOF */ ! 196: clrbuf(bp); ! 197: bp->b_resid = bp->b_bcount; ! 198: iodone(bp); ! 199: return; ! 200: } ! 201: } ! 202: if ((bp->b_flags&B_READ) == 0) ! 203: { ! 204: t_flags[minor(bp->b_dev)&03] |= T_WRITTEN; ! 205: /* Change software location of EOF */ ! 206: *p = dbtofsb(bp->b_blkno) + 1; ! 207: } ! 208: } ! 209: ! 210: bp->av_forw = 0; ! 211: ! 212: (void) spl5(); ! 213: if (tmtab.b_actf == NULL) ! 214: tmtab.b_actf = bp; ! 215: else ! 216: tmtab.b_actl->av_forw = bp; ! 217: tmtab.b_actl = bp; ! 218: if (tmtab.b_active == NULL) ! 219: tmstart(); ! 220: (void) spl0(); ! 221: } ! 222: ! 223: tmstart() ! 224: { ! 225: register struct buf *bp; ! 226: register com; ! 227: register unit; ! 228: register daddr_t blkno; ! 229: ! 230: loop: ! 231: if ((bp = tmtab.b_actf) == 0) ! 232: return; ! 233: unit = minor(bp->b_dev)&03; ! 234: blkno = t_blkno[unit]; ! 235: if (t_openf[unit] < 0 || (TMADDR->tmcs & CRDY) == NULL) ! 236: { ! 237: bp->b_flags |= B_ERROR; ! 238: goto next; ! 239: } ! 240: com = IENABLE | (unit << 8) | GO; ! 241: ! 242: if (minor(bp->b_dev) & U_DUALD) ! 243: com &= D1600; ! 244: else ! 245: com |= D800; ! 246: ! 247: if (bp == &ctmbuf) ! 248: { ! 249: if (bp->b_command == NOP) ! 250: { ! 251: /* return device status */ ! 252: bp->b_status = TMADDR->tmer; ! 253: goto next; ! 254: } ! 255: com |= 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 = com; ! 260: return; ! 261: } ! 262: if (blkno != dbtofsb(bp->b_blkno)) ! 263: { ! 264: /* Block mode, seek to correct block */ ! 265: tmtab.b_active = SSEEK; ! 266: if (blkno < dbtofsb(bp->b_blkno)) ! 267: { ! 268: com |= SFORW; ! 269: TMADDR->tmbc = blkno - dbtofsb(bp->b_blkno); ! 270: } ! 271: else ! 272: { ! 273: com |= SREV; ! 274: TMADDR->tmbc = dbtofsb(bp->b_blkno) - blkno; ! 275: } ! 276: TMADDR->tmcs = com; ! 277: return; ! 278: } ! 279: if (tmtab.b_un.b_addr == 0) ! 280: tmtab.b_un.b_addr = (caddr_t)ubasetup(bp,1); ! 281: ! 282: /* Set high 2 bits of UNIBUS address */ ! 283: com |= (((long)tmtab.b_un.b_addr >> (16-4)) & 060); ! 284: ! 285: tmtab.b_active = SIO; ! 286: com |= ((bp->b_flags & B_READ) ? RCOM : ((tmtab.b_errcnt) ? WIRG : WCOM )); ! 287: TMADDR->tmbc = -bp->b_bcount; ! 288: TMADDR->tmba = ((int)tmtab.b_un.b_addr & 0xffff); ! 289: TMADDR->tmcs = com; ! 290: return; ! 291: ! 292: next: ! 293: if (tmtab.b_un.b_addr != 0) ! 294: { ! 295: ubafree(tmtab.b_un.b_addr); ! 296: tmtab.b_un.b_addr = 0; ! 297: } ! 298: tmtab.b_actf = bp->av_forw; ! 299: iodone(bp); ! 300: goto loop; ! 301: } ! 302: ! 303: tmintr() ! 304: { ! 305: register struct buf *bp; ! 306: register state, unit; ! 307: ! 308: if (t_flags[NUNIT] & T_WANTED) ! 309: { ! 310: /* wake up any rewind sleepers*/ ! 311: t_flags[NUNIT] &= ~T_WANTED; ! 312: wakeup((caddr_t)&t_flags[NUNIT]); ! 313: } ! 314: if ((bp = tmtab.b_actf) == NULL) ! 315: return; ! 316: ! 317: unit = minor(bp->b_dev)&03; ! 318: state = tmtab.b_active; ! 319: tmtab.b_active = NULL; ! 320: if (TMADDR->tmcs < 0) ! 321: { ! 322: /* ! 323: * On error, first wait for gap shutdown ! 324: */ ! 325: while(TMADDR->tmer & GAPSD) ; ! 326: ! 327: if (TMADDR->tmer&EOF) ! 328: { ! 329: /* EOF, set nxrec to sought block */ ! 330: t_nxrec[unit] = dbtofsb(bp->b_blkno); ! 331: state = SCOM; ! 332: TMADDR->tmbc = -bp->b_bcount; ! 333: goto out; ! 334: } ! 335: if ((bp->b_flags&B_READ) && (TMADDR->tmer&(HARD|RLE)) == RLE) ! 336: goto out; ! 337: if ((TMADDR->tmer&(HARD|EOF)) == NULL && state==SIO) ! 338: { ! 339: /* if not a hard error or eof and in sequential mode */ ! 340: if (++tmtab.b_errcnt < 3) ! 341: { ! 342: if((TMADDR->tmer&~RLE) != 0xC0) ! 343: t_blkno[unit]++; ! 344: else ! 345: printf("TM UBA late error\n"); ! 346: if(tmtab.b_un.b_addr) ! 347: { ! 348: ubafree(tmtab.b_un.b_addr); ! 349: tmtab.b_un.b_addr = 0; ! 350: } ! 351: /* retry: skip reverse one and do IO again */ ! 352: tmstart(); ! 353: return; ! 354: } ! 355: } ! 356: else if(t_openf[unit]>0 && bp!=&rtmbuf && (TMADDR->tmer&EOF)==0) ! 357: t_openf[unit] = -1; ! 358: deverror(bp, TMADDR->tmer&0xffff, TMADDR->tmcs&0xffff); ! 359: bp->b_flags |= B_ERROR; ! 360: state = SIO; ! 361: } ! 362: out: ! 363: switch (state) ! 364: { ! 365: case SIO: ! 366: t_blkno[unit]++; ! 367: ! 368: case SCOM: ! 369: if(bp == &ctmbuf) ! 370: if(bp->b_command == SFORW || bp->b_command == SREV) ! 371: { ! 372: if(bp->b_command == SREV) ! 373: t_blkno[unit] -= -bp->b_repcnt; ! 374: else ! 375: t_blkno[unit] += -bp->b_repcnt; ! 376: } ! 377: else if(++bp->b_repcnt) ! 378: break; ! 379: tmtab.b_errcnt = 0; ! 380: tmtab.b_actf = bp->av_forw; ! 381: bp->b_resid = -TMADDR->tmbc; ! 382: if(tmtab.b_un.b_addr != 0) ! 383: { ! 384: ubafree(tmtab.b_un.b_addr); ! 385: tmtab.b_un.b_addr = 0; ! 386: } ! 387: iodone(bp); ! 388: break; ! 389: ! 390: case SSEEK: ! 391: t_blkno[unit] = dbtofsb(bp->b_blkno); ! 392: break; ! 393: ! 394: default: ! 395: return; ! 396: } ! 397: tmstart(); ! 398: } ! 399: ! 400: tmread(dev) ! 401: { ! 402: tmphys(dev); ! 403: physio(tmstrategy, &rtmbuf, dev, B_READ, minphys); ! 404: } ! 405: ! 406: tmwrite(dev) ! 407: { ! 408: tmphys(dev); ! 409: physio(tmstrategy, &rtmbuf, dev, B_WRITE, minphys); ! 410: } ! 411: ! 412: tmphys(dev) ! 413: { ! 414: register unit; ! 415: register daddr_t a; ! 416: ! 417: unit = minor(dev) & 03; ! 418: a = dbtofsb(u.u_offset >> 9); ! 419: t_blkno[unit] = a; ! 420: t_nxrec[unit] = a + 1; ! 421: } ! 422: ! 423: # define NTMIOCTRL (sizeof tmiolist) ! 424: ! 425: char tmiolist[] = ! 426: { ! 427: SFORW, /* 0 = skip forward */ ! 428: SREV, /* 1 = skip reverse */ ! 429: WEOF, /* 2 = Write EOF */ ! 430: REW, /* 3 = rewind */ ! 431: 0, /* 4 = skip forward file */ ! 432: 0 /* 5 = skip reverse file */ ! 433: }; ! 434: ! 435: tmioctrl(dev, cmd, arg, flag) ! 436: register dev_t dev; ! 437: register int cmd, flag, arg; ! 438: { ! 439: register ioctr; ! 440: ! 441: if((unsigned)cmd >= NTMIOCTRL || arg <= 0) ! 442: u.u_error = ENXIO; ! 443: else ! 444: { ! 445: if(cmd > 3) ! 446: { ! 447: /* Skip forward/reverse file(s) */ ! 448: cmd -= 3; ! 449: ioctr = arg; ! 450: arg = -1; ! 451: } ! 452: else ! 453: ioctr = 1; ! 454: do ! 455: (void) tcommand(dev, tmiolist[cmd], arg); ! 456: while(--ioctr); ! 457: } ! 458: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.