Annotation of coherent/b/STREAMS/io.386/ft.c, revision 1.1.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.