|
|
1.1 ! root 1: extern int OUTB_DB; ! 2: ! 3: int FT_BLAB = 0; ! 4: int FT_ACKBLAB = 0; ! 5: ! 6: /* ! 7: * File: ft.c ! 8: * ! 9: * Purpose: Floppy tape device control. ! 10: * Requires 765 controller module fdc.c ! 11: * FDC = floppy disk controller, e.g. NEC upd765 ! 12: * ! 13: * Revised: Tue Jun 29 08:22:14 1993 CDT ! 14: * ! 15: * To do: ! 16: * Read fractional segment or block, then come back for the rest. ! 17: * Coordinate conversion: tape <--> pseudo diskette ! 18: * Skip entire segment if bad block map says > 28 bad blocks. ! 19: * ECC. ! 20: * QIC-40. ! 21: * 205' cartridges. ! 22: * Write. ! 23: * Bad block map. ! 24: * Don't rewind on close (or on next open?). ! 25: * Timeout protection whenever sleeping on FDC interrupt. ! 26: * VTBL ! 27: * Ability to read/write DOS tapes. ! 28: * Compression. ! 29: * ioctl: get info and status ! 30: * ioctl: format ! 31: * ioctl: rewind, retension, wind to end of data ! 32: * Ioctl: mapPhysUser() for improved speed. ! 33: */ ! 34: ! 35: /* ! 36: * Here is the protocol for QIC report commands, I think: ! 37: * ! 38: * Send QIC report command to FDC (this will be an FDC seek command). ! 39: * FDC interrupts when step pulses are sent. ! 40: * Send Sense Interrupt Status to FDC. (Clears interrupt line.) ! 41: * Read interrupt status from FDC. ! 42: * - Get ACK from tape drive. Want Track 0 true. Variable latency. ! 43: * Do ! 44: * Send Sense Drive Status to FDC. ! 45: * Read drive status from FDC, including Track 0 bit. ! 46: * Until Track 0 true. ! 47: * - Get data bits for the report command. ! 48: * For number-of-data-bits-in-report times ! 49: * Send QIC Report Next Bit command to FDC. ! 50: * FDC interrupts when step pulses are sent. ! 51: * Send Sense Interrupt Status to FDC. ! 52: * Read interrupt status from FDC. ! 53: * Send Sense Drive Status to FDC. ! 54: * Read drive status from FDC, including Track 0 bit. ! 55: * Save Track 0 bit value into report data. ! 56: * End for ! 57: * - Get final Track 0 true from tape drive. ! 58: * Send QIC Report Next Bit command to FDC. ! 59: * FDC interrupts when step pulses are sent. ! 60: * Send Sense Interrupt Status to FDC. ! 61: * Read interrupt status from FDC. ! 62: * Send Sense Drive Status to FDC. ! 63: * Read drive status from FDC, including Track 0 bit. ! 64: * Track 0 bit must be true. ! 65: */ ! 66: ! 67: /* ! 68: * ---------------------------------------------------------------------- ! 69: * Includes. ! 70: */ ! 71: #include <sys/coherent.h> ! 72: ! 73: #include <errno.h> ! 74: #include <sys/buf.h> ! 75: #include <sys/con.h> ! 76: #include <sys/devices.h> ! 77: #include <sys/dmac.h> ! 78: #include <sys/fdc765.h> ! 79: #include <sys/fdioctl.h> ! 80: #include <sys/file.h> ! 81: #include <sys/sched.h> ! 82: #include <sys/stat.h> ! 83: #include <sys/xl.h> ! 84: #include <sys/xlfdc.h> ! 85: #include <sys/xlft.h> ! 86: ! 87: /* ! 88: * ---------------------------------------------------------------------- ! 89: * Definitions. ! 90: * Constants. ! 91: * Macros with argument lists. ! 92: * Typedefs. ! 93: * Enums. ! 94: */ ! 95: #define FT_MAX_NBUF 150 /* NBUF patch value is limited to this. */ ! 96: ! 97: #define FT_BFRSZ 32768 /* 32k, size of QIC-80 segment */ ! 98: #define FT_BLKSZ 1024 /* 1k, size of QIC-80 block */ ! 99: #define FT_BLK_PER_SEG 32 /* 32 blocks per segment */ ! 100: #define FT_NUM_ECC_BLKS 3 /* 3 ECC blocks per segment */ ! 101: ! 102: #define FT_ACK_TRIES 20 /* max # of tries for ACK to QIC rpt cmd*/ ! 103: #define FT_CAL_TRIES 2 /* max # of tries for seek load point */ ! 104: ! 105: #define FT_CAL_SECS 120 /* max # seconds for seek load point */ ! 106: #define FT_PAUSE_SECS 15 /* max # seconds for pause */ ! 107: #define FT_RDY_SECS 120 /* max # seconds for drive ready */ ! 108: #define FT_SEEK_SECS 15 /* max # seconds for seek head to track */ ! 109: #define FT_WIND_SECS 180 /* max # seconds for wind or rewind */ ! 110: ! 111: #define FT_INITIAL_TRACK 0 ! 112: #define FT_INITIAL_PHY_SEG 3 /* Skip 2 format headers + VTBL */ ! 113: ! 114: #define FT_OPEN_ERR(msg) {devmsg(dev,msg);goto badFtOpen;} ! 115: #define FT_READ_ERR(msg) {devmsg(dev,msg);goto badFtRead;} ! 116: ! 117: /* ! 118: * Macros to get information from tape unit number, which is 0..3. ! 119: * Unit 0 is soft select - no motor on. ! 120: * Units 1..3 are hardware select. ! 121: */ ! 122: #define FT_DRIVE(unit) (unit) ! 123: #define FT_MOTOR(unit) ((unit > 0) ? FDC_MOTOR_ON : FDC_MOTOR_OFF) ! 124: #define FT_SOFT_SELECT(unit) (unit == 0) ! 125: ! 126: /* Divide, rounding up if remainder is nonzero. */ ! 127: #define FT_DIV_RU(dividend, divisor) \ ! 128: (((dividend) + (divisor) - 1) / (divisor)) ! 129: ! 130: /* Real (tape) and pseudo (diskette) parameters for each cartridge format. */ ! 131: struct FtParm { ! 132: /* Tape parameters. */ ! 133: uint segPerTrk; ! 134: uint tracks; ! 135: ! 136: /* FDC pseudo parameters. */ ! 137: uint blkPerTrk; ! 138: uint heads; ! 139: uint cyls; ! 140: }; ! 141: ! 142: /* Driver state variables. */ ! 143: struct FT { ! 144: /* booleans */ ! 145: unchar ft_wakeMeUp; /* 1 = sleeping til next FDC IRQ */ ! 146: unchar ft_dumpIrq; /* 1 = dump IRQ status */ ! 147: unchar ft_ackNeeded; /* 1 = awaiting ACK to rpt cmd */ ! 148: unchar ft_ackMissed; /* 1 = wanted ACK, didn't get */ ! 149: unchar ft_open; /* 1 = device is open */ ! 150: unchar ft_refd; /* 1 = found reference burst */ ! 151: unchar ft_useEcc; /* 1 = Reed-Solomon enabled */ ! 152: unchar ft_useBadMap; /* 1 = use bad block map */ ! 153: ! 154: /* very short ints */ ! 155: unchar ft_pcn; /* present cylinder # */ ! 156: unchar ft_bitsNeeded; /* # of Report Next Bit's to do */ ! 157: unchar ft_bitsRcvd; /* # of report bits received */ ! 158: unchar ft_drv; /* drive number, 0..3 */ ! 159: unchar ft_fmt; /* index into ftParm */ ! 160: ! 161: unchar ft_cyl; /* cylinder FDC - C */ ! 162: unchar ft_head; /* head FDC - H */ ! 163: unchar ft_blk; /* block FDC - R */ ! 164: unchar ft_ssz; /* record size FDC - N */ ! 165: ! 166: /* short ints */ ! 167: ushort ft_report; /* where reported bits go */ ! 168: ushort ft_track; /* track for next access */ ! 169: ushort ft_phySeg; /* segment # for next access */ ! 170: ! 171: /* other structs */ ! 172: TIM ft_tim; ! 173: }; ! 174: ! 175: /* Descriptor for a run of good blocks within a single segment. */ ! 176: struct FtRun { ! 177: uint blkToRead; /* Next block wanted from current segment */ ! 178: uint blksRead; /* Number of blocks read from this seg */ ! 179: uint runLength; /* Number of good blocks in current run */ ! 180: }; ! 181: ! 182: /* ! 183: * ---------------------------------------------------------------------- ! 184: * Functions. ! 185: * Import Functions. ! 186: * Export Functions. ! 187: * Local Functions. ! 188: */ ! 189: extern int nulldev(); ! 190: extern char * getDmaMem(); ! 191: ! 192: /* CON entry points. */ ! 193: static int ftblock(); ! 194: static int ftclose(); ! 195: static int ftioctl(); ! 196: static int ftload(); ! 197: static int ftopen(); ! 198: static int ftread(); ! 199: static int ftunload(); ! 200: static int ftwrite(); ! 201: ! 202: /* Debug routines. */ ! 203: static void ftDbPrintCmd(); ! 204: static void ftDbPrintErr(); ! 205: static void ftDbPrintPos(); ! 206: static void ftDbPrintStat(); ! 207: static void ftDbPrtStat(); ! 208: ! 209: /* Support routines. */ ! 210: static int ftCmd(); ! 211: static int ftCmdArg(); ! 212: static int ftCmdSend(); ! 213: static void ftFdcPos(); ! 214: static int ftGetBlkRun(); ! 215: static void ftGetInfo(); ! 216: static void ftIrqHandler(); ! 217: static int ftReadBlkRun(); ! 218: static int ftReadBlks(); ! 219: static int ftReadID(); ! 220: static int ftReadSegs(); ! 221: static int ftReadyWait(); ! 222: static int ftRecal(); ! 223: static void ftResetFDC(); ! 224: static void ftRptBegin(); ! 225: static void ftRptUpdate(); ! 226: static int ftSeg(); ! 227: static void ftSelect(); ! 228: static int ftSkipBack(); ! 229: static int ftSkipFwd(); ! 230: static int ftStartTape(); ! 231: static int ftStopTape(); ! 232: static int ftStsWthErr(); ! 233: static int ftWait(); ! 234: ! 235: /* ! 236: * ---------------------------------------------------------------------- ! 237: * Global Data. ! 238: * Import Variables. ! 239: * Export Variables. ! 240: * Local Variables. ! 241: */ ! 242: ! 243: CON ftcon = { ! 244: DFCHR, /* Flags */ ! 245: FL_MAJOR, /* Major index */ ! 246: ftopen, /* Open */ ! 247: ftclose, /* Close */ ! 248: ftblock, /* Block */ ! 249: ftread, /* Read */ ! 250: ftwrite, /* Write */ ! 251: ftioctl, /* Ioctl */ ! 252: nulldev, /* Powerfail */ ! 253: nulldev, /* Timeout */ ! 254: ftload, /* Load */ ! 255: ftunload, /* Unload */ ! 256: nulldev /* Poll */ ! 257: }; ! 258: ! 259: /* ! 260: * Patchable values. ! 261: * ! 262: * FT_NBUF = number of 32 Kbyte segment buffers allocated. In the ! 263: * present memory model, this buffer space cannot be used for ! 264: * anything else, and is part of the "PhysMem" pool reserved at ! 265: * startup. The buffer set is attached at ftBigBuf during ftload(). ! 266: * FT_CUSHION = number of segments we try to have between current ! 267: * physical position of tape when stopped and the next segment to ! 268: * be accessed. The cushion allows time for the tape to come up to ! 269: * speed. ! 270: */ ! 271: ! 272: int FT_NBUF = 16; ! 273: int FT_CUSHION = 5; /* # of segs passed during start/stop */ ! 274: ! 275: /* Parameters for FDC Specify Command */ ! 276: int FT_SRT_2 = 0xE; ! 277: int FT_SRT_3 = 0xD; ! 278: int FT_HUT = 0xF; ! 279: int FT_HLT = 0x1; ! 280: ! 281: static struct FT ft; ! 282: static struct FtParm ftParm[] = { ! 283: /* segments/track, tracks, blocks/pseudotrack, heads, cylinders */ ! 284: { 150, 28, 128, 7, 150 }, /* QIC-80, 307.5' */ ! 285: { 100, 28, 128, 5, 150 }, /* QIC-80, 205' */ ! 286: { 102, 20, 128, 2, 255 }, /* QIC-40, 307.5' */ ! 287: { 68, 20, 128, 2, 170 } /* QIC-40, 205' */ ! 288: }; ! 289: ! 290: /* ! 291: * DMA store. ! 292: * ftBigBuf is the virtual address of an aligned, physically contiguous ! 293: * buffer area, FT_NBUF segments in length. ! 294: * ftBufBlks[s] says how many blocks (0..32) in segment s of ftBigBuf were ! 295: * successfully read. These blocks are contiguous, aligned at the start ! 296: * of segment buffer s. ! 297: * ftBadBlkCt[s] says how many blocks in segment s of ftBigBuf could not be ! 298: * read due to FDC error. This number is in the range (0..2) = ! 299: * (0..FT_NUM_ECC_BLKS). It gives a count of blocks that should have ! 300: * been read (i.e., not listed in the bad block table) and that may be ! 301: * recovered using ecc. ! 302: * ftBadBlk[s][e] is the block number in segment s where read error ! 303: * number e (0..2) occurred. ! 304: * ftSegCt is the number of segment buffers in ftBigBuf which have data. ! 305: * ftCurrentSeg is the segment number being read, < ftSegCt. ! 306: * ftOffset is byte offset within current segment for next access. ! 307: */ ! 308: static unchar * ftBigBuf; ! 309: static unchar ftBufBlks[FT_MAX_NBUF]; ! 310: static unchar ftBadBlkCt[FT_MAX_NBUF]; ! 311: static unchar ftBadBlk[FT_MAX_NBUF][FT_NUM_ECC_BLKS]; ! 312: static int ftSegCt; ! 313: static int ftCurrentSeg; ! 314: static int ftOffset; ! 315: ! 316: /* Strings where multibyte FDC commands are built. */ ! 317: ! 318: unchar rwCmd[] = { ! 319: 0x46, /* FDC read, skip deleted data, MFM. */ ! 320: 0, /* Head 0, unit 0. */ ! 321: 0, /* C = FDC cylinder */ ! 322: 0, /* H = FDC head */ ! 323: 1, /* R = FDC block number (1-based) */ ! 324: 3, /* N = block length (3 = 1024 bytes) */ ! 325: 226, /* EOT = last block number on cylinder */ ! 326: 1, /* GPL = number of bytes in gap 3 */ ! 327: 255 /* DTL, use 0xFF when N != 0 */ ! 328: }; ! 329: ! 330: /* Read/write command bytes. */ ! 331: enum { ! 332: RW_CMD_RD = 0x46, ! 333: RW_CMD_WR = 0x45 ! 334: }; ! 335: ! 336: /* Offsets into rwCmd. */ ! 337: enum { ! 338: RW_CMD_VERB = 0, ! 339: RW_CMD_UNIT = 1, ! 340: RW_CMD_CYL = 2, ! 341: RW_CMD_HEAD = 3, ! 342: RW_CMD_SCTR = 4, ! 343: RW_CMD_SCSZ = 5, /* encoded block length */ ! 344: RW_CMD_SCHI = 6, /* high block number */ ! 345: RW_CMD_GPL = 7, ! 346: RW_CMD_DTL = 8, ! 347: RW_CMD_LEN = 9 ! 348: }; ! 349: ! 350: /* ! 351: * ---------------------------------------------------------------------- ! 352: * Code. ! 353: */ ! 354: ! 355: /* ! 356: * CON struct routines. ! 357: */ ! 358: ! 359: /************************************************************************ ! 360: * ftblock ! 361: * ! 362: * Tape is not a block device, but we need a block entry point since ! 363: * the same driver controls diskette access. ! 364: ***********************************************************************/ ! 365: static int ! 366: ftblock(bp) ! 367: BUF *bp; ! 368: { ! 369: u.u_error = EIO; ! 370: bp->b_flag |= BFERR; ! 371: bdone(bp); ! 372: return; ! 373: } ! 374: ! 375: /************************************************************************ ! 376: * ftclose ! 377: * ! 378: ***********************************************************************/ ! 379: static int ! 380: ftclose(dev, mode) ! 381: dev_t dev; ! 382: int mode; ! 383: { ! 384: printf("ftclose "); ! 385: ! 386: setFtIntr(1); ! 387: if (FT_SOFT_SELECT(ft.ft_drv)) ! 388: ftCmd(QIC_CMD_SS_OFF); ! 389: ! 390: ft.ft_open = 0; ! 391: setFtIntr(0); ! 392: } ! 393: ! 394: /************************************************************************* ! 395: * ftioctl ! 396: * Handle tape drive & controller commands like erase, rewind, ! 397: * retension, read filemark, and write filemark ! 398: ************************************************************************/ ! 399: ftioctl(dev, cmd, arg) ! 400: register int dev, cmd; ! 401: int arg; ! 402: { ! 403: } ! 404: ! 405: /************************************************************************* ! 406: * ftload ! 407: ************************************************************************/ ! 408: static int ! 409: ftload() ! 410: { ! 411: uint bigBufLen; ! 412: ! 413: if (FT_NBUF > FT_MAX_NBUF) ! 414: FT_NBUF = FT_MAX_NBUF; ! 415: ! 416: bigBufLen = FT_NBUF * FT_BFRSZ; ! 417: ftIntr = ftIrqHandler; ! 418: if ((ftBigBuf = getDmaMem(bigBufLen, FT_BFRSZ)) == NULL) ! 419: printf("ERROR - can't allocate %d bytes for ft buffers\n", ! 420: bigBufLen); ! 421: } ! 422: ! 423: /************************************************************************ ! 424: * ftopen ! 425: * ! 426: ***********************************************************************/ ! 427: static int ! 428: ftopen(dev, mode) ! 429: dev_t dev; ! 430: int mode; ! 431: { ! 432: unsigned int drvStat; ! 433: int i; ! 434: int bit; ! 435: int result; ! 436: int notReady; ! 437: int drvStatus; ! 438: int putCount; ! 439: ! 440: /* Couldn't allocate buffer area. */ ! 441: if (ftBigBuf == NULL) { ! 442: devmsg(dev, "no buffers "); ! 443: u.u_error = EIO; ! 444: return; ! 445: } ! 446: ! 447: /* Can't append to tape. */ ! 448: if (mode & IPAPPEND) { ! 449: devmsg(dev, "can't append "); ! 450: u.u_error = EINVAL; ! 451: return; ! 452: } ! 453: ! 454: /* Only one open at a time. */ ! 455: if (ft.ft_open) { ! 456: devmsg(dev, "only one ftopen at a time "); ! 457: u.u_error = EBUSY; ! 458: return; ! 459: } ! 460: ft.ft_open = 1; ! 461: ! 462: ft.ft_drv = FT_UNIT(dev); ! 463: ! 464: if (!setFtIntr(1)) ! 465: FT_OPEN_ERR("fdc unavailable "); ! 466: ! 467: ftIntr = ftIrqHandler; ! 468: ! 469: /* Select tape drive. */ ! 470: ftSelect(ft.ft_drv); ! 471: ! 472: if (ftCmd(QIC_CMD_RST)) ! 473: FT_OPEN_ERR("soft reset failed "); ! 474: ! 475: /* Need to wait a second after QIC software reset. */ ! 476: ftWait(HZ); ! 477: ! 478: /* Re-Select tape drive (reset clears soft select). */ ! 479: ftSelect(ft.ft_drv); ! 480: ! 481: /* HERE is the test for tape drive present. */ ! 482: drvStatus = ftStsWthErr(); ! 483: if (drvStatus == -1) ! 484: FT_OPEN_ERR("get drive status failed "); ! 485: ! 486: /* Wait for drive to be ready, or give up. */ ! 487: if(ftReadyWait(FT_RDY_SECS)) ! 488: FT_OPEN_ERR("Tape Drive Not Ready"); ! 489: ! 490: /* Need Cartridge Present to be true. */ ! 491: if ((ft.ft_report & QIC_STAT_PRSNT) == 0) ! 492: FT_OPEN_ERR("No Cartridge"); ! 493: ! 494: /* Initialize state variables & such. */ ! 495: ft.ft_refd = 0; ! 496: ft.ft_fmt = 0; /* 307.5' QIC-80 */ ! 497: ft.ft_useEcc = 0; /* No ECC. Yet. */ ! 498: ft.ft_useBadMap = 0; /* No bad block map use. Yet. */ ! 499: ! 500: /* Wrap-up. */ ! 501: fdcSpecify(FT_SRT_3, FT_HUT, FT_HLT); ! 502: setFtIntr(0); ! 503: return; ! 504: ! 505: /* Error exit. */ ! 506: badFtOpen: ! 507: ! 508: u.u_error = EIO; ! 509: ft.ft_open = 0; ! 510: fdcSpecify(FT_SRT_3, FT_HUT, FT_HLT); ! 511: fdcDrvSelect(0, FDC_MOTOR_OFF); ! 512: if (FT_SOFT_SELECT(ft.ft_drv)) ! 513: ftCmd(QIC_CMD_SS_OFF); ! 514: setFtIntr(0); ! 515: return; ! 516: } ! 517: ! 518: /************************************************************************ ! 519: * ftread ! 520: * ! 521: * if tape not referenced ! 522: * seek load point ! 523: * wait for ready ! 524: * if tape still not referenced ! 525: * abort read - tape not formatted ! 526: * set next access to track 0, segment 3 ! 527: * while more data is to be read ! 528: * read as much as possible into DMA buffer area ! 529: * abort in case of read error ! 530: * iowrite() - copy DMA buffers into user space ! 531: ***********************************************************************/ ! 532: static int ! 533: ftread(dev, iop) ! 534: dev_t dev; ! 535: IO * iop; ! 536: { ! 537: #if 0 ! 538: unchar drvStatus; ! 539: uint calTries; ! 540: int segsWanted; ! 541: unchar * bufPtr; ! 542: int i; ! 543: int bytesInBuffer; ! 544: int dataBlksPerSeg; ! 545: int dataBytesPerSeg; ! 546: ! 547: /* Has reference burst been seen? */ ! 548: drvStatus = ftStsWthErr(); ! 549: if (drvStatus == -1) ! 550: FT_READ_ERR("get drive status failed "); ! 551: ! 552: /* ! 553: * If not, look for reference burst now. ! 554: * If this fails, it's probably due to unformatted tape. ! 555: */ ! 556: if ((drvStatus & QIC_STAT_REFD) == 0) { ! 557: ftCmd(QIC_CMD_CAL); ! 558: if (ftReadyWait(FT_CAL_SECS)) ! 559: FT_READ_ERR("seek load point failed"); ! 560: ! 561: /* Again, has reference burst been seen? */ ! 562: drvStatus = ftStsWthErr(); ! 563: if (drvStatus == -1) ! 564: FT_READ_ERR("get drive status failed "); ! 565: ! 566: if ((drvStatus & QIC_STAT_REFD) == 0) ! 567: FT_READ_ERR("seek load point failed"); ! 568: ! 569: /* Initialize access coordinates for next read. */ ! 570: ft.ft_track = FT_INITIAL_TRACK; ! 571: ft.ft_phySeg = FT_INITIAL_PHY_SEG; ! 572: } ! 573: ! 574: /* ! 575: * Compute expected number of data blocks, and bytes, in a segment. ! 576: * This is an estimate, as it does not consider bad blocks that are ! 577: * mapped out. ! 578: */ ! 579: dataBlksPerSeg = FT_BLK_PER_SEG; ! 580: if (ft.ft_useEcc) ! 581: dataBlksPerSeg -= FT_NUM_ECC_BLKS; ! 582: dataBytesPerSeg = dataBlksPerSeg * FT_BLKSZ; ! 583: ! 584: /* ! 585: * While there is input needed ! 586: * If DMA buffer is used up ! 587: * Load DMA buffer area from tape. ! 588: * Update DMA buffer stats: ! 589: * Number of valid segments = number of segments read ! 590: * Current segment and current offset both = 0 ! 591: * Transfer data: ! 592: * Source is DMA buffer, current segment and offset. ! 593: * Destination is IO struct. ! 594: * Update DMA buffer current segment and offset. ! 595: */ ! 596: while (iop->io_ioc) { ! 597: ! 598: /* Do we need to fill DMA buffer from tape? */ ! 599: if (ftCurrentSeg >= ftSegCt) { ! 600: ! 601: /* Estimate how many segments will need to be read. */ ! 602: segsWanted = FT_DIV_RU(iop->io_ioc, dataBytesPerSeg); ! 603: ! 604: /* Try to fill DMA buffer area. */ ! 605: ftSegCt = ftReadSegs(segsWanted); ! 606: ! 607: /* Update current DMA data pointer. */ ! 608: ftCurrentSeg = 0; ! 609: ftOffset = 0; ! 610: ! 611: /* Abort read if something went wrong. */ ! 612: if (ftSegCt == -1) ! 613: FT_READ_ERR("ftBufRead failed"); ! 614: ! 615: /* Terminate read if at end of tape. */ ! 616: if (ftSegCt == 0) ! 617: break; ! 618: ! 619: /* HERE is where ecc will be done. */ ! 620: /* This will involve decrementing ftBufBlks[?] by 3. */ ! 621: } ! 622: ! 623: XXX ! 624: /* Transfer data from DMA buffer to IO area. */ ! 625: while ! 626: for (i = 0, bufPtr = ftCurrentSeg; ! 627: bufPtr += FT_BFRSZ, i < ftSegCt; i++) { ! 628: ! 629: bytesInBuffer = ftBufBlks[i] * FT_BLKSZ; ! 630: if (bytesInBuffer != 0) { ! 631: ! 632: int transferCount = iop->io_ioc; ! 633: ! 634: if (transferCount > bytesInBuffer) ! 635: transferCount = bytesInBuffer; ! 636: ! 637: /* May transfer less than a segment. */ ! 638: if (bytesInBuffer > iop->io_ioc) ! 639: bytesInBuffer = iop->io_ioc; ! 640: iowrite(iop, bufPtr, bytesInBuffer); ! 641: } ! 642: } ! 643: } ! 644: ! 645: return; ! 646: ! 647: badFtRead: ! 648: SET_U_ERROR(EIO, "ftread"); ! 649: return; ! 650: #endif ! 651: } ! 652: ! 653: /************************************************************************ ! 654: * ftunload ! 655: * ! 656: ***********************************************************************/ ! 657: static int ! 658: ftunload() ! 659: { ! 660: } ! 661: ! 662: /************************************************************************ ! 663: * ftwrite ! 664: * ! 665: ***********************************************************************/ ! 666: static int ! 667: ftwrite(dev, iop) ! 668: dev_t dev; ! 669: IO * iop; ! 670: { ! 671: if (!ft.ft_open) { /* exit if not open */ ! 672: u.u_error = EIO; ! 673: return; ! 674: } ! 675: } ! 676: ! 677: /********************* ! 678: ********************** ! 679: ** ! 680: ** Support routines. ! 681: ** ! 682: ********************** ! 683: **********************/ ! 684: ! 685: /************************************************************************ ! 686: * ftCmd ! 687: * ! 688: * Given a QIC-117 command number, send the command. ! 689: * If report bits are expected in response, initialize the bit counter. ! 690: * Then sleep until the commmand is done and report bits are gathered. ! 691: ***********************************************************************/ ! 692: static int ! 693: ftCmd(cmd) ! 694: int cmd; ! 695: { ! 696: int bitsNeeded; ! 697: ! 698: if (cmd != QIC_CMD_STS) ! 699: printf("[%d]", cmd); ! 700: ! 701: /* Will sleep until command done and report bits are in. */ ! 702: ft.ft_wakeMeUp = 1; ! 703: ! 704: /* ! 705: * The following commands expect report bits from the tape drive. ! 706: * After receiving the QIC command (and subsequent delay), ! 707: * the drive sends a leading ACK bit (always 1). This bit is ! 708: * not counted in the numbers below. ! 709: * Subseqeunt bits are sent in response to Report Next Bit, ! 710: * least significant bit first, then a trailing 1. ! 711: * The value of bitsNeeded is either one more than the number of ! 712: * data bits in the report, or zero. ! 713: ! 714: */ ! 715: switch(cmd) { ! 716: case QIC_CMD_STS: ! 717: case QIC_CMD_DRVCN: ! 718: case QIC_CMD_ROMVN: ! 719: case QIC_CMD_TPSTAT: ! 720: bitsNeeded = 9; ! 721: break; ! 722: case QIC_CMD_ECD: ! 723: case QIC_CMD_VNDID: ! 724: bitsNeeded = 17; ! 725: break; ! 726: default: ! 727: bitsNeeded = 0; ! 728: } ! 729: ftRptBegin(bitsNeeded); ! 730: ft.ft_ackMissed = 0; ! 731: ! 732: ftCmdSend(cmd); ! 733: ! 734: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftCmd")) { ! 735: if (FT_BLAB) ! 736: printf("sig to cmd %d ", cmd); ! 737: /* Signal woke us prematurely. */ ! 738: return -1; ! 739: } else if (ft.ft_ackMissed) { ! 740: if (FT_BLAB) ! 741: printf(" Ack missed "); ! 742: ft.ft_ackMissed = 0; ! 743: return -1; ! 744: } else ! 745: return 0; ! 746: } ! 747: ! 748: /************************************************************************ ! 749: * ftCmdArg ! 750: * ! 751: * Like ftCmd, except this routine sends command arguments. ! 752: * No setup for report next bit. ! 753: * Different debug print handling. ! 754: ***********************************************************************/ ! 755: static int ! 756: ftCmdArg(arg) ! 757: int arg; ! 758: { ! 759: int bitsNeeded; ! 760: ! 761: printf("(%d)", arg); ! 762: ! 763: /* Will sleep until stepper pulses sent. */ ! 764: ft.ft_wakeMeUp = 1; ! 765: ! 766: bitsNeeded = 0; ! 767: ftRptBegin(bitsNeeded); ! 768: ft.ft_ackMissed = 0; ! 769: ! 770: ftCmdSend(arg); ! 771: ! 772: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftArg")) { ! 773: ! 774: /* Signal woke us prematurely. */ ! 775: printf("sig to arg %d ", arg); ! 776: ! 777: return -1; ! 778: } else ! 779: return 0; ! 780: } ! 781: ! 782: /************************************************************************ ! 783: * ftCmdSend ! 784: * ! 785: * Given a QIC-117 command number, cause that number of step pulses ! 786: * to be sent from the FDC by faking a seek command. ! 787: ***********************************************************************/ ! 788: static int ! 789: ftCmdSend(cmd) ! 790: int cmd; ! 791: { ! 792: /* ncn = new cylinder #. */ ! 793: unsigned char ncn; ! 794: ! 795: /* ! 796: * Will fake a seek command. ! 797: * Figure out whether to simulate seek to lower or higher ! 798: * cylinder number. ! 799: */ ! 800: if (ft.ft_pcn >= cmd) ! 801: ncn = ft.ft_pcn - cmd; ! 802: else ! 803: ncn = ft.ft_pcn + cmd; ! 804: ! 805: fdcSeek(ft.ft_drv, 0, ncn); ! 806: } ! 807: ! 808: /************************************************************************ ! 809: * ftFdcPos() ! 810: * ! 811: * Given track relative segment within the tape track, and relative block ! 812: * within the segment, store C/H/R (cylinder/head/record) diskette pseudo ! 813: * coordinates into 3-element unchar array given. ! 814: ***********************************************************************/ ! 815: static void ! 816: ftFdcPos(track, segment, block, cmdTbl) ! 817: int track, segment; ! 818: unchar * cmdTbl; ! 819: { ! 820: } ! 821: ! 822: /************************************************************************ ! 823: * ftGetBlkRun() ! 824: * ! 825: * Given the next block desired from the current segment, get starting ! 826: * block number and number of blocks in next run of consecutive good ! 827: * blocks. ! 828: * This routine checks the bad block map for the cartridge, if this ! 829: * feature is enabled. ! 830: * We are at a lower level than ecc, so all 32 blocks in a segment are ! 831: * considered. Ecc, if enabled, will be applied to the results of ! 832: * run-level processing. ! 833: * Return 0 if a run can be found, -1 if no further run of good blocks ! 834: * exists in the current segment. ! 835: ***********************************************************************/ ! 836: static int ! 837: ftGetBlkRun(ftrp) ! 838: struct FtRun * ftrp; ! 839: { ! 840: int retval; ! 841: ! 842: if (ft.ft_useBadMap) { ! 843: printf("Bad block map not enabled yet.\n"); ! 844: /* Will modify blkToRead and runLength fields here. */ ! 845: retval = -1; ! 846: } else { ! 847: if (ftrp->blkToRead < FT_BLK_PER_SEG) { ! 848: ftrp->runLength = FT_BLK_PER_SEG - ftrp->blkToRead; ! 849: retval = -1; ! 850: } else ! 851: retval = 0; ! 852: } ! 853: return retval; ! 854: } ! 855: ! 856: /************************************************************************ ! 857: * ftGetInfo ! 858: * ! 859: * Issue several QIC report commands - all but Report Drive Status ! 860: * and Report Error Code. ! 861: ***********************************************************************/ ! 862: static void ! 863: ftGetInfo(dev) ! 864: dev_t dev; ! 865: { ! 866: if (ftCmd(QIC_CMD_DRVCN)) ! 867: devmsg(dev, "Warning: get drive configuration failed"); ! 868: else ! 869: devmsg(dev, "Drive Configuration = %x", ft.ft_report); ! 870: ! 871: if (ftCmd(QIC_CMD_ROMVN)) ! 872: devmsg(dev, "Warning: get ROM version failed"); ! 873: else ! 874: devmsg(dev, "Rom Version = 0x%x", ft.ft_report); ! 875: ! 876: if (ftCmd(QIC_CMD_VNDID)) ! 877: devmsg(dev, "Warning: get vendor ID failed"); ! 878: else ! 879: devmsg(dev, "Vendor ID = 0x%x", ft.ft_report); ! 880: ! 881: if (ftCmd(QIC_CMD_TPSTAT)) ! 882: devmsg(dev, "Warning: get tape status failed"); ! 883: else ! 884: devmsg(dev, "Tape Status = 0x%x", ft.ft_report); ! 885: } ! 886: ! 887: /************************************************************************ ! 888: * ftIrqHandler ! 889: * ! 890: * Interrupt handler. ! 891: ***********************************************************************/ ! 892: static void ! 893: ftIrqHandler() ! 894: { ! 895: int i, bit; ! 896: ! 897: /* ! 898: * Need to get FDC status from result phase - fdcCmdStatus - ! 899: * or clear interrupt - fdcIntStatus - that may have been ! 900: * generated by diskette change or seek/recal complete. ! 901: */ ! 902: if (FDC_BUSY()) { ! 903: fdcCmdStatus(); ! 904: } else { ! 905: fdcIntStatus(); ! 906: /* WARNING - should squawk if wrong number of status bytes. */ ! 907: ft.ft_pcn = fdc.fdc_intstat[1]; ! 908: } ! 909: ! 910: /* If ACK needed, try several times to get it. */ ! 911: if (ft.ft_ackNeeded) { ! 912: for (i = 0; i < FT_ACK_TRIES; i++) { ! 913: fdcDrvStatus(ft.ft_drv, FDC_HEAD_0); ! 914: fdcCmdStatus(); ! 915: bit = (fdc.fdc_cmdstat[0] & ST3_T0) ? 1 : 0; ! 916: if (FT_ACKBLAB) ! 917: putchar(bit?'|':'o'); ! 918: if (bit) { ! 919: ft.ft_ackNeeded = 0; ! 920: break; ! 921: } ! 922: /* Wait about 20 usec. then try again. */ ! 923: busyWait2(NULL, 20); ! 924: } ! 925: ! 926: /* ! 927: * Tape Drive did not send ACK in response to QIC ! 928: * Report command. Probably the command is not ! 929: * supported by this drive, or there is no drive ! 930: * present. Set ackMissed flag and clean up. ! 931: */ ! 932: if (ft.ft_ackNeeded) { ! 933: ft.ft_ackNeeded = 0; ! 934: ft.ft_ackMissed = 1; ! 935: ft.ft_bitsNeeded = 0; ! 936: if (ft.ft_wakeMeUp) { ! 937: ft.ft_wakeMeUp = 0; ! 938: wakeup(&ft.ft_wakeMeUp); ! 939: } ! 940: } ! 941: } else if (ft.ft_bitsNeeded) { ! 942: ! 943: /* Report bits are needed. Get ST3. */ ! 944: fdcDrvStatus(ft.ft_drv, FDC_HEAD_0); ! 945: fdcCmdStatus(); ! 946: ! 947: /* Get next report bit by checking Track Zero bit in ST3 */ ! 948: if (fdc.fdc_ncmdstat == 1) { ! 949: int bit; ! 950: ! 951: bit = (fdc.fdc_cmdstat[0] & ST3_T0) ? 1 : 0; ! 952: ftRptUpdate(bit); ! 953: } else { ! 954: printf("rnb status bad "); ! 955: } ! 956: } ! 957: ! 958: /* ! 959: * If more report bits will be needed ! 960: * Send request for next bit. ! 961: * Else ! 962: * See if original requestor needs wakeup, etc. ! 963: */ ! 964: if (ft.ft_bitsNeeded) { ! 965: ftCmdSend(QIC_CMD_RNB); ! 966: } else { ! 967: if (ft.ft_wakeMeUp) { ! 968: ft.ft_wakeMeUp = 0; ! 969: wakeup(&ft.ft_wakeMeUp); ! 970: } ! 971: ! 972: /* Print debug output if needed. */ ! 973: if (ft.ft_dumpIrq) { ! 974: ft.ft_dumpIrq = 0; ! 975: defer(ftDbPrtStat); ! 976: } ! 977: } ! 978: } ! 979: ! 980: /*********************************************************************** ! 981: * ftRead1Seg ! 982: * ! 983: * Given buffer number (0..FT_NBUF-1), try to read the next segment ! 984: * into that segment buffer in ftBigBuf DMA area. ! 985: * Set ftBufBlks[bufn] to the number of blocks not marked bad. ! 986: * Valid blocks are deposited contiguously starting at the beginning of ! 987: * segment buffer[bufn]. ! 988: * ! 989: * Tape should be in properly positioned and in motion when this ! 990: * function is called. ! 991: * ! 992: * Initialize number of blocks read to 0, in local counter and in buffer ! 993: * table. ! 994: * Initialize number of next tape block (relative to start of segment) ! 995: * to read to 0. ! 996: * Loop ! 997: * Check bad block map (if using bad block map) to find the next run ! 998: * of readable blocks, if any, in the current segment. ! 999: * If there are no further runs of good blocks in the current segment ! 1000: * Exit loop. ! 1001: * Try to read the next run of blocks. ! 1002: * If successful, this will: ! 1003: * Increment number of blocks read by length of current run. ! 1004: * Update the number of the next block to read. ! 1005: * If too many read failures (> 3 if ecc, > 0 if no ecc) ! 1006: * Return -1 (segment read failed). ! 1007: * Endloop ! 1008: * ! 1009: * Store number of blocks read into ftBufBlks table. ! 1010: * Update current segment and track numbers. (Advance to next segment.) ! 1011: * Return 0 (success). ! 1012: ***********************************************************************/ ! 1013: static int ! 1014: ftRead1Seg(bufn) ! 1015: uint bufn; ! 1016: { ! 1017: struct FtRun ftRun; ! 1018: struct FtParm *fp; ! 1019: ! 1020: /* Get parameter set pointer. */ ! 1021: fp = ftParm + ft.ft_fmt; ! 1022: ! 1023: ftBufBlks[bufn] = 0; ! 1024: ftRun.blksRead = 0; ! 1025: ! 1026: ftRun.blkToRead = 0; ! 1027: ! 1028: for (;;) { ! 1029: if (ftGetBlkRun(&ftRun)) ! 1030: break; ! 1031: if (ftReadBlkRun(&ftRun, bufn)) ! 1032: return -1; ! 1033: } ! 1034: ! 1035: ftBufBlks[bufn] = ftRun.blksRead; ! 1036: ! 1037: ft.ft_phySeg++; ! 1038: if (ft.ft_phySeg == fp->segPerTrk ! 1039: && ft.ft_track <= (fp->tracks - 1)) { ! 1040: ft.ft_track++; ! 1041: ft.ft_phySeg = 0; ! 1042: } ! 1043: ! 1044: return 0; ! 1045: } ! 1046: ! 1047: /*********************************************************************** ! 1048: * ftReadID ! 1049: * ! 1050: * Send FDC Read ID command and store results in ft context. ! 1051: * Return 0 on success, -1 on failure (signal). ! 1052: * ! 1053: * Of principal interest is fdc.fdc_cmdstat[5] - present block number. ! 1054: ***********************************************************************/ ! 1055: static int ! 1056: ftReadID() ! 1057: { ! 1058: ft.ft_wakeMeUp = 1; ! 1059: fdcReadID(ft.ft_drv, 0); ! 1060: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftReadID")) ! 1061: return -1; ! 1062: else { ! 1063: if (fdc.fdc_ncmdstat != 7) { ! 1064: printf("ftReadID bad command status: %d", ! 1065: fdc.fdc_ncmdstat); ! 1066: return -1; ! 1067: } else { ! 1068: ft.ft_cyl = fdc.fdc_cmdstat[3]; ! 1069: ft.ft_head = fdc.fdc_cmdstat[4]; ! 1070: ft.ft_blk = fdc.fdc_cmdstat[5]; ! 1071: ft.ft_ssz = fdc.fdc_cmdstat[6]; ! 1072: } ! 1073: return 0; ! 1074: } ! 1075: } ! 1076: ! 1077: /*********************************************************************** ! 1078: * ftReadSegs() ! 1079: * ! 1080: * Given a segment count, try to read the given number of segments from ! 1081: * the curent track. ! 1082: * Return the number of segments read (0 if at end of tape), -1 if failure. ! 1083: * ! 1084: * Reading a segment may yield from 0 to 32 blocks, depending on how ! 1085: * many bad blocks are marked in the segment and whether ecc is used. ! 1086: ***********************************************************************/ ! 1087: static int ! 1088: ftReadSegs(segsWanted) ! 1089: uint segsWanted; ! 1090: { ! 1091: int segsOnTrack; ! 1092: int segsRead; ! 1093: struct FtParm *fp; ! 1094: ! 1095: /* Get parameter set pointer. */ ! 1096: fp = ftParm + ft.ft_fmt; ! 1097: ! 1098: /* ! 1099: * Calculate how many segments are left on the current track. ! 1100: * If no segments left on current track ! 1101: * Return no segments read. ! 1102: */ ! 1103: segsOnTrack = fp->segPerTrk - ft.ft_phySeg; ! 1104: if (segsOnTrack == 0) ! 1105: return 0; ! 1106: ! 1107: /* ! 1108: * Will do a multisegment read. ! 1109: * Requested number of segments will be the least of: ! 1110: * - number of segments wanted ! 1111: * - number of segments there is room for in DMA area ! 1112: * - number of segments remaining on current tape track ! 1113: */ ! 1114: if (segsWanted > FT_NBUF) ! 1115: segsWanted = FT_NBUF; ! 1116: if (segsWanted > segsOnTrack) ! 1117: segsWanted = segsOnTrack; ! 1118: ! 1119: /* ! 1120: * Try to position and start tape. ! 1121: * Read as many segments as possible. ! 1122: * If there is an irrecoverable read error ! 1123: * Abort multisegment read. ! 1124: * Stop tape. ! 1125: */ ! 1126: if (ftStartTape()) ! 1127: return -1; ! 1128: for (segsRead = 0; segsRead < segsWanted; segsRead++) { ! 1129: if (ftRead1Seg(segsRead)) { ! 1130: segsRead = -1; ! 1131: break; ! 1132: } ! 1133: } ! 1134: ftStopTape(); ! 1135: ! 1136: /* Return the number of segments successfully read. */ ! 1137: return segsRead; ! 1138: } ! 1139: ! 1140: /*********************************************************************** ! 1141: * ftReadyWait ! 1142: * ! 1143: * Keep checking drive status every second until drive is ready or ! 1144: * the specified number of seconds has elapsed. ! 1145: * Return 0 if drive ready, -1 if timeout or signal or protocol failure. ! 1146: ***********************************************************************/ ! 1147: static int ! 1148: ftReadyWait(seconds) ! 1149: uint seconds; ! 1150: { ! 1151: uint i; ! 1152: int retval = -1; ! 1153: int drvStatus; ! 1154: ! 1155: for (i = 0; i < seconds; i++) { ! 1156: drvStatus = ftStsWthErr(); ! 1157: ! 1158: /* Protocol failure? */ ! 1159: if (drvStatus == -1) ! 1160: break; ! 1161: ! 1162: /* Drive ready? Change return value to show success. */ ! 1163: if (drvStatus & QIC_STAT_RDY) { ! 1164: retval = 0; ! 1165: break; ! 1166: } ! 1167: ! 1168: /* Signal arrived while waiting a second? */ ! 1169: if (ftWait(HZ)) ! 1170: break; ! 1171: } ! 1172: ! 1173: return retval; ! 1174: } ! 1175: ! 1176: /************************************************************************ ! 1177: * ftRecal ! 1178: * ! 1179: * Send Recalibrate command to FDC and wait for it to finish. ! 1180: * Return 0 if normal operation, -1 if signaled before recal complete. ! 1181: ***********************************************************************/ ! 1182: static int ! 1183: ftRecal() ! 1184: { ! 1185: ft.ft_wakeMeUp = 1; ! 1186: fdcRecal(ft.ft_drv); ! 1187: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRecal")) ! 1188: return -1; ! 1189: else ! 1190: return 0; ! 1191: } ! 1192: ! 1193: /************************************************************************ ! 1194: * ftResetFDC ! 1195: * ! 1196: * Reset the FDC and wait for the resulting interrupt. ! 1197: * Reset is done keeping the current unit selected. ! 1198: ***********************************************************************/ ! 1199: static void ! 1200: ftResetFDC() ! 1201: { ! 1202: /* ! 1203: * Since FDC reset generates an interrupt, we need to tell the ! 1204: * interrupt handler there will be *no* report bits incoming. ! 1205: */ ! 1206: ftRptBegin(0); ! 1207: ! 1208: ft.ft_pcn = 0; ! 1209: ft.ft_wakeMeUp = 1; ! 1210: fdcResetSel(FT_DRIVE(ft.ft_drv), FT_MOTOR(ft.ft_drv)); ! 1211: x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRstFDC"); ! 1212: } ! 1213: ! 1214: /************************************************************************ ! 1215: * ftRptBegin ! 1216: * ! 1217: * Initialize ft state information in preparation for QIC report command. ! 1218: * ! 1219: * Argument "bitCount" is the total number of bits expected, including ! 1220: * initial ACK and final TRUE. It is 1 more than the number of ! 1221: * Report Next Bit Commands that will be issued. ! 1222: ***********************************************************************/ ! 1223: static void ! 1224: ftRptBegin(bitCount) ! 1225: int bitCount; ! 1226: { ! 1227: ft.ft_bitsNeeded = bitCount; ! 1228: ft.ft_bitsRcvd = 0; ! 1229: ft.ft_report = 0; ! 1230: ft.ft_ackNeeded = (bitCount) ? 1 : 0; ! 1231: } ! 1232: ! 1233: /************************************************************************ ! 1234: * ftSeg() ! 1235: * ! 1236: * Given pseudo cylinder, head, and block numbers from FDC, ! 1237: * calculate the segment number relative to start of current track. ! 1238: ***********************************************************************/ ! 1239: static int ! 1240: ftSeg(c, h, r) ! 1241: int c, h, r; ! 1242: { ! 1243: int lsn; /* Logical block (not segment) number. */ ! 1244: int seg; ! 1245: struct FtParm *fp; ! 1246: ! 1247: /* Get parameter set pointer. */ ! 1248: fp = ftParm + ft.ft_fmt; ! 1249: ! 1250: /* Compute logical block number. */ ! 1251: lsn = (r - 1) + c * fp->blkPerTrk + h * fp->blkPerTrk * fp->cyls; ! 1252: ! 1253: /* Divide with truncation to get containing segment number. */ ! 1254: seg = lsn / FT_BLK_PER_SEG; ! 1255: ! 1256: /* Compute segment number relative to start of track. */ ! 1257: seg %= fp->segPerTrk; ! 1258: ! 1259: return seg; ! 1260: } ! 1261: ! 1262: /************************************************************************ ! 1263: * ftRptUpdate ! 1264: * ! 1265: * Acquire another bit for QIC report command. ! 1266: * Last bit is discarded. Other bits are accumulated, ! 1267: * least significant bit first, into ft_report. ! 1268: ***********************************************************************/ ! 1269: static void ! 1270: ftRptUpdate(bit) ! 1271: int bit; ! 1272: { ! 1273: ft.ft_bitsNeeded--; ! 1274: ft.ft_bitsRcvd++; ! 1275: ! 1276: if (ft.ft_bitsNeeded == 0) { ! 1277: if (bit != 1) ! 1278: printf("Missing final TRUE "); ! 1279: } else { ! 1280: ft.ft_report |= (bit << (ft.ft_bitsRcvd - 1)); ! 1281: } ! 1282: } ! 1283: ! 1284: /************************************************************************ ! 1285: * ftSelect ! 1286: * ! 1287: * Select tape unit. ! 1288: ***********************************************************************/ ! 1289: static void ! 1290: ftSelect() ! 1291: { ! 1292: fdcRate(FDC_RATE_500K); ! 1293: fdcDrvSelect(FT_DRIVE(ft.ft_drv), FT_MOTOR(ft.ft_drv)); ! 1294: ! 1295: /* Reset FDC and Initialize pseudo cylinder number for QIC commands. */ ! 1296: ftResetFDC(ft.ft_drv); ! 1297: ! 1298: fdcSpecify(FT_SRT_2, FT_HUT, FT_HLT); ! 1299: ! 1300: if (FT_SOFT_SELECT(ft.ft_drv)) { ! 1301: ftCmd(77); ! 1302: ftWait(2); ! 1303: ftCmd(QIC_CMD_SS1); ! 1304: ftWait(2); ! 1305: ftCmd(QIC_CMD_SS2); ! 1306: ftWait(2); ! 1307: } ! 1308: ! 1309: #if 0 ! 1310: /* 80 MB nseg_p_track = 100, nseg_p_head = 600, nseg_p_cyl = 4 */ ! 1311: /* 40 MB nseg_p_track = 68, nseg_p_head = 680, nseg_p_cyl = 4 */ ! 1312: if (ftfmt) { ! 1313: nseg_p_track = 100; /* set for 80 MB drive */ ! 1314: nseg_p_head = 600; ! 1315: nseg_p_cyl = 4; ! 1316: } else { ! 1317: nseg_p_track = 68; /* set for 40 MB drive */ ! 1318: nseg_p_head = 680; ! 1319: nseg_p_cyl = 4; ! 1320: } ! 1321: #endif ! 1322: } ! 1323: ! 1324: /************************************************************************ ! 1325: * ftSkipBack() ! 1326: * ! 1327: * Skip segments in logical backward direction. ! 1328: * Return 0 on success, -1 on failure. ! 1329: ***********************************************************************/ ! 1330: static int ! 1331: ftSkipBack(segCount) ! 1332: uint segCount; ! 1333: { ! 1334: /* If possible, use short (non-extended) form of skip command. */ ! 1335: if ((segCount & ~0xFF) == 0) { ! 1336: if (ftCmd(QIC_CMD_SKPB)) ! 1337: return -1; ! 1338: ftCmdArg((segCount & 0xF) +2); ! 1339: ftCmdArg((segCount >> 4) +2); ! 1340: } else { ! 1341: if (ftCmd(QIC_CMD_SKPBX)) ! 1342: return -1; ! 1343: ftCmdArg((segCount & 0xF) +2); ! 1344: ftCmdArg(((segCount >> 4) & 0xF) +2); ! 1345: ftCmdArg(((segCount >> 8) & 0xF) +2); ! 1346: } ! 1347: } ! 1348: ! 1349: /************************************************************************ ! 1350: * ftSkipFwd() ! 1351: * ! 1352: * Skip segments in logical forward direction. ! 1353: * Return 0 on success, -1 on failure. ! 1354: ***********************************************************************/ ! 1355: static int ! 1356: ftSkipFwd(segCount) ! 1357: int segCount; ! 1358: { ! 1359: /* If possible, use short (non-extended) form of skip command. */ ! 1360: if ((segCount & ~0xFF) == 0) { ! 1361: if (ftCmd(QIC_CMD_SKPF)) ! 1362: return -1; ! 1363: ftCmdArg((segCount & 0xF) +2); ! 1364: ftCmdArg((segCount >> 4) +2); ! 1365: } else { ! 1366: if (ftCmd(QIC_CMD_SKPFX)) ! 1367: return -1; ! 1368: ftCmdArg((segCount & 0xF) +2); ! 1369: ftCmdArg(((segCount >> 4) & 0xF) +2); ! 1370: ftCmdArg(((segCount >> 8) & 0xF) +2); ! 1371: } ! 1372: } ! 1373: ! 1374: /************************************************************************ ! 1375: * ftStartTape ! 1376: * ! 1377: * Try to get tape into position to read next segment of interest, then ! 1378: * put tape in motion. ! 1379: * ! 1380: * Return 0 on success. ! 1381: * Return -1 on failure and make sure tape is stopped. ! 1382: * ! 1383: * Seek head to current track. ! 1384: * Wait for drive ready. ! 1385: * If trying to read first segment of any track ! 1386: * If even track ! 1387: * Rewind tape. ! 1388: * Else (odd track) ! 1389: * Full forward tape. ! 1390: * Wait for drive ready. ! 1391: * Logical forward. ! 1392: * Else (reading after first segment) ! 1393: * Pause. (Backs up a couple segments.) ! 1394: * Wait for drive ready. ! 1395: * While (not in position) ! 1396: * Logical forward. ! 1397: * Read segment ID. ! 1398: * If current segment >= desired segment ! 1399: * Compute skip count. ! 1400: * Skip back some number of segments. ! 1401: * Wait for drive ready. ! 1402: * Else if current segment << desired segment ! 1403: * Compute skip count. ! 1404: * Skip forward some number of segments. ! 1405: * Wait for drive ready. ! 1406: * Else tape is in position. ! 1407: * Endwhile ! 1408: ***********************************************************************/ ! 1409: static int ! 1410: ftStartTape() ! 1411: { ! 1412: int tries; ! 1413: int notInPlace; ! 1414: unchar currentSeg; ! 1415: int skipCount; ! 1416: ! 1417: ftCmd(QIC_CMD_SEEK); ! 1418: ftCmdArg(2); ! 1419: if(ftReadyWait(FT_SEEK_SECS)) ! 1420: return -1; ! 1421: ! 1422: if (ft.ft_phySeg == 0) { ! 1423: if ((ft.ft_track & 1) == 0) ! 1424: ftCmd(QIC_CMD_BOT); ! 1425: else ! 1426: ftCmd(QIC_CMD_EOT); ! 1427: if(ftReadyWait(FT_WIND_SECS)) ! 1428: return -1; ! 1429: ftCmd(QIC_CMD_FWD); ! 1430: } else { ! 1431: ftCmd(QIC_CMD_PAUS); ! 1432: if(ftReadyWait(FT_PAUSE_SECS)) ! 1433: return -1; ! 1434: ! 1435: notInPlace = 1; ! 1436: for (tries = 0; tries < 4 && notInPlace; tries++) { ! 1437: ftCmd(QIC_CMD_FWD); ! 1438: if (ftReadID()) ! 1439: continue; /* Will try again. */ ! 1440: currentSeg = ftSeg(fdc.fdc_cmdstat[3], ! 1441: fdc.fdc_cmdstat[4], fdc.fdc_cmdstat[5]); ! 1442: if (currentSeg >= ft.ft_phySeg) { ! 1443: skipCount = currentSeg - ft.ft_phySeg ! 1444: + FT_CUSHION; ! 1445: ftSkipBack(skipCount); ! 1446: } else if (currentSeg < ft.ft_phySeg - FT_CUSHION) { ! 1447: skipCount = ft.ft_phySeg - currentSeg ! 1448: - FT_CUSHION; ! 1449: ftSkipFwd(skipCount); ! 1450: } else ! 1451: notInPlace = 0; ! 1452: } /* end for */ ! 1453: } ! 1454: ! 1455: if (notInPlace) { ! 1456: ftStopTape(); ! 1457: return -1; ! 1458: } ! 1459: ! 1460: return 0; ! 1461: } ! 1462: ! 1463: /************************************************************************ ! 1464: * ftStopTape ! 1465: * ! 1466: * Send QIC stop tape command, then sleep til drive ready. ! 1467: * Return 0 if success, 1 if timed out before sensing drive ready. ! 1468: ***********************************************************************/ ! 1469: static int ! 1470: ftStopTape() ! 1471: { ! 1472: /* Stop, wait for ready. */ ! 1473: ftCmd(QIC_CMD_STOP); ! 1474: return ftReadyWait(15); ! 1475: } ! 1476: ! 1477: /************************************************************************ ! 1478: * ftStsWthErr ! 1479: * ! 1480: * Do Report Drive Status. ! 1481: * If error detected, to Report Error Code. ! 1482: * Uses sleep, so may not be used in timeout/interrupt/load/unload, etc. ! 1483: * Return status if ok, -1 on protocol failure. ! 1484: ***********************************************************************/ ! 1485: static int ! 1486: ftStsWthErr() ! 1487: { ! 1488: int retval; ! 1489: ! 1490: if (ftCmd(QIC_CMD_STS)) ! 1491: return -1; ! 1492: ! 1493: retval = ft.ft_report; ! 1494: ! 1495: if (FT_BLAB) ! 1496: ftDbPrintStat(ft.ft_report); ! 1497: ! 1498: if (ft.ft_report & QIC_STAT_ERR) { ! 1499: if (ftCmd(QIC_CMD_ECD)) ! 1500: return -1; ! 1501: ftDbPrintErr(ft.ft_report); ! 1502: } ! 1503: return retval; ! 1504: } ! 1505: ! 1506: /************************************************************************ ! 1507: * ftWait ! 1508: * ! 1509: * Wait the specified number of ticks. ! 1510: * Return 0 if full wait occurs, -1 if signaled. ! 1511: * Uses sleep, so may not be used in timeout/interrupt/load/unload, etc. ! 1512: ***********************************************************************/ ! 1513: static int ! 1514: ftWait(ticks) ! 1515: uint ticks; ! 1516: { ! 1517: timeout(&ft.ft_tim, ticks, wakeup, &ft.ft_wakeMeUp); ! 1518: return x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftWait"); ! 1519: } ! 1520: ! 1521: /********************* ! 1522: ********************** ! 1523: ** ! 1524: ** Debug Area. ! 1525: ** ! 1526: ********************** ! 1527: **********************/ ! 1528: ! 1529: static char *qicErr[] = { ! 1530: "NULL err", ! 1531: "command received while drive not ready", ! 1532: "cartridge not present or removed", ! 1533: "motor speed error (not within 1%)", ! 1534: "motor speed fault (jammed, or gross speed error)", ! 1535: "cartridge write protected", ! 1536: "undefined or reserved command code", ! 1537: "illegal track address specified for seek", ! 1538: "illegal command in report subcontext", ! 1539: "illegal entry into a diagnostic mode", ! 1540: "broken tape detected (based on hole sensor)", ! 1541: "warning - read gain setting error", ! 1542: "command received while error status pending (obsolete)", ! 1543: "command received while new cartridge pending", ! 1544: "command illegal or undefined in primary mode", ! 1545: "command illegal or undefined in format mode", ! 1546: "command illegal or undefined in verify mode", ! 1547: "logical forward not at logical BOT in format mode", ! 1548: "logical EOT before all segments generated", ! 1549: "command illegal when cartridge not referenced", ! 1550: "self-diagnostic failed (cannot be cleared)", ! 1551: "warning EEPROM not initialized, defaults set", ! 1552: "EEPROM corrupt or hardware failure", ! 1553: "motion timeout error", ! 1554: "data segment too long - logical forward or pause", ! 1555: "transmit overrun (obsolete)", ! 1556: "power on reset occurred", ! 1557: "software reset occurred", ! 1558: "diagnostic mode 1 error", ! 1559: "diagnostic mode 2 error", ! 1560: "command received during noninterruptible process", ! 1561: "rate selection error", ! 1562: "illegal command while in high speed mode", ! 1563: "illegal seek segment value" ! 1564: }; ! 1565: ! 1566: static char *qicStat[] = { ! 1567: "drive ready or idle", ! 1568: "error detected", ! 1569: "cartridge present", ! 1570: "cartridge write protected", ! 1571: "new cartridge", ! 1572: "cartridge referenced", ! 1573: "at physical BOT", ! 1574: "at physical EOT" ! 1575: }; ! 1576: ! 1577: static char *qicCmd[] = { ! 1578: "NULL cmd", ! 1579: "soft reset", ! 1580: "report next bit", ! 1581: "pause", ! 1582: "micro step pause", ! 1583: "alternate command timeout", ! 1584: "report drive status", ! 1585: "report error code", ! 1586: "report drive configuration", ! 1587: "report ROM version", ! 1588: "logical forward", ! 1589: "physical reverse", ! 1590: "physical forward", ! 1591: "seek head to track", ! 1592: "seek load point", ! 1593: "enter format mode", ! 1594: "write reference burst", ! 1595: "enter verify mode", ! 1596: "stop tape", ! 1597: "reserved (19)", ! 1598: "reserved (20)", ! 1599: "micro step head up", ! 1600: "micro step head down", ! 1601: "reserved (23)", ! 1602: "reserved (24)", ! 1603: "skip n segments reverse", ! 1604: "skip n segments forward", ! 1605: "select rate", ! 1606: "enter diag mode 1", ! 1607: "enter diag mode 2", ! 1608: "enter primary mode", ! 1609: "reserved (31)", ! 1610: "report vendor ID", ! 1611: "report tape status", ! 1612: "skip n segments extended reverse", ! 1613: "skip n segments extended forward" ! 1614: }; ! 1615: ! 1616: /* print command as [command] */ ! 1617: static void ! 1618: ftDbPrintCmd(cmd) ! 1619: unsigned int cmd; ! 1620: { ! 1621: if (cmd >= 1 && cmd < sizeof(qicCmd)/sizeof(qicCmd[0])) { ! 1622: if (cmd != QIC_CMD_RNB) ! 1623: printf("[%s] ", qicCmd[cmd]); ! 1624: } else ! 1625: printf("[%x] ", cmd); ! 1626: } ! 1627: ! 1628: /* print 2-byte error status as <error-code,command> */ ! 1629: static void ! 1630: ftDbPrintErr(errword) ! 1631: unsigned int errword; ! 1632: { ! 1633: unsigned int lo, hi; ! 1634: ! 1635: lo = errword & 0xff; ! 1636: hi = (errword >> 8) & 0xff; ! 1637: ! 1638: if (lo >= 1 && lo < sizeof(qicErr)/sizeof(qicErr[0])) ! 1639: printf("<%s,", qicErr[lo]); ! 1640: else ! 1641: printf("<%x,", lo); ! 1642: ! 1643: if (hi >= 1 && hi < sizeof(qicCmd)/sizeof(qicCmd[0])) ! 1644: printf("%s> ", qicCmd[hi]); ! 1645: else ! 1646: printf("%x> ", hi); ! 1647: } ! 1648: ! 1649: /* print current FDC position as C= H= R= N=. */ ! 1650: static void ! 1651: ftDbPrintPos() ! 1652: { ! 1653: printf("C=%d H=%d R=%d N=%d ", ! 1654: ft.ft_cyl, ft.ft_head, ft.ft_blk, ft.ft_ssz); ! 1655: } ! 1656: ! 1657: /* print tape status as { status string,... } */ ! 1658: static void ! 1659: ftDbPrintStat(stat) ! 1660: unsigned int stat; ! 1661: { ! 1662: int i; ! 1663: ! 1664: printf("{ "); ! 1665: for (i = 0; i < 8; i++) { ! 1666: if (stat & (1 << i)) ! 1667: printf("%s, ", qicStat[i]); ! 1668: } ! 1669: putchar('}'); ! 1670: } ! 1671: ! 1672: /************************************************************************ ! 1673: * ftDbPrtStat ! 1674: * ! 1675: * For debugging, print command status and interrupt status to console. ! 1676: ***********************************************************************/ ! 1677: static void ! 1678: ftDbPrtStat() ! 1679: { ! 1680: int i; ! 1681: ! 1682: printf("[["); ! 1683: if (fdc.fdc_ncmdstat) { ! 1684: printf("cmd "); ! 1685: for (i = 0; i < fdc.fdc_ncmdstat; i++) ! 1686: printf("%x ", fdc.fdc_cmdstat[i]); ! 1687: } ! 1688: if (fdc.fdc_nintstat) { ! 1689: printf("int "); ! 1690: for (i = 0; i < fdc.fdc_nintstat; i++) ! 1691: printf("%x ", fdc.fdc_intstat[i]); ! 1692: } ! 1693: printf("]] "); ! 1694: } ! 1695: ! 1696: #if defined(FT_DEAD_CODE) ! 1697: /********************* ! 1698: ********************** ! 1699: ** ! 1700: ** Test Read of Segment 0. ! 1701: ** ! 1702: ********************** ! 1703: **********************/ ! 1704: FT_BLAB = 0; ! 1705: ! 1706: #if 0 ! 1707: /* Rewind, wait until ready. */ ! 1708: ftCmd(QIC_CMD_BOT); ! 1709: if(ftReadyWait(15)) { ! 1710: printf("Not ready after rewind "); ! 1711: goto rd0done; ! 1712: } ! 1713: ! 1714: /* Stop, wait for ready. */ ! 1715: ftCmd(QIC_CMD_STOP); ! 1716: if(ftReadyWait(15)) { ! 1717: printf("Not ready after stop tape 1 "); ! 1718: goto rd0done; ! 1719: } ! 1720: #endif ! 1721: ! 1722: /* Seek head to track 0, wait for ready. */ ! 1723: ftCmd(QIC_CMD_SEEK); ! 1724: ftCmdArg(2); ! 1725: if(ftReadyWait(15)) { ! 1726: printf("Not ready after seek to track 0 "); ! 1727: goto rd0done; ! 1728: } ! 1729: ! 1730: #if 0 ! 1731: /* Stop, wait for ready. */ ! 1732: ftCmd(QIC_CMD_STOP); ! 1733: if(ftReadyWait(15)) { ! 1734: printf("Not ready after stop tape 2 "); ! 1735: goto rd0done; ! 1736: } ! 1737: ! 1738: /* Skip back 68 segments. SKPB. Wait for ready. */ ! 1739: ftCmd(QIC_CMD_SKPB); ! 1740: ftCmdArg(6); ! 1741: ftCmdArg(6); ! 1742: if(ftReadyWait(15)) { ! 1743: printf("Not ready after skip back 68 "); ! 1744: goto rd0done; ! 1745: } ! 1746: #endif ! 1747: ! 1748: /* Logical forward. */ ! 1749: ftCmd(QIC_CMD_FWD); ! 1750: ! 1751: for (i = 0; i < 3; i++) { ! 1752: /* Setup DMA */ ! 1753: if (!dmaon(DMA_CH2, vtop(ftBigBuf)+(i*FT_BFRSZ), FT_BFRSZ, DMA_TO_MEM)) { ! 1754: printf("Ft dma straddle "); ! 1755: goto rd0done; ! 1756: } ! 1757: dmago(DMA_CH2); ! 1758: ! 1759: /* Send Read command to FDC */ ! 1760: ft.ft_wakeMeUp = 1; ! 1761: ft.ft_dumpIrq = 1; ! 1762: rwCmd[4] = (i*32)+1; ! 1763: if ((putCount = fdcPutStr(rwCmd, RD_CMD_LEN)) != RD_CMD_LEN) { ! 1764: printf("only wrote %d bytes of rwCmd ", putCount); ! 1765: goto rd0done; ! 1766: } ! 1767: ! 1768: /* Wait for interrupt when read is done. */ ! 1769: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRd0")) { ! 1770: printf("signaled before DMA done "); ! 1771: goto rd0done; ! 1772: } ! 1773: ! 1774: /* Turn off the DMA channel. */ ! 1775: if ((putCount = dmaoff(DMA_CH2)) != 0) { ! 1776: printf("DMA residual %d bytes ", putCount); ! 1777: goto rd0done; ! 1778: } ! 1779: } ! 1780: ! 1781: /* Stop the tape. */ ! 1782: ftCmd(QIC_CMD_STOP); ! 1783: if(ftReadyWait(15)) { ! 1784: printf("not ready after stop tape "); ! 1785: goto rd0done; ! 1786: } ! 1787: ! 1788: /* Quick check on data received. */ ! 1789: for (i = 0; i < 4; i++) ! 1790: printf("%d:%x ", i, ftBigBuf[i]); ! 1791: ! 1792: rd0done: ! 1793: FT_BLAB = 0; ! 1794: /********************* ! 1795: ********************** ! 1796: ** ! 1797: ** End of Read Test. ! 1798: ** ! 1799: ********************** ! 1800: **********************/ ! 1801: /* old stuff from read routine */ ! 1802: uint src, dest; ! 1803: uint startSeg, endSeg; ! 1804: ! 1805: src = iop->io_seek; ! 1806: dest = iop->io.pbase; ! 1807: ! 1808: #if 0 ! 1809: /* ! 1810: * Seek 0-32767 is header segment. ! 1811: */ ! 1812: startSeg = src >> 15; ! 1813: endSeg = (src + iop->io_ioc - 1) >> 15; ! 1814: ! 1815: if (startSeg != endSeg || startSeg > 0) { ! 1816: u.u_error = EFAULT; ! 1817: return; ! 1818: } ! 1819: #endif ! 1820: ! 1821: src += (uint)ftBigBuf; ! 1822: ! 1823: iowrite(iop, src, iop->io_ioc); ! 1824: ! 1825: return; ! 1826: #endif ! 1827: #if 0 ! 1828: /************************************************************************ ! 1829: * ftBufRead ! 1830: * ! 1831: * Given a read count in bytes, read as much as possible into the DMA ! 1832: * buffer area. ! 1833: * Return the number of bytes retrieved, or -1 if total failure. ! 1834: ***********************************************************************/ ! 1835: static int ! 1836: ftBufRead(bytesWanted) ! 1837: int bytesWanted; ! 1838: { ! 1839: int bytesToRead; ! 1840: uint bigBufLen = FT_NBUF * FT_BFRSZ; ! 1841: int blocksWanted, blocksRead; ! 1842: unchar * dmaBufPtr = ftBigBuf; ! 1843: ! 1844: /* Try for the smaller of amount wanted and buffer size. */ ! 1845: bytesToRead = (bytesWanted > bigBufLen) ? bigBufLen : bytesWanted; ! 1846: ! 1847: /* WARNING: The following will change when we read the bad block map! */ ! 1848: ! 1849: /* Calculate the number of 1K byte tape blocks to read. */ ! 1850: blocksWanted = (bytesToRead + FT_BLKSZ - 1) / FT_BLKSZ; ! 1851: ! 1852: /* Keep asking for blocks until we have them all. */ ! 1853: while (blocksWanted > 0) { ! 1854: blocksRead = ftReadBlks(dmaBufPtr, blocksWanted); ! 1855: if (blocksRead < 0) /* Failure! */ ! 1856: break; ! 1857: dmaBufPtr += FT_BLKSZ; ! 1858: blocksWanted -= blocksRead; ! 1859: bytesToRead -= blocksRead * FT_BLKSZ; ! 1860: if (bytesToRead < 0) ! 1861: bytesToRead = 0; ! 1862: } ! 1863: ! 1864: /* Return the number of bytes read into the DMA buffer. */ ! 1865: return bytesWanted - bytesToRead; ! 1866: } ! 1867: ! 1868: /*********************************************************************** ! 1869: * ftReadBlkRun() ! 1870: * ! 1871: * Given the location of the next run of good blocks to read from tape ! 1872: * and the index where to put it, try to read a run of blocks into ! 1873: * DMA buffer area. ! 1874: * ! 1875: * Requirement: tape must be positioned properly and in motion. ! 1876: * ! 1877: * Return 0 on success (the number of failed block reads does not exceed ! 1878: * the maximum allowable), or -1 on failure. ! 1879: * On success, update blkToRead and blksRead fields of the FtRun struct ! 1880: * passed in. Also update error count and location tables for the current ! 1881: * segment buffer. ! 1882: * ! 1883: * Initialize retry count. ! 1884: * Initialize retry starting block. ! 1885: * While length of current run is > 0 blocks ! 1886: * Make a command to request the run of blocks from the FDC. ! 1887: * Send the command. ! 1888: * When FDC done, get report phase info from FDC. ! 1889: * Update blkToRead, blksRead, and runLength based on FDC report. ! 1890: * Conditionally update retry count and retry starting block. ! 1891: * If FDC reports error ! 1892: * If retry limit not exceeded ! 1893: * Increment retry count. ! 1894: * Reposition with micro step. ! 1895: * Else ! 1896: * If allowable error limit for this segment exceeded ! 1897: * Return read failure. ! 1898: * Else ! 1899: * Save relative block number of failed block for the segment. ! 1900: * Update bad read count for the segment. ! 1901: * Advance blkToRead, blksRead, and runLength to point past ! 1902: * current bad block (may decrement runLength to zero). ! 1903: * Endwhile ! 1904: * ! 1905: uint blkToRead; /* Next block wanted from current segment */ ! 1906: uint blksRead; /* Number of blocks read from this seg */ ! 1907: uint runLength; /* Number of good blocks in current run */ ! 1908: ***********************************************************************/ ! 1909: static int ! 1910: ftReadBlkRun(ftrp, bufn) ! 1911: struct FtRun * ftrp; ! 1912: int bufn; ! 1913: { ! 1914: ! 1915: #if 0 ! 1916: int putCount; ! 1917: struct FtParm *fp; ! 1918: ! 1919: /* Get parameter set pointer. */ ! 1920: fp = ftParm + ft.ft_fmt; ! 1921: ! 1922: /* Sanity check - don't try to read past end of track. */ ! 1923: if (ft.ft_phySeg >= fp->segPerTrk) ! 1924: return -1; ! 1925: ! 1926: /* Set up DMA */ ! 1927: if (!dmaon(DMA_CH2, vtop(ftBigBuf + (bufn * FT_BFRSZ)), FT_BFRSZ, ! 1928: DMA_TO_MEM)) { ! 1929: printf("Ft dma straddle "); ! 1930: return -1; ! 1931: } ! 1932: dmago(DMA_CH2); ! 1933: ! 1934: /* ! 1935: * Make a read command. ! 1936: * Enter diskette pseudo coordinates into FDC read command. ! 1937: * C = rwCmd[2], H = rwCmd[3], R = rwCmd[4] ! 1938: */ ! 1939: rwCmd[RW_CMD_VERB] = RW_CMD_RD; ! 1940: rwCmd[RW_CMD_UNIT] = ft.ft_drv; ! 1941: ftFdcPos(ft.ft_track, ft.ft_phySeg, rwCmd + RW_CMD_CYL); ! 1942: rwCmd[RW_CMD_SCHI] = fp->blkPerTrk; ! 1943: ! 1944: /* Send Read command to FDC */ ! 1945: ft.ft_wakeMeUp = 1; ! 1946: ft.ft_dumpIrq = 1; ! 1947: if ((putCount = fdcPutStr(rwCmd, RW_CMD_LEN)) != RW_CMD_LEN) { ! 1948: printf("only wrote %d bytes of rwCmd ", putCount); ! 1949: return -1; ! 1950: } ! 1951: ! 1952: /* Wait for interrupt when read is done. */ ! 1953: if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRd1S")) { ! 1954: printf("signaled before DMA done "); ! 1955: return -1; ! 1956: } ! 1957: ! 1958: /* Turn off the DMA channel. */ ! 1959: if ((putCount = dmaoff(DMA_CH2)) != 0) { ! 1960: printf("DMA residual %d bytes ", putCount); ! 1961: return -1; ! 1962: } ! 1963: ! 1964: /* Update current segment pointer. */ ! 1965: ft.ft_phySeg++; ! 1966: if (ft.ft_phySeg == fp->segPerTrk && ft.ft_track <= (fp->tracks - 1)) { ! 1967: ft.ft_track++; ! 1968: ft.ft_phySeg = 0; ! 1969: } ! 1970: ! 1971: return 0; ! 1972: #endif ! 1973: } ! 1974: ! 1975: /*********************************************************************** ! 1976: * ftReadBlks() ! 1977: * ! 1978: * Given a pointer into the DMA buffer area and a block count, try to ! 1979: * read the given number of blocks. May read fewer due to error or ! 1980: * reaching end of track. ! 1981: * Return the number of blocks read, or -1 in case of total failure. ! 1982: ***********************************************************************/ ! 1983: static int ! 1984: ftReadBlks(dmaBufPtr, blocksWanted); ! 1985: unchar * dmaBufPtr; ! 1986: uint blocksWanted; ! 1987: { ! 1988: int segsWanted, segsOnTrack; ! 1989: ! 1990: /* ! 1991: * See how many segments are left on the current track. ! 1992: * If no segments left on current track ! 1993: * If on last track of cartridge ! 1994: * Return failure. ! 1995: * Increment current track number. ! 1996: * Reset current segment number. ! 1997: */ ! 1998: segsOnTrack = ft.ft_segsPerTrk - ft.ft_phySeg; ! 1999: if (segsOnTrack == 0) { ! 2000: if (ft.ft_track + 1 >= ft.ft_trksPerCart) ! 2001: return -1; ! 2002: ft.ft_track++; ! 2003: ft.ft_phySeg = 0; ! 2004: } ! 2005: ! 2006: /* WARNING: This will change with Reed-Solomon ecc. */ ! 2007: ! 2008: /* ! 2009: * Calculate how many segments to go after. ! 2010: * First, round up the number of requested blocks. ! 2011: * Take the smaller of these. ! 2012: */ ! 2013: segsWanted = (blocksWanted + FT_BLK_PER_SEG - 1) / FT_BLK_PER_SEG; ! 2014: if (segsWanted > segsOnTrk) ! 2015: segsWanted = segsOnTrk; ! 2016: ! 2017: /* Now ask for a bunch of segments, all from the same track. */ ! 2018: return ftReadSegs(dmaBufPtr, segsWanted); ! 2019: } ! 2020: ! 2021: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.