1: /*
   2:  *	SCCS id	@(#)ts.c	2.1 (Berkeley)	8/5/83
   3:  */
   4: 
   5: /*
   6:  *	TS11 tape driver
   7:  */
   8: 
   9: #include "ts.h"
  10: #if NTS > 0
  11: #include "param.h"
  12: #include <sys/buf.h>
  13: #include <sys/dir.h>
  14: #include <sys/conf.h>
  15: #include <sys/file.h>
  16: #include <sys/user.h>
  17: #include <sys/tsreg.h>
  18: #ifdef  TS_IOCTL
  19: #include <sys/mtio.h>
  20: #endif
  21: 
  22: /*
  23:  * Software state per tape transport:
  24:  *
  25:  * 1. A tape drive is a unique-open device:  we refuse opens when it is already.
  26:  * 2. We keep track of the current position on a block tape and seek
  27:  *    before operations by forward/back spacing if necessary.
  28:  * 3. We remember if the last operation was a write on a tape, so if a tape
  29:  *    is open read write and the last thing done is a write we can
  30:  *    write a standard end of tape mark (two eofs).
  31:  * 4. We remember the status registers after the last command, using
  32:  *    them internally and returning them to the SENSE ioctl.
  33:  */
  34: struct  ts_softc {
  35:     char    sc_openf;
  36:     char    sc_lastiow;
  37:     short   sc_resid;
  38:     daddr_t sc_blkno;
  39:     daddr_t sc_nxrec;
  40:     struct  ts_cmd  sc_cmd;
  41:     struct  ts_sts  sc_sts;
  42:     struct  ts_char sc_char;
  43: } ts_softc[NTS];
  44: 
  45: struct  buf tstab;
  46: struct  buf ctsbuf;
  47: /*
  48:  * Raw tape operations use rtsbuf.  The driver
  49:  * notices when rtsbuf is being used and allows the user
  50:  * program to continue after errors and read records
  51:  * not of the standard length (BSIZE).
  52:  */
  53: struct  buf rtsbuf;
  54: 
  55: struct  tsdevice *TSADDR;
  56: 
  57: #define INF     ((daddr_t) ((u_short) 65535))
  58: #define T_NOREWIND  0200
  59: #define TSUNIT(dev) (minor(dev) & 03)
  60: #define tswait(r)   while (((TSADDR->(r)) & TS_SSR) == 0)
  61: 
  62:     /* command code definitions */
  63: 
  64: /*
  65:  * States for tstab.b_active, the state flag.
  66:  * This is used to sequence control in the driver.
  67:  */
  68: #define SSEEK       1   /* seeking */
  69: #define SIO     2   /* doing seq. i/o */
  70: #define SCOM        3   /* sending a control command */
  71: #define SREW        4   /* sending a drive rewind */
  72: 
  73: tsattach(addr, unit)
  74: struct tsdevice *addr;
  75: {
  76:     /*
  77: 	 * This driver supports only one controller.
  78: 	 */
  79:     if (unit == 0) {
  80:         TSADDR = addr;
  81:         return(1);
  82:     }
  83:     return(0);
  84: }
  85: 
  86: /*
  87:  * Open the device.  Tapes are unique open
  88:  * devices so we refuse if it is already open.
  89:  * We also check that a tape is available and
  90:  * don't block waiting here:  if you want to wait
  91:  * for a tape you should timeout in user code.
  92:  */
  93: tsopen(dev, flag)
  94: dev_t   dev;
  95: {
  96:     register tsunit;
  97:     register struct ts_softc *sc;
  98: 
  99:     tsunit = TSUNIT(dev);
 100:     if (TSADDR == (struct tsdevice *) NULL || tsunit >= NTS
 101:         || (sc = &ts_softc[tsunit])->sc_openf) {
 102:         u.u_error = ENXIO;
 103:         return;
 104:     }
 105:     if(tsinit(tsunit)) {
 106:         u.u_error = ENXIO;
 107:         return;
 108:     }
 109:     tstab.b_flags |= B_TAPE;
 110:     tscommand(dev, TS_SENSE, 1);
 111:     if ((sc->sc_sts.s_xs0 & TS_ONL) == 0) {
 112:         uprintf("ts%d: not online\n", tsunit);
 113:         u.u_error = EIO;
 114:         return;
 115:     }
 116:     if ((flag & (FREAD | FWRITE)) == FWRITE
 117:         && (sc->sc_sts.s_xs0 & TS_WLK)) {
 118:         uprintf("ts%d: no write ring\n", tsunit);
 119:         u.u_error = EIO;
 120:         return;
 121:     }
 122:     sc->sc_openf = 1;
 123:     sc->sc_blkno = (daddr_t) 0;
 124:     sc->sc_nxrec = INF;
 125:     sc->sc_lastiow = 0;
 126: }
 127: 
 128: /*
 129:  * Close tape device.
 130:  *
 131:  * If tape was open for writing or last operation was
 132:  * a write, then write two EOF's and backspace over the last one.
 133:  * Unless his is a non-rewinding special file, rewind the tape.
 134:  * Make the tape available to others.
 135:  */
 136: tsclose(dev, flag)
 137: register dev_t  dev;
 138: {
 139:     register struct ts_softc *sc = &ts_softc[TSUNIT(dev)];
 140: 
 141:     if(flag == FWRITE || ((flag & FWRITE) && sc->sc_lastiow)) {
 142:         tscommand(dev, TS_WEOF, 1);
 143:         tscommand(dev, TS_WEOF, 1);
 144:         tscommand(dev, TS_SREV, 1);
 145:     }
 146:     if ((minor(dev) & T_NOREWIND) == 0 )
 147:         /*
 148: 		 * 0 count means don't hang waiting for rewind complete.
 149: 		 * Rather ctsbuf stays busy until the operation completes
 150: 		 * preventing further opens from completing by
 151: 		 * preventing a TS_SENSE from completing.
 152: 		 */
 153:         tscommand(dev, TS_REV, 0);
 154:     sc->sc_openf = 0;
 155: }
 156: 
 157: /*
 158:  * Execute a command on the tape drive
 159:  * a specified number of times.
 160:  */
 161: tscommand(dev, com, count)
 162: dev_t   dev;
 163: register u_short count;
 164: {
 165:     register s;
 166:     register struct buf *bp;
 167: 
 168:     bp = &ctsbuf;
 169:     s = spl5();
 170:     while(bp->b_flags & B_BUSY) {
 171:         /*
 172: 		 * This special check is because B_BUSY never
 173: 		 * gets cleared in the non-waiting rewind case.
 174: 		 */
 175:         if (bp->b_repcnt == 0 && (bp->b_flags & B_DONE))
 176:             break;
 177:         bp->b_flags |= B_WANTED;
 178:         sleep((caddr_t) bp, PRIBIO);
 179:     }
 180:     bp->b_flags = B_BUSY | B_READ;
 181:     splx(s);
 182:     bp->b_dev = dev;
 183:     bp->b_repcnt = -count;
 184:     bp->b_command = com;
 185:     bp->b_blkno = (daddr_t) 0;
 186:     tsstrategy(bp);
 187:     /*
 188: 	 * In case of rewind from close, don't wait.
 189: 	 * This is the only case where count can be 0.
 190: 	 */
 191:     if (count == 0)
 192:         return;
 193:     iowait(bp);
 194:     if(bp->b_flags & B_WANTED)
 195:         wakeup((caddr_t) bp);
 196:     bp->b_flags &= B_ERROR;
 197: }
 198: 
 199: /*
 200:  * Queue a tape operation.
 201:  */
 202: tsstrategy(bp)
 203: register struct buf *bp;
 204: {
 205:     register s;
 206: 
 207: #ifdef UNIBUS_MAP
 208:     if (bp != &ctsbuf)
 209:         mapalloc(bp);
 210: #endif
 211:     bp->av_forw = NULL;
 212:     s = spl5();
 213:     if (tstab.b_actf == NULL)
 214:         tstab.b_actf = bp;
 215:     else
 216:         tstab.b_actl->av_forw = bp;
 217:     tstab.b_actl = bp;
 218:     /*
 219: 	 * If the controller is not busy, get
 220: 	 * it going.
 221: 	 */
 222:     if (tstab.b_active == 0)
 223:         tsstart();
 224:     splx(s);
 225: }
 226: 
 227: /*
 228:  * Start activity on a ts controller.
 229:  */
 230:  tsstart()
 231:  {
 232:     daddr_t blkno;
 233:     int cmd, s, tsunit;
 234:     register struct ts_softc *sc;
 235:     register struct ts_cmd *tc;
 236:     register struct buf *bp;
 237: 
 238:     /*
 239: 	 * Start the controller if there is something for it to do.
 240: 	 */
 241: loop:
 242:     if ((bp = tstab.b_actf) == NULL)
 243:         return;
 244:     tsunit = TSUNIT(bp->b_dev);
 245:     sc = &ts_softc[tsunit];
 246:     tc = &sc->sc_cmd;
 247:     /*
 248: 	 * Default is that last command was NOT a write command;
 249: 	 * if we do a write command we will notice this in tsintr().
 250: 	 */
 251:     sc->sc_lastiow = 0;
 252:     if (sc->sc_openf < 0 || (TSADDR->tssr & TS_OFL)) {
 253:         /*
 254: 		 * Have had a hard error on a non-raw tape
 255: 		 * or the tape unit is now unavailable
 256: 		 * (e.g. taken off line).
 257: 		 */
 258:         bp->b_flags |= B_ERROR;
 259:         goto next;
 260:     }
 261:     if (bp == &ctsbuf) {
 262:         /*
 263: 		 * Execute control operation with the specified count.
 264: 		 */
 265:         tstab.b_active = bp->b_command == TS_REW ?  SREW : SCOM;
 266:         tc->c_repcnt = bp->b_repcnt;
 267:         goto dobpcmd;
 268:     }
 269:     /*
 270: 	 * The following checks handle boundary cases for operation
 271: 	 * on non-raw tapes.  On raw tapes the initialization of
 272: 	 * sc->sc_nxrec by tsphys causes them to be skipped normally
 273: 	 * (except in the case of retries).
 274: 	 */
 275:     if(dbtofsb(bp->b_blkno) > sc->sc_nxrec) {
 276:         /*
 277: 		 * Can't read past known end-of-file.
 278: 		 */
 279:         bp->b_flags |= B_ERROR;
 280:         bp->b_error = ENXIO;
 281:         goto next;
 282:     }
 283:     if(dbtofsb(bp->b_blkno) == sc->sc_nxrec && bp->b_flags & B_READ) {
 284:         /*
 285: 		 * Reading at end of file returns 0 bytes.
 286: 		 * Buffer will be cleared (if written) in writei.
 287: 		 */
 288:         bp->b_resid = bp->b_bcount;
 289:         goto next;
 290:     }
 291:     if((bp->b_flags & B_READ) == 0)
 292:         sc->sc_nxrec = dbtofsb(bp->b_blkno) + 1;
 293:     /*
 294: 	 * If the data transfer command is in the correct place,
 295: 	 * set up all registers and do the transfer.
 296: 	 */
 297:     if ((blkno = sc->sc_blkno) == dbtofsb(bp->b_blkno)) {
 298:         tc->c_size = bp->b_bcount;
 299:         if ((bp->b_flags & B_READ) == 0)
 300:             cmd = TS_WCOM;
 301:         else
 302:             cmd = TS_RCOM;
 303:         if (tstab.b_errcnt)
 304:             cmd |= TS_RETRY;
 305:         tstab.b_active = SIO;
 306:         tc->c_cmd = TS_ACK | TS_CVC | TS_IE | cmd;
 307:         TSADDR->tsdb = &sc->sc_cmd.c_cmd;
 308:         return;
 309:     }
 310:     /*
 311: 	 * Tape positioned incorrectly;
 312: 	 * set to seek forward or backward to the correct spot.
 313: 	 * This happens for raw tapes only on error retries.
 314: 	 */
 315:     tstab.b_active = SSEEK;
 316:     if(blkno < dbtofsb(bp->b_blkno)) {
 317:         bp->b_command = TS_SFORW;
 318:         bp->b_repcnt = dbtofsb(bp->b_blkno) - blkno;
 319:     } else
 320:         {
 321:         bp->b_command = TS_SREV;
 322:         bp->b_repcnt = blkno - dbtofsb(bp->b_blkno);
 323:     }
 324: 
 325: dobpcmd:
 326:     /*
 327: 	 * Do the command in bp.
 328: 	 */
 329:     tc->c_cmd = TS_ACK | TS_CVC | TS_IE | bp->b_command;
 330:     TSADDR->tsdb = &sc->sc_cmd.c_cmd;
 331:     return;
 332: 
 333: next:
 334:     tstab.b_errcnt = 0;
 335:     tstab.b_actf = bp->av_forw;
 336:     iodone(bp);
 337:     goto loop;
 338: }
 339: 
 340: /*
 341:  * TS interrupt routine
 342:  */
 343: tsintr()
 344: {
 345:     register state;
 346:     register struct buf *bp;
 347:     register struct ts_softc *sc;
 348:     int tsunit, err;
 349: 
 350:     if((bp = tstab.b_actf) == NULL)
 351:         return;
 352:     tsunit = TSUNIT (bp->b_dev);
 353: 
 354:     /*
 355: 	 * If last command was a rewind, and tape is still
 356: 	 * rewinding, wait for the rewind complete interrupt.
 357: 	 *
 358: 	 * SHOULD NEVER GET AN INTERRUPT IN THIS STATE.
 359: 	 */
 360:     if (tstab.b_active == SREW) {
 361:         tstab.b_active = SCOM;
 362:         if ((TSADDR->tssr & TS_SSR) == 0)
 363:             return;
 364:     }
 365: 
 366:     /*
 367: 	 * An operation completed... record status
 368: 	 */
 369:     sc = &ts_softc[tsunit];
 370:     if ((bp->b_flags & B_READ) == 0)
 371:         sc->sc_lastiow = 1;
 372:     state = tstab.b_active;
 373:     tstab.b_active = 0;
 374: 
 375:     /*
 376: 	 * Check for errors.
 377: 	 */
 378:     if(TSADDR->tssr & TS_SC) {
 379:         switch (TSADDR->tssr & TS_TC) {
 380:             case TS_UNREC:  /* unrecoverable */
 381:             case TS_FATAL:  /* fatal error */
 382:             case TS_ATTN:   /* attention (shouldn't happen) */
 383:             case TS_RECNM:  /* recoverable, no motion */
 384:                 break;
 385: 
 386:             case TS_SUCC:   /* successful termination */
 387:                 goto ignoreerr;
 388:                 /*NOTREACHED*/
 389: 
 390:             case TS_ALERT:  /* tape status alert */
 391:                 /*
 392: 				 * If we hit the end of the tape file,
 393: 				 * update our position.
 394: 				 */
 395:                 if (sc->sc_sts.s_xs0 & (TS_TMK | TS_EOT)) {
 396:                     tsseteof(bp);   /* set blkno and nxrec */
 397:                     state = SCOM;   /* force completion */
 398:                     /*
 399: 					 * Stuff bc so it will be unstuffed
 400: 					 * correctly later to get resid.
 401: 					 */
 402:                     sc->sc_sts.s_rbpcr = bp->b_bcount;
 403:                     goto opdone;
 404:                     /*NOTREACHED*/
 405:                 }
 406:                 /*
 407: 				 * If we were reading raw tape and the record
 408: 				 * was too long or too short, then we don't
 409: 				 * consider this an error.
 410: 				 */
 411:                 if (bp == &rtsbuf && (bp->b_flags & B_READ)
 412:                     && sc->sc_sts.s_xs0 & (TS_RLS | TS_RLL))
 413:                     goto ignoreerr;
 414:                     /*NOTREACHED*/
 415: 
 416:             case TS_RECOV:  /* recoverable, tape moved */
 417:                 /*
 418: 				 * If this was an i/o operation,
 419: 				 * retry up to 8 times.
 420: 				 */
 421:                 if (state == SIO) {
 422:                     if (++tstab.b_errcnt < 7)
 423:                         goto opcont;
 424:                     else
 425:                         sc->sc_blkno++;
 426:                 } else
 427:                     {
 428:                     /*
 429: 					 * Non-i/o errors on non-raw tape
 430: 					 * cause it to close.
 431: 					 */
 432:                     if (sc->sc_openf > 0 && bp != &rtsbuf)
 433:                         sc->sc_openf = -1;
 434:                 }
 435:                 break;
 436:             case TS_REJECT:
 437:                 if (state == SIO && sc->sc_sts.s_xs0 & TS_WLE)
 438:                     printf("ts%d: no write ring\n", tsunit);
 439:                 if ((sc->sc_sts.s_xs0 & TS_ONL) == 0)
 440:                     printf("ts%d: not online\n", tsunit);
 441:                 break;
 442:         }
 443:         /*
 444: 		 * Couldn't recover error.
 445: 		 */
 446: #ifdef  UCB_DEVERR
 447:         printf("ts%d: hard error bn%d xs0=%b", TSUNIT(bp->b_dev),
 448:              bp->b_blkno, sc->sc_sts.s_xs0, TSXS0_BITS);
 449:         if (sc->sc_sts.s_xs1)
 450:             printf(" xs1=%b", sc->sc_sts.s_xs1, TSXS1_BITS);
 451:         if (sc->sc_sts.s_xs2)
 452:             printf(" xs2=%b", sc->sc_sts.s_xs2, TSXS2_BITS);
 453:         if (sc->sc_sts.s_xs3)
 454:             printf(" xs3=%b\n", sc->sc_sts.s_xs3, TSXS3_BITS);
 455: #else
 456:         deverror(bp, sc->sc_sts.s_xs0, sc->sc_sts.s_xs1);
 457:         printf("%o,%o\n", sc->sc_sts.s_xs2, sc->sc_sts.s_xs3);
 458: #endif
 459:         bp->b_flags |= B_ERROR;
 460:         goto opdone;
 461:         /*NOTREACHED*/
 462:     }
 463:     /*
 464: 	 * Advance tape control finite state machine.
 465: 	 */
 466: ignoreerr:
 467:     switch (state) {
 468:         case SIO:
 469:             /*
 470: 			 * Read/write increments tape block number.
 471: 			 */
 472:             sc->sc_blkno++;
 473:             goto opdone;
 474:             /*NOTREACHED*/
 475: 
 476:         case SCOM:
 477:             /*
 478: 			 * For forward/backward space record
 479: 			 * update current position.
 480: 			 */
 481:             if (bp == &ctsbuf)
 482:                 switch (bp->b_command) {
 483:                     case TS_SFORW:
 484:                         sc->sc_blkno += bp->b_repcnt;
 485:                         break;
 486: 
 487:                     case TS_SREV:
 488:                         sc->sc_blkno -= bp->b_repcnt;
 489:                         break;
 490:                 }
 491:             goto opdone;
 492:             /*NOTREACHED*/
 493: 
 494:         case SSEEK:
 495:             sc->sc_blkno = dbtofsb(bp->b_blkno);
 496:             goto opcont;
 497:             /*NOTREACHED*/
 498: 
 499:         default:
 500:             panic("tsintr");
 501:             /*NOTREACHED*/
 502:     }
 503: 
 504: opdone:
 505:     /*
 506: 	 * Reset error count and remove
 507: 	 * from device queue.
 508: 	 */
 509:     tstab.b_errcnt = 0;
 510:     tstab.b_actf = bp->av_forw;
 511:     bp->b_resid = sc->sc_sts.s_rbpcr;
 512:     iodone(bp);
 513: 
 514: opcont:
 515:     tsstart();
 516: }
 517: 
 518: tsseteof(bp)
 519: register struct buf *bp;
 520: {
 521:     register tsunit = TSUNIT(bp->b_dev);
 522:     register struct ts_softc *sc = &ts_softc[tsunit];
 523: 
 524:     if (bp == &ctsbuf) {
 525:         if (sc->sc_blkno > dbtofsb(bp->b_blkno)) {
 526:             /* reversing */
 527:             sc->sc_nxrec = dbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr;
 528:             sc->sc_blkno = sc->sc_nxrec;
 529:         }
 530:         else
 531:             {
 532:             /* spacing forward */
 533:             sc->sc_blkno = dbtofsb(bp->b_blkno) - sc->sc_sts.s_rbpcr;
 534:             sc->sc_nxrec = sc->sc_blkno - 1;
 535:         }
 536:         return;
 537:     }
 538:     else
 539:         /* eof on read */
 540:         sc->sc_nxrec = dbtofsb(bp->b_blkno);
 541: }
 542: 
 543: /*
 544:  * Initialize the TS11.
 545:  */
 546: tsinit(tsunit)
 547: {
 548:     register struct tsdevice *tsaddr = TSADDR;
 549:     struct  ts_softc *sc = &ts_softc[tsunit];
 550:     register struct ts_cmd *tcmd = &sc->sc_cmd;
 551:     register struct ts_char *tchar = &sc->sc_char;
 552: 
 553:     if (tsaddr->tssr & (TS_NBA | TS_OFL)) {
 554:         tsaddr->tssr = 0;       /* subsystem initialize */
 555:         tswait(tssr);
 556:         if (((u_short) tcmd) & 03) {
 557:             printf("ts%d: addr mod 4 != 0\n", tsunit);
 558:             return (1);
 559:         }
 560:         tchar->char_bptr = &sc->sc_sts;
 561:         tchar->char_bae = 0;
 562:         tchar->char_size = sizeof(struct ts_sts);
 563:         tchar->char_mode = TS_ESS;
 564:         tcmd->c_cmd = TS_ACK | TS_SETCHR;
 565:         tcmd->c_loba = tchar;
 566:         tcmd->c_hiba = 0;
 567:         tcmd->c_size = sizeof(struct ts_char);
 568:         tsaddr->tsdb = tcmd;
 569:         tswait(tssr);
 570:         if (tsaddr->tssr & TS_NBA)
 571:             return (1);
 572:     }
 573:     else
 574:         return(0);
 575: }
 576: 
 577: tsread(dev)
 578: register dev_t  dev;
 579: {
 580:     tsphys(dev);
 581:     bphysio(tsstrategy, &rtsbuf, dev, B_READ);
 582: }
 583: 
 584: tswrite(dev)
 585: register dev_t  dev;
 586: {
 587:     tsphys(dev);
 588:     bphysio(tsstrategy, &rtsbuf, dev, B_WRITE);
 589: }
 590: 
 591: tsphys(dev)
 592: dev_t   dev;
 593: {
 594:     register struct ts_softc *sc;
 595:     daddr_t a;
 596: 
 597:     sc = &ts_softc[TSUNIT(dev)];
 598:     a = dbtofsb(u.u_offset >> 9);
 599:     sc->sc_blkno = a;
 600:     sc->sc_nxrec = a + 1;
 601: }
 602: 
 603: #ifdef  TS_IOCTL
 604: /*ARGSUSED*/
 605: tsioctl(dev, cmd, addr, flag)
 606: dev_t   dev;
 607: caddr_t addr;
 608: {
 609:     register struct ts_softc *sc = &ts_softc[TSUNIT(dev)];
 610:     register struct buf *bp = &ctsbuf;
 611:     register callcount;
 612:     u_short fcount;
 613:     struct  mtop mtop;
 614:     struct  mtget mtget;
 615:     /* we depend on the values and order of the MT codes here */
 616:     static tsops[] = {TS_WEOF,TS_SFORW,TS_SREV,TS_SFORW,TS_SREV,TS_REW,TS_OFFL,TS_SENSE};
 617: 
 618:     switch (cmd) {
 619: 
 620:     case MTIOCTOP:  /* tape operation */
 621:         if (copyin((caddr_t)addr, (caddr_t)&mtop, sizeof(mtop))) {
 622:             u.u_error = EFAULT;
 623:             return;
 624:         }
 625:         switch(mtop.mt_op) {
 626:         case MTWEOF:
 627:             callcount = mtop.mt_count;
 628:             fcount = 1;
 629:             break;
 630:         case MTFSF:
 631:         case MTBSF:
 632:         case MTFSR:
 633:         case MTBSR:
 634:             callcount = 1;
 635:             fcount = mtop.mt_count;
 636:             break;
 637:         case MTREW:
 638:         case MTOFFL:
 639:         case MTNOP:
 640:             callcount = 1;
 641:             fcount = 1;
 642:             break;
 643:         default:
 644:             u.u_error = ENXIO;
 645:             return;
 646:         }
 647:         if (callcount <= 0 || fcount <= 0) {
 648:             u.u_error = ENXIO;
 649:             return;
 650:         }
 651:         while (--callcount >= 0) {
 652:             tscommand(dev, tsops[mtop.mt_op], fcount);
 653:             if ((mtop.mt_op == MTFSR || mtop.mt_op == MTBSR) &&
 654:                 bp->b_resid) {
 655:                 u.u_error = EIO;
 656:                 break;
 657:             }
 658:             if ((bp->b_flags & B_ERROR) || sc->sc_sts.s_xs0 & TS_BOT)
 659:                 break;
 660:         }
 661:         geterror(bp);
 662:         return;
 663:     case MTIOCGET:
 664:         mtget.mt_dsreg = 0;
 665:         mtget.mt_erreg = sc->sc_sts.s_xs0;
 666:         mtget.mt_resid = sc->sc_resid;
 667:         mtget.mt_type = MT_ISTS;
 668:         if (copyout((caddr_t)&mtget, addr, sizeof(mtget)))
 669:             u.u_error = EFAULT;
 670:         return;
 671:     default:
 672:         u.u_error = ENXIO;
 673:     }
 674: }
 675: #endif	TS_IOCTL
 676: #endif	NTS

Defined functions

tsattach defined in line 73; never used
tsclose defined in line 136; never used
tscommand defined in line 161; used 6 times
tsinit defined in line 546; used 1 times
tsintr defined in line 343; used 4 times
tsioctl defined in line 605; never used
tsopen defined in line 93; never used
tsphys defined in line 591; used 2 times
tsread defined in line 577; never used
tsseteof defined in line 518; used 1 times
tsstart defined in line 230; used 2 times
tsstrategy defined in line 202; used 3 times
tswrite defined in line 584; never used

Defined variables

TSADDR defined in line 55; used 10 times
ctsbuf defined in line 46; used 6 times
rtsbuf defined in line 53; used 4 times
ts_softc defined in line 43; used 8 times
tstab defined in line 45; used 23 times

Defined struct's

ts_softc defined in line 34; used 16 times

Defined macros

INF defined in line 57; used 1 times
SCOM defined in line 70; used 3 times
SIO defined in line 69; used 3 times
SREW defined in line 71; used 2 times
SSEEK defined in line 68; used 1 times
TSUNIT defined in line 59; used 8 times
T_NOREWIND defined in line 58; used 1 times
tswait defined in line 60; used 2 times
Last modified: 1983-08-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1390
Valid CSS Valid XHTML 1.0 Strict