Annotation of Gnu-Mach/i386/i386at/nfd.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * Copyright (c) 1994 Shantanu Goel
                      3:  * All Rights Reserved.
                      4:  * 
                      5:  * Permission to use, copy, modify and distribute this software and its
                      6:  * documentation is hereby granted, provided that both the copyright
                      7:  * notice and this permission notice appear in all copies of the
                      8:  * software, derivative works or modified versions, and any portions
                      9:  * thereof, and that both notices appear in supporting documentation.
                     10:  * 
                     11:  * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     12:  * CONDITION.  THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     13:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     14:  */
                     15: 
                     16: #include <fd.h>
                     17: #if NFD > 0
                     18: /*
                     19:  * Floppy disk driver.
                     20:  *
                     21:  * Supports:
                     22:  * 1 controller and 2 drives.
                     23:  * Media change and automatic media detection.
                     24:  * Arbitrarily sized read/write requests.
                     25:  * Misaligned requests
                     26:  * DMA above 16 Meg
                     27:  *
                     28:  * TODO:
                     29:  * 1) Real probe routines for controller and drives.
                     30:  * 2) Support for multiple controllers.  The driver does
                     31:  * not assume a single controller since all functions
                     32:  * take the controller and/or device structure as an
                     33:  * argument, however the probe routines limit the
                     34:  * number of controllers and drives to 1 and 2 respectively.
                     35:  * 3) V_VERIFY ioctl.
                     36:  * 4) User defined diskette parameters.
                     37:  * 5) Detect Intel 82077 or compatible and use its FIFO mode.
                     38:  *
                     39:  * Shantanu Goel ([email protected])
                     40:  */
                     41: #include <sys/types.h>
                     42: #include <sys/ioctl.h>
                     43: #include "vm_param.h"
                     44: #include <kern/time_out.h>
                     45: #include <vm/pmap.h>
                     46: #include <device/param.h>
                     47: #include <device/buf.h>
                     48: #include <device/errno.h>
                     49: #include <chips/busses.h>
                     50: #include <i386/machspl.h>
                     51: #include <i386/pio.h>
                     52: #include <i386at/cram.h>
                     53: #include <i386at/disk.h>
                     54: #include <i386at/nfdreg.h>
                     55: 
                     56: /*
                     57:  * Number of drives supported by an FDC.
                     58:  * The controller is actually capable of
                     59:  * supporting 4 drives, however, most (all?)
                     60:  * board implementations only support 2.
                     61:  */
                     62: #define NDRIVES_PER_FDC        2
                     63: #define NFDC           ((NFD + NDRIVES_PER_FDC - 1) / NDRIVES_PER_FDC)
                     64: 
                     65: #define fdunit(dev)    (((int)(dev) >> 6) & 3)
                     66: #define fdmedia(dev)   ((int)(dev) & 3)
                     67: 
                     68: #define b_cylin                b_resid
                     69: #define B_FORMAT       B_MD1
                     70: 
                     71: #define SECSIZE                512
                     72: 
                     73: #define DMABSIZE       (18*1024)       /* size of DMA bounce buffer */
                     74: 
                     75: #define OP_TIMEOUT     5               /* time to wait (secs) for an
                     76:                                           operation before giving up */
                     77: #define MOTOR_TIMEOUT  5               /* time to wait (secs) before turning
                     78:                                           off an idle drive motor */
                     79: #define MAX_RETRIES    48              /* number of times to try
                     80:                                           an I/O operation */
                     81: 
                     82: #define SRTHUT         0xdf            /* step rate/head unload time */
                     83: #define HLTND          0x02            /* head load time/dma mode */
                     84: 
                     85: /*
                     86:  * DMA controller.
                     87:  *
                     88:  * XXX: There should be a generic <i386/dma.h> file.
                     89:  */
                     90: 
                     91: /*
                     92:  * Ports
                     93:  */
                     94: #define DMA2_PAGE      0x81    /* channel 2, page register */
                     95: #define DMA2_ADDR      0x04    /* channel 2, addr register */
                     96: #define DMA2_COUNT     0x05    /* channel 2, count register */
                     97: #define DMA_STATUS     0x08    /* status register */
                     98: #define DMA_COMMAND    0x08    /* command register */
                     99: #define DMA_WREQ       0x09    /* request register */
                    100: #define DMA_SINGLEMSK  0x0a    /* single mask register */
                    101: #define DMA_MODE       0x0b    /* mode register */
                    102: #define DMA_FLIPFLOP   0x0c    /* pointer flip/flop */
                    103: #define DMA_TEMP       0x0d    /* temporary register */
                    104: #define DMA_MASTERCLR  0x0d    /* master clear */
                    105: #define DMA_CLRMASK    0x0e    /* clear mask register */
                    106: #define DMA_ALLMASK    0x0f    /* all mask register */
                    107: 
                    108: /*
                    109:  * Commands
                    110:  */
                    111: #define DMA_WRITE      0x46    /* write on channel 2 */
                    112: #define DMA_READ       0x4a    /* read on channel 2 */
                    113: 
                    114: /*
                    115:  * Autoconfiguration stuff.
                    116:  */
                    117: struct bus_ctlr *fdminfo[NFDC];
                    118: struct bus_device *fddinfo[NFD];
                    119: int    fdstd[] = { 0 };
                    120: int    fdprobe(), fdslave(), fdintr();
                    121: void   fdattach();
                    122: struct bus_driver fddriver = {
                    123:        fdprobe, fdslave, fdattach, 0, fdstd, "fd", fddinfo, "fdc", fdminfo
                    124: };
                    125: 
                    126: /*
                    127:  * Per-controller state.
                    128:  */
                    129: struct fdcsoftc {
                    130:        int     sc_flags;
                    131: #define FDF_WANT       0x01    /* someone needs direct controller access */
                    132: #define FDF_RESET      0x02    /* controller needs reset */
                    133: #define FDF_LIMIT      0x04    /* limit transfer to a single sector */
                    134: #define FDF_BOUNCE     0x08    /* using bounce buffer */
                    135:        int     sc_state;       /* transfer fsm */
                    136:        caddr_t sc_addr;        /* buffer address */
                    137:        int     sc_resid;       /* amount left to transfer */
                    138:        int     sc_amt;         /* amount currently being transferred */
                    139:        int     sc_op;          /* operation being performed */
                    140:        int     sc_mode;        /* DMA mode */
                    141:        int     sc_sn;          /* sector number */
                    142:        int     sc_tn;          /* track number */
                    143:        int     sc_cn;          /* cylinder number */
                    144:        int     sc_recalerr;    /* # recalibration errors */
                    145:        int     sc_seekerr;     /* # seek errors */
                    146:        int     sc_ioerr;       /* # i/o errors */
                    147:        int     sc_dor;         /* copy of digital output register */
                    148:        int     sc_rate;        /* copy of transfer rate register */
                    149:        int     sc_wticks;      /* watchdog */
                    150:        u_int   sc_buf;         /* buffer for transfers > 16 Meg */
                    151:        u_char  sc_cmd[9];      /* command buffer */
                    152:        u_char  sc_results[7];  /* operation results */
                    153: } fdcsoftc[NFDC];
                    154: 
                    155: #define sc_st0 sc_results[0]
                    156: #define sc_st3 sc_results[0]
                    157: #define sc_st1 sc_results[1]
                    158: #define sc_pcn sc_results[1]
                    159: #define sc_st2 sc_results[2]
                    160: #define sc_c   sc_results[3]
                    161: #define sc_h   sc_results[4]
                    162: #define sc_r   sc_results[5]
                    163: #define sc_n   sc_results[6]
                    164: 
                    165: /*
                    166:  * Transfer states.
                    167:  */
                    168: #define IDLE           0       /* controller is idle */
                    169: #define RESET          1       /* reset controller */
                    170: #define RESETDONE      2       /* reset completion interrupt */
                    171: #define RECAL          3       /* recalibrate drive */
                    172: #define RECALDONE      4       /* recalibration complete interrupt */
                    173: #define SEEK           5       /* perform seek on drive */
                    174: #define SEEKDONE       6       /* seek completion interrupt */
                    175: #define TRANSFER       7       /* perform transfer on drive */
                    176: #define TRANSFERDONE   8       /* transfer completion interrupt */
                    177: 
                    178: /*
                    179:  * Per-drive state.
                    180:  */
                    181: struct fdsoftc {
                    182:        int     sc_flags;
                    183: #define FDF_RECAL      0x02    /* drive needs recalibration */
                    184: #define FDF_SEEK       0x04    /* force seek during auto-detection */
                    185: #define FDF_AUTO       0x08    /* performing auto-density */
                    186: #define FDF_AUTOFORCE  0x10    /* force auto-density */
                    187: #define FDF_INIT       0x20    /* drive is being initialized */
                    188:        int     sc_type;        /* drive type */
                    189:        struct  fddk *sc_dk;    /* diskette type */
                    190:        int     sc_cyl;         /* current head position */
                    191:        int     sc_mticks;      /* motor timeout */
                    192: } fdsoftc[NFD];
                    193: 
                    194: struct buf fdtab[NFDC];        /* controller queues */
                    195: struct buf fdutab[NFD];        /* drive queues */
                    196: 
                    197: /*
                    198:  * Floppy drive type names.
                    199:  */
                    200: char   *fdnames[] = { "360K", "1.2 Meg", "720K", "1.44 Meg" };
                    201: #define NTYPES (sizeof(fdnames) / sizeof(fdnames[0]))
                    202: 
                    203: /*
                    204:  * Floppy diskette parameters.
                    205:  */
                    206: struct fddk {
                    207:        int     dk_nspu;        /* sectors/unit */
                    208:        int     dk_nspc;        /* sectors/cylinder */
                    209:        int     dk_ncyl;        /* cylinders/unit */
                    210:        int     dk_nspt;        /* sectors/track */
                    211:        int     dk_step;        /* !=0 means double track steps */
                    212:        int     dk_gap;         /* read/write gap length */
                    213:        int     dk_fgap;        /* format gap length */
                    214:        int     dk_rate;        /* transfer rate */
                    215:        int     dk_drives;      /* bit mask of drives that accept diskette */
                    216:        char    *dk_name;       /* type name */
                    217: } fddk[] = {
                    218:        /*
                    219:         * NOTE: largest density for each drive type must be first so
                    220:         * fdauto() tries it before any lower ones.
                    221:         */
                    222:        { 2880, 36, 80, 18, 0, 0x1b, 0x6c, 0x00, 0x08, "1.44 Meg" },
                    223:        { 2400, 30, 80, 15, 0, 0x1b, 0x54, 0x00, 0x02,  "1.2 Meg" },
                    224:        { 1440, 18, 80,  9, 0, 0x2a, 0x50, 0x02, 0x0c,     "720K" },
                    225:        {  720, 18, 40,  9, 1, 0x23, 0x50, 0x01, 0x02,     "360K" },
                    226:        {  720, 18, 40,  9, 0, 0x2a, 0x50, 0x02, 0x01,  "360K PC" }
                    227: };
                    228: #define NDKTYPES       (sizeof(fddk) / sizeof(fddk[0]))
                    229: 
                    230: /*
                    231:  * For compatibility with old driver.
                    232:  * This array is indexed by the old floppy type codes
                    233:  * and points to the corresponding entry for that
                    234:  * type in fddk[] above.
                    235:  */
                    236: struct fddk *fdcompat[NDKTYPES];
                    237: 
                    238: int    fdwstart = 0;
                    239: int    fdstrategy(), fdformat();
                    240: char   *fderrmsg();
                    241: void   fdwatch(), fdminphys(), fdspinup(), wakeup();
                    242: 
                    243: #define FDDEBUG
                    244: #ifdef FDDEBUG
                    245: int fddebug = 0;
                    246: #define DEBUGF(n, stmt)        { if (fddebug >= (n)) stmt; }
                    247: #else
                    248: #define DEBUGF(n, stmt)
                    249: #endif
                    250: 
                    251: /*
                    252:  * Probe for a controller.
                    253:  */
                    254: int
                    255: fdprobe(xxx, um)
                    256:        int xxx;
                    257:        struct bus_ctlr *um;
                    258: {
                    259:        struct fdcsoftc *fdc;
                    260: 
                    261:        if (um->unit >= NFDC) {
                    262:                printf("fdc%d: not configured\n", um->unit);
                    263:                return (0);
                    264:        }
                    265:        if (um->unit > 0)       /* XXX: only 1 controller */
                    266:                return (0);
                    267: 
                    268:        /*
                    269:         * XXX: need real probe
                    270:         */
                    271:        take_ctlr_irq(um);
                    272:        printf("%s%d: port 0x%x, spl %d, pic %d.\n",
                    273:               um->name, um->unit, um->address, um->sysdep, um->sysdep1);
                    274: 
                    275:        /*
                    276:         * Set up compatibility array.
                    277:         */
                    278:        fdcompat[0] = &fddk[2];
                    279:        fdcompat[1] = &fddk[0];
                    280:        fdcompat[2] = &fddk[3];
                    281:        fdcompat[3] = &fddk[1];
                    282: 
                    283:        fdc = &fdcsoftc[um->unit];
                    284:        fdc->sc_rate = -1;
                    285:        if (!fdc->sc_buf) {
                    286:                fdc->sc_buf = alloc_dma_mem(DMABSIZE, 64*1024);
                    287:                if (fdc->sc_buf == 0)
                    288:                        panic("fd: alloc_dma_mem() failed");
                    289:        }
                    290:        fdc->sc_dor = DOR_RSTCLR | DOR_IENABLE;
                    291:        outb(FD_DOR(um->address), fdc->sc_dor);
                    292:        return (1);
                    293: }
                    294: 
                    295: /*
                    296:  * Probe for a drive.
                    297:  */
                    298: int
                    299: fdslave(ui)
                    300:        struct bus_device *ui;
                    301: {
                    302:        struct fdsoftc *sc;
                    303: 
                    304:        if (ui->unit >= NFD) {
                    305:                printf("fd%d: not configured\n", ui->unit);
                    306:                return (0);
                    307:        }
                    308:        if (ui->unit > 1)       /* XXX: only 2 drives */
                    309:                return (0);
                    310: 
                    311:        /*
                    312:         * Find out from CMOS if drive exists.
                    313:         */
                    314:        sc = &fdsoftc[ui->unit];
                    315:        outb(CMOS_ADDR, 0x10);
                    316:        sc->sc_type = inb(CMOS_DATA);
                    317:        if (ui->unit == 0)
                    318:                sc->sc_type >>= 4;
                    319:        sc->sc_type &= 0x0f;
                    320:        return (sc->sc_type);
                    321: }
                    322: 
                    323: /*
                    324:  * Attach a drive to the system.
                    325:  */
                    326: void
                    327: fdattach(ui)
                    328:        struct bus_device *ui;
                    329: {
                    330:        struct fdsoftc *sc;
                    331: 
                    332:        sc = &fdsoftc[ui->unit];
                    333:        if (--sc->sc_type >= NTYPES) {
                    334:                printf(": unknown drive type %d", sc->sc_type);
                    335:                ui->alive = 0;
                    336:                return;
                    337:        }
                    338:        printf(": %s", fdnames[sc->sc_type]);
                    339:        sc->sc_flags = FDF_RECAL | FDF_SEEK | FDF_AUTOFORCE;
                    340: }
                    341: 
                    342: int
                    343: fdopen(dev, mode)
                    344:        dev_t dev;
                    345:        int mode;
                    346: {
                    347:        int unit = fdunit(dev), error;
                    348:        struct bus_device *ui;
                    349:        struct fdsoftc *sc;
                    350: 
                    351:        if (unit >= NFD || (ui = fddinfo[unit]) == 0 || ui->alive == 0)
                    352:                return (ENXIO);
                    353: 
                    354:        /*
                    355:         * Start watchdog.
                    356:         */
                    357:        if (!fdwstart) {
                    358:                fdwstart++;
                    359:                timeout(fdwatch, 0, hz);
                    360:        }
                    361:        /*
                    362:         * Do media detection if drive is being opened for the
                    363:         * first time or diskette has been changed since the last open.
                    364:         */
                    365:        sc = &fdsoftc[unit];
                    366:        if ((sc->sc_flags & FDF_AUTOFORCE) || fddskchg(ui)) {
                    367:                if (error = fdauto(dev))
                    368:                        return (error);
                    369:                sc->sc_flags &= ~FDF_AUTOFORCE;
                    370:        }
                    371:        return (0);
                    372: }
                    373: 
                    374: int
                    375: fdclose(dev)
                    376:        dev_t dev;
                    377: {
                    378:        int s, unit = fdunit(dev);
                    379:        struct fdsoftc *sc = &fdsoftc[unit];
                    380: 
                    381:        /*
                    382:         * Wait for pending operations to complete.
                    383:         */
                    384:        s = splbio();
                    385:        while (fdutab[unit].b_active) {
                    386:                sc->sc_flags |= FDF_WANT;
                    387:                assert_wait((event_t)sc, FALSE);
                    388:                thread_block((void (*)())0);
                    389:        }
                    390:        splx(s);
                    391:        return (0);
                    392: }
                    393: 
                    394: int
                    395: fdread(dev, ior)
                    396:        dev_t dev;
                    397:        io_req_t ior;
                    398: {
                    399:        return (block_io(fdstrategy, fdminphys, ior));
                    400: }
                    401: 
                    402: int
                    403: fdwrite(dev, ior)
                    404:        dev_t dev;
                    405:        io_req_t ior;
                    406: {
                    407:        return (block_io(fdstrategy, fdminphys, ior));
                    408: }
                    409: 
                    410: int
                    411: fdgetstat(dev, flavor, status, status_count)
                    412:        dev_t dev;
                    413:        dev_flavor_t flavor;
                    414:        dev_status_t status;
                    415:        mach_msg_type_number_t *status_count;
                    416: {
                    417:        switch (flavor) {
                    418: 
                    419:        case DEV_GET_SIZE:
                    420:        {
                    421:                int *info;
                    422:                io_return_t error;
                    423:                struct disk_parms dp;
                    424: 
                    425:                if (error = fdgetparms(dev, &dp))
                    426:                        return (error);
                    427:                info = (int *)status;
                    428:                info[DEV_GET_SIZE_DEVICE_SIZE] = dp.dp_pnumsec * SECSIZE;
                    429:                info[DEV_GET_SIZE_RECORD_SIZE] = SECSIZE;
                    430:                *status_count = DEV_GET_SIZE_COUNT;
                    431:                return (D_SUCCESS);
                    432:        }
                    433:        case V_GETPARMS:
                    434:                if (*status_count < (sizeof(struct disk_parms) / sizeof(int)))
                    435:                        return (D_INVALID_OPERATION);
                    436:                *status_count = sizeof(struct disk_parms) / sizeof(int);
                    437:                return (fdgetparms(dev, (struct disk_parms *)status));
                    438: 
                    439:        default:
                    440:                return (D_INVALID_OPERATION);
                    441:        }
                    442: }
                    443: 
                    444: int
                    445: fdsetstat(dev, flavor, status, status_count)
                    446:        dev_t dev;
                    447:        dev_flavor_t flavor;
                    448:        dev_status_t status;
                    449:        mach_msg_type_number_t status_count;
                    450: {
                    451:        switch (flavor) {
                    452: 
                    453:        case V_SETPARMS:
                    454:                return (fdsetparms(dev, *(int *)status));
                    455: 
                    456:        case V_FORMAT:
                    457:                return (fdformat(dev, (union io_arg *)status));
                    458: 
                    459:        case V_VERIFY:
                    460:                /*
                    461:                 * XXX: needs to be implemented
                    462:                 */
                    463:                return (D_SUCCESS);
                    464: 
                    465:        default:
                    466:                return (D_INVALID_OPERATION);
                    467:        }
                    468: }
                    469: 
                    470: int
                    471: fddevinfo(dev, flavor, info)
                    472:        dev_t dev;
                    473:        int flavor;
                    474:        char *info;
                    475: {
                    476:        switch (flavor) {
                    477: 
                    478:        case D_INFO_BLOCK_SIZE:
                    479:                *(int *)info = SECSIZE;
                    480:                return (D_SUCCESS);
                    481: 
                    482:        default:
                    483:                return (D_INVALID_OPERATION);
                    484:        }
                    485: }
                    486: 
                    487: /*
                    488:  * Allow arbitrary transfers.  Standard minphys restricts
                    489:  * transfers to a maximum of 256K preventing us from reading
                    490:  * an entire diskette in a single system call.
                    491:  */
                    492: void
                    493: fdminphys(ior)
                    494:        io_req_t ior;
                    495: {
                    496: }
                    497: 
                    498: /*
                    499:  * Return current media parameters.
                    500:  */
                    501: int
                    502: fdgetparms(dev, dp)
                    503:        dev_t dev;
                    504:        struct disk_parms *dp;
                    505: {
                    506:        struct fddk *dk = fdsoftc[fdunit(dev)].sc_dk;
                    507: 
                    508:        dp->dp_type = DPT_FLOPPY;
                    509:        dp->dp_heads = 2;
                    510:        dp->dp_sectors = dk->dk_nspt;
                    511:        dp->dp_pstartsec = 0;
                    512:        dp->dp_cyls = dk->dk_ncyl;
                    513:        dp->dp_pnumsec = dk->dk_nspu;
                    514:        return (0);
                    515: }
                    516: 
                    517: /*
                    518:  * Set media parameters.
                    519:  */
                    520: int
                    521: fdsetparms(dev, type)
                    522:        dev_t dev;
                    523:        int type;
                    524: {
                    525:        struct fdsoftc *sc;
                    526:        struct fddk *dk;
                    527: 
                    528:        if (type < 0 || type >= NDKTYPES)
                    529:                return (EINVAL);
                    530:        dk = fdcompat[type];
                    531:        sc = &fdsoftc[fdunit(dev)];
                    532:        if ((dk->dk_drives & (1 << sc->sc_type)) == 0)
                    533:                return (EINVAL);
                    534:        sc->sc_dk = dk;
                    535:        return (D_SUCCESS);
                    536: }
                    537: 
                    538: /*
                    539:  * Format a floppy.
                    540:  */
                    541: int
                    542: fdformat(dev, arg)
                    543:        dev_t dev;
                    544:        union io_arg *arg;
                    545: {
                    546:        int i, j, sect, error = 0;
                    547:        unsigned track, num_trks;
                    548:        struct buf *bp;
                    549:        struct fddk *dk;
                    550:        struct format_info *fmt;
                    551: 
                    552:        dk = fdsoftc[fdunit(dev)].sc_dk;
                    553:        num_trks = arg->ia_fmt.num_trks;
                    554:        track = arg->ia_fmt.start_trk;
                    555:        if (num_trks == 0 || track + num_trks > (dk->dk_ncyl << 1)
                    556:            || arg->ia_fmt.intlv >= dk->dk_nspt)
                    557:                return (EINVAL);
                    558: 
                    559:        bp = (struct buf *)geteblk(SECSIZE);
                    560:        bp->b_dev = dev;
                    561:        bp->b_bcount = dk->dk_nspt * sizeof(struct format_info);
                    562:        bp->b_blkno = track * dk->dk_nspt;
                    563: 
                    564:        while (num_trks-- > 0) {
                    565:                /*
                    566:                 * Set up format information.
                    567:                 */
                    568:                fmt = (struct format_info *)bp->b_un.b_addr;
                    569:                for (i = 0; i < dk->dk_nspt; i++)
                    570:                        fmt[i].sector = 0;
                    571:                for (i = 0, j = 0, sect = 1; i < dk->dk_nspt; i++) {
                    572:                        fmt[j].cyl = track >> 1;
                    573:                        fmt[j].head = track & 1;
                    574:                        fmt[j].sector = sect++;
                    575:                        fmt[j].secsize = 2;
                    576:                        if ((j += arg->ia_fmt.intlv) < dk->dk_nspt)
                    577:                                continue;
                    578:                        for (j -= dk->dk_nspt; j < dk->dk_nspt; j++)
                    579:                                if (fmt[j].sector == 0)
                    580:                                        break;
                    581:                }
                    582:                bp->b_flags = B_FORMAT;
                    583:                fdstrategy(bp);
                    584:                biowait(bp);
                    585:                if (bp->b_flags & B_ERROR) {
                    586:                        error = bp->b_error;
                    587:                        break;
                    588:                }
                    589:                bp->b_blkno += dk->dk_nspt;
                    590:                track++;
                    591:        }
                    592:        bp->b_flags &= ~B_FORMAT;
                    593:        brelse(bp);
                    594:        return (error);
                    595: }
                    596: 
                    597: /*
                    598:  * Strategy routine.
                    599:  * Enqueue a request on drive queue.
                    600:  */
                    601: int
                    602: fdstrategy(bp)
                    603:        struct buf *bp;
                    604: {
                    605:        int unit = fdunit(bp->b_dev), s;
                    606:        int bn, sz, maxsz;
                    607:        struct buf *dp;
                    608:        struct bus_device *ui = fddinfo[unit];
                    609:        struct fddk *dk = fdsoftc[unit].sc_dk;
                    610: 
                    611:        bn = bp->b_blkno;
                    612:        sz = (bp->b_bcount + SECSIZE - 1) / SECSIZE;
                    613:        maxsz = dk->dk_nspu;
                    614:        if (bn < 0 || bn + sz > maxsz) {
                    615:                if (bn == maxsz) {
                    616:                        bp->b_resid = bp->b_bcount;
                    617:                        goto done;
                    618:                }
                    619:                sz = maxsz - bn;
                    620:                if (sz <= 0) {
                    621:                        bp->b_error = EINVAL;
                    622:                        bp->b_flags |= B_ERROR;
                    623:                        goto done;
                    624:                }
                    625:                bp->b_bcount = sz * SECSIZE;
                    626:        }
                    627:        bp->b_cylin = bn / dk->dk_nspc;
                    628:        dp = &fdutab[unit];
                    629:        s = splbio();
                    630:        disksort(dp, bp);
                    631:        if (!dp->b_active) {
                    632:                fdustart(ui);
                    633:                if (!fdtab[ui->mi->unit].b_active)
                    634:                        fdstart(ui->mi);
                    635:        }
                    636:        splx(s);
                    637:        return;
                    638:  done:
                    639:        biodone(bp);
                    640:        return;
                    641: }
                    642: 
                    643: /*
                    644:  * Unit start routine.
                    645:  * Move request from drive to controller queue.
                    646:  */
                    647: int
                    648: fdustart(ui)
                    649:        struct bus_device *ui;
                    650: {
                    651:        struct buf *bp;
                    652:        struct buf *dp;
                    653: 
                    654:        bp = &fdutab[ui->unit];
                    655:        if (bp->b_actf == 0)
                    656:                return;
                    657:        dp = &fdtab[ui->mi->unit];
                    658:        if (dp->b_actf == 0)
                    659:                dp->b_actf = bp;
                    660:        else
                    661:                dp->b_actl->b_forw = bp;
                    662:        bp->b_forw = 0;
                    663:        dp->b_actl = bp;
                    664:        bp->b_active++;
                    665: }
                    666: 
                    667: /*
                    668:  * Start output on controller.
                    669:  */
                    670: int
                    671: fdstart(um)
                    672:        struct bus_ctlr *um;
                    673: {
                    674:        struct buf *bp;
                    675:        struct buf *dp;
                    676:        struct fdsoftc *sc;
                    677:        struct fdcsoftc *fdc;
                    678:        struct bus_device *ui;
                    679:        struct fddk *dk;
                    680: 
                    681:        /*
                    682:         * Pull a request from the controller queue.
                    683:         */
                    684:        dp = &fdtab[um->unit];
                    685:        if ((bp = dp->b_actf) == 0)
                    686:                return;
                    687:        bp = bp->b_actf;
                    688: 
                    689:        fdc = &fdcsoftc[um->unit];
                    690:        ui = fddinfo[fdunit(bp->b_dev)];
                    691:        sc = &fdsoftc[ui->unit];
                    692:        dk = sc->sc_dk;
                    693: 
                    694:        /*
                    695:         * Mark controller busy.
                    696:         */
                    697:        dp->b_active++;
                    698: 
                    699:        /*
                    700:         * Figure out where this request is going.
                    701:         */
                    702:        fdc->sc_cn = bp->b_cylin;
                    703:        fdc->sc_sn = bp->b_blkno % dk->dk_nspc;
                    704:        fdc->sc_tn = fdc->sc_sn / dk->dk_nspt;
                    705:        fdc->sc_sn %= dk->dk_nspt;
                    706: 
                    707:        /*
                    708:         * Set up for multi-sector transfer.
                    709:         */
                    710:        fdc->sc_op = ((bp->b_flags & B_FORMAT) ? CMD_FORMAT
                    711:                      : ((bp->b_flags & B_READ) ? CMD_READ : CMD_WRITE));
                    712:        fdc->sc_mode = (bp->b_flags & B_READ) ? DMA_WRITE : DMA_READ;
                    713:        fdc->sc_addr = bp->b_un.b_addr;
                    714:        fdc->sc_resid = bp->b_bcount;
                    715:        fdc->sc_wticks = 0;
                    716:        fdc->sc_recalerr = 0;
                    717:        fdc->sc_seekerr = 0;
                    718:        fdc->sc_ioerr = 0;
                    719: 
                    720:        /*
                    721:         * Set initial transfer state.
                    722:         */
                    723:        if (fdc->sc_flags & FDF_RESET)
                    724:                fdc->sc_state = RESET;
                    725:        else if (sc->sc_flags & FDF_RECAL)
                    726:                fdc->sc_state = RECAL;
                    727:        else if (sc->sc_cyl != fdc->sc_cn)
                    728:                fdc->sc_state = SEEK;
                    729:        else
                    730:                fdc->sc_state = TRANSFER;
                    731: 
                    732:        /*
                    733:         * Set transfer rate.
                    734:         */
                    735:        if (fdc->sc_rate != dk->dk_rate) {
                    736:                fdc->sc_rate = dk->dk_rate;
                    737:                outb(FD_RATE(um->address), fdc->sc_rate);
                    738:        }
                    739:        /*
                    740:         * Turn on drive motor.
                    741:         * Don't start I/O if drive is spinning up.
                    742:         */
                    743:        if (fdmotoron(ui)) {
                    744:                timeout(fdspinup, (void *)um, hz / 2);
                    745:                return;
                    746:        }
                    747:        /*
                    748:         * Call transfer state routine to do the actual I/O.
                    749:         */
                    750:        fdstate(um);
                    751: }
                    752: 
                    753: /*
                    754:  * Interrupt routine.
                    755:  */
                    756: int
                    757: fdintr(ctlr)
                    758:        int ctlr;
                    759: {
                    760:        int timedout;
                    761:        u_char results[7];
                    762:        struct buf *bp;
                    763:        struct bus_device *ui;
                    764:        struct fdsoftc *sc;
                    765:        struct buf *dp = &fdtab[ctlr];
                    766:        struct fdcsoftc *fdc = &fdcsoftc[ctlr];
                    767:        struct bus_ctlr *um = fdminfo[ctlr];
                    768: 
                    769:        if (!dp->b_active) {
                    770:                printf("fdc%d: stray interrupt\n", ctlr);
                    771:                return;
                    772:        }
                    773:        timedout = fdc->sc_wticks >= OP_TIMEOUT;
                    774:        fdc->sc_wticks = 0;
                    775:        bp = dp->b_actf->b_actf;
                    776:        ui = fddinfo[fdunit(bp->b_dev)];
                    777:        sc = &fdsoftc[ui->unit];
                    778: 
                    779:        /*
                    780:         * Operation timed out, terminate request.
                    781:         */
                    782:        if (timedout) {
                    783:                fderror("timed out", ui);
                    784:                fdmotoroff(ui);
                    785:                sc->sc_flags |= FDF_RECAL;
                    786:                bp->b_flags |= B_ERROR;
                    787:                bp->b_error = ENXIO;
                    788:                fddone(ui, bp);
                    789:                return;
                    790:        }
                    791:        /*
                    792:         * Read results from FDC.
                    793:         * For transfer completion they can be read immediately.
                    794:         * For anything else, we must issue a Sense Interrupt
                    795:         * Status Command.  We keep issuing this command till
                    796:         * FDC returns invalid command status.  The Controller Busy
                    797:         * bit in the status register indicates completion of a
                    798:         * read/write/format operation.
                    799:         */
                    800:        if (inb(FD_STATUS(um->address)) & ST_CB) {
                    801:                if (!fdresults(um, fdc->sc_results))
                    802:                        return;
                    803:        } else {
                    804:                while (1) {
                    805:                        fdc->sc_cmd[0] = CMD_SENSEI;
                    806:                        if (!fdcmd(um, 1)) {
                    807:                                DEBUGF(2, printf(2, "fd%d: SENSEI failed\n"));
                    808:                                return;
                    809:                        }
                    810:                        if (!fdresults(um, results))
                    811:                                return;
                    812:                        if ((results[0] & ST0_IC) == 0x80)
                    813:                                break;
                    814:                        if ((results[0] & ST0_US) == ui->slave) {
                    815:                                fdc->sc_results[0] = results[0];
                    816:                                fdc->sc_results[1] = results[1];
                    817:                        }
                    818:                }
                    819:        }
                    820:        /*
                    821:         * Let transfer state routine handle the rest.
                    822:         */
                    823:        fdstate(um);
                    824: }
                    825: 
                    826: /*
                    827:  * Transfer finite state machine driver.
                    828:  */
                    829: int
                    830: fdstate(um)
                    831:        struct bus_ctlr *um;
                    832: {
                    833:        int unit, max, pa, s;
                    834:        struct buf *bp;
                    835:        struct fdsoftc *sc;
                    836:        struct bus_device *ui;
                    837:        struct fddk *dk;
                    838:        struct fdcsoftc *fdc = &fdcsoftc[um->unit];
                    839: 
                    840:        bp = fdtab[um->unit].b_actf->b_actf;
                    841:        ui = fddinfo[fdunit(bp->b_dev)];
                    842:        sc = &fdsoftc[ui->unit];
                    843:        dk = sc->sc_dk;
                    844: 
                    845:        while (1) switch (fdc->sc_state) {
                    846: 
                    847:        case RESET:
                    848:                /*
                    849:                 * Reset the controller.
                    850:                 */
                    851:                fdreset(um);
                    852:                return;
                    853: 
                    854:        case RESETDONE:
                    855:                /*
                    856:                 * Reset complete.
                    857:                 * Mark all drives as needing recalibration
                    858:                 * and issue specify command.
                    859:                 */
                    860:                for (unit = 0; unit < NFD; unit++)
                    861:                        if (fddinfo[unit] && fddinfo[unit]->alive
                    862:                            && fddinfo[unit]->mi == um)
                    863:                                fdsoftc[unit].sc_flags |= FDF_RECAL;
                    864:                fdc->sc_cmd[0] = CMD_SPECIFY;
                    865:                fdc->sc_cmd[1] = SRTHUT;
                    866:                fdc->sc_cmd[2] = HLTND;
                    867:                if (!fdcmd(um, 3))
                    868:                        return;
                    869:                fdc->sc_flags &= ~FDF_RESET;
                    870:                fdc->sc_state = RECAL;
                    871:                break;
                    872: 
                    873:        case RECAL:
                    874:                /*
                    875:                 * Recalibrate drive.
                    876:                 */
                    877:                fdc->sc_state = RECALDONE;
                    878:                fdc->sc_cmd[0] = CMD_RECAL;
                    879:                fdc->sc_cmd[1] = ui->slave;
                    880:                fdcmd(um, 2);
                    881:                return;
                    882: 
                    883:        case RECALDONE:
                    884:                /*
                    885:                 * Recalibration complete.
                    886:                 */
                    887:                if ((fdc->sc_st0 & ST0_IC) || (fdc->sc_st0 & ST0_EC)) {
                    888:                        if (++fdc->sc_recalerr == 2) {
                    889:                                fderror("recalibrate failed", ui);
                    890:                                goto bad;
                    891:                        }
                    892:                        fdc->sc_state = RESET;
                    893:                        break;
                    894:                }
                    895:                sc->sc_flags &= ~FDF_RECAL;
                    896:                fdc->sc_recalerr = 0;
                    897:                sc->sc_cyl = -1;
                    898:                fdc->sc_state = SEEK;
                    899:                break;
                    900: 
                    901:        case SEEK:
                    902:                /*
                    903:                 * Perform seek operation.
                    904:                 */
                    905:                fdc->sc_state = SEEKDONE;
                    906:                fdc->sc_cmd[0] = CMD_SEEK;
                    907:                fdc->sc_cmd[1] = (fdc->sc_tn << 2) | ui->slave;
                    908:                fdc->sc_cmd[2] = fdc->sc_cn;
                    909:                if (dk->dk_step)
                    910:                        fdc->sc_cmd[2] <<= 1;
                    911:                fdcmd(um, 3);
                    912:                return;
                    913: 
                    914:        case SEEKDONE:
                    915:                /*
                    916:                 * Seek complete.
                    917:                 */
                    918:                if (dk->dk_step)
                    919:                        fdc->sc_pcn >>= 1;
                    920:                if ((fdc->sc_st0 & ST0_IC) || (fdc->sc_st0 & ST0_SE) == 0
                    921:                    || fdc->sc_pcn != fdc->sc_cn) {
                    922:                        if (++fdc->sc_seekerr == 2) {
                    923:                                fderror("seek failed", ui);
                    924:                                goto bad;
                    925:                        }
                    926:                        fdc->sc_state = RESET;
                    927:                        break;
                    928:                }
                    929:                fdc->sc_seekerr = 0;
                    930:                sc->sc_cyl = fdc->sc_pcn;
                    931:                fdc->sc_state = TRANSFER;
                    932:                break;
                    933: 
                    934:        case TRANSFER:
                    935:                /*
                    936:                 * Perform I/O transfer.
                    937:                 */
                    938:                fdc->sc_flags &= ~FDF_BOUNCE;
                    939:                pa = pmap_extract(kernel_pmap, fdc->sc_addr);
                    940:                if (fdc->sc_op == CMD_FORMAT) {
                    941:                        max = sizeof(struct format_info) * dk->dk_nspt;
                    942:                } else if (fdc->sc_flags & FDF_LIMIT) {
                    943:                        fdc->sc_flags &= ~FDF_LIMIT;
                    944:                        max = SECSIZE;
                    945:                } else {
                    946:                        max = (dk->dk_nspc - dk->dk_nspt * fdc->sc_tn
                    947:                               - fdc->sc_sn) * SECSIZE;
                    948:                }
                    949:                if (max > fdc->sc_resid)
                    950:                        max = fdc->sc_resid;
                    951:                if (pa >= 16*1024*1024) {
                    952:                        fdc->sc_flags |= FDF_BOUNCE;
                    953:                        pa = fdc->sc_buf;
                    954:                        if (max < DMABSIZE)
                    955:                                fdc->sc_amt = max;
                    956:                        else
                    957:                                fdc->sc_amt = DMABSIZE;
                    958:                } else {
                    959:                        int prevpa, curpa, omax;
                    960:                        vm_offset_t va;
                    961: 
                    962:                        omax = max;
                    963:                        if (max > 65536 - (pa & 0xffff))
                    964:                                max = 65536 - (pa & 0xffff);
                    965:                        fdc->sc_amt = I386_PGBYTES - (pa & (I386_PGBYTES - 1));
                    966:                        va = (vm_offset_t)fdc->sc_addr + fdc->sc_amt;
                    967:                        prevpa = pa & ~(I386_PGBYTES - 1);
                    968:                        while (fdc->sc_amt < max) {
                    969:                                curpa = pmap_extract(kernel_pmap, va);
                    970:                                if (curpa >= 16*1024*1024
                    971:                                    || curpa != prevpa + I386_PGBYTES)
                    972:                                        break;
                    973:                                fdc->sc_amt += I386_PGBYTES;
                    974:                                va += I386_PGBYTES;
                    975:                                prevpa = curpa;
                    976:                        }
                    977:                        if (fdc->sc_amt > max)
                    978:                                fdc->sc_amt = max;
                    979:                        if (fdc->sc_op == CMD_FORMAT) {
                    980:                                if (fdc->sc_amt != omax) {
                    981:                                        fdc->sc_flags |= FDF_BOUNCE;
                    982:                                        pa = fdc->sc_buf;
                    983:                                        fdc->sc_amt = omax;
                    984:                                }
                    985:                        } else if (fdc->sc_amt != fdc->sc_resid) {
                    986:                                if (fdc->sc_amt < SECSIZE) {
                    987:                                        fdc->sc_flags |= FDF_BOUNCE;
                    988:                                        pa = fdc->sc_buf;
                    989:                                        if (omax > DMABSIZE)
                    990:                                                fdc->sc_amt = DMABSIZE;
                    991:                                        else
                    992:                                                fdc->sc_amt = omax;
                    993:                                } else
                    994:                                        fdc->sc_amt &= ~(SECSIZE - 1);
                    995:                        }
                    996:                }
                    997: 
                    998:                DEBUGF(2, printf("fd%d: TRANSFER: amt %d cn %d tn %d sn %d\n",
                    999:                                 ui->unit, fdc->sc_amt, fdc->sc_cn,
                   1000:                                 fdc->sc_tn, fdc->sc_sn + 1));
                   1001: 
                   1002:                if ((fdc->sc_flags & FDF_BOUNCE) && fdc->sc_op != CMD_READ) {
                   1003:                        fdc->sc_flags &= ~FDF_BOUNCE;
                   1004:                        bcopy(fdc->sc_addr, (caddr_t)phystokv(fdc->sc_buf),
                   1005:                              fdc->sc_amt);
                   1006:                }
                   1007:                /*
                   1008:                 * Set up DMA.
                   1009:                 */
                   1010:                s = sploff();
                   1011:                outb(DMA_SINGLEMSK, 0x04 | 0x02);
                   1012:                outb(DMA_FLIPFLOP, 0);
                   1013:                outb(DMA_MODE, fdc->sc_mode);
                   1014:                outb(DMA2_ADDR, pa);
                   1015:                outb(DMA2_ADDR, pa >> 8);
                   1016:                outb(DMA2_PAGE, pa >> 16);
                   1017:                outb(DMA2_COUNT, fdc->sc_amt - 1);
                   1018:                outb(DMA2_COUNT, (fdc->sc_amt - 1) >> 8);
                   1019:                outb(DMA_SINGLEMSK, 0x02);
                   1020:                splon(s);
                   1021: 
                   1022:                /*
                   1023:                 * Issue command to FDC.
                   1024:                 */
                   1025:                fdc->sc_state = TRANSFERDONE;
                   1026:                fdc->sc_cmd[0] = fdc->sc_op;
                   1027:                fdc->sc_cmd[1] = (fdc->sc_tn << 2) | ui->slave;
                   1028:                if (fdc->sc_op == CMD_FORMAT) {
                   1029:                        fdc->sc_cmd[2] = 0x02;
                   1030:                        fdc->sc_cmd[3] = dk->dk_nspt;
                   1031:                        fdc->sc_cmd[4] = dk->dk_fgap;
                   1032:                        fdc->sc_cmd[5] = 0xda;
                   1033:                        fdcmd(um, 6);
                   1034:                } else {
                   1035:                        fdc->sc_cmd[2] = fdc->sc_cn;
                   1036:                        fdc->sc_cmd[3] = fdc->sc_tn;
                   1037:                        fdc->sc_cmd[4] = fdc->sc_sn + 1;
                   1038:                        fdc->sc_cmd[5] = 0x02;
                   1039:                        fdc->sc_cmd[6] = dk->dk_nspt;
                   1040:                        fdc->sc_cmd[7] = dk->dk_gap;
                   1041:                        fdc->sc_cmd[8] = 0xff;
                   1042:                        fdcmd(um, 9);
                   1043:                }
                   1044:                return;
                   1045: 
                   1046:        case TRANSFERDONE:
                   1047:                /*
                   1048:                 * Transfer complete.
                   1049:                 */
                   1050:                if (fdc->sc_st0 & ST0_IC) {
                   1051:                        fdc->sc_ioerr++;
                   1052:                        if (sc->sc_flags & FDF_AUTO) {
                   1053:                                /*
                   1054:                                 * Give up on second try if
                   1055:                                 * media detection is in progress.
                   1056:                                 */
                   1057:                                if (fdc->sc_ioerr == 2)
                   1058:                                        goto bad;
                   1059:                                fdc->sc_state = RECAL;
                   1060:                                break;
                   1061:                        }
                   1062:                        if (fdc->sc_ioerr == MAX_RETRIES) {
                   1063:                                fderror(fderrmsg(ui), ui);
                   1064:                                goto bad;
                   1065:                        }
                   1066:                        /*
                   1067:                         * Give up immediately on write-protected diskettes.
                   1068:                         */
                   1069:                        if (fdc->sc_st1 & ST1_NW) {
                   1070:                                fderror("write-protected diskette", ui);
                   1071:                                goto bad;
                   1072:                        }
                   1073:                        /*
                   1074:                         * Limit transfer to a single sector.
                   1075:                         */
                   1076:                        fdc->sc_flags |= FDF_LIMIT;
                   1077:                        /*
                   1078:                         * Every fourth attempt recalibrate the drive.
                   1079:                         * Every eight attempt reset the controller.
                   1080:                         * Also, every eighth attempt inform user
                   1081:                         * about the error.
                   1082:                         */
                   1083:                        if (fdc->sc_ioerr & 3)
                   1084:                                fdc->sc_state = TRANSFER;
                   1085:                        else if (fdc->sc_ioerr & 7)
                   1086:                                fdc->sc_state = RECAL;
                   1087:                        else {
                   1088:                                fdc->sc_state = RESET;
                   1089:                                fderror(fderrmsg(ui), ui);
                   1090:                        }
                   1091:                        break;
                   1092:                }
                   1093:                /*
                   1094:                 * Transfer completed successfully.
                   1095:                 * Advance counters/pointers, and if more
                   1096:                 * is left, initiate I/O.
                   1097:                 */
                   1098:                if (fdc->sc_flags & FDF_BOUNCE) {
                   1099:                        fdc->sc_flags &= ~FDF_BOUNCE;
                   1100:                        bcopy((caddr_t)phystokv(fdc->sc_buf), fdc->sc_addr,
                   1101:                              fdc->sc_amt);
                   1102:                }
                   1103:                if ((fdc->sc_resid -= fdc->sc_amt) == 0) {
                   1104:                        bp->b_resid = 0;
                   1105:                        fddone(ui, bp);
                   1106:                        return;
                   1107:                }
                   1108:                fdc->sc_state = TRANSFER;
                   1109:                fdc->sc_ioerr = 0;
                   1110:                fdc->sc_addr += fdc->sc_amt;
                   1111:                if (fdc->sc_op == CMD_FORMAT) {
                   1112:                        fdc->sc_sn = 0;
                   1113:                        if (fdc->sc_tn == 1) {
                   1114:                                fdc->sc_tn = 0;
                   1115:                                fdc->sc_cn++;
                   1116:                                fdc->sc_state = SEEK;
                   1117:                        } else
                   1118:                                fdc->sc_tn = 1;
                   1119:                } else {
                   1120:                        fdc->sc_sn += fdc->sc_amt / SECSIZE;
                   1121:                        while (fdc->sc_sn >= dk->dk_nspt) {
                   1122:                                fdc->sc_sn -= dk->dk_nspt;
                   1123:                                if (fdc->sc_tn == 1) {
                   1124:                                        fdc->sc_tn = 0;
                   1125:                                        fdc->sc_cn++;
                   1126:                                        fdc->sc_state = SEEK;
                   1127:                                } else
                   1128:                                        fdc->sc_tn = 1;
                   1129:                        }
                   1130:                }
                   1131:                break;
                   1132: 
                   1133:        default:
                   1134:                printf("fd%d: invalid state\n", ui->unit);
                   1135:                panic("fdstate");
                   1136:                /*NOTREACHED*/
                   1137:        }
                   1138:  bad:
                   1139:        bp->b_flags |= B_ERROR;
                   1140:        bp->b_error = EIO;
                   1141:        sc->sc_flags |= FDF_RECAL;
                   1142:        fddone(ui, bp);
                   1143: }
                   1144: 
                   1145: /*
                   1146:  * Terminate current request and start
                   1147:  * any others that are queued.
                   1148:  */
                   1149: int
                   1150: fddone(ui, bp)
                   1151:        struct bus_device *ui;
                   1152:        struct buf *bp;
                   1153: {
                   1154:        struct bus_ctlr *um = ui->mi;
                   1155:        struct fdsoftc *sc = &fdsoftc[ui->unit];
                   1156:        struct fdcsoftc *fdc = &fdcsoftc[um->unit];
                   1157:        struct buf *dp = &fdtab[um->unit];
                   1158: 
                   1159:        DEBUGF(1, printf("fd%d: fddone()\n", ui->unit));
                   1160: 
                   1161:        /*
                   1162:         * Remove this request from queue.
                   1163:         */
                   1164:        if (bp) {
                   1165:                fdutab[ui->unit].b_actf = bp->b_actf;
                   1166:                biodone(bp);
                   1167:                bp = &fdutab[ui->unit];
                   1168:                dp->b_actf = bp->b_forw;
                   1169:        } else
                   1170:                bp = &fdutab[ui->unit];
                   1171: 
                   1172:        /*
                   1173:         * Mark controller and drive idle.
                   1174:         */
                   1175:        dp->b_active = 0;
                   1176:        bp->b_active = 0;
                   1177:        fdc->sc_state = IDLE;
                   1178:        sc->sc_mticks = 0;
                   1179:        fdc->sc_flags &= ~(FDF_LIMIT|FDF_BOUNCE);
                   1180: 
                   1181:        /*
                   1182:         * Start up other requests.
                   1183:         */
                   1184:        fdustart(ui);
                   1185:        fdstart(um);
                   1186: 
                   1187:        /*
                   1188:         * Wakeup anyone waiting for drive or controller.
                   1189:         */
                   1190:        if (sc->sc_flags & FDF_WANT) {
                   1191:                sc->sc_flags &= ~FDF_WANT;
                   1192:                wakeup((void *)sc);
                   1193:        }
                   1194:        if (fdc->sc_flags & FDF_WANT) {
                   1195:                fdc->sc_flags &= ~FDF_WANT;
                   1196:                wakeup((void *)fdc);
                   1197:        }
                   1198: }
                   1199: 
                   1200: /*
                   1201:  * Check if diskette change has occured since the last open.
                   1202:  */
                   1203: int
                   1204: fddskchg(ui)
                   1205:        struct bus_device *ui;
                   1206: {
                   1207:        int s, dir;
                   1208:        struct fdsoftc *sc = &fdsoftc[ui->unit];
                   1209:        struct bus_ctlr *um = ui->mi;
                   1210:        struct fdcsoftc *fdc = &fdcsoftc[um->unit];
                   1211: 
                   1212:        /*
                   1213:         * Get access to controller.
                   1214:         */
                   1215:        s = splbio();   
                   1216:        while (fdtab[um->unit].b_active) {
                   1217:                fdc->sc_flags |= FDF_WANT;
                   1218:                assert_wait((event_t)fdc, FALSE);
                   1219:                thread_block((void (*)())0);
                   1220:        }
                   1221:        fdtab[um->unit].b_active = 1;
                   1222:        fdutab[ui->unit].b_active = 1;
                   1223: 
                   1224:        /*
                   1225:         * Turn on drive motor and read digital input register.
                   1226:         */
                   1227:        if (fdmotoron(ui)) {
                   1228:                timeout(wakeup, (void *)fdc, hz / 2);
                   1229:                assert_wait((event_t)fdc, FALSE);
                   1230:                thread_block((void (*)())0);
                   1231:        }
                   1232:        dir = inb(FD_DIR(um->address));
                   1233:        fddone(ui, NULL);
                   1234:        splx(s);
                   1235: 
                   1236:        if (dir & DIR_DSKCHG) {
                   1237:                printf("fd%d: diskette change detected\n", ui->unit);
                   1238:                sc->sc_flags |= FDF_SEEK;
                   1239:                return (1);
                   1240:        }
                   1241:        return (0);
                   1242: }
                   1243: 
                   1244: /*
                   1245:  * Do media detection.
                   1246:  */
                   1247: int
                   1248: fdauto(dev)
                   1249:        dev_t dev;
                   1250: {
                   1251:        int i, error = 0;
                   1252:        struct buf *bp;
                   1253:        struct bus_device *ui = fddinfo[fdunit(dev)];
                   1254:        struct fdsoftc *sc = &fdsoftc[ui->unit];
                   1255:        struct fddk *dk, *def = 0;
                   1256: 
                   1257:        sc->sc_flags |= FDF_AUTO;
                   1258:        bp = (struct buf *)geteblk(SECSIZE);
                   1259:        for (i = 0, dk = fddk; i < NDKTYPES; i++, dk++) {
                   1260:                if ((dk->dk_drives & (1 << sc->sc_type)) == 0)
                   1261:                        continue;
                   1262:                if (def == 0)
                   1263:                        def = dk;
                   1264:                sc->sc_dk = dk;
                   1265:                bp->b_flags = B_READ;
                   1266:                bp->b_dev = dev;
                   1267:                bp->b_bcount = SECSIZE;
                   1268:                if (sc->sc_flags & FDF_SEEK) {
                   1269:                        sc->sc_flags &= ~FDF_SEEK;
                   1270:                        bp->b_blkno = 100;
                   1271:                } else
                   1272:                        bp->b_blkno = 0;
                   1273:                fdstrategy(bp);
                   1274:                biowait(bp);
                   1275:                if ((bp->b_flags & B_ERROR) == 0 || bp->b_error == ENXIO)
                   1276:                        break;
                   1277:        }
                   1278:        if (i == NDKTYPES) {
                   1279:                printf("fd%d: couldn't detect type, using %s\n",
                   1280:                       ui->unit, def->dk_name);
                   1281:                sc->sc_dk = def;
                   1282:        } else if ((bp->b_flags & B_ERROR) == 0)
                   1283:                printf("fd%d: detected %s\n", ui->unit, sc->sc_dk->dk_name);
                   1284:        else
                   1285:                error = ENXIO;
                   1286:        sc->sc_flags &= ~FDF_AUTO;
                   1287:        brelse(bp);
                   1288:        return (error);
                   1289: }
                   1290: 
                   1291: /*
                   1292:  * Turn on drive motor and select drive.
                   1293:  */
                   1294: int
                   1295: fdmotoron(ui)
                   1296:        struct bus_device *ui;
                   1297: {
                   1298:        int bit;
                   1299:        struct bus_ctlr *um = ui->mi;
                   1300:        struct fdcsoftc *fdc = &fdcsoftc[um->unit];
                   1301: 
                   1302:        bit = 1 << (ui->slave + 4);
                   1303:        if ((fdc->sc_dor & bit) == 0) {
                   1304:                fdc->sc_dor &= ~3;
                   1305:                fdc->sc_dor |= bit | ui->slave;
                   1306:                outb(FD_DOR(um->address), fdc->sc_dor);
                   1307:                return (1);
                   1308:        }
                   1309:        if ((fdc->sc_dor & 3) != ui->slave) {
                   1310:                fdc->sc_dor &= ~3;
                   1311:                fdc->sc_dor |= ui->slave;
                   1312:                outb(FD_DOR(um->address), fdc->sc_dor);
                   1313:        }
                   1314:        return (0);
                   1315: }
                   1316: 
                   1317: /*
                   1318:  * Turn off drive motor.
                   1319:  */
                   1320: int
                   1321: fdmotoroff(ui)
                   1322:        struct bus_device *ui;
                   1323: {
                   1324:        struct bus_ctlr *um = ui->mi;
                   1325:        struct fdcsoftc *fdc = &fdcsoftc[um->unit];
                   1326: 
                   1327:        fdc->sc_dor &= ~(1 << (ui->slave + 4));
                   1328:        outb(FD_DOR(um->address), fdc->sc_dor);
                   1329: }
                   1330: 
                   1331: /*
                   1332:  * This routine is invoked via timeout() by fdstart()
                   1333:  * to call fdstate() at splbio.
                   1334:  */
                   1335: void
                   1336: fdspinup(um)
                   1337:        struct bus_ctlr *um;
                   1338: {
                   1339:        int s;
                   1340: 
                   1341:        s = splbio();
                   1342:        fdstate(um);
                   1343:        splx(s);
                   1344: }
                   1345: 
                   1346: /*
                   1347:  * Watchdog routine.
                   1348:  * Check for hung operations.
                   1349:  * Turn off motor of idle drives.
                   1350:  */
                   1351: void
                   1352: fdwatch()
                   1353: {
                   1354:        int unit, s;
                   1355:        struct bus_device *ui;
                   1356: 
                   1357:        timeout(fdwatch, 0, hz);
                   1358:        s = splbio();
                   1359:        for (unit = 0; unit < NFDC; unit++)
                   1360:                if (fdtab[unit].b_active
                   1361:                    && ++fdcsoftc[unit].sc_wticks == OP_TIMEOUT)
                   1362:                        fdintr(unit);
                   1363:        for (unit = 0; unit < NFD; unit++) {
                   1364:                if ((ui = fddinfo[unit]) == 0 || ui->alive == 0)
                   1365:                        continue;
                   1366:                if (fdutab[unit].b_active == 0
                   1367:                    && (fdcsoftc[ui->mi->unit].sc_dor & (1 << (ui->slave + 4)))
                   1368:                    && ++fdsoftc[unit].sc_mticks == MOTOR_TIMEOUT)
                   1369:                        fdmotoroff(ui);
                   1370:        }
                   1371:        splx(s);
                   1372: }
                   1373: 
                   1374: /*
                   1375:  * Print an error message.
                   1376:  */
                   1377: int
                   1378: fderror(msg, ui)
                   1379:        char *msg;
                   1380:        struct bus_device *ui;
                   1381: {
                   1382:        struct fdcsoftc *fdc = &fdcsoftc[ui->mi->unit];
                   1383: 
                   1384:        printf("fd%d: %s, %sing cn %d tn %d sn %d\n", ui->unit, msg,
                   1385:               (fdc->sc_op == CMD_READ ? "read"
                   1386:                : (fdc->sc_op == CMD_WRITE ? "writ" : "formatt")),
                   1387:               fdc->sc_cn, fdc->sc_tn, fdc->sc_sn + 1);
                   1388: }
                   1389: 
                   1390: /*
                   1391:  * Return an error message for an I/O error.
                   1392:  */
                   1393: char *
                   1394: fderrmsg(ui)
                   1395:        struct bus_device *ui;
                   1396: {
                   1397:        struct fdcsoftc *fdc = &fdcsoftc[ui->mi->unit];
                   1398: 
                   1399:        if (fdc->sc_st1 & ST1_EC)
                   1400:                return ("invalid sector");
                   1401:        if (fdc->sc_st1 & ST1_DE)
                   1402:                return ("CRC error");
                   1403:        if (fdc->sc_st1 & ST1_OR)
                   1404:                return ("DMA overrun");
                   1405:        if (fdc->sc_st1 & ST1_ND)
                   1406:                return ("sector not found");
                   1407:        if (fdc->sc_st1 & ST1_NW)
                   1408:                return ("write-protected diskette");
                   1409:        if (fdc->sc_st1 & ST1_MA)
                   1410:                return ("missing address mark");
                   1411:        return ("hard error");
                   1412: }
                   1413: 
                   1414: /*
                   1415:  * Output a command to FDC.
                   1416:  */
                   1417: int
                   1418: fdcmd(um, n)
                   1419:        struct bus_ctlr *um;
                   1420:        int n;
                   1421: {
                   1422:        int i, j;
                   1423:        struct fdcsoftc *fdc = &fdcsoftc[um->unit];
                   1424: 
                   1425:        for (i = j = 0; i < 200; i++) {
                   1426:                if ((inb(FD_STATUS(um->address)) & (ST_RQM|ST_DIO)) != ST_RQM)
                   1427:                        continue;
                   1428:                outb(FD_DATA(um->address), fdc->sc_cmd[j++]);
                   1429:                if (--n == 0)
                   1430:                        return (1);
                   1431:        }
                   1432:        /*
                   1433:         * Controller is not responding, reset it.
                   1434:         */
                   1435:        DEBUGF(1, printf("fdc%d: fdcmd() failed\n", um->unit));
                   1436:        fdreset(um);
                   1437:        return (0);
                   1438: }
                   1439: 
                   1440: /*
                   1441:  * Read results from FDC.
                   1442:  */
                   1443: int
                   1444: fdresults(um, rp)
                   1445:        struct bus_ctlr *um;
                   1446:        u_char *rp;
                   1447: {
                   1448:        int i, j, status;
                   1449: 
                   1450:        for (i = j = 0; i < 200; i++) {
                   1451:                status = inb(FD_STATUS(um->address));
                   1452:                if ((status & ST_RQM) == 0)
                   1453:                        continue;
                   1454:                if ((status & ST_DIO) == 0)
                   1455:                        return (j);
                   1456:                if (j == 7)
                   1457:                        break;
                   1458:                *rp++ = inb(FD_DATA(um->address));
                   1459:                j++;
                   1460:        }
                   1461:        /*
                   1462:         * Controller is not responding, reset it.
                   1463:         */
                   1464:        DEBUGF(1, printf("fdc%d: fdresults() failed\n", um->unit));
                   1465:        fdreset(um);
                   1466:        return (0);
                   1467: }
                   1468: 
                   1469: /*
                   1470:  * Reset controller.
                   1471:  */
                   1472: int
                   1473: fdreset(um)
                   1474:        struct bus_ctlr *um;
                   1475: {
                   1476:        struct fdcsoftc *fdc = &fdcsoftc[um->unit];
                   1477: 
                   1478:        outb(FD_DOR(um->address), fdc->sc_dor & ~(DOR_RSTCLR|DOR_IENABLE));
                   1479:        fdc->sc_state = RESETDONE;
                   1480:        fdc->sc_flags |= FDF_RESET;
                   1481:        outb(FD_DOR(um->address), fdc->sc_dor);
                   1482: }
                   1483: 
                   1484: #endif /* NFD > 0 */

unix.superglobalmegacorp.com

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