Annotation of coherent/b/kernel/io.386/xlft.c, revision 1.1

1.1     ! root        1: #define MWC_FT 1
        !             2: 
        !             3: /*
        !             4:  * File:       xlft.c
        !             5:  *
        !             6:  * Purpose:    Floppy tape device control.
        !             7:  *             Inspired by the Archive "xl" driver.
        !             8:  *             Requires 765 controller module fdc.c
        !             9:  *             FDC = floppy disk controller, e.g. NEC upd765
        !            10:  *
        !            11:  * Revised: Tue Jun  1 19:16:37 1993 CDT
        !            12:  */
        !            13: 
        !            14: /*
        !            15:  * Here is the protocol for QIC report commands, I think:
        !            16:  * 
        !            17:  * Send QIC report command to FDC (this will be an FDC seek command).
        !            18:  * FDC interrupts when step pulses are sent.
        !            19:  * Send Sense Interrupt Status to FDC.  (Clears interrupt line.)
        !            20:  * Read interrupt status from FDC.
        !            21:  * - Get ACK from tape drive.  Want Track 0 true.  Variable latency.
        !            22:  * Do
        !            23:  *   Send Sense Drive Status to FDC.
        !            24:  *   Read drive status from FDC, including Track 0 bit.
        !            25:  * Until Track 0 true.
        !            26:  * - Get data bits for the report command.
        !            27:  * For number-of-data-bits-in-report times
        !            28:  *   Send QIC Report Next Bit command to FDC.
        !            29:  *   FDC interrupts when step pulses are sent.
        !            30:  *   Send Sense Interrupt Status to FDC.
        !            31:  *   Read interrupt status from FDC.
        !            32:  *   Send Sense Drive Status to FDC.
        !            33:  *   Read drive status from FDC, including Track 0 bit.
        !            34:  *   Save Track 0 bit value into report data.
        !            35:  * End for
        !            36:  * - Get final Track 0 true from tape drive.
        !            37:  * Send QIC Report Next Bit command to FDC.
        !            38:  * FDC interrupts when step pulses are sent.
        !            39:  * Send Sense Interrupt Status to FDC.
        !            40:  * Read interrupt status from FDC.
        !            41:  * Send Sense Drive Status to FDC.
        !            42:  * Read drive status from FDC, including Track 0 bit.
        !            43:  * Track 0 bit must be true.
        !            44:  */
        !            45: 
        !            46: /*
        !            47:  * ----------------------------------------------------------------------
        !            48:  * Includes.
        !            49:  */
        !            50: #include       <sys/coherent.h>
        !            51: 
        !            52: #include       <errno.h>
        !            53: #include       <sys/buf.h>
        !            54: #include       <sys/con.h>
        !            55: #include       <sys/devices.h>
        !            56: #include       <sys/fdc765.h>
        !            57: #include       <sys/fdioctl.h>
        !            58: #include       <sys/inode.h>
        !            59: #include       <sys/sched.h>
        !            60: #include       <sys/stat.h>
        !            61: #include       <sys/xl.h>
        !            62: #include       <sys/xlfdc.h>
        !            63: #include       <sys/xlft.h>
        !            64: #include       <sys/xl8237.h>
        !            65: 
        !            66: /*
        !            67:  * ----------------------------------------------------------------------
        !            68:  * Definitions.
        !            69:  *     Constants.
        !            70:  *     Macros with argument lists.
        !            71:  *     Typedefs.
        !            72:  *     Enums.
        !            73:  */
        !            74: #define        HDRSZ   0x4000          /* 16k, size of qic-40 header           */
        !            75: #define        BFRSZ   0x8000          /* 32k, size of qic-40 buffer           */
        !            76: 
        !            77: #define MAX_PCN                200
        !            78: 
        !            79: /* compatibility area */
        !            80: 
        !            81: #define bcopy(src, dest, nbytes)       memcpy(dest, src, nbytes)
        !            82: #define copyin(userSrc, drvrDest, nbytes) \
        !            83:        ukcopy(userSrc, drvrDest, nbytes)
        !            84: #define copyout(drvrSrc, userDest, nbytes) \
        !            85:        kucopy(drvrSrc, userDest, nbytes)
        !            86: #define getfdc(unit)                   setFtIntr(1)
        !            87: #define getfdcn(unit)                  setFtIntr(1)
        !            88: #define kvtophys(vaddr)                        vtop(vaddr)
        !            89: #define relfdc()                       setFtIntr(0)
        !            90: #define sleep(address, priority)       \
        !            91:        x_sleep(address, pritape, slpriSigLjmp, #address)
        !            92: #define spl5()                         sphi()
        !            93: #define splx(lvl)                      spl(lvl)
        !            94: #define        tenmicrosec()                   busyWait2(NULL, 12)
        !            95: 
        !            96: static void    cmn_err();
        !            97: 
        !            98: enum {
        !            99:        CE_CONT = 0,            /* used to continue a previous message */
        !           100:        CE_NOTE,                /* used to display a NOTICE: message */
        !           101:        CE_WARN,                /* used to display a WARNING: message */
        !           102:        CE_PANIC,               /* used to display a PANIC: message */
        !           103:        CE_INVALID              /* used to warn about invalid severity */
        !           104: };
        !           105: 
        !           106: /************************************************************************/
        !           107: /*     Additional fdc equates                                          */
        !           108: /************************************************************************/
        !           109: 
        !           110: #define        FDTMO   65535           /* xlfdc_in_byte, xlfdc_out_byte timeout*/
        !           111: #define        IOTMO   (12 * HZ)       /* io timeout                           */
        !           112: #define        TMSKP   18              /* # segments missed if IOTMO           */
        !           113: 
        !           114: #define FT_ACK_TRIES   5       /* max # of tries for ACK to QIC rpt cmd*/
        !           115: 
        !           116: /*
        !           117:  * ----------------------------------------------------------------------
        !           118:  * Functions.
        !           119:  *     Import Functions.
        !           120:  *     Export Functions.
        !           121:  *     Local Functions.
        !           122:  */
        !           123: extern int     nulldev();
        !           124: 
        !           125: extern int     xl_tbi();       /* init ecc tables                      */
        !           126: extern int     xl_enc();       /* encode ecc data                      */
        !           127: extern int     xl_dec();       /* decode ecc data                      */
        !           128: 
        !           129: /* CON entry points. */
        !           130: static int     ftblock();
        !           131: static int     ftclose();
        !           132: static int     ftioctl();
        !           133: static int     ftload();
        !           134: static int     ftopen();
        !           135: static int     ftread();
        !           136: static int     ftunload();
        !           137: static int     ftwrite();
        !           138: 
        !           139: static int     getmem();
        !           140: static int     putrb();
        !           141: static struct  rb *getrb();
        !           142: static void    stdma();
        !           143: static void    strbfm();               /* set up rb for format         */
        !           144: static  void   strbsg();
        !           145: static  void   stseg();
        !           146: static  void   wvtbl();
        !           147: 
        !           148: static void    xlcal(), xlcal0(), (*pfcal)();  /* calibrate            */
        !           149: static void    xlcomplete();
        !           150: static void    xldelay(), (*pfdly)();  /* "delay"                      */
        !           151: static void    xldma();
        !           152: static unchar  xlfdc_in_byte();
        !           153: static unchar  xlfdc_out_byte();
        !           154: static unchar  xlfdc_out_str();
        !           155: static void    xlfdc_reset();
        !           156: static void    xlflush();
        !           157: static void    xlfmq(), xlfmq0(), xlfmq1(), xlfmq2(); /* format queue  */
        !           158: static void    xlfms(), xlfm0(), (*pffms)();   /* format segment       */
        !           159: static int     xlformat();             /* format main routine          */
        !           160: static void    xlgtdat();
        !           161: static void    xlhalt(), (*pfhlt)();   /* halt tape motion             */
        !           162: static void    xlintr(), (*pfint)();   /* xl2 ptr to intr handler      */
        !           163: static void    xlnull();
        !           164: static int     xlopn();
        !           165: static void    xloutput_step();        /* output steps, exit=pfint     */
        !           166: static void    xlpark(), (*pfprk)();
        !           167: static void    xlpark0(), xlpark1(), xlpark2();
        !           168: static void    xlpos(), xlpos0(), xlpos1(), xlpos2(), xlpos3(), (*pfpos)();
        !           169: static void    xlptdat();
        !           170: static void    xlque(), xlqr0(), xlqw0();
        !           171: static void    xlrds(), xlrd0(), xlrd1(), (*pfrds)();  /* read segment */
        !           172: static void    xlreadid(), xlreadid0(), (*pfrdi)();    /* read id      */
        !           173: static void    xlready(), xlready0(), (*pfrdy)(); /* "wait" for ready  */
        !           174: static void    xlrel();
        !           175: static void    xlreset(), xlreset0(), (*pfrst)();      /* reset drive  */
        !           176: static void    xlrn9(), xlrn17();
        !           177: static void    xlrnb(), xlrnb0(), (*pfrnb)();  /* report next bits     */
        !           178: static void    xlrqr();
        !           179: static void    xlseek(), (*pfsek)();   /* seek to tptrk                */
        !           180: static void    xlseek0(), xlseek1();
        !           181: static void    xlsel();
        !           182: static void    xlskipb(), (*pfskp)();  /* skip n segs back             */
        !           183: static void    xlskipb0(), xlskipb1(), xlskipb2();
        !           184: static void    xlstatus(), (*pfsts)(); /* get status                   */
        !           185: static void    xlstatus0(), xlstatus1();
        !           186: static void    xltimout(), xltimfn();
        !           187: static int     xlwait();
        !           188: static void    xlwds(), (*pfwds)();    /* write del adm segment        */
        !           189: static void    xlwts(), (*pfwts)();    /* write segment                */
        !           190: static void    xlwt0(), xlwt1();
        !           191: 
        !           192: static void    xlDbPrintErr(), xlDbPrintCmd(), xlDbPrintStat();
        !           193: 
        !           194: static void    ftDbPrtStat();
        !           195: static int     ftCmd();
        !           196: static void    ftIrqHandler();
        !           197: static int     ftRecal();
        !           198: static void    ftResetFDC();
        !           199: static void    ftRptBegin();
        !           200: static void    ftRptUpdate();
        !           201: static void    ftSelect();
        !           202: 
        !           203: /*
        !           204:  * ----------------------------------------------------------------------
        !           205:  * Global Data.
        !           206:  *     Import Variables.
        !           207:  *     Export Variables.
        !           208:  *     Local Variables.
        !           209:  */
        !           210: 
        !           211: /* from assembler module */
        !           212: extern ushort  *xltbl;         /* ptr to rb.tbl                        */
        !           213: extern unchar  xlbst;          /* base sector for segment              */
        !           214: extern unchar  xlsct;          /* sector # for next chunk              */
        !           215: extern int     xlcnt;          /* # bytes to xfer next chunk           */
        !           216: extern int     xlofs;          /* offset for next chunk                */
        !           217: 
        !           218: CON    ftxlcon = {
        !           219:        DFCHR,                          /* Flags */
        !           220:        FL_MAJOR,                       /* Major index */
        !           221:        ftopen,                         /* Open */
        !           222:        ftclose,                        /* Close */
        !           223:        ftblock,                        /* Block */
        !           224:        ftread,                         /* Read */
        !           225:        ftwrite,                        /* Write */
        !           226:        ftioctl,                        /* Ioctl */
        !           227:        nulldev,                        /* Powerfail */
        !           228:        nulldev,                        /* Timeout */
        !           229:        ftload,                         /* Load */
        !           230:        ftunload,                       /* Unload */
        !           231:        nulldev                         /* Poll */
        !           232: };
        !           233: 
        !           234: /*
        !           235:  * Patchable variables.
        !           236:  */
        !           237: int    XL_VERBOSE = 1;
        !           238: int    XL_NBUFS = 17;          /* ~ 3K total 'DATA' for driver         */
        !           239:                                /* 1.25K for ecc, + XL_NBUFS * 94       */
        !           240: 
        !           241: /* Parameters for FDC Specify Command */
        !           242: int FT_SRT = 0xE;
        !           243: int FT_HUT = 0xF;
        !           244: int FT_HLT = 0x1;
        !           245: 
        !           246: /************************************************************************/
        !           247: /*     UNIX data areas  and externals                                  */
        !           248: /************************************************************************/
        !           249: static ulong   allocated_add;  /* mem allocate addr for kernel buffer  */
        !           250: 
        !           251: /************************************************************************/
        !           252: /*     data area                                                       */
        !           253: /************************************************************************/
        !           254: static int     xldataw;                /* data queue wakeup flag       */
        !           255: static int     xlcompw;                /* completion wakeup flag       */
        !           256: static int     xlfreew;                /* free queue wakeup flag       */
        !           257: static int     xlcompf;                /* completion flag              */
        !           258: static int     xlnactw;                /* inactive wakeup flag         */
        !           259: static int     xlskip_count;           /* # segments to skip           */
        !           260: 
        !           261: static fplng   ptr_header;             /* ptr to header bfr            */
        !           262: static fplng   ptr_buffer;             /* ptr to bfr                   */
        !           263: 
        !           264: static struct  rb  * rbmp;             /* request packet pool          */
        !           265: 
        !           266: static struct  rbq xlfree_q;           /* free queue                   */
        !           267: static struct  rbq req;                /* request queue                */
        !           268: static struct  rbq data_queue;         /* read data queue              */
        !           269: 
        !           270: static int     xlmem_allocated = 0;    /* set if memory allocated      */
        !           271: 
        !           272: static struct  {                       /* flags                        */
        !           273:        unsigned short init :1;
        !           274:        unsigned short open :1;
        !           275:        unsigned short writ :1;
        !           276:        unsigned short cal  :1;
        !           277:        unsigned short actv :1;
        !           278:        unsigned short tmov :1;
        !           279:        unsigned short werr :1;
        !           280: }f;
        !           281: 
        !           282: static int     nseg_p_track;           /* # segments/track             */
        !           283: static int     nseg_p_head;            /* # segments/head              */
        !           284: static int     nseg_p_cyl;             /* # segments/cylinder          */
        !           285: 
        !           286: static int     fdcmd;                  /* last fdc cmd                 */
        !           287: 
        !           288: static unchar  status_buf[10];         /* status buffer                */
        !           289:                                        /* bytes 0-6 = 8272 status      */
        !           290:                                        /*      7   = nec phase err     */
        !           291:                                        /*      8   = 8272 st3          */
        !           292: 
        !           293: static ushort  xlrnbw;                 /* xl2 report next bit word     */
        !           294: static unchar  xlster;                 /* set if last bit not a 1      */
        !           295: static unchar  xl6sts;                 /* xl2 status                   */
        !           296: static unchar  xlests;
        !           297: static ushort  xl7sts;
        !           298: static int     xlbcnt;                 /* xlrnb counter, # of sts bits */
        !           299: 
        !           300: static unchar  fdstb[4] = { 0x1c, 0x2d, 0x4e, 0x8f };
        !           301: static unchar  fdsel, unit, fdselr, ftfmt;
        !           302: 
        !           303: static ushort  sgwrd;                  /* strbsg params                */
        !           304: static ulong   sgmap;
        !           305: 
        !           306: static paddr_t xadr;                   /* segment io params            */
        !           307: static struct  rb *xprb;
        !           308: static ushort  xtbl;
        !           309: static int     xsct;
        !           310: static int     xrty;
        !           311: static int     xstop;                  /* stop io flag (close)         */
        !           312: 
        !           313: static int     tptrk;                  /* current tape track           */
        !           314: static int     tpseg;                  /* next tape segment            */
        !           315: static int     fmtrk;                  /* format track                 */
        !           316: static int     vftrk;                  /* verify track (debug display) */
        !           317: 
        !           318: static int     xltimoutf = 0;          /* timeout flag                 */
        !           319: 
        !           320: /*     fdc commands                                                    */
        !           321: static unchar  sf2cms[3] = { 0x03, 0xef, 0x02 };
        !           322: 
        !           323: static unchar  sf3cms[3] = { 0x03, 0xdf, 0x02 };
        !           324: static unchar  sekcms[3] = { 0x0f, 0x00, 0x00 };
        !           325: static unchar  rdicms[2] = { 0x4a, 0x00 };
        !           326: static unchar  rwdcms[9] = { 0x46, 0, 0, 0, 0, 3, 226, 1, 0xff };
        !           327: static unchar  fmtcms[6] = { 0x4d, 0, 3, 32, 233, 0x6d };
        !           328: /*             sekcms[2] = current track, see xlintr()         */
        !           329: 
        !           330: static unchar  vtbl[] = "VTBL";
        !           331: static unchar  xnxnm[] = "unix";
        !           332: static unchar  xnxvs[20] = {
        !           333:                                0x55, 0xaa, 0x55, 0xaa, 0x02, 0x00, 0x00, 0x00,
        !           334:                                0x01, 0x00, 0x02, 0x00, 0x4f, 0x05, 0x00, 0x00,
        !           335:                                0x00, 0x00, 0x00, 0x00
        !           336:                        };
        !           337: 
        !           338: static int     h0sgn, h1sgn;           /* header seg #                 */
        !           339: static int     volume_seg_num;         /* volume seg #                 */
        !           340: static int     data_seg_num;           /* data seg #                   */
        !           341: static int     curr_seg_num;           /* current seg #                */
        !           342: static int     read_ahead_seg_num;     /* read ahead seg #             */
        !           343: static struct  rb *cprb;               /* offset to current rb         */
        !           344: static fpchr   cptr;                   /* ptr to current bfr           */
        !           345: static int     cnbr;                   /* # bytes remaining            */
        !           346: static fpchr   wptr;                   /* copy of cptr for write encod */
        !           347: static int     last_seg_num;           /* last segment                 */
        !           348: static int     lnbr;                   /* last seg # bytes             */
        !           349: 
        !           350: static int     rnbr;                   /* # requested bytes remaining  */
        !           351: static int     rcnt;                   /* # bytes to copy              */
        !           352: 
        !           353: static struct  rb *fprb;               /* used to enque requests       */
        !           354: 
        !           355: static TIM     xltmo, xldly;
        !           356: 
        !           357: static struct  FT {
        !           358:        unchar  ft_pcn;                 /* present cylinder #           */
        !           359:        unchar  ft_bitsNeeded;          /* # of Report Next Bit's to do */
        !           360:        unchar  ft_bitsRcvd;            /* # of report bits received    */
        !           361:        unchar  ft_wakeMeUp;            /* 1 = sleeping til next FDC IRQ */
        !           362:        unchar  ft_dumpIrq;             /* 1 = dump IRQ status          */
        !           363:        unchar  ft_ackNeeded;           /* 1 = awaiting ACK to rpt cmd  */
        !           364:        ushort  ft_report;              /* where reported bits go       */
        !           365:        TIM     ft_tim;
        !           366: } ft;
        !           367: 
        !           368: /*
        !           369:  * ----------------------------------------------------------------------
        !           370:  * Code.
        !           371:  */
        !           372: 
        !           373: /*
        !           374:  * CON struct routines.
        !           375:  */
        !           376: 
        !           377: /************************************************************************/
        !           378: /*     ftblock                                                         */
        !           379: /*                                                                     */
        !           380: /* Tape is not a block device, but we need a block entry point since   */
        !           381: /* the same driver controls diskette access.                           */
        !           382: /************************************************************************/
        !           383: static int
        !           384: ftblock(bp)
        !           385: BUF *bp;
        !           386: {
        !           387:        u.u_error = EIO;
        !           388:        bp->b_flag |= BFERR;
        !           389:        bdone(bp);
        !           390:        return;
        !           391: }
        !           392: 
        !           393: /************************************************************************
        !           394:  * ftclose
        !           395:  *
        !           396:  ***********************************************************************/
        !           397: static int
        !           398: ftclose(dev, mode)
        !           399: dev_t dev;
        !           400: int mode;
        !           401: {
        !           402: #if 1
        !           403:        printf("ftclose ");
        !           404:        f.open = 0;
        !           405: #else
        !           406:        if (f.open) {
        !           407:                /* f.open = 0;          reset open flag  U001           */
        !           408:                xlflush();              /* flush all bfrs               */
        !           409:                if (f.werr)             /* flag error if occurred       */
        !           410:                        u.u_error = EIO;
        !           411: 
        !           412:                getfdc(unit);   
        !           413:                xlsel(unit);
        !           414:                if (minor(dev) & M_REW) { /* rewind if rewind_on_close  */
        !           415:                        pfprk = xlcomplete;/* clear drive status and rewind*/
        !           416:                        xlpark();
        !           417:                        xlwait();
        !           418:                } else {
        !           419:                        pfsts = xlcomplete;     /* clear drive status   */
        !           420:                        xlstatus();
        !           421:                        xlwait();
        !           422:                }
        !           423:                xlrel();
        !           424:                relfdc();
        !           425:                f.open = 0;             /* reset open flag      U001    */
        !           426:                cmn_err(CE_CONT, "xlclose: xlster %x  f.werr %d\n", xlster, f.werr);
        !           427:        }
        !           428: #endif
        !           429: }
        !           430: 
        !           431: /************************************************************************/
        !           432: /*     ftioctl                                                         */
        !           433: /*     Handle tape drive & controller commands like erase, rewind,     */
        !           434: /*     retension, read filemark, and write filemark                    */
        !           435: /************************************************************************/
        !           436: ftioctl(dev, cmd, arg)
        !           437: register int   dev, cmd;
        !           438: int            arg;
        !           439: {
        !           440:        int                     xlarg;  /* ioctl argument               */
        !           441:        union   xl_status       xl;     /* status structure             */
        !           442: 
        !           443:        cmn_err(CE_CONT, "ftioctl: cmd %x\n", cmd);
        !           444: 
        !           445:        if ((cmd & 0xff00) != XLIOC) {
        !           446:                u.u_error = EINVAL;
        !           447:                return;
        !           448:        }
        !           449: 
        !           450:        getfdc(unit);                   /* get control of fdc           */
        !           451:        xlsel(unit);                    /* select tape drive            */
        !           452: 
        !           453:        switch (cmd) {
        !           454:        case XL_DEBUG:
        !           455:                if  (copyin(arg, (caddr_t)&XL_VERBOSE, sizeof(int)) == -1)
        !           456:                        u.u_error = EFAULT;
        !           457:                break;
        !           458:        case XL_STATUS:                 /* read status                  */
        !           459:                /*
        !           460:                * Report current status, then clear
        !           461:                * any errors by reading the status again.
        !           462:                */
        !           463:                xl.stat[0] = xl6sts;
        !           464:                xl.stat[1] = xl7sts;
        !           465:                xl.stat[2] = xl7sts >> 8;
        !           466: 
        !           467:                if (copyout(xl.stat, arg, sizeof(xl.stat)) == -1)
        !           468:                        u.u_error = EFAULT;
        !           469:                else {
        !           470:                        xlster = 0;
        !           471:                        xlests = 0;
        !           472:                        xl7sts = 0;
        !           473:                        pfsts = xlcomplete;
        !           474:                        xlstatus();
        !           475:                        xlwait();
        !           476:                        if (f.werr)     /* flag error if occurred       */
        !           477:                                u.u_error = EIO;
        !           478:                        break;
        !           479: 
        !           480:                case XL_RESET:          /* reset drive                  */
        !           481:                        pfrst = xlcomplete;
        !           482:                        xlreset();
        !           483:                        xlwait();
        !           484:                        if (f.werr)     /* flag error if occurred       */
        !           485:                                u.u_error = EIO;
        !           486:                        break;
        !           487: 
        !           488:                case XL_RETEN :         /* retention tape               */
        !           489:                        pfint = xlready;
        !           490:                        pfrdy = xlcomplete;
        !           491:                        xloutput_step(QIC_CMD_EOT);
        !           492:                        xlwait();
        !           493: 
        !           494:                        pfint = xlready;
        !           495:                        pfrdy = xlcomplete;
        !           496:                        xloutput_step(QIC_CMD_BOT);
        !           497:                        xlwait();
        !           498:                        if (xlster)
        !           499:                                u.u_error = ENXIO;
        !           500: 
        !           501:                        break;
        !           502: 
        !           503:                case XL_REWIND:         /* rewind                       */
        !           504:                        pfint = xlready;
        !           505:                        pfrdy = xlcomplete;
        !           506:                        xloutput_step(QIC_CMD_BOT);
        !           507:                        xlwait();
        !           508:                        if (xlster)
        !           509:                                u.u_error = ENXIO;
        !           510:                        break;
        !           511: 
        !           512:                case XL_ERASE:          /* erase tape                   */
        !           513:                        break;
        !           514: 
        !           515:                case XL_AMOUNT:         /* report amount of data xfered */
        !           516:                        /*if (copyout(&ct_amount, arg, sizeof(ct_amount)) == -1)
        !           517:                        u.u_error = EFAULT;*/
        !           518:                        break;
        !           519: 
        !           520:                case XL_FORMAT:         /* format tape                  */
        !           521:                        if  (copyin(arg, (caddr_t) &xlarg, sizeof(int)) == -1)
        !           522:                                u.u_error = EFAULT;
        !           523: 
        !           524:                        else if ((xlarg >= 0 && xlarg <= 14 && ftfmt == 0) ||
        !           525:                                 (xlarg >= 0 && xlarg <= 28 && ftfmt == 1)) {
        !           526:                                xlformat(xlarg);
        !           527:                                if (f.werr)     /* flag err if occurred */
        !           528:                                        u.u_error = EIO;
        !           529:                        } else          /* invalid track number         */
        !           530:                                u.u_error = EINVAL;
        !           531:                }
        !           532:                break;
        !           533:        case XL_RFM:                    /* read file mark               */
        !           534:                ;                       /* not implemented              */
        !           535: 
        !           536:        default:
        !           537:                u.u_error = EINVAL;
        !           538:                break;
        !           539:        }
        !           540:        xlrel();                        /* release fdc                  */
        !           541:        relfdc();
        !           542:        cmn_err(CE_CONT, "xlioctl: returning\n");
        !           543: }
        !           544: 
        !           545: /************************************************************************/
        !           546: /*     ftload                                                          */
        !           547: /************************************************************************/
        !           548: static int
        !           549: ftload()
        !           550: {
        !           551:        register int    eflag;
        !           552:        register int    s, t;
        !           553: 
        !           554: #if MWC_FT
        !           555:        ftIntr = ftIrqHandler;
        !           556: #else
        !           557:        ftIntr = xlintr;
        !           558: #endif
        !           559: 
        !           560:        f.init = 0;                     /* reset flags                  */
        !           561:        f.open = 0;
        !           562:        f.cal = 0;
        !           563:        f.actv = 0;
        !           564:        f.tmov = 0;
        !           565:        xlnactw = 0;
        !           566:        xlfreew = 0;
        !           567:        xldataw = 0;
        !           568:        xlcompw = 0;
        !           569:        xlcompf = 0;
        !           570:        xlster = 0;
        !           571:        status_buf[7] = 0;
        !           572:        pfint = xlnull;                 /* reset ptr to fun             */
        !           573:        xl_tbi();                       /* init ecc tables              */
        !           574:        if(getmem())
        !           575:                printf("XL: getmem() failed.\n");
        !           576:        else
        !           577:                printf("Archive xl floppy tape driver v1.0 COH loaded\n");
        !           578: }
        !           579: 
        !           580: /************************************************************************
        !           581:  * ftopen
        !           582:  *
        !           583:  ***********************************************************************/
        !           584: static int
        !           585: ftopen(dev, mode)
        !           586: dev_t dev;
        !           587: int mode;
        !           588: {
        !           589:        unsigned int drvStat;
        !           590:        int i;
        !           591:        int bit;
        !           592:        int result;
        !           593: 
        !           594: printf("ftopen %x ", dev);
        !           595: 
        !           596:        /* Can't append to tape. */
        !           597:        if (mode & IPAPPEND) {
        !           598: printf("can't append ");
        !           599:                u.u_error = EINVAL;
        !           600:                return;
        !           601:        }
        !           602: 
        !           603:        /* Only one open at a time. */
        !           604:        if (f.open) {
        !           605: printf("only one ftopen at a time ");
        !           606:                u.u_error = EBUSY;
        !           607:                return;
        !           608:        }
        !           609:        f.open = 1;
        !           610: 
        !           611:        unit = FT_UNIT(dev);            /* set unit #                   */
        !           612: 
        !           613:        if (! getfdcn(unit)) {  /* get control of fdc           */
        !           614: printf("fdc unavailable ");
        !           615:                u.u_error = EBUSY;      /* exit if fdc is being used    */
        !           616:                f.open = 0;
        !           617:                return;
        !           618:        }
        !           619: 
        !           620: #if MWC_FT
        !           621: {
        !           622:        ftIntr = ftIrqHandler;
        !           623: 
        !           624:        /* Select tape drive. */
        !           625:        /* ftSelect(unit); */
        !           626:        fdcRate(FDC_RATE_500K);         /* set transfer rate            */
        !           627:        fdcDrvSelect(unit, FDC_MOTOR_ON);               /* 1=motor on                   */
        !           628: 
        !           629:        /* Reset FDC and Initialize pseudo cylinder number for QIC commands. */
        !           630:        ftResetFDC(unit);
        !           631: 
        !           632:        fdcSpecify(FT_SRT, FT_HUT, FT_HLT);
        !           633: 
        !           634:        /* 80 MB nseg_p_track = 100, nseg_p_head = 600, nseg_p_cyl = 4  */
        !           635:        /* 40 MB nseg_p_track = 68, nseg_p_head = 680, nseg_p_cyl = 4   */
        !           636:        if (ftfmt) {
        !           637:                nseg_p_track = 100;     /* set for 80 MB drive          */
        !           638:                nseg_p_head = 600;
        !           639:                nseg_p_cyl = 4;
        !           640:        } else {
        !           641:                nseg_p_track = 68;      /* set for 40 MB drive          */
        !           642:                nseg_p_head = 680;
        !           643:                nseg_p_cyl = 4;
        !           644:        }
        !           645: 
        !           646:        if (ftCmd(QIC_CMD_RST)) {
        !           647: printf("soft reset failed ");
        !           648:                u.u_error = EIO;
        !           649:                f.open = 0;
        !           650:                setFtIntr(0);
        !           651:                return;
        !           652:        }
        !           653: 
        !           654: printf("zzz ");
        !           655:        /* Now wait a second. */
        !           656:        timeout(&ft.ft_tim, HZ, wakeup, &ft.ft_wakeMeUp);
        !           657:        x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRstWt");
        !           658: printf("!! ");
        !           659: 
        !           660:        if (ftCmd(QIC_CMD_STS)) {
        !           661: printf("get drive status failed ");
        !           662:                u.u_error = EIO;
        !           663:                f.open = 0;
        !           664:                setFtIntr(0);
        !           665:                return;
        !           666:        }
        !           667:        xlDbPrintStat(ft.ft_report);
        !           668: 
        !           669:        if (ftCmd(QIC_CMD_ECD)) {
        !           670: printf("get error code failed ");
        !           671:                u.u_error = EIO;
        !           672:                f.open = 0;
        !           673:                setFtIntr(0);
        !           674:                return;
        !           675:        }
        !           676:        xlDbPrintErr(ft.ft_report);
        !           677: 
        !           678:        if (ftCmd(QIC_CMD_STS)) {
        !           679: printf("get drive status failed ");
        !           680:                u.u_error = EIO;
        !           681:                f.open = 0;
        !           682:                setFtIntr(0);
        !           683:                return;
        !           684:        }
        !           685:        xlDbPrintStat(ft.ft_report);
        !           686: 
        !           687: }
        !           688:        xlrel();
        !           689:        relfdc();
        !           690: #else
        !           691:        xlsel(unit);
        !           692: 
        !           693:        if (0 == f.init) {              /* init drive if 1st time       */
        !           694:                pfrst = xlcomplete;
        !           695:                xlreset();
        !           696:                if (xlwait()) {
        !           697: printf("init interrupted ");
        !           698:                        u.u_error = EINTR;
        !           699:                        f.open = 0;
        !           700:                        relfdc();
        !           701:                        return;
        !           702:                }
        !           703:                f.init = 1;
        !           704:        }
        !           705: 
        !           706:        if (!xlopn(minor(dev))) {       /* open drive                   */
        !           707:                /* init current params                                  */
        !           708:                read_ahead_seg_num = curr_seg_num = data_seg_num;
        !           709:                cmn_err(CE_CONT, "xlopen: volume_seg_num %d  data_seg_num %d  last_seg_num %d  lnbr %d\n",
        !           710:                   volume_seg_num, data_seg_num, last_seg_num, lnbr);
        !           711: 
        !           712:                cnbr = 0;
        !           713:                xstop = 0;
        !           714:                f.writ = 0;
        !           715:                f.werr = 0;
        !           716:        } else {
        !           717: printf("xlopn failed ");
        !           718:                u.u_error = ENODEV;     /* set no device                */
        !           719:                f.open = 0;
        !           720:        }
        !           721:        xlrel();                        /* release fdc                  */
        !           722:        relfdc();
        !           723:        cmn_err(CE_CONT, "xlopen: xlster %x, xl6sts %x, xlests %x, xl7sts %x\n",
        !           724:           xlster, xl6sts, xlests, xl7sts);
        !           725: #endif
        !           726: }
        !           727: 
        !           728: /************************************************************************
        !           729:  * ftread
        !           730:  *
        !           731:  ***********************************************************************/
        !           732: static int
        !           733: ftread(dev, iop)
        !           734: dev_t dev;
        !           735: IO * iop;
        !           736: {
        !           737:        if (!f.open) {                  /* exit if not open             */
        !           738:                u.u_error = EIO;
        !           739:                return;
        !           740:        }
        !           741:        xlgtdat(iop);
        !           742: }
        !           743: 
        !           744: /************************************************************************
        !           745:  * ftunload
        !           746:  *
        !           747:  ***********************************************************************/
        !           748: static int
        !           749: ftunload()
        !           750: {
        !           751: }
        !           752: 
        !           753: /************************************************************************
        !           754:  * ftwrite
        !           755:  *
        !           756:  ***********************************************************************/
        !           757: static int
        !           758: ftwrite(dev, iop)
        !           759: dev_t dev;
        !           760: IO * iop;
        !           761: {
        !           762:        if (!f.open) {                  /* exit if not open             */
        !           763:                u.u_error = EIO;
        !           764:                return;
        !           765:        }
        !           766:        if (xl6sts & XLSWRP) {          /* exit if write protect        */
        !           767:                u.u_error = EIO;
        !           768:                return;
        !           769:        }
        !           770:        while(fprb = getrb(&data_queue))/* rel any pending read bfrs*/
        !           771:                putrb(&xlfree_q, fprb);/* allows swt from read to write*/
        !           772:        f.writ = 1;                     /* set write flag               */
        !           773:        xlptdat(iop);
        !           774:        if (f.werr)                     /* flag error if occurred       */
        !           775:                u.u_error = EIO;
        !           776: }
        !           777: 
        !           778: /*
        !           779:  * Support routines.
        !           780:  */
        !           781: 
        !           782: /************************************************************************/
        !           783: /*     cmn_err() - doesn't really belong here                          */
        !           784: /************************************************************************/
        !           785: static void
        !           786: cmn_err(level, format)
        !           787: int level;
        !           788: char * format;
        !           789: {
        !           790:        if (XL_VERBOSE)
        !           791:                printf("%r ", &format);
        !           792: }
        !           793: 
        !           794: /************************************************************************/
        !           795: /*     dsperr  display floppy error                                    */
        !           796: /************************************************************************/
        !           797: static int
        !           798: dsperr()
        !           799: {                                      /* disregard fdc ecc error */
        !           800:        if (!(status_buf[0] == 0x41 &&
        !           801:               status_buf[1] == 0x20 &&
        !           802:               status_buf[2] == 0x20)) 
        !           803:                cmn_err(CE_CONT, "fdcerr: ST0=%x ST1=%x ST2=%x\n",
        !           804:                        status_buf[0], status_buf[1], status_buf[2]);
        !           805: }
        !           806: 
        !           807: /*
        !           808:  * For debugging, print command status and interrupt status to console.
        !           809:  */
        !           810: static void
        !           811: ftDbPrtStat()
        !           812: {
        !           813:        int i;
        !           814: 
        !           815:        printf("[[");
        !           816:        if (fdc.fdc_ncmdstat) {
        !           817:                printf("cmd ");
        !           818:                for (i = 0; i < fdc.fdc_ncmdstat; i++)
        !           819:                        printf("%x ", fdc.fdc_cmdstat[i]);
        !           820:        }
        !           821:        if (fdc.fdc_nintstat) {
        !           822:                printf("int ");
        !           823:                for (i = 0; i < fdc.fdc_nintstat; i++)
        !           824:                        printf("%x ", fdc.fdc_intstat[i]);
        !           825:        }
        !           826:        printf("]] ");
        !           827: }
        !           828: 
        !           829: /*
        !           830:  * Given a QIC-117 command number, cause that number of step pulses
        !           831:  * to be sent from the FDC by faking a seek command.
        !           832:  */
        !           833: static int
        !           834: ftCmdSend(cmd)
        !           835: int cmd;
        !           836: {
        !           837:        /* Like NEC - pcn=present cylinder #; ncn=new cylinder #. */
        !           838:        unsigned char ncn;
        !           839:        
        !           840:        xlDbPrintCmd(cmd);
        !           841: 
        !           842:        /*
        !           843:         * Will fake a seek command.
        !           844:         * Figure out whether to simulate seek to lower or higher
        !           845:         * cylinder number.
        !           846:         */
        !           847:        if (ft.ft_pcn + cmd <= MAX_PCN) {
        !           848:                ncn = ft.ft_pcn + cmd;
        !           849:        } else if (ft.ft_pcn - cmd >= 0) {
        !           850:                ncn = ft.ft_pcn - cmd;
        !           851:        } else {
        !           852:                printf("ftCmd %d invalid, pcn %d ", cmd, ft.ft_pcn);
        !           853:                return -1;
        !           854:        }
        !           855: 
        !           856:        ft.ft_dumpIrq = 1;
        !           857:        fdcSeek(unit, 0, ncn);
        !           858: }
        !           859: 
        !           860: /*
        !           861:  * Given a QIC-117 command number, send the command.
        !           862:  * If report bits are expected in response, initialize the bit counter.
        !           863:  * Then sleep until the commmand is done and report bits are gathered.
        !           864:  */
        !           865: static int
        !           866: ftCmd(cmd)
        !           867: int cmd;
        !           868: {
        !           869:        int     bitsNeeded;
        !           870: 
        !           871:        /* Will sleep until command done and report bits are in. */
        !           872:        ft.ft_wakeMeUp = 1;
        !           873: 
        !           874:        /*
        !           875:         * The following commands expect report bits from the tape drive.
        !           876:         * After receiving the QIC command (and subsequent delay),
        !           877:         * the drive sends a leading ACK bit (always 1).  This bit is
        !           878:         * not counted in the numbers below.
        !           879:         * Subseqeunt bits are sent in response to Report Next Bit,
        !           880:         * least significant bit first, then a trailing 1.
        !           881:         * The value of bitsNeeded is either one more than the number of
        !           882:         * data bits in the report, or zero.
        !           883: 
        !           884:         */
        !           885:        switch(cmd) {
        !           886:        case QIC_CMD_STS:
        !           887:        case QIC_CMD_DRVCN:
        !           888:        case QIC_CMD_ROMVN:
        !           889:        case QIC_CMD_TPSTAT:
        !           890:                bitsNeeded = 9;
        !           891:                break;
        !           892:        case QIC_CMD_ECD:
        !           893:        case QIC_CMD_VNDID:
        !           894:                bitsNeeded = 17;
        !           895:                break;
        !           896:        default:
        !           897:                bitsNeeded = 0;
        !           898:        }
        !           899:        ftRptBegin(bitsNeeded);
        !           900: 
        !           901:        ftCmdSend(cmd);
        !           902: 
        !           903:        if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftCmd"))
        !           904:                /* Signal woke us prematurely. */
        !           905:                return -1;
        !           906:        else {
        !           907:                return 0;
        !           908:        }
        !           909: }
        !           910: 
        !           911: /*
        !           912:  * Interrupt handler.
        !           913:  */
        !           914: static void
        !           915: ftIrqHandler()
        !           916: {
        !           917:        int i, bit, unit;
        !           918: 
        !           919:        /*
        !           920:         * Need to get FDC status from result phase - fdcCmdStatus -
        !           921:         * or clear interrupt - fdcIntStatus - that may have been
        !           922:         * generated by diskette change or seek/recal complete.
        !           923:         */
        !           924:        if (FDC_BUSY()) {
        !           925:                fdcCmdStatus();
        !           926:        } else {
        !           927:                fdcIntStatus();
        !           928: /* WARNING - should squawk if wrong number of status bytes. */
        !           929:                ft.ft_pcn = fdc.fdc_intstat[1];
        !           930:                unit = fdc.fdc_intstat[0] & 3;
        !           931:        }
        !           932: 
        !           933:        /* If ACK needed, try several times to get it. */
        !           934:        if (ft.ft_ackNeeded) {
        !           935:                for (i = 0; i < FT_ACK_TRIES; i++) {
        !           936:                        fdcDrvStatus(unit, FDC_HEAD_0);
        !           937:                        fdcCmdStatus();
        !           938:                        bit = (fdc.fdc_cmdstat[0] & ST3_T0) ? 1 : 0;
        !           939: putchar(bit ? '|' : 'o');
        !           940:                        if (bit) {      
        !           941:                                ft.ft_ackNeeded = 0;
        !           942:                                break;
        !           943:                        }
        !           944:                        /* Wait about 20 usec. then try again. */
        !           945:                        busyWait2(NULL, 20);
        !           946:                }
        !           947: 
        !           948:                if (ft.ft_ackNeeded) {
        !           949: /* Need error recovery here! */
        !           950:                        printf("<= Missing ACK ");
        !           951:                        ft.ft_ackNeeded = 0;
        !           952:                }
        !           953:        } else if (ft.ft_bitsNeeded) {
        !           954:                /*
        !           955:                 * If report bits are needed
        !           956:                 *   Get current report bit.
        !           957:                 */
        !           958: 
        !           959:                /*
        !           960:                 * Need unit # for Sense Drive Status command.
        !           961:                 * Get it from preceding Sense Interrupt command.
        !           962:                 */
        !           963:                fdcDrvStatus(unit, FDC_HEAD_0);
        !           964:                fdcCmdStatus();
        !           965: 
        !           966:                /* Get next report bit by checking Track Zero bit in ST3 */
        !           967:                if (fdc.fdc_ncmdstat == 1) {
        !           968:                        int bit;
        !           969: 
        !           970:                        bit = (fdc.fdc_cmdstat[0] & ST3_T0) ? 1 : 0;
        !           971:                        printf("%d", bit);
        !           972:                        ftRptUpdate(bit);
        !           973:                } else {
        !           974:                        printf("rnb status bad ");
        !           975:                }
        !           976:        }
        !           977: 
        !           978:        /*
        !           979:         * If more report bits will be needed
        !           980:         *   Send request for next bit.
        !           981:         * Else
        !           982:         *   See if original requestor needs wakeup, etc.
        !           983:         */
        !           984:        if (ft.ft_bitsNeeded) {
        !           985:                ftCmdSend(QIC_CMD_RNB);
        !           986:        } else {
        !           987:                if (ft.ft_wakeMeUp) {
        !           988:                        ft.ft_wakeMeUp = 0;
        !           989:                        wakeup(&ft.ft_wakeMeUp);
        !           990:                }
        !           991: 
        !           992:                /* Print debug output if needed. */
        !           993:                if (ft.ft_dumpIrq) {
        !           994:                        ft.ft_dumpIrq = 0;
        !           995:                        defer(ftDbPrtStat);
        !           996:                }
        !           997:        }
        !           998: }
        !           999: 
        !          1000: /*
        !          1001:  * Send Recalibrate command to FDC and wait for it to finish.
        !          1002:  *
        !          1003:  * Return 0 if normal operation, -1 if signaled before recal complete.
        !          1004:  */
        !          1005: static int
        !          1006: ftRecal(unit)
        !          1007: int unit;
        !          1008: {
        !          1009:        ft.ft_wakeMeUp = 1;
        !          1010:        fdcRecal(unit);
        !          1011:        if (x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRecal"))
        !          1012:                return -1;
        !          1013:        else
        !          1014:                return 0;
        !          1015: }
        !          1016: 
        !          1017: /************************************************************************
        !          1018:  * ftResetFDC
        !          1019:  *
        !          1020:  * Reset the FDC and wait for the resulting interrupt.
        !          1021:  * Reset is done keeping the unit in question selected.
        !          1022:  ***********************************************************************/
        !          1023: static void
        !          1024: ftResetFDC(unit)
        !          1025: {
        !          1026:        /*
        !          1027:         * Since FDC reset generates an interrupt, we need to tell the
        !          1028:         * interrupt handler there will be *no* report bits incoming.
        !          1029:         */
        !          1030:        ftRptBegin(0);
        !          1031: 
        !          1032:        ft.ft_pcn = 0;
        !          1033:        ft.ft_wakeMeUp = 1;
        !          1034:        fdcResetSel(unit, FDC_MOTOR_ON);
        !          1035:        x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftRstFDC");
        !          1036: }
        !          1037: 
        !          1038: /************************************************************************
        !          1039:  * ftRptBegin
        !          1040:  *
        !          1041:  * Initialize ft state information in preparation for QIC report command.
        !          1042:  *
        !          1043:  * Argument "bitCount" is the total number of bits expected, including
        !          1044:  * initial ACK and final TRUE.  It is 1 more than the number of
        !          1045:  * Report Next Bit Commands that will be issued.
        !          1046:  ***********************************************************************/
        !          1047: static void
        !          1048: ftRptBegin(bitCount)
        !          1049: int bitCount;
        !          1050: {
        !          1051:        ft.ft_bitsNeeded = bitCount;
        !          1052:        ft.ft_bitsRcvd = 0;
        !          1053:        ft.ft_report = 0;
        !          1054:        ft.ft_ackNeeded = (bitCount) ? 1 : 0;
        !          1055: }
        !          1056: 
        !          1057: /************************************************************************
        !          1058:  * ftRptUpdate
        !          1059:  *
        !          1060:  * Acquire another bit for QIC report command.
        !          1061:  * Last bit is discarded.  Other bits are accumulated,
        !          1062:  * least significant bit first, into ft_report.
        !          1063:  ***********************************************************************/
        !          1064: static void
        !          1065: ftRptUpdate(bit)
        !          1066: int bit;
        !          1067: {
        !          1068:        ft.ft_bitsNeeded--;
        !          1069:        ft.ft_bitsRcvd++;
        !          1070: 
        !          1071:        if (ft.ft_bitsNeeded == 0) {
        !          1072:                if (bit != 1)
        !          1073:                        printf("Missing final TRUE ");
        !          1074:        } else {
        !          1075:                ft.ft_report |= (bit << (ft.ft_bitsRcvd - 1));
        !          1076:        }
        !          1077: }
        !          1078: 
        !          1079: /*
        !          1080:  * Select tape unit.
        !          1081:  */
        !          1082: static void
        !          1083: ftSelect(unit)
        !          1084: int unit;
        !          1085: {
        !          1086:        fdcRate(FDC_RATE_500K);         /* set transfer rate            */
        !          1087:        fdcDrvSelect(unit, 1);          /* 1=motor on                   */
        !          1088: 
        !          1089:        /* Toggle FDC reset line, then wait for its interrupt.          */
        !          1090:        ft.ft_wakeMeUp = 1;
        !          1091:        fdcResetSel(unit, 1);           /* Reset, preserving selection  */
        !          1092:        x_sleep(&ft.ft_wakeMeUp, pritape, slpriSigCatch, "ftSelect");
        !          1093: 
        !          1094:        fdcSpecify(FT_SRT, FT_HUT, FT_HLT);
        !          1095: 
        !          1096:        /* 80 MB nseg_p_track = 100, nseg_p_head = 600, nseg_p_cyl = 4  */
        !          1097:        /* 40 MB nseg_p_track = 68, nseg_p_head = 680, nseg_p_cyl = 4   */
        !          1098:        if (ftfmt) {
        !          1099:                nseg_p_track = 100;     /* set for 80 MB drive          */
        !          1100:                nseg_p_head = 600;
        !          1101:                nseg_p_cyl = 4;
        !          1102:        } else {
        !          1103:                nseg_p_track = 68;      /* set for 40 MB drive          */
        !          1104:                nseg_p_head = 680;
        !          1105:                nseg_p_cyl = 4;
        !          1106:        }
        !          1107: }
        !          1108: 
        !          1109: /************************************************************************
        !          1110:  * getmem
        !          1111:  *
        !          1112:  * Grab XL_NBUFS # of 32k DMA buffers.
        !          1113:  * Only use 16k of one of these, for QIC headers.
        !          1114:  *
        !          1115:  * Return 0 on success, 1 on failure.
        !          1116:  ***********************************************************************/
        !          1117: static int
        !          1118: getmem()
        !          1119: {
        !          1120:        register        int     i, nb;
        !          1121:        struct          rb      *prb;
        !          1122:        unsigned int    tmpad, highAddr;
        !          1123: 
        !          1124:        if (xlmem_allocated)
        !          1125:                return 0;
        !          1126: 
        !          1127:        nb = XL_NBUFS;
        !          1128:        if (nb < 4)
        !          1129:                nb = 4;
        !          1130: 
        !          1131:        rbmp = (struct rb *)kalloc(XL_NBUFS * sizeof(struct rb));
        !          1132:        if (rbmp == NULL) {
        !          1133:                printf("XL: initial kalloc() failed\n");
        !          1134:                return 1;
        !          1135:        }
        !          1136: 
        !          1137:        allocated_add = getDmaMem(nb * BFRSZ, BFRSZ);
        !          1138:        if (allocated_add == NULL) {
        !          1139:                printf("XL: getDmaMem() failed\n");
        !          1140:                return 1;
        !          1141:        }
        !          1142: 
        !          1143:        highAddr = allocated_add + (nb * BFRSZ);
        !          1144: 
        !          1145:        cmn_err(CE_CONT, "Allocated %d buffers.  Virtual <%x-%x>.  "
        !          1146:          "Physical <%x-%x>.\n",
        !          1147:          nb, allocated_add, highAddr, vtop(allocated_add), vtop(highAddr));
        !          1148: 
        !          1149:        /* tmpad = 1st 32k bfr adr                      */
        !          1150:        tmpad = (allocated_add + BFRSZ);
        !          1151: 
        !          1152:        ptr_header = (fplng)allocated_add;
        !          1153: 
        !          1154:        xlfree_q.top = prb = rbmp;/* build free pool    */
        !          1155:        for (i = 0; i < (nb - 1); ++i) {
        !          1156:                xlfree_q.bot = prb;
        !          1157:                ++prb;
        !          1158:                xlfree_q.bot->nxt = prb;
        !          1159:                xlfree_q.bot->adr = tmpad;
        !          1160:                tmpad += BFRSZ;
        !          1161:        }
        !          1162:        xlfree_q.bot->nxt = 0;
        !          1163: 
        !          1164:        cmn_err(CE_CONT, "getmem: allocated %d buffers\n", nb);
        !          1165: 
        !          1166:        xlmem_allocated = 1;
        !          1167:        data_queue.top = 0;
        !          1168:        data_queue.bot = 0;
        !          1169:        return 0;
        !          1170: }
        !          1171: 
        !          1172: /************************************************************************/
        !          1173: /*     getrb   get request buffer from queue                           */
        !          1174: /************************************************************************/
        !          1175: static struct  rb *
        !          1176: getrb(prbq)
        !          1177: struct rbq     *prbq;
        !          1178: {
        !          1179:        struct  rb *prb;
        !          1180:        int     ilv;
        !          1181: 
        !          1182:        if (0 == (prb = prbq->top))     /* return if empty              */
        !          1183:                return 0;
        !          1184:        ilv = spl5();                   /* playing with queue           */
        !          1185:        prbq->top = prb->nxt;           /* advance top ptr              */
        !          1186:        if (0 == prbq->top)
        !          1187:                prbq->bot = 0;
        !          1188:        splx(ilv);                      /* done with queue              */
        !          1189:        return prb;
        !          1190: }
        !          1191: 
        !          1192: /************************************************************************/
        !          1193: /*     putrb   add req buf to end of queue                             */
        !          1194: /*     return 1 if added to empty queue                                */
        !          1195: /************************************************************************/
        !          1196: static int
        !          1197: putrb(prbq, prb)
        !          1198: struct rbq     *prbq;
        !          1199: struct rb      *prb;
        !          1200: {
        !          1201:        int     ilv;
        !          1202: 
        !          1203:        prb->nxt = 0;                   /* reset this buf's fwd ptr     */
        !          1204:        ilv = spl5();                   /* playing with queues          */
        !          1205:        if (0 == prbq->top) {           /* if empty queue,              */
        !          1206:                prbq->top = prb;        /* pnt top and bot to new buf   */
        !          1207:                prbq->bot = prb;
        !          1208:                splx(ilv);
        !          1209:                return 1;
        !          1210:        } else {
        !          1211:                (prbq->bot)->nxt = prb;/* else pnt old end to new buf   */
        !          1212:                prbq->bot = prb;        /* and bot to new buf           */
        !          1213:                splx(ilv);
        !          1214:                return 0;
        !          1215:        }
        !          1216: }
        !          1217: 
        !          1218: /************************************************************************/
        !          1219: /*     stdma    set dma                                                */
        !          1220: /************************************************************************/
        !          1221: static void
        !          1222: stdma(mode, adr, count)
        !          1223: int    mode;
        !          1224: paddr_t        adr;
        !          1225: int    count;
        !          1226: {
        !          1227:        cmn_err(CE_CONT, "dir: %x Vadd: %x, Padd: %x, count: %x\n",
        !          1228:          mode, adr, kvtophys(adr), count);
        !          1229: 
        !          1230:        /* dma_param(DMA_CH2, mode, kvtophys(adr), count - 1); */
        !          1231:        /* dma_enable(DMA_CH2); */
        !          1232:        xldma((char)(mode + DMA_CH2), (long)kvtophys(adr), count - 1);
        !          1233: }
        !          1234: 
        !          1235: /************************************************************************/
        !          1236: /*     strbfm  set up rb params for format                             */
        !          1237: /************************************************************************/
        !          1238: static void
        !          1239: strbfm(prb)
        !          1240: struct rb      *prb;
        !          1241: {
        !          1242:        register fpchr  p0;
        !          1243:        register int d0;
        !          1244:        int     d1;
        !          1245: 
        !          1246:        d0 = prb->sgn;                  /* get segment #                */
        !          1247:        prb->hed = d0/nseg_p_head;      /* set up fdc params            */
        !          1248:        d0 = d0 % nseg_p_head;
        !          1249:        prb->cyl = d0/nseg_p_cyl;
        !          1250:        prb->sct = ((d0 % nseg_p_cyl) << 5) + 1;
        !          1251: 
        !          1252:        p0 = (fpchr)cprb->adr;
        !          1253: 
        !          1254:        /*                              fill format bfr                 */
        !          1255: 
        !          1256:        d0 = prb->sct;
        !          1257:        for (d1 = d0 + 32; d0 != d1; ++d0) {
        !          1258:                *p0++ = prb->cyl;
        !          1259:                *p0++ = prb->hed;
        !          1260:                *p0++ = d0;
        !          1261:                *p0++ = 3;
        !          1262:        }
        !          1263: }
        !          1264: 
        !          1265: /************************************************************************/
        !          1266: /*     strbsg  set up rb params for segment                            */
        !          1267: /*             should be called at task time                           */
        !          1268: /*                                                                     */
        !          1269: /*     rb.tbl  is used to skip bad sectors in segments.                */
        !          1270: /*             segments are split up into "chunks"                     */
        !          1271: /*             index into rb.tbl with relative sector.                 */
        !          1272: /*             each word in rb.tbl:                                    */
        !          1273: /*             bits 15-10:  sector count for chunk                     */
        !          1274: /*             bits  9- 5:  dma offset for chunk                       */
        !          1275: /*             bits  4- 0:  sector # for chunk                         */
        !          1276: /************************************************************************/
        !          1277: static void
        !          1278: strbsg(prb)
        !          1279: struct rb      *prb;
        !          1280: {
        !          1281:        register int    d0, d1, d2;
        !          1282:        ushort          *p0;
        !          1283: 
        !          1284:        prb->erc = 0;                   /* reset error count            */
        !          1285:        d0 = prb->sgn;                  /* set tape params              */
        !          1286:        prb->trk = d0 / nseg_p_track;
        !          1287:        prb->tps = d0 % nseg_p_track;
        !          1288:        prb->hed = d0 / nseg_p_head;    /* set up fdc params            */
        !          1289:        d0 = d0 % nseg_p_head;
        !          1290:        prb->cyl = d1 = d0 / nseg_p_cyl;
        !          1291:        prb->sct = d0 = ((d0 % nseg_p_cyl) << 5) + 1;
        !          1292:        if (d0 == 1) {                  /* set up position params       */
        !          1293:                --d1;
        !          1294:                d0 = (nseg_p_cyl << 5) - 16;
        !          1295:        }
        !          1296:        else
        !          1297:                d0 -= 16;
        !          1298:        prb->idc = d1;
        !          1299:        prb->ids = d0;
        !          1300:        d2 = 32;                        /* set up rb.tbl                */
        !          1301:        sgwrd = 0;
        !          1302:        sgmap = prb->map;
        !          1303:        p0 = prb->tbl;
        !          1304:        prb->nbk = 0;
        !          1305:        while(d2) {
        !          1306:                d0 = d2;                /* d0 = # scts to skip          */
        !          1307:                while(sgmap & 1) {
        !          1308:                        --d2;
        !          1309:                        sgmap >>= 1;
        !          1310:                }
        !          1311:                d0 -= d2;
        !          1312:                sgwrd += d0;            /* bump sct # in sgwrd          */
        !          1313:                if (!d2)                /* exit if done                 */
        !          1314:                        break;
        !          1315:                d1 = d2;                /* d1 = # scts this chunk       */
        !          1316:                while(d2 && 0 == (sgmap & 1)) {
        !          1317:                        --d2;
        !          1318:                        sgmap >>= 1;
        !          1319:                }
        !          1320:                d1 -= d2;
        !          1321:                prb->nbk += d1;         /* adjust # blocks in segment   */
        !          1322:                sgwrd += d1 << 10;      /* set count in sgwrd           */
        !          1323:                while(d0) {             /* fill table for skipped scts  */
        !          1324:                        *p0++ = sgwrd;
        !          1325:                        --d0;
        !          1326:                }
        !          1327:                while(d1) {             /* for each sct xferred         */
        !          1328:                        *p0++ = sgwrd;  /* store table entry            */
        !          1329:                        sgwrd += 0xfc21;/* dec cnt, bump ofset bump sct */
        !          1330:                        --d1;
        !          1331:                }
        !          1332:        }
        !          1333:        for (++d0; d0; --d0)            /* zero out rest of rb.tbl      */
        !          1334:                *p0++ = 0;
        !          1335: }
        !          1336: 
        !          1337: /************************************************************************/
        !          1338: /*     stseg   set up segment io                                       */
        !          1339: /************************************************************************/
        !          1340: static void
        !          1341: stseg(prb)
        !          1342: struct rb      *prb;
        !          1343: {
        !          1344:        rwdcms[1] = unit;               /* set rwdcmd constants         */
        !          1345:        rwdcms[2] = prb->cyl;
        !          1346:        rwdcms[3] = prb->hed;
        !          1347:        xadr = prb->adr;                /* set base adr                 */
        !          1348:        xsct = prb->sct;                /* set base sct                 */
        !          1349:        xrty = 6;                       /* set default # retries        */
        !          1350: }
        !          1351: 
        !          1352: /************************************************************************/
        !          1353: /*     wvtbl   create volume table entry                               */
        !          1354: /************************************************************************/
        !          1355: static void
        !          1356: wvtbl()
        !          1357: {
        !          1358:        xlvtbl  *p;
        !          1359:        int     ilvl;
        !          1360:        int     i;
        !          1361: 
        !          1362:        ilvl = spl5();                  /*   wait for a new buffer      */
        !          1363:        while(!(cprb = getrb(&xlfree_q))) {
        !          1364:                if (!f.actv)
        !          1365:                        xlque();
        !          1366:                xlfreew = 1;
        !          1367:                sleep(&xlfreew, PRIBIO);
        !          1368:        }
        !          1369:        splx(ilvl);
        !          1370:        p = (xlvtbl *)cprb->adr;
        !          1371:        wptr = (fpchr)p;                /* save ptr for encode          */
        !          1372:        for (i = 0; vtbl[i]; ++i)
        !          1373:                p->ident[i] = vtbl[i];
        !          1374:        p->data_seg_num = (unsigned short)data_seg_num;
        !          1375:        p->last_seg_num = (unsigned short)curr_seg_num - 1;
        !          1376:        for (i = 0; p->op_system[i] = xnxnm[i]; ++i);
        !          1377: 
        !          1378:        for (ilvl = 0; ilvl < 43; ++ilvl)       /* fill zero not implemented */ 
        !          1379:                p->p1[ilvl] = 0;
        !          1380:        p->c_seq_num = 1;                       /* cartridge sequence # =1   */
        !          1381: 
        !          1382:        for (ilvl = 0; ilvl < 34; ++ilvl)       /* fill zero                 */
        !          1383:                p->p3[ilvl] = 0;
        !          1384: 
        !          1385:        p->last_blk_size = (unsigned short)(lnbr - cnbr);
        !          1386:        cprb->sgn = volume_seg_num;
        !          1387:        cprb->map = ptr_header[volume_seg_num + 0x200];
        !          1388:        cprb->fun = RBFWT;
        !          1389:        strbsg(cprb);
        !          1390:        xl_enc(wptr, cprb->nbk);
        !          1391:        putrb(&req, cprb);
        !          1392:        ilvl = spl5();
        !          1393:        if (!f.actv)
        !          1394:                xlque();
        !          1395:        splx(ilvl);
        !          1396: }
        !          1397: 
        !          1398: /************************************************************************/
        !          1399: /*     xlcal()         calibrate drive                                 */
        !          1400: /*                     exits via (*xlosb)()                            */
        !          1401: /************************************************************************/
        !          1402: static void
        !          1403: xlcal()
        !          1404: {
        !          1405:        if (xlster) {                   /* exit if error                */
        !          1406:                (*pfcal)();
        !          1407:                return;
        !          1408:        }
        !          1409:        f.cal = 0;                      /* reset calibrate sent flag    */
        !          1410:        pfrdy = xlcal0;                 /* wait for ready               */
        !          1411:        xlready();
        !          1412: }
        !          1413: 
        !          1414: static void
        !          1415: xlcal0()
        !          1416: {
        !          1417:        if (xlster) {                   /* exit if error                */
        !          1418:                (*pfcal)();
        !          1419:                return;
        !          1420:        }
        !          1421:        if ((xl6sts & 0xf7) == 0x65) {/* if ok, seek track 0, exit      */
        !          1422: printf("xlcal:Seek tk 0 ");
        !          1423:                tptrk = 0;
        !          1424:                pfsek = pfcal;
        !          1425:                xlseek();
        !          1426:                return;
        !          1427:        }
        !          1428:        if ((xl6sts & XLSREF) == 0) {/* if not referenced               */
        !          1429: printf("xlcal:calibrate ");
        !          1430:                if (f.cal) {            /* and calibrate sent, exit     */
        !          1431:                        (*pfcal)();
        !          1432:                        return;
        !          1433:                }
        !          1434:                f.cal = 1;              /* else send calibrate          */
        !          1435:                pfint = xlready;
        !          1436:                xloutput_step(QIC_CMD_CAL);
        !          1437:                return;
        !          1438:        }
        !          1439:        pfint = xlready;                /* rewind tape                  */
        !          1440:        xloutput_step(QIC_CMD_BOT);
        !          1441: }
        !          1442: 
        !          1443: /************************************************************************/
        !          1444: /*     xlcomplete  interrupt sequence complete                         */
        !          1445: /************************************************************************/
        !          1446: static void
        !          1447: xlcomplete()
        !          1448: {
        !          1449:        pfint = xlnull;                 /* clean up int handler         */
        !          1450:        xlcompf = 1;                    /* indicate completion          */
        !          1451:        if (xlcompw) {                  /* wake up if waiting           */
        !          1452:                xlcompw = 0;
        !          1453:                wakeup(&xlcompw);
        !          1454:        }
        !          1455: }
        !          1456: 
        !          1457: /************************************************************************/
        !          1458: /*     xldelay         delay for cnt ticks                             */
        !          1459: /************************************************************************/
        !          1460: static void
        !          1461: xldelay(cnt)
        !          1462: int    cnt;
        !          1463: {
        !          1464:        if (cnt)
        !          1465:                timeout(&xldly, cnt, pfdly, 0);
        !          1466:        else
        !          1467:                timeout(&xldly, cnt, NULL, 0);
        !          1468: }
        !          1469: 
        !          1470: /************************************************************************/
        !          1471: /*     xldma                                                           */
        !          1472: /************************************************************************/
        !          1473: static void
        !          1474: xldma(rw, addr, count)
        !          1475: char   rw;
        !          1476: long   addr;
        !          1477: int    count;
        !          1478: {
        !          1479:        int     oldpri;
        !          1480: 
        !          1481:        oldpri = sphi();
        !          1482:        outb(DMA1CBPFF, 0);
        !          1483:        outb(DMA1WMR, rw);
        !          1484:        outb(DMA1BCA2, addr & 0xff);
        !          1485:        outb(DMA1BCA2, (addr >> 8) & 0xff);
        !          1486:        outb(DMACH2PG, (addr >> 16) & 0xff);
        !          1487:        tenmicrosec();
        !          1488:        outb(DMA1BCWC2, count & 0xff);
        !          1489:        outb(DMA1BCWC2, (count >> 8) & 0xff);
        !          1490:        spl(oldpri);
        !          1491:        outb(DMA1WSMR, 2);
        !          1492: }
        !          1493: 
        !          1494: /************************************************************************/
        !          1495: /*     xlfdc_in_byte   input byte from fdc                             */
        !          1496: /************************************************************************/
        !          1497: static unchar
        !          1498: xlfdc_in_byte()                                /* input byte from fdc          */
        !          1499: {
        !          1500:        register int    d0;
        !          1501: 
        !          1502:        for (d0 = FDTMO; d0; --d0) {    /* wait for ready               */
        !          1503: 
        !          1504:                /* Wait for Request from Master asserted. */
        !          1505:                if (inb(FDSTAT) & 0x80) {
        !          1506:                        /* exit if in output mode                       */
        !          1507:                        if ((inb(FDSTAT) & 0x40) == 0)
        !          1508:                                return(status_buf[7] = -1);
        !          1509:                        return(inb(FDDATA));
        !          1510:                }
        !          1511:        }
        !          1512:        return(status_buf[7] = -1);     /* exit if timeout              */
        !          1513: }
        !          1514: 
        !          1515: /************************************************************************/
        !          1516: /*     xlfdc_out_byte  output byte to fdc                              */
        !          1517: /************************************************************************/
        !          1518: static unchar
        !          1519: xlfdc_out_byte(chr)                    /* output byte to fdc           */
        !          1520: int    chr;
        !          1521: {
        !          1522:        register int    d0;
        !          1523: 
        !          1524:        for (d0 = FDTMO; d0; --d0) {    /* wait for ready               */
        !          1525: 
        !          1526:                /* Wait for Request from Master asserted. */
        !          1527:                if (inb(FDSTAT) & 0x80) {
        !          1528:                        /* exit if in status mode                       */
        !          1529:                        if (inb(FDSTAT) & 0x40)
        !          1530:                                return(status_buf[7] = -1);
        !          1531:                        outb(FDDATA, chr);      /* output byte, exit ok */
        !          1532:                        return 0;
        !          1533:                }
        !          1534:        }
        !          1535:        return(status_buf[7] = -1);     /* exit if timeout              */
        !          1536: }
        !          1537: 
        !          1538: /************************************************************************/
        !          1539: /*     xlfdc_out_str   output cmd string to fdc                        */
        !          1540: /************************************************************************/
        !          1541: static unchar
        !          1542: xlfdc_out_str(cms, cnt)                /* output command string        */
        !          1543: unchar *cms;
        !          1544: int    cnt;
        !          1545: {
        !          1546:        register unchar *p0, *p1;
        !          1547: 
        !          1548:        p0 = cms;                       /* set up for output            */
        !          1549:        fdcmd = *p0;                    /* save command type            */
        !          1550:        for (p1 = p0 + cnt; p0 != p1; ++p0) {
        !          1551:                if (xlfdc_out_byte((int)(*p0)))/* stop if error */
        !          1552:                        break;
        !          1553:        }
        !          1554:        return(status_buf[7]);   /* exit ok                     */
        !          1555: }
        !          1556: 
        !          1557: /************************************************************************/
        !          1558: /*     xlfdc_reset     reset fdc                                       */
        !          1559: /************************************************************************/
        !          1560: static void
        !          1561: xlfdc_reset()                          /* fdc reset                    */
        !          1562: {
        !          1563:        sekcms[1] = 0xff;
        !          1564:        status_buf[7] = 0;              /* reset error flag             */
        !          1565:        outb(FDCTRL, fdselr);           /* reset fdc                    */
        !          1566:        outb(FDCTRL, fdsel);
        !          1567: }
        !          1568: 
        !          1569: /************************************************************************/
        !          1570: /*     xlflush flush any pending io's                                  */
        !          1571: /************************************************************************/
        !          1572: static void
        !          1573: xlflush(dev)
        !          1574: {
        !          1575:        int     ilvl;
        !          1576: 
        !          1577:        xstop = 1;                      /* stop any pending reads       */
        !          1578:        if (f.writ) {                   /* flush any pending writes     */
        !          1579:                if (cnbr && cprb->fun == RBFWT) {
        !          1580:                        xl_enc(wptr, cprb->nbk);
        !          1581:                        putrb(&req, cprb);
        !          1582:                }
        !          1583:                ilvl = spl5();
        !          1584:                if (!f.actv)
        !          1585:                        xlque();
        !          1586:                splx(ilvl);
        !          1587:                wvtbl();
        !          1588:        }
        !          1589:        ilvl = spl5();                  /* wait for idle state          */
        !          1590:        while(f.actv) {
        !          1591:                xlnactw = 1;
        !          1592:                sleep(&xlnactw, PRIBIO);
        !          1593:        }
        !          1594:        splx(ilvl);
        !          1595:        cnbr = 0;
        !          1596:        xstop = 0;
        !          1597:        while(cprb = getrb(&data_queue))/* relse pending read bfrs      */
        !          1598:                putrb(&xlfree_q, cprb);
        !          1599:        while(cprb = getrb(&req))       /* release any pending que bfrs */
        !          1600:                putrb(&xlfree_q, cprb);
        !          1601: }
        !          1602: 
        !          1603: /************************************************************************/
        !          1604: /*     xlfmq   format queue handler                                    */
        !          1605: /************************************************************************/
        !          1606: static void
        !          1607: xlfmq()
        !          1608: {
        !          1609:        while(xprb = getrb(&req)) {     /* while more to do             */
        !          1610:                if (!f.actv) {          /* if not active, start tape    */
        !          1611:                        f.actv = 1;
        !          1612:                        f.tmov = 1;
        !          1613:                        pfint = xlfmq0;
        !          1614:                        xloutput_step(QIC_CMD_FWD);
        !          1615:                        return;
        !          1616:                }
        !          1617:                else{
        !          1618:                        pffms = xlfmq1; /* else, continue format        */
        !          1619:                        xlfms();
        !          1620:                        return;
        !          1621:                }
        !          1622:        }
        !          1623: 
        !          1624:        pfrdy = xlfmq2;                 /* wait for tape stopped        */
        !          1625:        xlready();
        !          1626:        return;
        !          1627: }
        !          1628: 
        !          1629: static void
        !          1630: xlfmq0()
        !          1631: {
        !          1632:        pffms = xlfmq1;
        !          1633:        xlfms();
        !          1634:        return;
        !          1635: }
        !          1636: 
        !          1637: static void
        !          1638: xlfmq1()
        !          1639: {
        !          1640:        if (xprb->sts)          /* set f.werr if error          */
        !          1641:                f.werr = 1;
        !          1642:        putrb(&xlfree_q, xprb); /* relse bfr back to free pool  */
        !          1643:        if (xlfreew) {                  /* wakeup if needed             */
        !          1644:                xlfreew = 0;
        !          1645:                wakeup(&xlfreew);
        !          1646:        }
        !          1647:        xlfmq();                        /* start next i/o               */
        !          1648: }
        !          1649: 
        !          1650: static void
        !          1651: xlfmq2()
        !          1652: {
        !          1653:        if (xlnactw) {                  /* if sleepg on xlnactw, wakeup */
        !          1654:                xlnactw = 0;
        !          1655:                wakeup(&xlnactw);
        !          1656:        }
        !          1657:        f.actv = 0;                     /* rset actv, moving flgs, exit */
        !          1658:        f.tmov = 0;
        !          1659:        return;
        !          1660: }
        !          1661: 
        !          1662: /************************************************************************/
        !          1663: /*     xlfms   format a segment                                        */
        !          1664: /************************************************************************/
        !          1665: static void
        !          1666: xlfms()
        !          1667: {
        !          1668:        pfint = xlfm0;                  /* set up for format            */
        !          1669:        xprb->sts = 0;
        !          1670:        if (f.werr) {                   /* if error, do idle int        */
        !          1671:                xloutput_step(0);
        !          1672:                return;
        !          1673:        }
        !          1674:        fmtcms[1] = unit;
        !          1675:        stdma(DMA_Wrmode, xprb->adr, 128);
        !          1676: 
        !          1677:        xltimout(IOTMO);                /* do the format                */
        !          1678:        xlfdc_out_str(fmtcms, 6);
        !          1679:        if (status_buf[7]) {            /* exit if nec error            */
        !          1680:                xltimout(0);
        !          1681:                xlster |= XLSNEC;
        !          1682:                xprb->sts = 1;
        !          1683:                pfint = xlnull;
        !          1684:                (*pffms)();
        !          1685:                return;
        !          1686:        }
        !          1687: }
        !          1688: 
        !          1689: static void
        !          1690: xlfm0()
        !          1691: {
        !          1692:        if (status_buf[0] & 0xc0)
        !          1693:                xprb->sts = 1;
        !          1694:        (*pffms)();
        !          1695: }
        !          1696: 
        !          1697: /************************************************************************/
        !          1698: /*     xlformat                format tape, task time                  */
        !          1699: /************************************************************************/
        !          1700: static int
        !          1701: xlformat(ntrkf)
        !          1702: int    ntrkf;
        !          1703: {
        !          1704:        int     ilvl, i;
        !          1705:        fplng   p0;
        !          1706: 
        !          1707:        cmn_err(CE_CONT, "xlformat: formatting %d tracks\n", ntrkf);
        !          1708: 
        !          1709:        pfint = xlready;                /* rewind tape                  */
        !          1710:        pfrdy = xlcomplete;
        !          1711:        xloutput_step(QIC_CMD_BOT);
        !          1712:        xlwait();
        !          1713:        if (xlster)
        !          1714:                return 2;
        !          1715: 
        !          1716:        bcopy((fpchr)xnxvs, ptr_header, 20);    /* init header          */
        !          1717:        bcopy(ptr_header + 4, ptr_header + 5, 16 * 1024 - 20);
        !          1718: 
        !          1719:        pfint = xlcomplete;             /* format mode                  */
        !          1720:        xloutput_step(QIC_CMD_FMD);
        !          1721:        xlwait();
        !          1722: 
        !          1723:        cmn_err(CE_CONT, "writing reference bursts...\n");
        !          1724:        pfint = xlready;
        !          1725:        pfrdy = xlcomplete;
        !          1726:        xloutput_step(QIC_CMD_WRF);     /* start wrt reference bursts   */
        !          1727:        xlwait();
        !          1728: 
        !          1729:        cmn_err(CE_CONT, "reference bursts write done, starting format...\n");
        !          1730: 
        !          1731:        f.werr = 0;
        !          1732: 
        !          1733:        for (fmtrk = 0; fmtrk < ntrkf; fmtrk += 2) {
        !          1734: 
        !          1735:                tptrk = fmtrk;          /* set tape track               */
        !          1736:                curr_seg_num = fmtrk * nseg_p_track;
        !          1737: 
        !          1738:                pfint = xlcomplete;     /* normal mode                  */
        !          1739:                xloutput_step(QIC_CMD_NMD);
        !          1740:                xlwait();
        !          1741: 
        !          1742:                pfint = xlcomplete;     /* format mode                  */
        !          1743:                xloutput_step(QIC_CMD_FMD);
        !          1744:                xlwait();
        !          1745:                /*                              format a track pair     */
        !          1746:                do{
        !          1747:                        cmn_err(CE_CONT, "\tformatting track %d\n", tptrk);
        !          1748:                        pfsek = xlcomplete;     /* seek to track        */
        !          1749:                        xlseek();
        !          1750:                        xlwait();
        !          1751:                        for (last_seg_num = curr_seg_num + nseg_p_track; curr_seg_num != last_seg_num; ++curr_seg_num) {
        !          1752:                                /* wait for a new buffer                */
        !          1753:                                ilvl = spl5();  
        !          1754:                                while(!(cprb = getrb(&xlfree_q))) {
        !          1755:                                        if (!f.actv)
        !          1756:                                                xlfmq();
        !          1757:                                        xlfreew = 1;
        !          1758:                                        sleep(&xlfreew, PRIBIO);
        !          1759:                                }
        !          1760:                                splx(ilvl);
        !          1761:                                /* set up buffer                        */
        !          1762:                                cprb->sgn = curr_seg_num;
        !          1763:                                strbfm(cprb);
        !          1764:                                putrb(&req, cprb);
        !          1765:                        }       /* queue up format request              */
        !          1766: 
        !          1767:                        ilvl = spl5();  /* track done, wait for idle    */
        !          1768:                        while(f.actv) {
        !          1769:                                xlnactw = 1;
        !          1770:                                sleep(&xlnactw, PRIBIO);
        !          1771:                        }
        !          1772:                        splx(ilvl);
        !          1773:                        ++tptrk;
        !          1774:                }  while(tptrk & 1);
        !          1775:                if (f.werr) {           /* exit if error formatting     */
        !          1776:                        pfprk = xlcomplete;
        !          1777:                        xlpark();
        !          1778:                        xlwait();
        !          1779:                        return 1;
        !          1780:                }
        !          1781: 
        !          1782:                /*                              verify a track pair     */
        !          1783:                pfint = xlcomplete;     /* normal mode                  */
        !          1784:                xloutput_step(QIC_CMD_NMD);
        !          1785:                xlwait();
        !          1786: 
        !          1787:                pfint = xlcomplete;     /* verify mode                  */
        !          1788:                xloutput_step(QIC_CMD_VMD);
        !          1789:                xlwait();
        !          1790: 
        !          1791:                /* set up for verify                                    */
        !          1792:                curr_seg_num = fmtrk * nseg_p_track;
        !          1793:                xlrel();
        !          1794:                relfdc();
        !          1795:                vftrk = -1;
        !          1796: 
        !          1797:                read_ahead_seg_num = curr_seg_num;/* queue up requests  */
        !          1798:                while(cprb = getrb(&xlfree_q)) {
        !          1799:                        cprb->sgn = read_ahead_seg_num;
        !          1800:                        cprb->map = 0L;
        !          1801:                        cprb->fun = RBFRD;
        !          1802:                        strbsg(cprb);
        !          1803:                        cprb->erc = 3;  /* no errors allowed            */
        !          1804:                        putrb(&req, cprb);
        !          1805:                        ++read_ahead_seg_num;
        !          1806:                }
        !          1807:                for (last_seg_num = curr_seg_num + 2 * nseg_p_track; curr_seg_num != last_seg_num; ++curr_seg_num ) {
        !          1808:                        ilvl = spl5();  /* wait for a new buffer        */
        !          1809:                        while(!(cprb = getrb(&data_queue))) {
        !          1810:                                if (!f.actv)
        !          1811:                                        xlque();
        !          1812:                                xldataw = 1;
        !          1813:                                sleep(&xldataw, PRIBIO);
        !          1814:                        }
        !          1815:                        splx(ilvl);
        !          1816:                        if (vftrk != cprb->trk) {
        !          1817:                                vftrk = cprb->trk;
        !          1818:                                cmn_err(CE_CONT, "\tverifying track %d\n", vftrk);
        !          1819:                        }
        !          1820:                        if (cprb->sts) /* mask out segment if error     */
        !          1821:                                *(ptr_header + 0x200 + cprb->sgn) = 0xffffffffL;
        !          1822:                        /* generate another request or                  */
        !          1823:                        if (read_ahead_seg_num != last_seg_num) {
        !          1824:                                cprb->sgn = read_ahead_seg_num;
        !          1825:                                cprb->map = 0L;
        !          1826:                                cprb->fun = RBFRD;
        !          1827:                                strbsg(cprb);
        !          1828:                                cprb->erc = 3;
        !          1829:                                putrb(&req, cprb);
        !          1830:                                ++read_ahead_seg_num;
        !          1831:                        } else {
        !          1832:                                putrb(&xlfree_q, cprb);
        !          1833:                        }
        !          1834:                }       /*  release buffer                              */
        !          1835: 
        !          1836:                ilvl = spl5();  /* track pair done, wait for idle       */
        !          1837:                while(f.actv) {
        !          1838:                        xlnactw = 1;
        !          1839:                        sleep(&xlnactw, PRIBIO);
        !          1840:                }
        !          1841:                splx(ilvl);
        !          1842: 
        !          1843:                getfdc(unit);   /* get fdc again                */
        !          1844:                xlsel(unit);
        !          1845:        }
        !          1846: 
        !          1847:        if (xlster) {                   /* if fatal error, exit         */
        !          1848:                pfprk = xlcomplete;
        !          1849:                xlpark();
        !          1850:                xlwait();
        !          1851:                return 1;
        !          1852:        }
        !          1853: 
        !          1854:        pfint = xlcomplete;             /* normal mode                  */
        !          1855:        xloutput_step(QIC_CMD_NMD);
        !          1856:        xlwait();
        !          1857: 
        !          1858:        /*      done with format / verify                               */
        !          1859:        /*      now find out where headers and volumne table go         */
        !          1860: 
        !          1861:        p0 = ptr_header + 0x200;
        !          1862:        for (i = 0; *p0++; ++i);        /* set hdr segment  #'s         */
        !          1863:        ((fpwrd)ptr_header)[3] = h0sgn = i;     /*  and vol segment     */
        !          1864:        do {
        !          1865:                ++i;
        !          1866:        } while(*p0++);
        !          1867:        ((fpwrd)ptr_header)[4] = h1sgn = i;
        !          1868:        do {
        !          1869:                ++i;
        !          1870:        } while(*p0++);
        !          1871:        ((fpwrd)ptr_header)[5] = volume_seg_num = i;
        !          1872:        /* set last seg number                                          */
        !          1873:        ((fpwrd)ptr_header)[6] = last_seg_num = ntrkf * nseg_p_track - 1;
        !          1874: 
        !          1875:        cmn_err(CE_CONT,
        !          1876:            "xlformat: h0sgn %d  h1sgn %d  volume_seg_num %d  last_seg_num %d\n",
        !          1877:           h0sgn, h1sgn, volume_seg_num, last_seg_num);
        !          1878: 
        !          1879:        pfprk = xlcomplete;             /* park tape                    */
        !          1880:        xlpark();
        !          1881:        xlwait();
        !          1882: 
        !          1883:        if (volume_seg_num > 10)        /* if too many bad segment exit */
        !          1884:                return 1;
        !          1885: 
        !          1886:        xlrel();                        /* relse fdc, so xlque can work */
        !          1887:        relfdc();
        !          1888: 
        !          1889:        /* start header writes                                          */
        !          1890:        for (curr_seg_num = 0; curr_seg_num <= volume_seg_num; ++curr_seg_num) {
        !          1891:                ilvl = spl5();          /*   get a buffer               */
        !          1892:                while(!(cprb = getrb(&xlfree_q))) {
        !          1893:                        if (!f.actv)
        !          1894:                                xlque();
        !          1895:                        xlfreew = 1;
        !          1896:                        sleep(&xlfreew, PRIBIO);
        !          1897:                }
        !          1898:                splx(ilvl);
        !          1899:                cprb->sgn = curr_seg_num;/* set up for hdr or del adm write */
        !          1900:                cprb->map = 0L;
        !          1901:                if (ptr_header[curr_seg_num + 0x200]) {
        !          1902:                        cmn_err(CE_CONT, "-");
        !          1903:                        cprb->fun = RBWFD;
        !          1904:                }
        !          1905:                else{
        !          1906:                        cmn_err(CE_CONT, "*");
        !          1907:                        cprb->fun = RBFWT;
        !          1908:                }
        !          1909:                strbsg(cprb);
        !          1910:                cptr = (fpchr)cprb->adr;
        !          1911: 
        !          1912:                bcopy(ptr_header, cptr, 16 * 1024);/* copy in header    */
        !          1913:                bcopy(cptr + 16 * 1024 - 4, cptr + 16 * 1024, 13 * 1024 - 4);
        !          1914:                xl_enc(cptr, cprb->nbk);
        !          1915:                putrb(&req, cprb);
        !          1916:        }               /* queue up the request */
        !          1917: 
        !          1918:        if (!f.actv)                    /* activate driver              */
        !          1919:                xlque();
        !          1920: 
        !          1921:        ilvl = spl5();                  /* wait for idle state          */
        !          1922:        while(f.actv) {
        !          1923:                xlnactw = 1;
        !          1924:                sleep(&xlnactw, PRIBIO);
        !          1925:        }
        !          1926:        splx(ilvl);
        !          1927: 
        !          1928:        getfdc(unit);                   /* park tape                    */
        !          1929:        xlsel(unit);
        !          1930:        pfprk = xlcomplete;
        !          1931:        xlpark();
        !          1932:        xlwait();
        !          1933:        return 0;
        !          1934: }
        !          1935: 
        !          1936: /************************************************************************/
        !          1937: /*     xlgtdat get data                                                */
        !          1938: /************************************************************************/
        !          1939: static void
        !          1940: xlgtdat(iop)
        !          1941: IO * iop;
        !          1942: {
        !          1943:        caddr_t p0;
        !          1944:        fpchr   p1;
        !          1945:        int     ilvl;
        !          1946: 
        !          1947:        /*      set up requests using all free buffers                  */
        !          1948:        xlrqr();
        !          1949: 
        !          1950:        /*      set up to xfer data to user buffer                      */
        !          1951: 
        !          1952:        rnbr = iop->io_ioc;             /* set request params           */
        !          1953:        p0 = iop->io.vbase;
        !          1954: 
        !          1955:        p1 = cptr;                      /* use local copy of cptr       */
        !          1956: 
        !          1957:        while(rnbr) {                   /* while more to xfer           */
        !          1958:                if (curr_seg_num > last_seg_num) {
        !          1959:                        break;
        !          1960:                }
        !          1961:                if (!cnbr) {            /* if a new segment is needed   */
        !          1962:                        ilvl = spl5();  /* wait for data                */
        !          1963:                        while(!(cprb = getrb(&data_queue))) {
        !          1964:                                if (!f.actv)
        !          1965:                                        xlque();
        !          1966:                                xldataw = 1;
        !          1967:                                sleep(&xldataw, PRIBIO);
        !          1968:                        }
        !          1969:                        splx(ilvl);
        !          1970: 
        !          1971:                        /*      just got a new buffer from data queue   */
        !          1972: 
        !          1973:                        p1 = (fpchr)cprb->adr;
        !          1974:                        if (cprb->sts) {/* check for errors             */
        !          1975:                                u.u_error = EIO;
        !          1976:                        }
        !          1977:                        else{
        !          1978:                                if (!xl_dec(p1, cprb->nbk, cprb->erc,
        !          1979:                                   cprb->ers[0], cprb->ers[1], cprb->ers[2])) {
        !          1980:                                        u.u_error = EIO;
        !          1981:                                }
        !          1982:                        }
        !          1983:                        /* cnbr = # data bytes                          */
        !          1984:                        cnbr = (cprb->nbk - 3) << 10;
        !          1985:                        if (cprb->sgn != curr_seg_num)
        !          1986:                                curr_seg_num = cprb->sgn;
        !          1987:                        if (cprb->sgn == last_seg_num) {
        !          1988:                                cnbr = lnbr;
        !          1989:                        }
        !          1990:                }
        !          1991:                /* copy some data                                       */
        !          1992:                rcnt = (cnbr >= rnbr) ? rnbr : cnbr;
        !          1993:                copyout(p1, p0, rcnt);
        !          1994:                p0 += rcnt;             /* adjust pointers and counts   */
        !          1995:                p1 += rcnt;
        !          1996:                rnbr -= rcnt;
        !          1997:                cnbr -= rcnt;
        !          1998:                iop->io_ioc -= rcnt;
        !          1999:                if (!cnbr) {            /* release bfr if done          */
        !          2000:                        putrb(&xlfree_q, cprb);
        !          2001:                        ++curr_seg_num;
        !          2002:                        xlrqr();
        !          2003:                }
        !          2004:        }                               /* set up new read request      */
        !          2005: 
        !          2006:        cptr = p1;                      /* update cptr                  */
        !          2007: }
        !          2008: 
        !          2009: /************************************************************************/
        !          2010: /*     xlhalt  halt tape                                               */
        !          2011: /************************************************************************/
        !          2012: static void
        !          2013: xlhalt()
        !          2014: {
        !          2015:        /* adjust tpseg for ramp down/up                                */
        !          2016:        if (f.tmov)
        !          2017:                tpseg += 2;
        !          2018:        f.tmov = 0;                     /* reset tape moving flag       */
        !          2019:        if (xlster) {                   /* exit if error                */
        !          2020:                (*pfhlt)();
        !          2021:                return;
        !          2022:        }
        !          2023:        pfint = xlready;                /* after stop cmd wait for rdy  */
        !          2024:        pfrdy = pfhlt;                  /* after ready, exit            */
        !          2025:        xloutput_step(QIC_CMD_STOP);
        !          2026: }
        !          2027: 
        !          2028: /************************************************************************/
        !          2029: /*     xlintr  xl interrupt handler                                    */
        !          2030: /************************************************************************/
        !          2031: static void
        !          2032: xlintr()                               /* fdc interrupt handler        */
        !          2033: {
        !          2034:        register unchar *p0, *p1;
        !          2035: 
        !          2036:        xltimout(0);                    /* reset interrupt timeout      */
        !          2037: 
        !          2038:        /*
        !          2039:         * Wait for Request from Master asserted in Main Status -
        !          2040:         * indicates data register available for read/write.
        !          2041:         */
        !          2042:        while (inb(FDSTAT) & 0x80 == 0);
        !          2043: 
        !          2044:        /* FDC busy indicates read/write command in progress. */
        !          2045:        if (inb(FDSTAT) & 0x10) {       /* br if non-data int           */
        !          2046:                p0 = status_buf;        /* set up                       */
        !          2047:                for (p1 = p0 + 7; p0 != p1; ++p0) {
        !          2048:                        *p0 = xlfdc_in_byte();  /* store next byte      */
        !          2049:                        if (status_buf[7]) {
        !          2050:                                xlster |= XLSNEC;
        !          2051:                                break;
        !          2052:                        }
        !          2053:                }
        !          2054:        } else {
        !          2055:                /* handle non-I/O int           */
        !          2056:                for(;;) {
        !          2057:                        if (xlfdc_out_byte(8))/* start sense int        */
        !          2058:                                break;
        !          2059:                        status_buf[0] = xlfdc_in_byte();/* get 1st sts byte*/
        !          2060:                        if (status_buf[7]) {
        !          2061:                                xlster |= XLSNEC;
        !          2062:                                break;
        !          2063:                        }
        !          2064:                        if (status_buf[0] == 0x80) {/* br if done       */
        !          2065:                                status_buf[0] = unit;
        !          2066:                                if (xltimoutf) {
        !          2067:                                        xltimoutf = 0;
        !          2068:                                        status_buf[0] = 0xc0;
        !          2069:                                }
        !          2070:                                break;
        !          2071:                        }
        !          2072:                        status_buf[1] = xlfdc_in_byte();/* get 2nd sts byte*/
        !          2073:                        /* update track if my unit                      */
        !          2074:                        if (unit == (3 & status_buf[0])) {
        !          2075:                                sekcms[2] = status_buf[1];
        !          2076:                        }
        !          2077:                        /* check for more bytes                         */
        !          2078:                }
        !          2079:        }
        !          2080:        (*pfint)();                     /* exit via caller handler      */
        !          2081:        return;
        !          2082: }
        !          2083: 
        !          2084: /************************************************************************/
        !          2085: /*     xlnull  null interrupt handler                                  */
        !          2086: /************************************************************************/
        !          2087: static void
        !          2088: xlnull()
        !          2089: {
        !          2090: }
        !          2091: 
        !          2092: /************************************************************************/
        !          2093: /*     xlopn   open tape (task time call)                              */
        !          2094: /************************************************************************/
        !          2095: static int
        !          2096: xlopn(dev)
        !          2097: dev_t  dev;
        !          2098: {
        !          2099:        register int    i;
        !          2100:        xlvtbl          *pp;
        !          2101: 
        !          2102: printf("xlopn ");
        !          2103: 
        !          2104:        /* try 100 times to see drive ready - will fix this later */
        !          2105:        for (i = 0; i < 100; i++) {
        !          2106:                xlster = 0;             /* reset error status           */
        !          2107:                xlests = 0;
        !          2108:                xl7sts = 0;
        !          2109:                pfsts = xlcomplete;     /* get drive status             */
        !          2110:                xlstatus();
        !          2111:                xlwait();
        !          2112: printf("try:%d ", i+1);
        !          2113:                if (xl6sts & XLSRDY)
        !          2114:                        break;
        !          2115:        }
        !          2116: 
        !          2117:        xlster &= ~XLSSFT;              /* clear soft error bits        */
        !          2118:        xlests = 0;
        !          2119:        xl7sts = 0;
        !          2120: 
        !          2121:        if (!(xl6sts & XLSCIN)) {       /* exit if no cartridge         */
        !          2122: printf("no cart ");
        !          2123:                xlster |= XLSSFT;
        !          2124:                return 2;
        !          2125:        }
        !          2126: 
        !          2127:        if (xlster) {                   /* exit if fatal error          */
        !          2128: printf("fatal error ");
        !          2129:                return 2;
        !          2130:        }
        !          2131: 
        !          2132:        if (dev & M_CTL) {              /* exit if control open         */
        !          2133:                volume_seg_num = data_seg_num = 0;
        !          2134:                return 0;
        !          2135:        }
        !          2136: 
        !          2137:        if (dev & M_RET) {              /* retension if retension_on_open */
        !          2138:                pfint = xlready;
        !          2139:                pfrdy = xlcomplete;
        !          2140:                xloutput_step(QIC_CMD_EOT);
        !          2141:                xlwait();
        !          2142:                if (xlster) {
        !          2143: printf("another fatal error ");
        !          2144:                        return 2;
        !          2145:                }
        !          2146:        }
        !          2147:        pfint = xlready;                /* rewind tape                  */
        !          2148:        pfrdy = xlcomplete;
        !          2149:        xloutput_step(QIC_CMD_BOT);
        !          2150:        xlwait();
        !          2151: printf("should now be at BOT ");
        !          2152:        if (xlster) {
        !          2153: printf("yet another fatal error ");
        !          2154:                return 2;
        !          2155:        }
        !          2156: 
        !          2157:        pfcal = xlcomplete;             /* calibrate drive              */
        !          2158:        xlcal();
        !          2159:        xlwait();
        !          2160: printf("should now be referenced ");
        !          2161:        if (xlster) {                   /* exit if fatal error          */
        !          2162: printf("still yet another fatal error ");
        !          2163:                return 2;
        !          2164:        }
        !          2165:        i = xl6sts & 0xf7;
        !          2166:        if (i == 0x45) {                /* return if no ref bursts      */
        !          2167: printf("no ref bursts ");
        !          2168:                return 1;
        !          2169:        }
        !          2170:        if (i != 0x65) {                /* return general error         */
        !          2171: printf("general error ");
        !          2172:                xlster |= XLSSFT;
        !          2173:                return 2;
        !          2174:        }
        !          2175:        xprb = getrb(&xlfree_q);        /* get a buffer for open        */
        !          2176:        xprb->sgn = 0;                  /* set up buffer                */
        !          2177: xlopn0:
        !          2178:        xprb->map = 0L;
        !          2179:        strbsg(xprb);
        !          2180: 
        !          2181:        ptr_buffer = (fplng)xprb->adr;
        !          2182: 
        !          2183:        pfpos = xlrds;                  /* read a segment               */
        !          2184:        pfrds = xlcomplete;
        !          2185:        xlpos();
        !          2186:        xlwait();
        !          2187: 
        !          2188:        if (!xprb->sts) {       /* ck for errors */
        !          2189: printf("xlopn trying ecc ");
        !          2190:                if (!xl_dec(ptr_buffer, xprb->nbk, xprb->erc,
        !          2191:                   xprb->ers[0], xprb->ers[1], xprb->ers[2])) {
        !          2192: printf("failed ");
        !          2193:                        xprb->sts = 1;
        !          2194:                } else {
        !          2195: printf("succeeded ");
        !          2196:                }
        !          2197:        }
        !          2198: 
        !          2199:        if (xprb->sts) {                /* if error, try next segment   */
        !          2200:                ++xprb->sgn;
        !          2201:                if (xprb->sgn < 10 && !xlster) {
        !          2202:                        goto xlopn0;
        !          2203:                }
        !          2204:        }
        !          2205:        if (xprb->sts) {                /* if fatal, return bfr & exit  */
        !          2206:                putrb(&xlfree_q, xprb);
        !          2207:                pfprk = xlcomplete;
        !          2208:                xlpark();
        !          2209:                xlwait();
        !          2210: printf("fatal ");
        !          2211:                return 2;
        !          2212:        }
        !          2213: 
        !          2214:        bcopy(ptr_buffer, ptr_header, HDRSZ);   /* copy header data     */
        !          2215: 
        !          2216:        volume_seg_num = ((fpwrd)ptr_header)[5];/* set seg numbers      */
        !          2217:        data_seg_num = volume_seg_num + 1;
        !          2218: 
        !          2219:        xprb->sgn = volume_seg_num;     /* read in volume segment       */
        !          2220:        xprb->map = ptr_header[volume_seg_num + 0x200];
        !          2221:        strbsg(xprb);
        !          2222:        pfpos = xlrds;
        !          2223:        pfrds = xlcomplete;
        !          2224:        xlpos();
        !          2225:        xlwait();
        !          2226: 
        !          2227:        if (!xprb->sts) {               /* ck for errors                */
        !          2228: printf("xlopn trying 2nd ecc ");
        !          2229:                if (!xl_dec(ptr_buffer, xprb->nbk, xprb->erc,
        !          2230:                   xprb->ers[0], xprb->ers[1], xprb->ers[2])) {
        !          2231: printf("failed ");
        !          2232:                        xprb->sts = 1;
        !          2233:                } else {
        !          2234: printf("succeeded ");
        !          2235:                }
        !          2236:        }
        !          2237: 
        !          2238:        /* set last seg num     */
        !          2239:        pp = (xlvtbl *)ptr_buffer;
        !          2240:        last_seg_num = (int)pp->last_seg_num;
        !          2241:        /* set last # bytes     */
        !          2242:        lnbr = (int)pp->last_blk_size;
        !          2243:        putrb(&xlfree_q, xprb); /* return buffer                */
        !          2244:        pfprk = xlcomplete;             /* park tape                    */
        !          2245:        xlpark();
        !          2246:        xlwait();
        !          2247:        if (xprb->sts) {                /* return error if error        */
        !          2248: printf("sts err ");
        !          2249:                return 2;
        !          2250:        }
        !          2251:        return 0;
        !          2252: }
        !          2253: 
        !          2254: /************************************************************************/
        !          2255: /*     xloutput_step   output cnt steps                                */
        !          2256: /************************************************************************/
        !          2257: static void
        !          2258: xloutput_step(cnt)                     /* output cnt steps             */
        !          2259: int    cnt;
        !          2260: {
        !          2261: 
        !          2262:        xlDbPrintCmd(cnt);
        !          2263: 
        !          2264:        sekcms[1] = unit;
        !          2265:        if (sekcms[2] > 80)
        !          2266:                sekcms[2] -= cnt;
        !          2267:        else
        !          2268:                sekcms[2] += cnt;
        !          2269:        xlfdc_out_str(sekcms, 3);       /* start seek cmd               */
        !          2270:        if (status_buf[7]) {            /* exit if nec error            */
        !          2271:                xlster |= XLSNEC;
        !          2272:                (*pfint)();
        !          2273:        }
        !          2274: }
        !          2275: 
        !          2276: /************************************************************************/
        !          2277: /*     xlpark  park tape                                               */
        !          2278: /************************************************************************/
        !          2279: static void
        !          2280: xlpark()
        !          2281: {
        !          2282:        if (xlster) {                   /* exit if error                */
        !          2283:                (*pfprk)();
        !          2284:                return;
        !          2285:        }
        !          2286:        pfsts = xlpark0;                /* clear any drive status       */
        !          2287:        xlstatus();
        !          2288: }
        !          2289: 
        !          2290: static void
        !          2291: xlpark0()
        !          2292: {
        !          2293:        if (xlster) {                   /* exit if error                */
        !          2294:                (*pfprk)();
        !          2295:                return;
        !          2296:        }
        !          2297:        pfint = xlpark1;                /* set normal mode              */
        !          2298:        xloutput_step(QIC_CMD_NMD);
        !          2299: }
        !          2300: 
        !          2301: static void
        !          2302: xlpark1()
        !          2303: {
        !          2304:        tpseg = tptrk = 0;              /* reset current track, segment */
        !          2305:        pfsek = xlpark2;                /* seek track 0                 */
        !          2306:        xlseek();
        !          2307: }
        !          2308: 
        !          2309: static void
        !          2310: xlpark2()
        !          2311: {
        !          2312:        if (xlster) {                   /* exit if error                */
        !          2313:                (*pfprk)();
        !          2314:                return;
        !          2315:        }
        !          2316:        pfint = xlready;                /* after rewind, wait for rdy   */
        !          2317:        pfrdy = pfprk;                  /* after ready, exit            */
        !          2318:        xloutput_step(QIC_CMD_BOT);     /* start rewind                 */
        !          2319: }
        !          2320: 
        !          2321: /************************************************************************/
        !          2322: /*     xlpos   position to segment                                     */
        !          2323: /*             in: xprb = pointer to r                                 */
        !          2324: /************************************************************************/
        !          2325: static void
        !          2326: xlpos()
        !          2327: {
        !          2328:        register int d0;
        !          2329: 
        !          2330:        cmn_err(CE_CONT, "xlpos ");
        !          2331: 
        !          2332:        if (xlster) {                   /* exit if error                */
        !          2333:                pfint = xlpos0;         /* use null int to cleanup stak */
        !          2334:                xloutput_step(0);
        !          2335:                return;
        !          2336:        }
        !          2337:        d0 = xprb->trk;
        !          2338:        if (tptrk != d0) {              /* if not same track            */
        !          2339:                if ((tptrk ^ d0) & 1)   /* adjust tpseg         */
        !          2340:                        tpseg = nseg_p_track + 5 - tpseg;
        !          2341:                /* adjust tpseg if 1st seg on trk                       */
        !          2342:                if (!xprb->tps)
        !          2343:                        tpseg = nseg_p_track;
        !          2344: printf("seek %d->%d ", tptrk, d0);
        !          2345:                tptrk = d0;             /* seek track                   */
        !          2346:                pfsek = xlpos0;
        !          2347:                xlseek();
        !          2348:                return;
        !          2349:        }
        !          2350: 
        !          2351:        d0 = xprb->tps;                 /* d0 = new tpseg               */
        !          2352:        /* adjust tpseg if 1st seg on trk                               */
        !          2353:        if (!d0)
        !          2354:                tpseg = nseg_p_track;
        !          2355:        if (d0 == tpseg && f.tmov == 1) { /* exit if on target          */
        !          2356: printf("xpos on target ");
        !          2357:                (*pfpos)();
        !          2358:                return;
        !          2359:        }
        !          2360:        if (d0 > tpseg) {               /* if before target read id     */
        !          2361: printf("before: %d < %d ", tpseg, d0);
        !          2362:                pfrdi = xlpos2;
        !          2363:                if (f.tmov) {
        !          2364:                        xlreadid();
        !          2365:                        return;
        !          2366:                }
        !          2367:                f.tmov = 1;
        !          2368:                pfint = xlreadid;
        !          2369:                xloutput_step(QIC_CMD_FWD);
        !          2370:                return;
        !          2371:        }
        !          2372:        else{
        !          2373:                pfskp = xlpos1;         /* else skip backwards          */
        !          2374:                xlskipb(tpseg - d0);
        !          2375:                return;
        !          2376:        }
        !          2377: }
        !          2378: 
        !          2379: static void
        !          2380: xlpos0()                               /* new track, tape stopped      */
        !          2381: {
        !          2382:        register int d0;
        !          2383: 
        !          2384:        if (xlster) {                   /* exit if error                */
        !          2385:                (*pfpos)();
        !          2386:                return;
        !          2387:        }
        !          2388:        d0 = xprb->tps;                 /* d0 = new tpseg               */
        !          2389:        /* adjust tpseg if 1st seg on trk                               */
        !          2390:        if (!d0)
        !          2391:                tpseg = nseg_p_track;
        !          2392:        if (d0 >= tpseg) {              /* if before target             */
        !          2393:                f.tmov = 1;
        !          2394:                pfint = xlreadid;       /* start tape fwd and read id   */
        !          2395:                pfrdi = xlpos2;
        !          2396:                xloutput_step(QIC_CMD_FWD);
        !          2397:                return;
        !          2398:        }
        !          2399:        else{
        !          2400:                pfskp = xlpos1;         /* else skip backwards          */
        !          2401:                xlskipb(tpseg - d0);
        !          2402:                return;
        !          2403:        }
        !          2404: }
        !          2405: 
        !          2406: static void
        !          2407: xlpos1()                               /* skip backwards done          */
        !          2408: {
        !          2409:        cmn_err(CE_CONT, "xlpos1()\n");
        !          2410: 
        !          2411:        if (xlster) {                   /* exit if error                */
        !          2412:                (*pfpos)();
        !          2413:                return;
        !          2414:        }
        !          2415:        f.tmov = 1;
        !          2416:        if (!xprb->tps) {               /* check for 1st seg on trk     */
        !          2417:                pfint = pfpos;
        !          2418:                xloutput_step(QIC_CMD_FWD);
        !          2419:                return;
        !          2420:        }
        !          2421:        pfint = xlreadid;               /* start tape fwd and read id's */
        !          2422:        pfrdi = xlpos2;
        !          2423:        xloutput_step(QIC_CMD_FWD);
        !          2424: }
        !          2425: 
        !          2426: static void
        !          2427: xlpos2()                               /* read id finished             */
        !          2428: {
        !          2429:        cmn_err(CE_CONT, "xlpos2()");
        !          2430: 
        !          2431:        if (xlster) {                   /* exit if error                */
        !          2432:                (*pfpos)();
        !          2433:                return;
        !          2434:        }
        !          2435:        if (status_buf[0] & 0xc0) {     /* error handler                */
        !          2436:                /* if crc error, read id again                          */
        !          2437:                if (status_buf[1] & 0x20) {
        !          2438: printf("crc err ");
        !          2439:                        xlreadid();
        !          2440:                        return;
        !          2441:                }
        !          2442:                pfhlt = xlpos3;
        !          2443:                xlhalt();
        !          2444:                return;
        !          2445:        }
        !          2446:        if (xprb->idc > status_buf[3] ||/* if bef tgt, read id again    */
        !          2447:                                        xprb->ids > status_buf[5]) {
        !          2448: printf("before target ");
        !          2449:                xlreadid();
        !          2450:                return;
        !          2451:        }
        !          2452:        if (xprb->cyl <= status_buf[3] &&       /* if past it back up   */
        !          2453:                                        xprb->sct <= status_buf[5]) {
        !          2454:                pfskp = xlpos1;
        !          2455:                xlskipb(9);
        !          2456:                return;
        !          2457:        }
        !          2458:                                        /* we are at target spot        */
        !          2459:        tpseg = xprb->tps;              /* set tpseg and exit           */
        !          2460:        (*pfpos)();
        !          2461: }
        !          2462: 
        !          2463: static void
        !          2464: xlpos3()                               /* status complete tape stopped */
        !          2465: {
        !          2466:        cmn_err(CE_CONT, "xlpos3()\n");
        !          2467: 
        !          2468:        if (xlster) {                   /* exit if error                */
        !          2469:                (*pfpos)();
        !          2470:                return;
        !          2471:        }
        !          2472:        if (xl6sts & (XLSEOT | XLSBOT)) {/* if end track skip backwd    */
        !          2473:                pfskp = xlpos1;
        !          2474:                xlskipb((int)(nseg_p_track + 5 - xprb->tps));
        !          2475:                return;
        !          2476:        }
        !          2477:        xlster |= XLSNID;               /* else can't read id's         */
        !          2478:        (*pfpos)();
        !          2479: }
        !          2480: 
        !          2481: /************************************************************************/
        !          2482: /*     xlptdat put data                                                */
        !          2483: /************************************************************************/
        !          2484: static void
        !          2485: xlptdat(iop)
        !          2486: IO * iop;
        !          2487: {
        !          2488:        caddr_t p0;
        !          2489:        fpchr   p1;
        !          2490:        int     ilvl;
        !          2491: 
        !          2492:        rnbr = iop->io_ioc;             /* set request params           */
        !          2493:        p0 = iop->io.vbase;
        !          2494:        while(rnbr) {
        !          2495:                if (!cnbr) {            /* if a new buffer is needed    */
        !          2496:                        ilvl = spl5();  /* wait for a new buffer        */
        !          2497:                        while(!(cprb = getrb(&xlfree_q))) {
        !          2498:                                if (!f.actv)
        !          2499:                                        xlque();
        !          2500:                                xlfreew = 1;
        !          2501:                                sleep(&xlfreew, PRIBIO);
        !          2502:                        }
        !          2503:                        splx(ilvl);
        !          2504:                        do{
        !          2505:                                /* set up segment                       */
        !          2506:                                cprb->sgn = curr_seg_num;
        !          2507:                                cprb->map = ptr_header[curr_seg_num + 0x200];
        !          2508:                                cprb->fun = RBFWT;
        !          2509:                                strbsg(cprb);
        !          2510:                                ++curr_seg_num;
        !          2511:                        }while(cprb->nbk < 4);
        !          2512:                        cnbr = (cprb->nbk - 3) << 10;   /* set params   */
        !          2513:                        lnbr = cnbr;
        !          2514:                        cptr = (fpchr)cprb->adr;
        !          2515:                        wptr = cptr;
        !          2516:                }               /* save ptr for later encode            */
        !          2517:                p1 = cptr;                      /* copy data            */
        !          2518:                rcnt = (cnbr >= rnbr) ? rnbr : cnbr;
        !          2519:                copyin(p0, p1, rcnt);
        !          2520:                p0 += rcnt;
        !          2521:                p1 += rcnt;
        !          2522:                cptr = p1;
        !          2523:                rnbr -= rcnt;           /* adjust count                 */
        !          2524:                cnbr -= rcnt;
        !          2525:                if (!cnbr) {            /* if filled, encode and q bfr  */
        !          2526:                        xl_enc(wptr, cprb->nbk);
        !          2527:                        putrb(&req, cprb);
        !          2528:                }
        !          2529:        }
        !          2530:        iop->io_ioc = 0;
        !          2531: }
        !          2532: 
        !          2533: /************************************************************************/
        !          2534: /*     xlque           process queue request                           */
        !          2535: /************************************************************************/
        !          2536: static void
        !          2537: xlque()
        !          2538: {
        !          2539:        cmn_err(CE_CONT, "xlque()\n");
        !          2540: xlque0:
        !          2541:        xprb = getrb(&req);             /* get next request             */
        !          2542:        if (!xprb) {                    /* if end queue and             */
        !          2543:                if (f.tmov) {           /* if tape moving, stop tape    */
        !          2544:                        cmn_err(CE_CONT, "xlque: stopping\n");
        !          2545:                        pfhlt = xlque;
        !          2546:                        xlhalt();
        !          2547:                        return;
        !          2548:                }
        !          2549:                cmn_err(CE_CONT, "xlque: inactive\n");
        !          2550: 
        !          2551:                if (f.actv) {           /* if active, release fdc       */
        !          2552:                        xlrel();
        !          2553:                        relfdc();
        !          2554:                }
        !          2555:                if (xlnactw) {          /* if sleeping on xlnactw, wakeup */
        !          2556:                        xlnactw = 0;
        !          2557:                        wakeup(&xlnactw);
        !          2558:                }
        !          2559:                f.actv = 0;             /* reset active flag, exit      */
        !          2560:                return;
        !          2561:        }
        !          2562:        if (!f.actv) {          /* if called from task (not active)     */
        !          2563:                getfdc(unit);   /*    get fdc                   */
        !          2564:                xlsel(unit);
        !          2565:        }
        !          2566:        f.actv = 1;
        !          2567:        switch(xprb->fun) {
        !          2568:        case RBFRD:                     /* read segment                 */
        !          2569:                if (xstop) {            /* if stop, ignore request      */
        !          2570:                        putrb(&xlfree_q, xprb);
        !          2571:                        goto xlque0;
        !          2572:                }
        !          2573:                pfpos = xlrds;
        !          2574:                pfrds = xlqr0;
        !          2575:                xlpos();
        !          2576:                return;
        !          2577:        case RBFWT:                     /* write segment                */
        !          2578:                pfpos = xlwts;
        !          2579:                pfwts = xlqw0;
        !          2580:                xlpos();
        !          2581:                return;
        !          2582:        case RBWFD:                     /* write del adr mrk segment    */
        !          2583:                pfpos = xlwds;
        !          2584:                pfwds = xlqw0;
        !          2585:                xlpos();
        !          2586:                return;
        !          2587:        default:
        !          2588:                ;
        !          2589:        }
        !          2590: }
        !          2591: 
        !          2592: static void
        !          2593: xlqr0()
        !          2594: {
        !          2595:        putrb(&data_queue, xprb);       /* add to data queue            */
        !          2596:        if (xldataw) {                  /* wakeup if needed             */
        !          2597:                xldataw = 0;
        !          2598:                wakeup(&xldataw);
        !          2599:        }
        !          2600:        xlque();                        /* start next i/o               */
        !          2601: }
        !          2602: 
        !          2603: static void
        !          2604: xlqw0()
        !          2605: {
        !          2606:        if (xprb->sts)          /* set f.werr if error          */
        !          2607:                f.werr = 1;
        !          2608:        putrb(&xlfree_q, xprb); /* relse bfr back to free pool  */
        !          2609:        if (xlfreew) {                  /* wakeup if needed             */
        !          2610:                xlfreew = 0;
        !          2611:                wakeup(&xlfreew);
        !          2612:        }
        !          2613:        xlque();                        /* start next i/o               */
        !          2614: }
        !          2615: 
        !          2616: /************************************************************************/
        !          2617: /*     xlrds   read segment                                            */
        !          2618: /*             in: xprb = pointer to rb                                */
        !          2619: /************************************************************************/
        !          2620: static void
        !          2621: xlrds()
        !          2622: {
        !          2623:        if (xlster || xstop) {          /* exit if error or stop        */
        !          2624:                pfint = xlrd0;          /* use null int to cleanup stck */
        !          2625:                xloutput_step(0);
        !          2626:                return;
        !          2627:        }
        !          2628:        rwdcms[0] = 0x46;               /* set for read                 */
        !          2629:        stseg(xprb);
        !          2630:        xrty = 2;                       /* 2 tries per sector           */
        !          2631:        xlrd0();                        /* start io                     */
        !          2632: }
        !          2633: 
        !          2634: static void
        !          2635: xlrd0()                                        /* initiate io                  */
        !          2636: {
        !          2637:        if (xlster || xstop) {          /* exit if error or stop        */
        !          2638: printf("xlrd0 - err xlster=%x xstop=%x ", xlster, xstop);
        !          2639:                pfint = xlnull;
        !          2640:                xprb->sts = 1;
        !          2641:                (*pfrds)();
        !          2642:                return;
        !          2643:        }
        !          2644:        pfint = xlrd1;                  /* set int handler              */
        !          2645:        xtbl = (xprb->tbl)[xsct - xprb->sct];/* get rb.tbl entry        */
        !          2646:        if (xtbl) {                   /* if more data, start other read */
        !          2647:                rwdcms[4] = (xtbl & 0x1f) + xprb->sct;
        !          2648:                stdma(DMA_Rdmode, xadr | ((xtbl & 0x3e0) << 5), (int)(xtbl & 0xfc00));
        !          2649:                xltimout(IOTMO);
        !          2650:                xlfdc_out_str(rwdcms, 9);
        !          2651:                if (status_buf[7]) {    /* exit if nec error    */
        !          2652:                        xltimout(0);
        !          2653:                        xlster |= XLSNEC;
        !          2654:                        pfint = xlnull;
        !          2655:                        (*pfrds)();
        !          2656:                        return;
        !          2657:                }
        !          2658:                return;
        !          2659:        }
        !          2660:        else{                           /* else, seg is done            */
        !          2661:                xprb->sts = 0;
        !          2662:                tpseg = xprb->tps + 1;
        !          2663:                if (tpseg == nseg_p_track) {    /* if last seg on trk,  */
        !          2664:                        pfrdy = pfrds;          /* exit via xlready     */
        !          2665:                        xlready();
        !          2666:                        return;
        !          2667:                }
        !          2668:                pfint = xlnull;         /* else just exit               */
        !          2669:                (*pfrds)();
        !          2670:                return;
        !          2671:        }
        !          2672: }
        !          2673: 
        !          2674: static void
        !          2675: xlrd1()
        !          2676: {
        !          2677:        if (xlster || xstop) {          /* exit if error or stop        */
        !          2678: printf("xlrd1 - err xlster=%x xstop=%x ", xlster, xstop);
        !          2679:                pfint = xlnull;
        !          2680:                xprb->sts = 1;
        !          2681:                (*pfrds)();
        !          2682:                return;
        !          2683:        }
        !          2684:        if (status_buf[0] & 0xc0) {     /* if error                     */
        !          2685:                dsperr();
        !          2686:                if (status_buf[2] & 0x40) {/* if del adr mark, exit     */
        !          2687:                        ++tpseg;
        !          2688:                        goto xlrd2;
        !          2689:                }
        !          2690:                if (status_buf[0] == 0xc0)/* adjust tpseg               */
        !          2691:                        tpseg += TMSKP;
        !          2692:                else{
        !          2693:                        tpseg += 2;
        !          2694:                }
        !          2695:                if (tpseg > nseg_p_track)
        !          2696:                        tpseg = nseg_p_track;
        !          2697: 
        !          2698:                if (status_buf[0] != 0xc0) { /* if not timeout  */
        !          2699:                        /* if no data read                              */
        !          2700:                        if (xsct == status_buf[5]) {
        !          2701:                                --xrty;         /* skip sct if 2nd time */
        !          2702:                                if (xrty == 0) {
        !          2703:                                        if (xprb->erc < 3) {
        !          2704:                                                xprb->ers[xprb->erc] = xsct-xprb->sct;
        !          2705:                                                ++xprb->erc;
        !          2706:                                                ++xsct;
        !          2707:                                                xrty = 2;
        !          2708:                                        }
        !          2709:                                        else{   /* fail if too many err */
        !          2710:                                                goto xlrd2;
        !          2711:                                        }
        !          2712:                                }
        !          2713:                        }
        !          2714:                        else{                   /* some data read in    */
        !          2715:                                xrty = 1;       /* 1mor try on this sct */
        !          2716:                                xsct = status_buf[5];
        !          2717:                        }
        !          2718:                }                               /* update xsct          */
        !          2719:                else{                           /* if timeout           */
        !          2720:                        --xrty;                 /* fail if too many err */
        !          2721:                        if (!xrty) {
        !          2722: xlrd2:
        !          2723: printf("xlrd2 - err xlster=%x xstop=%x ", xlster, xstop);
        !          2724:                                xprb->sts = 1;
        !          2725:                                pfint = xlnull;
        !          2726:                                (*pfrds)();
        !          2727:                                return;
        !          2728:                        }
        !          2729:                }
        !          2730:                pfpos = xlrd0;          /* restart io after positioning */
        !          2731:                xlpos();
        !          2732:                return;
        !          2733:        }
        !          2734: 
        !          2735:        /*      no errors, start io for next part of segment (if any)   */
        !          2736: 
        !          2737:        xsct = status_buf[5];           /* update xsct, start next io   */
        !          2738:        xlrd0();
        !          2739: }
        !          2740: 
        !          2741: /************************************************************************/
        !          2742: /*     xlreadid        read id                                                 */
        !          2743: /************************************************************************/
        !          2744: static void
        !          2745: xlreadid()
        !          2746: {
        !          2747:        cmn_err(CE_CONT, "xlreadid()");
        !          2748: 
        !          2749:        pfint = xlreadid0;              /* set pfint                    */
        !          2750:        xltimout(IOTMO);
        !          2751:        xlfdc_out_str(rdicms, 2);       /* start read id cmd            */
        !          2752:        if (xlster) {                   /* exit if error                */
        !          2753: printf("readid err ");
        !          2754:                xltimout(0);
        !          2755:                pfint = xlnull;
        !          2756:                (*pfrdi)();
        !          2757:                return;
        !          2758:        }
        !          2759: }
        !          2760: 
        !          2761: static void
        !          2762: xlreadid0()
        !          2763: {
        !          2764:        pfint = xlnull;                 /* reset pfint                  */
        !          2765:        (*pfrdi)();                     /* and exit                     */
        !          2766: }
        !          2767: 
        !          2768: /************************************************************************/
        !          2769: /*     xlready         wait for ready                                  */
        !          2770: /************************************************************************/
        !          2771: static void
        !          2772: xlready()
        !          2773: {
        !          2774:        if (xlster) {                   /* exit if error                */
        !          2775:                (*pfrdy)();
        !          2776:                return;
        !          2777:        }
        !          2778:        pfsts = xlready0;               /* get drive status             */
        !          2779:        xlstatus();
        !          2780: }
        !          2781: 
        !          2782: static void
        !          2783: xlready0()
        !          2784: {
        !          2785:        if (xlster || (xl6sts & XLSRDY)) {      /* exit if done         */
        !          2786:                (*pfrdy)();
        !          2787:                return;
        !          2788:        }
        !          2789:        xlstatus();                     /* else get status again        */
        !          2790: }
        !          2791: 
        !          2792: /************************************************************************/
        !          2793: /*     xlrel   release unit                                            */
        !          2794: /************************************************************************/
        !          2795: static void
        !          2796: xlrel()
        !          2797: {
        !          2798:        while(0x80 != (0xc0 & inb(FDSTAT)));  /* wait for ready */
        !          2799:        outb(FDCTRL, 0x0c);             /* deselect all units           */
        !          2800:        xlfdc_out_str(sf3cms, 3);       /* set step rate to 3ms         */
        !          2801: }
        !          2802: 
        !          2803: /************************************************************************/
        !          2804: /*     xlreset         reset drive                                     */
        !          2805: /************************************************************************/
        !          2806: static void
        !          2807: xlreset()
        !          2808: {
        !          2809:        pfint = xlreset0;               /* output 1 step                */
        !          2810:        xloutput_step(QIC_CMD_RST);
        !          2811: }
        !          2812: 
        !          2813: static void
        !          2814: xlreset0()
        !          2815: {
        !          2816:        pfint = xlnull;                 /* reset pfint                  */
        !          2817:        pfdly = xlready;                /* after delay "wait" for ready */
        !          2818:        pfrdy = pfrst;                  /* after ready, exit via pfrst  */
        !          2819:        xldelay(HZ);                    /* start delay                  */
        !          2820: }
        !          2821: 
        !          2822: /************************************************************************/
        !          2823: /*     xlrnb   report next bit(s)                                      */
        !          2824: /************************************************************************/
        !          2825: static void
        !          2826: xlrnb(cnt)
        !          2827: int    cnt;
        !          2828: {
        !          2829:        xlrnbw = 0;                     /* reset status int             */
        !          2830:        pfint = xlrnb0;                 /* set int handler              */
        !          2831:        xlbcnt = cnt;                   /* set up                       */
        !          2832:        xloutput_step(QIC_CMD_RNB);     /* start 2 step seek            */
        !          2833: }
        !          2834: 
        !          2835: static void
        !          2836: xlrn9()                                /* get 9 bits                   */
        !          2837: {
        !          2838:        unchar bit;
        !          2839: 
        !          2840:        /* Sense drive status. */
        !          2841:        xlfdc_out_byte(4);
        !          2842:        xlfdc_out_byte((int)unit);
        !          2843: 
        !          2844:        /* Read ST3, look at T0 bit. */
        !          2845:        bit = (0x10 & xlfdc_in_byte()) ? 1 : 0;
        !          2846:        printf("%d", bit);
        !          2847: 
        !          2848:        xlrnbw = 0;
        !          2849:        pfint = xlrnb0;
        !          2850:        xlbcnt = 9;
        !          2851:        xloutput_step(QIC_CMD_RNB);
        !          2852: }
        !          2853: 
        !          2854: static void
        !          2855: xlrn17()                               /* get 17 bits                  */
        !          2856: {
        !          2857:        xlrnbw = 0;
        !          2858:        pfint = xlrnb0;
        !          2859:        xlbcnt = 17;
        !          2860:        xloutput_step(QIC_CMD_RNB);
        !          2861: }
        !          2862: 
        !          2863: static void
        !          2864: xlrnb0()
        !          2865: {
        !          2866:        register int xlrnbb;            /* xl2 status bit               */
        !          2867:        int bit;
        !          2868: 
        !          2869:        /* Sense drive status. */
        !          2870:        xlfdc_out_byte(4);
        !          2871:        xlfdc_out_byte((int)unit);
        !          2872: 
        !          2873:        /* Read ST3, look at T0 bit. */
        !          2874:        bit = (0x10 & xlfdc_in_byte()) ? 1 : 0;
        !          2875:        printf("%d", bit);
        !          2876: 
        !          2877:        xlrnbb = bit ? 0x8000 : 0x0000;
        !          2878:        if (status_buf[7])              /* exit if nec handshake error  */
        !          2879:                xlster |= XLSNEC;
        !          2880:        if (xlster) {
        !          2881:                pfint = xlnull;
        !          2882:                (*pfrnb)();
        !          2883:                return;
        !          2884:        }
        !          2885:        --xlbcnt;
        !          2886:        if (xlbcnt) {                   /* if not done, shift in bit    */
        !          2887:                xlrnbw >>= 1;           /*  and continue                */
        !          2888:                xlrnbw |= xlrnbb;
        !          2889:                xloutput_step(QIC_CMD_RNB);
        !          2890:                return;
        !          2891:        } else {
        !          2892:                if (!xlrnbb)            /* last bit must = 1            */
        !          2893:                        xlster |= XLSLSB;
        !          2894:                pfint = xlnull;
        !          2895:                (*pfrnb)();             /* call end step handler        */
        !          2896:                return;
        !          2897:        }
        !          2898: }
        !          2899: 
        !          2900: /************************************************************************/
        !          2901: /*     xlrqr   set up read requests                                    */
        !          2902: /************************************************************************/
        !          2903: static void
        !          2904: xlrqr()
        !          2905: {
        !          2906:        while(fprb = getrb(&xlfree_q)) {/* enqueue any free bfrs        */
        !          2907: xlrqr0:
        !          2908:                if (read_ahead_seg_num > last_seg_num) {
        !          2909:                        putrb(&xlfree_q, fprb);
        !          2910:                        break;
        !          2911:                }
        !          2912:                fprb->sgn = read_ahead_seg_num;
        !          2913:                fprb->map = ptr_header[read_ahead_seg_num + 0x200];
        !          2914:                fprb->fun = RBFRD;
        !          2915:                strbsg(fprb);
        !          2916:                if (fprb->nbk < 4) {    /* skip if < 4 sectors          */
        !          2917:                        ++read_ahead_seg_num;
        !          2918:                        goto xlrqr0;
        !          2919:                }
        !          2920:                putrb(&req, fprb);      /* add bfr to req queue         */
        !          2921:                ++read_ahead_seg_num;
        !          2922:        }
        !          2923: }
        !          2924: 
        !          2925: /************************************************************************/
        !          2926: /*     xlseek  seek head to tptrk                                      */
        !          2927: /************************************************************************/
        !          2928: static void
        !          2929: xlseek()
        !          2930: {
        !          2931:        if (xlster) {                   /* exit if error                */
        !          2932:                (*pfsek)();
        !          2933:                return;
        !          2934:        }
        !          2935:        pfhlt = xlseek0;                /* halt tape                    */
        !          2936:        xlhalt();
        !          2937: }
        !          2938: 
        !          2939: static void
        !          2940: xlseek0()
        !          2941: {
        !          2942:        if (xlster) {                   /* exit if error                */
        !          2943:                (*pfsek)();
        !          2944:                return;
        !          2945:        }
        !          2946:        pfint = xlseek1;                /* do 13 steps                  */
        !          2947:        xloutput_step(QIC_CMD_SEEK);
        !          2948: }
        !          2949: 
        !          2950: static void
        !          2951: xlseek1()
        !          2952: {
        !          2953:        if (xlster) {                   /* exit if error                */
        !          2954:                (*pfsek)();
        !          2955:                return;
        !          2956:        }
        !          2957:        pfint = xlready;                /* after seek "wait" for rdy    */
        !          2958:        pfrdy = pfsek;                  /* after ready, exit            */
        !          2959:        xloutput_step(2 + tptrk);
        !          2960: }
        !          2961: 
        !          2962: /************************************************************************
        !          2963:  *     xlsel   select unit, wait for done
        !          2964:  ***********************************************************************/
        !          2965: static void
        !          2966: xlsel()
        !          2967: {
        !          2968:        fdsel = fdstb[unit];
        !          2969:        fdselr = 0xfb & fdsel;
        !          2970:        outb(FDCSR1, 0);                /* set 500khz speed             */
        !          2971:        outb(FDCTRL, fdsel);            /* select unit                  */
        !          2972:        pfint = xlcomplete;             /* reset fdc                    */
        !          2973:        xlfdc_reset();
        !          2974:        xlwait();
        !          2975:        xlfdc_out_str(sf2cms, 3);       /* set step rate to 2ms         */
        !          2976: 
        !          2977:        /* 80 MB nseg_p_track = 100, nseg_p_head = 600, nseg_p_cyl = 4  */
        !          2978:        /* 40 MB nseg_p_track = 68, nseg_p_head = 680, nseg_p_cyl = 4   */
        !          2979:        if (ftfmt) {
        !          2980:                nseg_p_track = 100;     /* set for 80 MB drive          */
        !          2981:                nseg_p_head = 600;
        !          2982:                nseg_p_cyl = 4;
        !          2983:        } else {
        !          2984:                nseg_p_track = 68;      /* set for 40 MB drive          */
        !          2985:                nseg_p_head = 680;
        !          2986:                nseg_p_cyl = 4;
        !          2987:        }
        !          2988: }
        !          2989: 
        !          2990: /************************************************************************/
        !          2991: /*     xlskipb         skip n segments back                            */
        !          2992: /************************************************************************/
        !          2993: static void
        !          2994: xlskipb(cnt)
        !          2995: int    cnt;
        !          2996: {
        !          2997:        if (xlster) {                   /* exit if error                */
        !          2998:                (*pfskp)();
        !          2999:                return;
        !          3000:        }
        !          3001:        f.tmov = 0;                     /* tape will be halted          */
        !          3002:        xlskip_count = cnt;             /* set skip count               */
        !          3003:        pfint = xlready;                /* stop tape first              */
        !          3004:        pfrdy = xlskipb0;
        !          3005:        xloutput_step(QIC_CMD_STOP);
        !          3006: }
        !          3007: 
        !          3008: static void
        !          3009: xlskipb0()
        !          3010: {
        !          3011:        pfint = xlskipb1;               /* start skip back cmd          */
        !          3012:        xloutput_step(QIC_CMD_SKPB);
        !          3013: }
        !          3014: 
        !          3015: static void
        !          3016: xlskipb1()
        !          3017: {
        !          3018:        if (xlster) {                   /* exit if error                */
        !          3019:                (*pfskp)();
        !          3020:                return;
        !          3021:        }
        !          3022:        pfint = xlskipb2;               /* issue 2nd part of cmd        */
        !          3023:        xloutput_step(2 + (0xf & xlskip_count));
        !          3024: }
        !          3025: 
        !          3026: static void
        !          3027: xlskipb2()
        !          3028: {
        !          3029:        if (xlster) {                   /* exit if error                */
        !          3030:                (*pfskp)();
        !          3031:                return;
        !          3032:        }
        !          3033:        /* after 3rd part cmd, wait for ready                           */
        !          3034:        pfint = xlready;
        !          3035:        pfrdy = pfskp;                  /* after ready, exit            */
        !          3036:        /* start 3rd part cmd   */
        !          3037:        xloutput_step(2 + (0xf & (xlskip_count >> 4)));
        !          3038: }
        !          3039: 
        !          3040: /************************************************************************/
        !          3041: /*     xlstatus()      get drive status                                */
        !          3042: /************************************************************************/
        !          3043: static void
        !          3044: xlstatus()
        !          3045: {
        !          3046:        if (xlster) {                   /* exit if error                */
        !          3047:                pfint = xlnull;
        !          3048:                (*pfsts)();
        !          3049:                return;
        !          3050:        }
        !          3051:        /* after 6 steps, get 9 report bits                             */
        !          3052:        pfint = xlrn9;
        !          3053:        pfrnb = xlstatus0;              /* after 9 bits, goto xlstatus0 */
        !          3054:        xloutput_step(QIC_CMD_STS);     /* start steps                  */
        !          3055: }
        !          3056: 
        !          3057: static void
        !          3058: xlstatus0()
        !          3059: {
        !          3060:        if (xlster) {                   /* exit if error                */
        !          3061:                pfint = xlnull;
        !          3062:                (*pfsts)();
        !          3063:                return;
        !          3064:        }
        !          3065: 
        !          3066:        xl6sts = xlrnbw >> 8;           /* set xl6sts                   */
        !          3067: 
        !          3068:        if (xl6sts == 0xff) {           /* exit if not tape drive       */
        !          3069:                xlster |= XLSNTD;
        !          3070:                pfint = xlnull;
        !          3071:                (*pfsts)();
        !          3072:                return;
        !          3073:        } else {
        !          3074:                xlDbPrintStat(xl6sts);
        !          3075:        }
        !          3076: 
        !          3077:        if (xl6sts & (XLSEXC | XLSCHG)) {/* if exception condition,     */
        !          3078:                xlests = xl6sts;        /* start type 7 status          */
        !          3079:                pfint = xlrn17;
        !          3080:                pfrnb = xlstatus1;
        !          3081:                xloutput_step(QIC_CMD_ECD);
        !          3082:                return;
        !          3083:        }
        !          3084: 
        !          3085:        if (xlests || !(xl6sts & XLSCIN)) { /* set soft err if needed   */
        !          3086: printf("soft err ");
        !          3087:                xlster |= XLSSFT;
        !          3088:        }
        !          3089: 
        !          3090:        pfint = xlnull;                 /* exit                         */
        !          3091:        (*pfsts)();
        !          3092: }
        !          3093: 
        !          3094: static void
        !          3095: xlstatus1()
        !          3096: {
        !          3097:        if (xlster) {                   /* exit if error                */
        !          3098:                pfint = xlnull;
        !          3099:                (*pfsts)();
        !          3100:                return;
        !          3101:        }
        !          3102:        xl7sts = xlrnbw;                /* save type 7 status           */
        !          3103:        xlDbPrintErr(xl7sts);
        !          3104:        pfint = xlrn9;                  /* restart normal status sequce */
        !          3105:        pfrnb = xlstatus0;
        !          3106:        xloutput_step(QIC_CMD_STS);
        !          3107: }
        !          3108: 
        !          3109: /************************************************************************
        !          3110:  *     xltimout                set timeout for int
        !          3111:  *
        !          3112:  * "cnt" is number of ticks.  if zero, cancel any pending timeout
        !          3113:  ***********************************************************************/
        !          3114: static void
        !          3115: xltimout(cnt)
        !          3116: int    cnt;
        !          3117: {
        !          3118:        if (cnt)
        !          3119:                timeout(&xltmo, cnt, xltimfn, 0);
        !          3120:        else
        !          3121:                timeout(&xltmo, cnt, NULL, 0);
        !          3122: }
        !          3123: 
        !          3124: static void
        !          3125: xltimfn()
        !          3126: {
        !          3127:        cmn_err(CE_CONT, "Timeout!!\n");
        !          3128:        xltimoutf = 1;
        !          3129:        xlfdc_reset();
        !          3130: }
        !          3131: 
        !          3132: /************************************************************************/
        !          3133: /*     xlwait  wait for xlcomplete (xlcompw wakeup)                    */
        !          3134: /************************************************************************/
        !          3135: static int
        !          3136: xlwait()
        !          3137: {
        !          3138:        register int ilvl;
        !          3139: 
        !          3140:        ilvl = spl5();
        !          3141:        while(!xlcompf) {               /* wait for xlcompf to be set   */
        !          3142:                xlcompw = 1;
        !          3143:                if (x_sleep(&xlcompw, pritape, slpriSigCatch, "xlwait")) {
        !          3144: printf("xlwait signaled ");
        !          3145:                        return 1;
        !          3146:                }
        !          3147:        }
        !          3148:        xlcompf = 0;                    /* reset flag                   */
        !          3149:        splx(ilvl);
        !          3150:        return 0;
        !          3151: }
        !          3152: 
        !          3153: /************************************************************************/
        !          3154: /*     xlwds   write del adm segment                                   */
        !          3155: /*             in: xprb = pointer to rb                                */
        !          3156: /************************************************************************/
        !          3157: static void
        !          3158: xlwds()
        !          3159: {
        !          3160:        pfwts = pfwds;                  /* using xlwts                  */
        !          3161:        if (xlster) {                   /* exit if error                */
        !          3162:                pfint = xlwt0;          /* use null int to cleanup stck */
        !          3163:                xloutput_step(0);
        !          3164:                return;
        !          3165:        }
        !          3166:        rwdcms[0] = 0x49;               /* set for write del adm        */
        !          3167:        stseg(xprb);
        !          3168:        xrty = 2;
        !          3169:        pfint = xlwt1;
        !          3170:        xlwt0();
        !          3171: }
        !          3172: 
        !          3173: /************************************************************************/
        !          3174: /*     xlwts   write segment                                           */
        !          3175: /*             in: xprb = pointer to rb                                */
        !          3176: /************************************************************************/
        !          3177: static void
        !          3178: xlwts()
        !          3179: {
        !          3180:        if (xlster) {                   /* exit if error                */
        !          3181:                pfint = xlwt0;          /* use null int to cleanup stck */
        !          3182:                xloutput_step(0);
        !          3183:                return;
        !          3184:        }
        !          3185:        rwdcms[0] = 0x45;               /* set for write                */
        !          3186:        stseg(xprb);
        !          3187:        xlwt0();
        !          3188: }
        !          3189: 
        !          3190: static void
        !          3191: xlwt0()                                        /* start io                     */
        !          3192: {
        !          3193:        if (xlster) {                   /* exit if error                */
        !          3194:                xprb->sts = 1;
        !          3195:                pfint = xlnull;
        !          3196:                (*pfwts)();
        !          3197:                return;
        !          3198:        }
        !          3199:        xtbl = (xprb->tbl)[xsct - xprb->sct];/* get rb.tbl entry        */
        !          3200:        if (xtbl) {                   /* if more data start other write */
        !          3201:                pfint = xlwt1;
        !          3202:                rwdcms[4] = (xtbl & 0x1f) + xprb->sct;
        !          3203:                stdma(DMA_Wrmode, xadr | ((xtbl & 0x3e0) << 5), (int)(xtbl & 0xfc00));
        !          3204:                xltimout(IOTMO);
        !          3205:                xlfdc_out_str(rwdcms, 9);
        !          3206:                if (status_buf[7]) {    /* exit if nec error    */
        !          3207:                        xltimout(0);
        !          3208:                        xlster |= XLSNEC;
        !          3209:                        xprb->sts = 1;
        !          3210:                        pfint = xlnull;
        !          3211:                        (*pfwts)();
        !          3212:                        return;
        !          3213:                }
        !          3214:                return;
        !          3215:        }
        !          3216:        else{                           /* else, seg is ok              */
        !          3217:                xprb->sts = 0;
        !          3218:                tpseg = xprb->tps + 1;
        !          3219:                if (tpseg == nseg_p_track) {    /* if last seg on trk,  */
        !          3220:                        pfrdy = pfwts;  /* exit via xlready             */
        !          3221:                        xlready();
        !          3222:                        return;
        !          3223:                }
        !          3224:                pfint = xlnull;         /* else just exit               */
        !          3225:                (*pfwts)();
        !          3226:                return;
        !          3227:        }
        !          3228: }
        !          3229: 
        !          3230: static void
        !          3231: xlwt1()
        !          3232: {
        !          3233:        if (xlster) {                   /* exit if error                */
        !          3234:                xprb->sts = 1;
        !          3235:                pfint = xlnull;
        !          3236:                (*pfwts)();
        !          3237:                return;
        !          3238:        }
        !          3239:        if (status_buf[0] & 0xc0) {     /* check for io error           */
        !          3240:                dsperr();
        !          3241:                if (status_buf[0] == 0xc0)/* adjust tpseg               */
        !          3242:                        tpseg += TMSKP;
        !          3243:                else
        !          3244:                        tpseg += 2;
        !          3245:                if (status_buf[0] != 0xc0)/* update xsct                */
        !          3246:                        xsct = status_buf[5];
        !          3247:                --xrty;                 /* retry if more to try         */
        !          3248:                if (xrty) {
        !          3249:                        pfpos = xlwt0;
        !          3250:                        xlpos();
        !          3251:                        return;
        !          3252:                }
        !          3253:                else{
        !          3254:                        /* if del adm write, continue                   */
        !          3255:                        if (rwdcms[0] == 0x49) {
        !          3256:                                ++xsct;
        !          3257:                                xrty = 2;
        !          3258:                                pfpos = xlwt0;
        !          3259:                                xlpos();
        !          3260:                                return;
        !          3261:                        }
        !          3262:                        xprb->sts = 1;  /* give up on segment, exit     */
        !          3263:                        pfint = xlnull;
        !          3264:                        (*pfwts)();
        !          3265:                        return;
        !          3266:                }
        !          3267:        }
        !          3268:        xsct = status_buf[5];           /* if no error, start next io   */
        !          3269:        xlwt0();
        !          3270: }
        !          3271: 
        !          3272: /******************* DEBUG AREA ******************/
        !          3273: static char    *qicErr[] = {
        !          3274:        "NULL err",
        !          3275:        "command received while drive not ready",
        !          3276:        "cartridge not present or removed",
        !          3277:        "motor speed error (not within 1%)",
        !          3278:        "motor speed fault (jammed, or gross speed error)",
        !          3279:        "cartridge write protected",
        !          3280:        "undefined or reserved command code",
        !          3281:        "illegal track address specified for seek",
        !          3282:        "illegal command in report subcontext",
        !          3283:        "illegal entry into a diagnostic mode",
        !          3284:        "broken tape detected (based on hole sensor)",
        !          3285:        "warning - read gain setting error",
        !          3286:        "command received while error status pending (obsolete)",
        !          3287:        "command received while new cartridge pending",
        !          3288:        "command illegal or undefined in primary mode",
        !          3289:        "command illegal or undefined in format mode",
        !          3290:        "command illegal or undefined in verify mode",
        !          3291:        "logical forward not at logical BOT in format mode",
        !          3292:        "logical EOT before all segments generated",
        !          3293:        "command illegal when cartridge not referenced",
        !          3294:        "self-diagnostic failed (cannot be cleared)",
        !          3295:        "warning EEPROM not initialized, defaults set",
        !          3296:        "EEPROM corrupt or hardware failure",
        !          3297:        "motion timeout error",
        !          3298:        "data segment too long - logical forward or pause",
        !          3299:        "transmit overrun (obsolete)",
        !          3300:        "power on reset occurred",
        !          3301:        "software reset occurred",
        !          3302:        "diagnostic mode 1 error",
        !          3303:        "diagnostic mode 2 error",
        !          3304:        "command received during noninterruptible process",
        !          3305:        "rate selection error",
        !          3306:        "illegal command while in high speed mode",
        !          3307:        "illegal seek segment value"
        !          3308: };
        !          3309: 
        !          3310: static char    *qicStat[] = {
        !          3311:        "drive ready or idle",
        !          3312:        "error detected",
        !          3313:        "cartridge present",
        !          3314:        "cartridge write protected",
        !          3315:        "new cartridge",
        !          3316:        "cartridge referenced",
        !          3317:        "at physical BOT",
        !          3318:        "at physical EOT"
        !          3319: };
        !          3320: 
        !          3321: static char    *qicCmd[] = {
        !          3322:        "NULL cmd",
        !          3323:        "soft reset",
        !          3324:        "report next bit",
        !          3325:        "pause",
        !          3326:        "micro step pause",
        !          3327:        "alternate command timeout",
        !          3328:        "report drive status",
        !          3329:        "report error code",
        !          3330:        "report drive configuration",
        !          3331:        "report ROM version",
        !          3332:        "logical forward",
        !          3333:        "physical reverse",
        !          3334:        "physical forward",
        !          3335:        "seek head to track",
        !          3336:        "seek load point",
        !          3337:        "enter format mode",
        !          3338:        "write reference burst",
        !          3339:        "enter verify mode",
        !          3340:        "stop tape",
        !          3341:        "reserved (19)",
        !          3342:        "reserved (20)",
        !          3343:        "micro step head up",
        !          3344:        "micro step head down",
        !          3345:        "reserved (23)",
        !          3346:        "reserved (24)",
        !          3347:        "skip n segments reverse",
        !          3348:        "skip n segments forward",
        !          3349:        "select rate",
        !          3350:        "enter diag mode 1",
        !          3351:        "enter diag mode 2",
        !          3352:        "enter primary mode",
        !          3353:        "reserved (31)",
        !          3354:        "report vendor ID",
        !          3355:        "report tape status",
        !          3356:        "skip n segments extended reverse",
        !          3357:        "skip n segments extended forward"
        !          3358: };
        !          3359: 
        !          3360: /* print 2-byte error status as <error-code,command> */
        !          3361: static void
        !          3362: xlDbPrintErr(errword)
        !          3363: unsigned int errword;
        !          3364: {
        !          3365:        unsigned int lo, hi;
        !          3366: 
        !          3367:        lo = errword & 0xff;
        !          3368:        hi = (errword >> 8) & 0xff;
        !          3369: 
        !          3370:        if (lo >= 1 && lo < sizeof(qicErr)/sizeof(qicErr[0]))
        !          3371:                printf("<%s,", qicErr[lo]);
        !          3372:        else
        !          3373:                printf("<%x,", lo);
        !          3374: 
        !          3375:        if (hi >= 1 && hi < sizeof(qicCmd)/sizeof(qicCmd[0]))
        !          3376:                printf("%s> ", qicCmd[hi]);
        !          3377:        else
        !          3378:                printf("%x> ", hi);
        !          3379: }
        !          3380: 
        !          3381: /* print command as [command] */
        !          3382: static void
        !          3383: xlDbPrintCmd(cmd)
        !          3384: unsigned int cmd;
        !          3385: {
        !          3386:        if (cmd >= 1 && cmd < sizeof(qicCmd)/sizeof(qicCmd[0])) {
        !          3387:                if (cmd == QIC_CMD_RNB)
        !          3388:                        putchar ('.');
        !          3389:                else
        !          3390:                        printf("[%s] ", qicCmd[cmd]);
        !          3391:        } else
        !          3392:                printf("[%d] ", cmd);
        !          3393: }
        !          3394: 
        !          3395: /* print tape status as { status string,... } */
        !          3396: static void
        !          3397: xlDbPrintStat(stat)
        !          3398: unsigned int stat;
        !          3399: {
        !          3400:        int i;
        !          3401: 
        !          3402:        printf("{ ");
        !          3403:        for (i = 0; i < 8; i++) {
        !          3404:                if (stat & (1 << i))
        !          3405:                        printf("%s, ", qicStat[i]);
        !          3406:        }
        !          3407:        putchar('}');
        !          3408: }

unix.superglobalmegacorp.com

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