Annotation of coherent/b/STREAMS/io.386/ft.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.