[BACK]Return to fd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / atari / dev

Annotation of src/sys/arch/atari/dev/fd.c, Revision 1.46.2.5

1.46.2.5! skrll       1: /*     $NetBSD: fd.c,v 1.46.2.4 2004/11/02 07:50:22 skrll Exp $        */
1.1       leo         2:
                      3: /*
                      4:  * Copyright (c) 1995 Leo Weppelman.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  * 3. All advertising materials mentioning features or use of this software
                     16:  *    must display the following acknowledgement:
                     17:  *      This product includes software developed by Leo Weppelman.
                     18:  * 4. The name of the author may not be used to endorse or promote products
                     19:  *    derived from this software without specific prior written permission
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     22:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     23:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     24:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     25:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     26:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     28:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     29:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     30:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     31:  */
                     32:
                     33: /*
                     34:  * This file contains a driver for the Floppy Disk Controller (FDC)
                     35:  * on the Atari TT. It uses the WD 1772 chip, modified for steprates.
                     36:  *
                     37:  * The ST floppy disk controller shares the access to the DMA circuitry
                     38:  * with other devices. For this reason the floppy disk controller makes
                     39:  * use of some special DMA accessing code.
                     40:  *
                     41:  * Interrupts from the FDC are in fact DMA interrupts which get their
                     42:  * first level handling in 'dma.c' . If the floppy driver is currently
                     43:  * using DMA the interrupt is signalled to 'fdcint'.
                     44:  *
                     45:  * TODO:
                     46:  *   - Test it with 2 drives (I don't have them)
                     47:  *   - Test it with an HD-drive (Don't have that either)
                     48:  *   - Finish ioctl's
                     49:  */
                     50:
1.46.2.1  skrll      51: #include <sys/cdefs.h>
1.46.2.5! skrll      52: __KERNEL_RCSID(0, "$NetBSD: fd.c,v 1.46.2.4 2004/11/02 07:50:22 skrll Exp $");
1.46.2.1  skrll      53:
1.14      mycroft    54: #include <sys/param.h>
                     55: #include <sys/systm.h>
1.35      thorpej    56: #include <sys/callout.h>
1.14      mycroft    57: #include <sys/kernel.h>
                     58: #include <sys/malloc.h>
                     59: #include <sys/buf.h>
1.46.2.4  skrll      60: #include <sys/bufq.h>
1.15      leo        61: #include <sys/proc.h>
1.14      mycroft    62: #include <sys/device.h>
                     63: #include <sys/ioctl.h>
                     64: #include <sys/fcntl.h>
                     65: #include <sys/conf.h>
                     66: #include <sys/disklabel.h>
                     67: #include <sys/disk.h>
                     68: #include <sys/dkbad.h>
                     69: #include <atari/atari/device.h>
1.19      leo        70: #include <atari/atari/stalloc.h>
1.14      mycroft    71: #include <machine/disklabel.h>
                     72: #include <machine/iomap.h>
                     73: #include <machine/mfp.h>
                     74: #include <machine/dma.h>
                     75: #include <machine/video.h>
1.20      leo        76: #include <machine/cpu.h>
1.18      leo        77: #include <atari/dev/ym2149reg.h>
1.14      mycroft    78: #include <atari/dev/fdreg.h>
1.1       leo        79:
                     80: /*
                     81:  * Be verbose for debugging
                     82:  */
1.4       leo        83: /*#define FLP_DEBUG    1 */
1.1       leo        84:
                     85: #define        FDC_MAX_DMA_AD  0x1000000       /* No DMA possible beyond       */
                     86:
                     87: /* Parameters for the disk drive. */
                     88: #define SECTOR_SIZE    512     /* physical sector size in bytes        */
                     89: #define NR_DRIVES      2       /* maximum number of drives             */
                     90: #define NR_TYPES       3       /* number of diskette/drive combinations*/
                     91: #define MAX_ERRORS     10      /* how often to try rd/wt before quitting*/
                     92: #define STEP_DELAY     6000    /* 6ms (6000us) delay after stepping    */
                     93:
                     94:
                     95: #define        INV_TRK         32000   /* Should fit in unsigned short         */
                     96: #define        INV_PART        NR_TYPES
                     97:
                     98: /*
                     99:  * Driver states
                    100:  */
                    101: #define        FLP_IDLE        0x00    /* floppy is idle                       */
                    102: #define        FLP_MON         0x01    /* idle with motor on                   */
                    103: #define        FLP_STAT        0x02    /* determine floppy status              */
                    104: #define        FLP_XFER        0x04    /* read/write data from floppy          */
                    105:
                    106: /*
                    107:  * Timer delay's
                    108:  */
                    109: #define        FLP_MONDELAY    (3 * hz)        /* motor-on delay               */
                    110: #define        FLP_XFERDELAY   (2 * hz)        /* timeout on transfer          */
                    111:
1.8       leo       112: /*
                    113:  * The density codes
                    114:  */
                    115: #define        FLP_DD          0               /* Double density               */
                    116: #define        FLP_HD          1               /* High density                 */
                    117:
1.1       leo       118:
                    119: #define        b_block         b_resid         /* FIXME: this is not the place */
                    120:
                    121: /*
                    122:  * Global data for all physical floppy devices
                    123:  */
                    124: static short   selected = 0;           /* drive/head currently selected*/
                    125: static short   motoron  = 0;           /* motor is spinning            */
                    126: static short   nopens   = 0;           /* Number of opens executed     */
                    127:
1.4       leo       128: static short   fd_state = FLP_IDLE;    /* Current driver state         */
1.46      wiz       129: static int     lock_stat= 0;           /* DMA locking status           */
1.1       leo       130: static short   fd_cmd   = 0;           /* command being executed       */
                    131: static char    *fd_error= NULL;        /* error from fd_xfer_ok()      */
                    132:
                    133: /*
                    134:  * Private per device data
                    135:  */
                    136: struct fd_softc {
1.13      thorpej   137:        struct device   sc_dv;          /* generic device info          */
                    138:        struct disk     dkdev;          /* generic disk info            */
1.38      hannken   139:        struct bufq_state bufq;         /* queue of buf's               */
1.35      thorpej   140:        struct callout  sc_motor_ch;
1.1       leo       141:        int             unit;           /* unit for atari controlling hw*/
                    142:        int             nheads;         /* number of heads in use       */
                    143:        int             nsectors;       /* number of sectors/track      */
1.8       leo       144:        int             density;        /* density code                 */
1.1       leo       145:        int             nblocks;        /* number of blocks on disk     */
                    146:        int             curtrk;         /* track head positioned on     */
                    147:        short           flags;          /* misc flags                   */
                    148:        short           part;           /* Current open partition       */
                    149:        int             sector;         /* logical sector for I/O       */
                    150:        caddr_t         io_data;        /* KVA for data transfer        */
                    151:        int             io_bytes;       /* bytes left for I/O           */
                    152:        int             io_dir;         /* B_READ/B_WRITE               */
                    153:        int             errcnt;         /* current error count          */
                    154:        u_char          *bounceb;       /* Bounce buffer                */
1.10      mycroft   155:
1.1       leo       156: };
                    157:
                    158: /*
                    159:  * Flags in fd_softc:
                    160:  */
1.4       leo       161: #define FLPF_NOTRESP   0x001           /* Unit not responding          */
                    162: #define FLPF_ISOPEN    0x002           /* Unit is open                 */
1.8       leo       163: #define FLPF_SPARE     0x004           /* Not used                     */
1.4       leo       164: #define FLPF_HAVELAB   0x008           /* We have a valid label        */
                    165: #define FLPF_BOUNCE    0x010           /* Now using the bounce buffer  */
                    166: #define FLPF_WRTPROT   0x020           /* Unit is write-protected      */
                    167: #define FLPF_EMPTY     0x040           /* Unit is empty                */
                    168: #define FLPF_INOPEN    0x080           /* Currently being opened       */
                    169: #define FLPF_GETSTAT   0x100           /* Getting unit status          */
1.1       leo       170:
                    171: struct fd_types {
                    172:        int             nheads;         /* Heads in use                 */
                    173:        int             nsectors;       /* sectors per track            */
                    174:        int             nblocks;        /* number of blocks             */
1.8       leo       175:        int             density;        /* density code                 */
1.24      leo       176:        const char      *descr;         /* type description             */
1.1       leo       177: } fdtypes[NR_TYPES] = {
1.24      leo       178:                { 1,  9,  720 , FLP_DD , "360KB" },     /* 360  Kb      */
                    179:                { 2,  9, 1440 , FLP_DD , "720KB" },     /* 720  Kb      */
                    180:                { 2, 18, 2880 , FLP_HD , "1.44MB" },    /* 1.44 Mb      */
1.1       leo       181: };
                    182:
1.30      leo       183: #define        FLP_TYPE_360    0               /* XXX: Please keep these in    */
                    184: #define        FLP_TYPE_720    1               /* sync with the numbering in   */
                    185: #define        FLP_TYPE_144    2               /* 'fdtypes' right above!       */
                    186:
                    187: /*
                    188:  * This is set only once at attach time. The value is determined by reading
                    189:  * the configuration switches and is one of the FLP_TYPE_*'s.
                    190:  * This is simular to the way Atari handles the _FLP cookie.
                    191:  */
                    192: static short   def_type = 0;           /* Reflects config-switches     */
                    193:
1.24      leo       194: #define        FLP_DEFTYPE     1               /* 720Kb, reasonable default    */
1.30      leo       195: #define        FLP_TYPE(dev)   ( DISKPART(dev) == 0 ? def_type : DISKPART(dev) - 1 )
1.24      leo       196:
1.17      leo       197: typedef void   (*FPV) __P((void *));
1.1       leo       198:
1.24      leo       199: dev_type_open(fdopen);
1.15      leo       200: dev_type_close(fdclose);
                    201: dev_type_read(fdread);
                    202: dev_type_write(fdwrite);
                    203: dev_type_ioctl(fdioctl);
1.39      gehenna   204: dev_type_strategy(fdstrategy);
1.15      leo       205:
                    206: /*
1.1       leo       207:  * Private drive functions....
                    208:  */
                    209: static void    fdstart __P((struct fd_softc *));
                    210: static void    fddone __P((struct fd_softc *));
1.4       leo       211: static void    fdstatus __P((struct fd_softc *));
1.1       leo       212: static void    fd_xfer __P((struct fd_softc *));
1.4       leo       213: static void    fdcint __P((struct fd_softc *));
1.1       leo       214: static int     fd_xfer_ok __P((struct fd_softc *));
                    215: static void    fdmotoroff __P((struct fd_softc *));
1.10      mycroft   216: static void    fdminphys __P((struct buf *));
1.1       leo       217: static void    fdtestdrv __P((struct fd_softc *));
1.26      thorpej   218: static void    fdgetdefaultlabel __P((struct fd_softc *, struct disklabel *,
                    219:                    int));
1.1       leo       220: static int     fdgetdisklabel __P((struct fd_softc *, dev_t));
1.8       leo       221: static int     fdselect __P((int, int, int));
                    222: static void    fddeselect __P((void));
1.12      leo       223: static void    fdmoff __P((struct fd_softc *));
1.17      leo       224:        u_char  read_fdreg __P((u_short));
                    225:        void    write_fdreg __P((u_short, u_short));
                    226:        u_char  read_dmastat __P((void));
1.1       leo       227:
1.4       leo       228: extern __inline__ u_char read_fdreg(u_short regno)
                    229: {
                    230:        DMA->dma_mode = regno;
                    231:        return(DMA->dma_data);
                    232: }
                    233:
                    234: extern __inline__ void write_fdreg(u_short regno, u_short val)
                    235: {
                    236:        DMA->dma_mode = regno;
                    237:        DMA->dma_data = val;
                    238: }
                    239:
                    240: extern __inline__ u_char read_dmastat(void)
                    241: {
                    242:        DMA->dma_mode = FDC_CS | DMA_SCREG;
                    243:        return(DMA->dma_stat);
                    244: }
                    245:
1.1       leo       246: /*
1.30      leo       247:  * Config switch stuff. Used only for the floppy type for now. That's
                    248:  * why it's here...
                    249:  * XXX: If needed in more places, it should be moved to it's own include file.
                    250:  * Note: This location _must_ be read as an u_short. Failure to do so
                    251:  *       will return garbage!
                    252:  */
                    253: static u_short rd_cfg_switch __P((void));
                    254: static u_short rd_cfg_switch(void)
                    255: {
                    256:        return(*((u_short*)AD_CFG_SWITCH));
                    257: }
                    258:
                    259: /*
                    260:  * Switch definitions.
                    261:  * Note: ON reads as a zero bit!
                    262:  */
                    263: #define        CFG_SWITCH_NOHD 0x4000
                    264:
                    265: /*
1.1       leo       266:  * Autoconfig stuff....
                    267:  */
1.28      leo       268: extern struct cfdriver fd_cd;
                    269:
1.25      leo       270: static int     fdcmatch __P((struct device *, struct cfdata *, void *));
1.21      cgd       271: static int     fdcprint __P((void *, const char *));
1.1       leo       272: static void    fdcattach __P((struct device *, struct device *, void *));
                    273:
1.42      thorpej   274: CFATTACH_DECL(fdc, sizeof(struct device),
                    275:     fdcmatch, fdcattach, NULL, NULL);
1.16      thorpej   276:
1.39      gehenna   277: const struct bdevsw fd_bdevsw = {
                    278:        fdopen, fdclose, fdstrategy, fdioctl, nodump, nosize, D_DISK
                    279: };
                    280:
                    281: const struct cdevsw fd_cdevsw = {
                    282:        fdopen, fdclose, fdread, fdwrite, fdioctl,
1.43      jdolecek  283:        nostop, notty, nopoll, nommap, nokqfilter, D_DISK
1.39      gehenna   284: };
                    285:
1.1       leo       286: static int
1.25      leo       287: fdcmatch(pdp, cfp, auxp)
1.1       leo       288: struct device  *pdp;
1.25      leo       289: struct cfdata  *cfp;
                    290: void           *auxp;
1.1       leo       291: {
1.36      leo       292:        static int      fdc_matched = 0;
                    293:
                    294:        /* Match only once */
                    295:        if(strcmp("fdc", auxp) || fdc_matched)
1.1       leo       296:                return(0);
1.36      leo       297:        fdc_matched = 1;
1.1       leo       298:        return(1);
                    299: }
                    300:
                    301: static void
                    302: fdcattach(pdp, dp, auxp)
                    303: struct device  *pdp, *dp;
                    304: void           *auxp;
                    305: {
                    306:        struct fd_softc fdsoftc;
1.15      leo       307:        int             i, nfound, first_found;
1.1       leo       308:
1.15      leo       309:        nfound = first_found = 0;
1.23      christos  310:        printf("\n");
1.8       leo       311:        fddeselect();
1.1       leo       312:        for(i = 0; i < NR_DRIVES; i++) {
                    313:
                    314:                /*
                    315:                 * Test if unit is present
                    316:                 */
                    317:                fdsoftc.unit  = i;
                    318:                fdsoftc.flags = 0;
1.15      leo       319:                st_dmagrab((dma_farg)fdcint, (dma_farg)fdtestdrv, &fdsoftc,
                    320:                                                                &lock_stat, 0);
1.5       leo       321:                st_dmafree(&fdsoftc, &lock_stat);
1.1       leo       322:
                    323:                if(!(fdsoftc.flags & FLPF_NOTRESP)) {
1.12      leo       324:                        if(!nfound)
                    325:                                first_found = i;
1.1       leo       326:                        nfound++;
                    327:                        config_found(dp, (void*)i, fdcprint);
                    328:                }
                    329:        }
                    330:
                    331:        if(nfound) {
1.35      thorpej   332:                struct fd_softc *fdsc = getsoftc(fd_cd, first_found);
1.12      leo       333:
                    334:                /*
                    335:                 * Make sure motor will be turned of when a floppy is
                    336:                 * inserted in the first selected drive.
                    337:                 */
                    338:                fdselect(first_found, 0, FLP_DD);
                    339:                fd_state = FLP_MON;
1.35      thorpej   340:                callout_reset(&fdsc->sc_motor_ch, 0, (FPV)fdmotoroff, fdsc);
1.12      leo       341:
1.1       leo       342:                /*
                    343:                 * enable disk related interrupts
                    344:                 */
1.29      leo       345:                MFP->mf_ierb |= IB_DINT;
                    346:                MFP->mf_iprb  = (u_int8_t)~IB_DINT;
                    347:                MFP->mf_imrb |= IB_DINT;
1.1       leo       348:        }
                    349: }
                    350:
                    351: static int
                    352: fdcprint(auxp, pnp)
                    353: void   *auxp;
1.21      cgd       354: const char     *pnp;
1.1       leo       355: {
1.24      leo       356:        if (pnp != NULL)
1.45      thorpej   357:                aprint_normal("fd%d at %s:", (int)auxp, pnp);
1.24      leo       358:
1.1       leo       359:        return(UNCONF);
                    360: }
                    361:
1.25      leo       362: static int     fdmatch __P((struct device *, struct cfdata *, void *));
1.1       leo       363: static void    fdattach __P((struct device *, struct device *, void *));
1.24      leo       364:
1.1       leo       365: struct dkdriver fddkdriver = { fdstrategy };
                    366:
1.42      thorpej   367: CFATTACH_DECL(fd, sizeof(struct fd_softc),
                    368:     fdmatch, fdattach, NULL, NULL);
1.16      thorpej   369:
1.27      thorpej   370: extern struct cfdriver fd_cd;
1.1       leo       371:
                    372: static int
1.25      leo       373: fdmatch(pdp, cfp, auxp)
1.1       leo       374: struct device  *pdp;
1.25      leo       375: struct cfdata  *cfp;
                    376: void           *auxp;
1.1       leo       377: {
                    378:        return(1);
                    379: }
                    380:
                    381: static void
                    382: fdattach(pdp, dp, auxp)
                    383: struct device  *pdp, *dp;
                    384: void           *auxp;
                    385: {
                    386:        struct fd_softc *sc;
1.30      leo       387:        struct fd_types *type;
                    388:        u_short         swtch;
1.1       leo       389:
                    390:        sc = (struct fd_softc *)dp;
1.30      leo       391:
1.35      thorpej   392:        callout_init(&sc->sc_motor_ch);
                    393:
1.30      leo       394:        /*
                    395:         * Find out if an Ajax chip might be installed. Set the default
                    396:         * floppy type accordingly.
                    397:         */
                    398:        swtch    = rd_cfg_switch();
                    399:        def_type = (swtch & CFG_SWITCH_NOHD) ? FLP_TYPE_720 : FLP_TYPE_144;
                    400:        type     = &fdtypes[def_type];
1.1       leo       401:
1.24      leo       402:        printf(": %s %d cyl, %d head, %d sec\n", type->descr,
                    403:                type->nblocks / (type->nsectors * type->nheads), type->nheads,
                    404:                type->nsectors);
1.1       leo       405:
1.13      thorpej   406:        /*
                    407:         * Initialize and attach the disk structure.
                    408:         */
                    409:        sc->dkdev.dk_name = sc->sc_dv.dv_xname;
1.1       leo       410:        sc->dkdev.dk_driver = &fddkdriver;
1.13      thorpej   411:        disk_attach(&sc->dkdev);
1.1       leo       412: }
                    413:
1.15      leo       414: int
1.46.2.5! skrll     415: fdioctl(dev, cmd, addr, flag, l)
1.1       leo       416: dev_t          dev;
                    417: u_long         cmd;
                    418: int            flag;
                    419: caddr_t                addr;
1.46.2.5! skrll     420: struct lwp     *l;
1.1       leo       421: {
                    422:        struct fd_softc *sc;
                    423:
1.16      thorpej   424:        sc = getsoftc(fd_cd, DISKUNIT(dev));
1.10      mycroft   425:
1.1       leo       426:        if((sc->flags & FLPF_HAVELAB) == 0)
                    427:                return(EBADF);
                    428:
                    429:        switch(cmd) {
                    430:                case DIOCSBAD:
                    431:                        return(EINVAL);
                    432:                case DIOCGDINFO:
1.13      thorpej   433:                        *(struct disklabel *)addr = *(sc->dkdev.dk_label);
1.1       leo       434:                        return(0);
                    435:                case DIOCGPART:
                    436:                        ((struct partinfo *)addr)->disklab =
1.13      thorpej   437:                                sc->dkdev.dk_label;
1.10      mycroft   438:                        ((struct partinfo *)addr)->part =
1.24      leo       439:                              &sc->dkdev.dk_label->d_partitions[RAW_PART];
1.1       leo       440:                        return(0);
                    441: #ifdef notyet /* XXX LWP */
                    442:                case DIOCSRETRIES:
                    443:                case DIOCSSTEP:
                    444:                case DIOCSDINFO:
                    445:                case DIOCWDINFO:
                    446:                case DIOCWLABEL:
1.26      thorpej   447:                        break;
1.1       leo       448: #endif /* notyet */
1.26      thorpej   449:                case DIOCGDEFLABEL:
                    450:                        fdgetdefaultlabel(sc, (struct disklabel *)addr,
                    451:                            RAW_PART);
                    452:                        return(0);
1.1       leo       453:        }
1.15      leo       454:        return(ENOTTY);
1.1       leo       455: }
                    456:
                    457: /*
                    458:  * Open the device. If this is the first open on both the floppy devices,
                    459:  * intialize the controller.
                    460:  * Note that partition info on the floppy device is used to distinguise
                    461:  * between 780Kb and 360Kb floppy's.
                    462:  *     partition 0: 360Kb
1.3       leo       463:  *     partition 1: 780Kb
1.1       leo       464:  */
1.15      leo       465: int
1.46.2.5! skrll     466: fdopen(dev, flags, devtype, l)
1.1       leo       467: dev_t          dev;
                    468: int            flags, devtype;
1.46.2.5! skrll     469: struct lwp     *l;
1.1       leo       470: {
                    471:        struct fd_softc *sc;
                    472:        int             sps;
                    473:
                    474: #ifdef FLP_DEBUG
1.24      leo       475:        printf("fdopen dev=0x%x\n", dev);
1.1       leo       476: #endif
                    477:
1.24      leo       478:        if(FLP_TYPE(dev) >= NR_TYPES)
1.1       leo       479:                return(ENXIO);
                    480:
1.16      thorpej   481:        if((sc = getsoftc(fd_cd, DISKUNIT(dev))) == NULL)
1.1       leo       482:                return(ENXIO);
                    483:
                    484:        /*
                    485:         * If no floppy currently open, reset the controller and select
                    486:         * floppy type.
                    487:         */
                    488:        if(!nopens) {
                    489:
                    490: #ifdef FLP_DEBUG
1.24      leo       491:                printf("fdopen device not yet open\n");
1.1       leo       492: #endif
                    493:                nopens++;
1.4       leo       494:                write_fdreg(FDC_CS, IRUPT);
1.8       leo       495:                delay(40);
1.1       leo       496:        }
                    497:
1.4       leo       498:        /*
                    499:         * Sleep while other process is opening the device
                    500:         */
                    501:        sps = splbio();
                    502:        while(sc->flags & FLPF_INOPEN)
1.24      leo       503:                tsleep((caddr_t)sc, PRIBIO, "fdopen", 0);
1.4       leo       504:        splx(sps);
                    505:
1.1       leo       506:        if(!(sc->flags & FLPF_ISOPEN)) {
                    507:                /*
                    508:                 * Initialise some driver values.
                    509:                 */
1.24      leo       510:                int     type;
1.1       leo       511:                void    *addr;
                    512:
1.24      leo       513:                type = FLP_TYPE(dev);
                    514:
1.38      hannken   515:                bufq_alloc(&sc->bufq, BUFQ_DISKSORT|BUFQ_SORT_RAWBLOCK);
1.1       leo       516:                sc->unit        = DISKUNIT(dev);
1.24      leo       517:                sc->part        = RAW_PART;
                    518:                sc->nheads      = fdtypes[type].nheads;
                    519:                sc->nsectors    = fdtypes[type].nsectors;
                    520:                sc->nblocks     = fdtypes[type].nblocks;
                    521:                sc->density     = fdtypes[type].density;
1.1       leo       522:                sc->curtrk      = INV_TRK;
                    523:                sc->sector      = 0;
                    524:                sc->errcnt      = 0;
                    525:                sc->bounceb     = (u_char*)alloc_stmem(SECTOR_SIZE, &addr);
                    526:                if(sc->bounceb == NULL)
                    527:                        return(ENOMEM); /* XXX */
                    528:
1.4       leo       529:                /*
                    530:                 * Go get write protect + loaded status
                    531:                 */
1.6       leo       532:                sc->flags |= FLPF_INOPEN|FLPF_GETSTAT;
1.4       leo       533:                sps = splbio();
1.15      leo       534:                st_dmagrab((dma_farg)fdcint, (dma_farg)fdstatus, sc,
                    535:                                                                &lock_stat, 0);
1.4       leo       536:                while(sc->flags & FLPF_GETSTAT)
1.24      leo       537:                        tsleep((caddr_t)sc, PRIBIO, "fdopen", 0);
1.4       leo       538:                splx(sps);
                    539:                wakeup((caddr_t)sc);
                    540:
                    541:                if((sc->flags & FLPF_WRTPROT) && (flags & FWRITE)) {
                    542:                        sc->flags = 0;
                    543:                        return(EPERM);
                    544:                }
                    545:                if(sc->flags & FLPF_EMPTY) {
                    546:                        sc->flags = 0;
                    547:                        return(ENXIO);
                    548:                }
1.6       leo       549:                sc->flags &= ~(FLPF_INOPEN|FLPF_GETSTAT);
                    550:                sc->flags |= FLPF_ISOPEN;
1.1       leo       551:        }
                    552:        else {
                    553:                /*
                    554:                 * Multiply opens are granted when accessing the same type of
                    555:                 * floppy (eq. the same partition).
                    556:                 */
1.24      leo       557:                if(sc->density != fdtypes[DISKPART(dev)].density)
1.1       leo       558:                        return(ENXIO);  /* XXX temporarely out of business */
                    559:        }
                    560:        fdgetdisklabel(sc, dev);
                    561: #ifdef FLP_DEBUG
1.24      leo       562:        printf("fdopen open succeeded on type %d\n", sc->part);
1.1       leo       563: #endif
1.15      leo       564:        return (0);
1.1       leo       565: }
                    566:
1.15      leo       567: int
1.46.2.5! skrll     568: fdclose(dev, flags, devtype, l)
1.1       leo       569: dev_t          dev;
                    570: int            flags, devtype;
1.46.2.5! skrll     571: struct lwp     *l;
1.1       leo       572: {
                    573:        struct fd_softc *sc;
                    574:
1.16      thorpej   575:        sc = getsoftc(fd_cd, DISKUNIT(dev));
1.1       leo       576:        free_stmem(sc->bounceb);
                    577:        sc->flags = 0;
                    578:        nopens--;
                    579:
                    580: #ifdef FLP_DEBUG
1.23      christos  581:        printf("Closed floppy device -- nopens: %d\n", nopens);
1.1       leo       582: #endif
1.4       leo       583:        return(0);
1.1       leo       584: }
                    585:
                    586: void
                    587: fdstrategy(bp)
                    588: struct buf     *bp;
                    589: {
1.11      leo       590:        struct fd_softc  *sc;
                    591:        struct disklabel *lp;
1.24      leo       592:        int              sps, sz;
1.1       leo       593:
1.16      thorpej   594:        sc = getsoftc(fd_cd, DISKUNIT(bp->b_dev));
1.1       leo       595:
                    596: #ifdef FLP_DEBUG
1.24      leo       597:        printf("fdstrategy: %p, b_bcount: %ld\n", bp, bp->b_bcount);
1.1       leo       598: #endif
                    599:
                    600:        /*
                    601:         * check for valid partition and bounds
                    602:         */
1.13      thorpej   603:        lp = sc->dkdev.dk_label;
1.11      leo       604:        if ((sc->flags & FLPF_HAVELAB) == 0) {
                    605:                bp->b_error = EIO;
                    606:                goto bad;
1.1       leo       607:        }
1.24      leo       608:        if (bp->b_blkno < 0 || (bp->b_bcount % SECTOR_SIZE)) {
                    609:                bp->b_error = EINVAL;
                    610:                goto bad;
                    611:        }
                    612:        if (bp->b_bcount == 0)
1.1       leo       613:                goto done;
                    614:
1.24      leo       615:        sz = howmany(bp->b_bcount, SECTOR_SIZE);
                    616:
                    617:        if (bp->b_blkno + sz > sc->nblocks) {
                    618:                sz = sc->nblocks - bp->b_blkno;
                    619:                if (sz == 0) /* Exactly at EndOfDisk */
                    620:                        goto done;
                    621:                if (sz < 0) { /* Past EndOfDisk */
                    622:                        bp->b_error = EINVAL;
                    623:                        goto bad;
                    624:                }
                    625:                /* Trucate it */
                    626:                if (bp->b_flags & B_RAW)
                    627:                        bp->b_bcount = sz << DEV_BSHIFT;
                    628:                else bp->b_bcount = sz * lp->d_secsize;
                    629:        }
1.32      thorpej   630:
                    631:        /* No partition translation. */
                    632:        bp->b_rawblkno = bp->b_blkno;
1.1       leo       633:
                    634:        /*
                    635:         * queue the buf and kick the low level code
                    636:         */
                    637:        sps = splbio();
1.38      hannken   638:        BUFQ_PUT(&sc->bufq, bp);        /* XXX disksort_cylinder */
1.11      leo       639:        if (!lock_stat) {
                    640:                if (fd_state & FLP_MON)
1.35      thorpej   641:                        callout_stop(&sc->sc_motor_ch);
1.1       leo       642:                fd_state = FLP_IDLE;
1.15      leo       643:                st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc,
                    644:                                                        &lock_stat, 0);
1.1       leo       645:        }
                    646:        splx(sps);
                    647:
                    648:        return;
1.11      leo       649: bad:
                    650:        bp->b_flags |= B_ERROR;
1.1       leo       651: done:
                    652:        bp->b_resid = bp->b_bcount;
                    653:        biodone(bp);
                    654: }
                    655:
                    656: int
1.15      leo       657: fdread(dev, uio, flags)
1.1       leo       658: dev_t          dev;
                    659: struct uio     *uio;
1.15      leo       660: int            flags;
1.1       leo       661: {
1.8       leo       662:        return(physio(fdstrategy, NULL, dev, B_READ, fdminphys, uio));
1.1       leo       663: }
                    664:
                    665: int
1.15      leo       666: fdwrite(dev, uio, flags)
1.1       leo       667: dev_t          dev;
                    668: struct uio     *uio;
1.15      leo       669: int            flags;
1.1       leo       670: {
1.8       leo       671:        return(physio(fdstrategy, NULL, dev, B_WRITE, fdminphys, uio));
1.1       leo       672: }
                    673:
                    674: /*
1.4       leo       675:  * Called through DMA-dispatcher, get status.
                    676:  */
                    677: static void
                    678: fdstatus(sc)
                    679: struct fd_softc        *sc;
                    680: {
                    681: #ifdef FLP_DEBUG
1.23      christos  682:        printf("fdstatus\n");
1.4       leo       683: #endif
                    684:        sc->errcnt = 0;
                    685:        fd_state   = FLP_STAT;
                    686:        fd_xfer(sc);
                    687: }
                    688:
                    689: /*
1.46      wiz       690:  * Called through the DMA-dispatcher. So we know we are the only ones
1.46.2.1  skrll     691:  * messing with the floppy-controller.
1.1       leo       692:  * Initialize some fields in the fdsoftc for the state-machine and get
                    693:  * it going.
                    694:  */
                    695: static void
                    696: fdstart(sc)
                    697: struct fd_softc        *sc;
                    698: {
                    699:        struct buf      *bp;
                    700:
1.38      hannken   701:        bp           = BUFQ_PEEK(&sc->bufq);
1.1       leo       702:        sc->sector   = bp->b_blkno;     /* Start sector for I/O         */
                    703:        sc->io_data  = bp->b_data;      /* KVA base for I/O             */
                    704:        sc->io_bytes = bp->b_bcount;    /* Transfer size in bytes       */
                    705:        sc->io_dir   = bp->b_flags & B_READ;/* Direction of transfer    */
                    706:        sc->errcnt   = 0;               /* No errors yet                */
                    707:        fd_state     = FLP_XFER;        /* Yes, we're going to transfer */
                    708:
1.13      thorpej   709:        /* Instrumentation. */
                    710:        disk_busy(&sc->dkdev);
                    711:
1.1       leo       712:        fd_xfer(sc);
                    713: }
                    714:
                    715: /*
                    716:  * The current transaction is finished (for good or bad). Let go of
1.46      wiz       717:  * the DMA-resources. Call biodone() to finish the transaction.
1.1       leo       718:  * Find a new transaction to work on.
                    719:  */
                    720: static void
                    721: fddone(sc)
                    722: register struct fd_softc       *sc;
                    723: {
1.33      leo       724:        struct buf      *bp;
1.1       leo       725:        struct fd_softc *sc1;
1.5       leo       726:        int             i, sps;
1.1       leo       727:
                    728:        /*
1.46      wiz       729:         * Give others a chance to use the DMA.
1.1       leo       730:         */
1.5       leo       731:        st_dmafree(sc, &lock_stat);
1.4       leo       732:
1.1       leo       733:
1.4       leo       734:        if(fd_state != FLP_STAT) {
                    735:                /*
                    736:                 * Finish current transaction.
                    737:                 */
1.5       leo       738:                sps = splbio();
1.38      hannken   739:                bp = BUFQ_GET(&sc->bufq);
1.31      thorpej   740:                if (bp == NULL)
1.4       leo       741:                        panic("fddone");
1.5       leo       742:                splx(sps);
1.4       leo       743:
                    744: #ifdef FLP_DEBUG
1.24      leo       745:                printf("fddone: unit: %d, buf: %p, resid: %d\n",sc->unit,bp,
1.4       leo       746:                                                                sc->io_bytes);
                    747: #endif
                    748:                bp->b_resid = sc->io_bytes;
1.13      thorpej   749:
1.44      mrg       750:                disk_unbusy(&sc->dkdev, (bp->b_bcount - bp->b_resid),
                    751:                    (bp->b_flags & B_READ));
1.13      thorpej   752:
1.4       leo       753:                biodone(bp);
                    754:        }
                    755:        fd_state = FLP_MON;
1.1       leo       756:
1.5       leo       757:        if(lock_stat)
1.1       leo       758:                return;         /* XXX Is this possible?        */
                    759:
                    760:        /*
                    761:         * Find a new transaction on round-robin basis.
                    762:         */
                    763:        for(i = sc->unit + 1; ;i++) {
1.16      thorpej   764:                if(i >= fd_cd.cd_ndevs)
1.1       leo       765:                        i = 0;
1.16      thorpej   766:                if((sc1 = fd_cd.cd_devs[i]) == NULL)
1.1       leo       767:                        continue;
1.38      hannken   768:                if (BUFQ_PEEK(&sc1->bufq) != NULL)
1.1       leo       769:                        break;
                    770:                if(i == sc->unit) {
1.35      thorpej   771:                        callout_reset(&sc->sc_motor_ch, FLP_MONDELAY,
                    772:                            (FPV)fdmotoroff, sc);
1.1       leo       773: #ifdef FLP_DEBUG
1.23      christos  774:                        printf("fddone: Nothing to do\n");
1.1       leo       775: #endif
                    776:                        return; /* No work */
                    777:                }
                    778:        }
                    779:        fd_state = FLP_IDLE;
                    780: #ifdef FLP_DEBUG
1.23      christos  781:        printf("fddone: Staring job on unit %d\n", sc1->unit);
1.1       leo       782: #endif
1.15      leo       783:        st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc1, &lock_stat, 0);
1.1       leo       784: }
                    785:
1.8       leo       786: static int
                    787: fdselect(drive, head, dense)
                    788: int    drive, head, dense;
                    789: {
1.18      leo       790:        int     i, spinning;
1.8       leo       791: #ifdef FLP_DEBUG
1.23      christos  792:        printf("fdselect: drive=%d, head=%d, dense=%d\n", drive, head, dense);
1.8       leo       793: #endif
                    794:        i = ((drive == 1) ? PA_FLOP1 : PA_FLOP0) | head;
                    795:        spinning = motoron;
                    796:        motoron  = 1;
                    797:
                    798:        switch(dense) {
                    799:                case FLP_DD:
                    800:                        DMA->dma_drvmode = 0;
                    801:                        break;
                    802:                case FLP_HD:
                    803:                        DMA->dma_drvmode = (FDC_HDSET|FDC_HDSIG);
                    804:                        break;
                    805:                default:
1.40      provos    806:                        panic("fdselect: unknown density code");
1.8       leo       807:        }
                    808:        if(i != selected) {
                    809:                selected = i;
1.20      leo       810:                ym2149_fd_select((i ^ PA_FDSEL));
1.8       leo       811:        }
                    812:        return(spinning);
                    813: }
                    814:
                    815: static void
                    816: fddeselect()
                    817: {
1.18      leo       818:        ym2149_fd_select(PA_FDSEL);
1.8       leo       819:        motoron = selected = 0;
                    820:        DMA->dma_drvmode   = 0;
                    821: }
                    822:
1.1       leo       823: /****************************************************************************
                    824:  * The following functions assume to be running as a result of a            *
                    825:  * disk-interrupt (e.q. spl = splbio).                                     *
                    826:  * They form the finit-state machine, the actual driver.                    *
                    827:  *                                                                          *
                    828:  *     fdstart()/ --> fd_xfer() -> activate hardware                       *
                    829:  *  fdopen()          ^                                                     *
                    830:  *                    |                                                     *
                    831:  *                    +-- not ready -<------------+                         *
                    832:  *                                                |                         *
                    833:  *  fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+                         *
                    834:  *  h/w interrupt                 |                                         *
                    835:  *                               \|/                                        *
                    836:  *                            finished ---> fdone()                         *
                    837:  *                                                                          *
                    838:  ****************************************************************************/
                    839: static void
                    840: fd_xfer(sc)
                    841: struct fd_softc        *sc;
                    842: {
1.15      leo       843:        register int    head;
1.1       leo       844:        register int    track, sector, hbit;
                    845:                 u_long phys_addr;
                    846:
1.15      leo       847:        head = track = 0;
1.4       leo       848:        switch(fd_state) {
                    849:            case FLP_XFER:
                    850:                /*
                    851:                 * Calculate head/track values
                    852:                 */
                    853:                track  = sc->sector / sc->nsectors;
                    854:                head   = track % sc->nheads;
                    855:                track  = track / sc->nheads;
1.1       leo       856: #ifdef FLP_DEBUG
1.23      christos  857:                printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head,
1.4       leo       858:                                                                track);
1.1       leo       859: #endif
1.4       leo       860:                break;
                    861:
                    862:            case FLP_STAT:
                    863:                /*
                    864:                 * FLP_STAT only wants to recalibrate
                    865:                 */
                    866:                sc->curtrk = INV_TRK;
                    867:                break;
                    868:            default:
                    869:                panic("fd_xfer: wrong state (0x%x)", fd_state);
                    870:        }
1.1       leo       871:
                    872:        /*
1.8       leo       873:         * Select the drive.
1.1       leo       874:         */
1.8       leo       875:        hbit = fdselect(sc->unit, head, sc->density) ? HBIT : 0;
1.1       leo       876:
                    877:        if(sc->curtrk == INV_TRK) {
1.10      mycroft   878:                /*
1.1       leo       879:                 * Recalibrate, since we lost track of head positioning.
                    880:                 * The floppy disk controller has no way of determining its
                    881:                 * absolute arm position (track).  Instead, it steps the
                    882:                 * arm a track at a time and keeps track of where it
                    883:                 * thinks it is (in software).  However, after a SEEK, the
                    884:                 * hardware reads information from the diskette telling
                    885:                 * where the arm actually is.  If the arm is in the wrong place,
                    886:                 * a recalibration is done, which forces the arm to track 0.
                    887:                 * This way the controller can get back into sync with reality.
                    888:                 */
1.8       leo       889:                fd_cmd = RESTORE;
1.4       leo       890:                write_fdreg(FDC_CS, RESTORE|VBIT|hbit);
1.35      thorpej   891:                callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY,
                    892:                    (FPV)fdmotoroff, sc);
1.1       leo       893:
                    894: #ifdef FLP_DEBUG
1.23      christos  895:                printf("fd_xfer:Recalibrating drive %d\n", sc->unit);
1.1       leo       896: #endif
                    897:                return;
                    898:        }
                    899:
1.4       leo       900:        write_fdreg(FDC_TR, sc->curtrk);
1.1       leo       901:
                    902:        /*
                    903:         * Issue a SEEK command on the indicated drive unless the arm is
                    904:         * already positioned on the correct track.
                    905:         */
                    906:        if(track != sc->curtrk) {
                    907:                sc->curtrk = track;     /* be optimistic */
1.4       leo       908:                write_fdreg(FDC_DR, track);
                    909:                write_fdreg(FDC_CS, SEEK|RATE6|VBIT|hbit);
1.35      thorpej   910:                callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY,
                    911:                    (FPV)fdmotoroff, sc);
1.1       leo       912:                fd_cmd = SEEK;
                    913: #ifdef FLP_DEBUG
1.23      christos  914:                printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit);
1.1       leo       915: #endif
                    916:                return;
                    917:        }
                    918:
                    919:        /*
                    920:         * The drive is now on the proper track. Read or write 1 block.
                    921:         */
                    922:        sector = sc->sector % sc->nsectors;
                    923:        sector++;       /* start numbering at 1 */
                    924:
1.4       leo       925:        write_fdreg(FDC_SR, sector);
1.1       leo       926:
                    927:        phys_addr = (u_long)kvtop(sc->io_data);
                    928:        if(phys_addr >= FDC_MAX_DMA_AD) {
                    929:                /*
                    930:                 * We _must_ bounce this address
                    931:                 */
                    932:                phys_addr = (u_long)kvtop(sc->bounceb);
                    933:                if(sc->io_dir == B_WRITE)
                    934:                        bcopy(sc->io_data, sc->bounceb, SECTOR_SIZE);
                    935:                sc->flags |= FLPF_BOUNCE;
                    936:        }
1.7       leo       937:        st_dmaaddr_set((caddr_t)phys_addr);     /* DMA address setup */
1.1       leo       938:
                    939: #ifdef FLP_DEBUG
1.24      leo       940:        printf("fd_xfer:Start io (io_addr:%lx)\n", (u_long)kvtop(sc->io_data));
1.1       leo       941: #endif
                    942:
                    943:        if(sc->io_dir == B_READ) {
                    944:                /* Issue the command */
1.4       leo       945:                st_dmacomm(DMA_FDC | DMA_SCREG, 1);
                    946:                write_fdreg(FDC_CS, F_READ|hbit);
1.1       leo       947:                fd_cmd = F_READ;
                    948:        }
                    949:        else {
                    950:                /* Issue the command */
1.4       leo       951:                st_dmacomm(DMA_WRBIT | DMA_FDC | DMA_SCREG, 1);
                    952:                write_fdreg(DMA_WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT);
1.1       leo       953:                fd_cmd = F_WRITE;
                    954:        }
1.35      thorpej   955:        callout_reset(&sc->sc_motor_ch, FLP_XFERDELAY, (FPV)fdmotoroff, sc);
1.1       leo       956: }
                    957:
                    958: /* return values of fd_xfer_ok(): */
                    959: #define X_OK                   0
                    960: #define X_AGAIN                        1
                    961: #define X_ERROR                        2
                    962: #define X_FAIL                 3
                    963:
                    964: /*
                    965:  * Hardware interrupt function.
                    966:  */
1.4       leo       967: static void
1.1       leo       968: fdcint(sc)
                    969: struct fd_softc        *sc;
                    970: {
                    971:        struct  buf     *bp;
                    972:
                    973: #ifdef FLP_DEBUG
1.23      christos  974:        printf("fdcint: unit = %d\n", sc->unit);
1.1       leo       975: #endif
                    976:
                    977:        /*
                    978:         * Cancel timeout (we made it, didn't we)
                    979:         */
1.35      thorpej   980:        callout_stop(&sc->sc_motor_ch);
1.1       leo       981:
                    982:        switch(fd_xfer_ok(sc)) {
                    983:                case X_ERROR :
                    984:                        if(++(sc->errcnt) < MAX_ERRORS) {
                    985:                                /*
                    986:                                 * Command failed but still retries left.
                    987:                                 */
                    988:                                break;
                    989:                        }
                    990:                        /* FALL THROUGH */
                    991:                case X_FAIL  :
                    992:                        /*
                    993:                         * Non recoverable error. Fall back to motor-on
                    994:                         * idle-state.
                    995:                         */
1.8       leo       996:                        if(fd_error != NULL) {
1.23      christos  997:                                printf("Floppy error: %s\n", fd_error);
1.8       leo       998:                                fd_error = NULL;
                    999:                        }
                   1000:
1.4       leo      1001:                        if(fd_state == FLP_STAT) {
                   1002:                                sc->flags |= FLPF_EMPTY;
                   1003:                                sc->flags &= ~FLPF_GETSTAT;
                   1004:                                wakeup((caddr_t)sc);
                   1005:                                fddone(sc);
                   1006:                                return;
                   1007:                        }
                   1008:
1.38      hannken  1009:                        bp = BUFQ_PEEK(&sc->bufq);
1.1       leo      1010:
                   1011:                        bp->b_error  = EIO;
                   1012:                        bp->b_flags |= B_ERROR;
1.8       leo      1013:                        fd_state     = FLP_MON;
1.1       leo      1014:
                   1015:                        break;
                   1016:                case X_AGAIN:
                   1017:                        /*
                   1018:                         * Start next part of state machine.
                   1019:                         */
                   1020:                        break;
                   1021:                case X_OK:
                   1022:                        /*
                   1023:                         * Command ok and finished. Reset error-counter.
                   1024:                         * If there are no more bytes to transfer fall back
                   1025:                         * to motor-on idle state.
                   1026:                         */
                   1027:                        sc->errcnt = 0;
1.4       leo      1028:
                   1029:                        if(fd_state == FLP_STAT) {
                   1030:                                sc->flags &= ~FLPF_GETSTAT;
                   1031:                                wakeup((caddr_t)sc);
                   1032:                                fddone(sc);
                   1033:                                return;
                   1034:                        }
                   1035:
1.1       leo      1036:                        if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ))
                   1037:                                bcopy(sc->bounceb, sc->io_data, SECTOR_SIZE);
                   1038:                        sc->flags &= ~FLPF_BOUNCE;
                   1039:
                   1040:                        sc->sector++;
                   1041:                        sc->io_data  += SECTOR_SIZE;
                   1042:                        sc->io_bytes -= SECTOR_SIZE;
                   1043:                        if(sc->io_bytes <= 0)
                   1044:                                fd_state = FLP_MON;
                   1045:        }
                   1046:        if(fd_state == FLP_MON)
                   1047:                fddone(sc);
                   1048:        else fd_xfer(sc);
                   1049: }
                   1050:
                   1051: /*
                   1052:  * Determine status of last command. Should only be called through
                   1053:  * 'fdcint()'.
                   1054:  * Returns:
                   1055:  *     X_ERROR : Error on command; might succeed next time.
                   1056:  *     X_FAIL  : Error on command; will never succeed.
                   1057:  *     X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete.
                   1058:  *     X_OK    : Command succeeded and is complete.
                   1059:  *
                   1060:  * This function only affects sc->curtrk.
                   1061:  */
                   1062: static int
                   1063: fd_xfer_ok(sc)
                   1064: register struct fd_softc       *sc;
                   1065: {
                   1066:        register int    status;
                   1067:
1.4       leo      1068: #ifdef FLP_DEBUG
1.23      christos 1069:        printf("fd_xfer_ok: cmd: 0x%x, state: 0x%x\n", fd_cmd, fd_state);
1.4       leo      1070: #endif
1.1       leo      1071:        switch(fd_cmd) {
                   1072:                case IRUPT:
                   1073:                        /*
                   1074:                         * Timeout. Force a recalibrate before we try again.
                   1075:                         */
1.8       leo      1076:                        status = read_fdreg(FDC_CS);
                   1077:
1.1       leo      1078:                        fd_error = "Timeout";
                   1079:                        sc->curtrk = INV_TRK;
                   1080:                        return(X_ERROR);
                   1081:                case F_READ:
                   1082:                        /*
                   1083:                         * Test for DMA error
                   1084:                         */
1.4       leo      1085:                        status = read_dmastat();
1.1       leo      1086:                        if(!(status & DMAOK)) {
1.46      wiz      1087:                                fd_error = "DMA error";
1.1       leo      1088:                                return(X_ERROR);
                   1089:                        }
                   1090:                        /*
                   1091:                         * Get controller status and check for errors.
                   1092:                         */
1.4       leo      1093:                        status = read_fdreg(FDC_CS);
1.1       leo      1094:                        if(status & (RNF | CRCERR | LD_T00)) {
                   1095:                                fd_error = "Read error";
                   1096:                                if(status & RNF)
                   1097:                                        sc->curtrk = INV_TRK;
                   1098:                                return(X_ERROR);
                   1099:                        }
                   1100:                        break;
                   1101:                case F_WRITE:
                   1102:                        /*
1.4       leo      1103:                         * Test for DMA error
                   1104:                         */
                   1105:                        status = read_dmastat();
                   1106:                        if(!(status & DMAOK)) {
1.46      wiz      1107:                                fd_error = "DMA error";
1.4       leo      1108:                                return(X_ERROR);
                   1109:                        }
                   1110:                        /*
1.1       leo      1111:                         * Get controller status and check for errors.
                   1112:                         */
1.4       leo      1113:                        status = read_fdreg(FDC_CS);
1.1       leo      1114:                        if(status & WRI_PRO) {
                   1115:                                fd_error = "Write protected";
                   1116:                                return(X_FAIL);
                   1117:                        }
                   1118:                        if(status & (RNF | CRCERR | LD_T00)) {
                   1119:                                fd_error = "Write error";
                   1120:                                sc->curtrk = INV_TRK;
                   1121:                                return(X_ERROR);
                   1122:                        }
                   1123:                        break;
                   1124:                case SEEK:
1.4       leo      1125:                        status = read_fdreg(FDC_CS);
1.1       leo      1126:                        if(status & (RNF | CRCERR)) {
                   1127:                                fd_error = "Seek error";
                   1128:                                sc->curtrk = INV_TRK;
                   1129:                                return(X_ERROR);
                   1130:                        }
                   1131:                        return(X_AGAIN);
                   1132:                case RESTORE:
                   1133:                        /*
                   1134:                         * Determine if the recalibration succeeded.
                   1135:                         */
1.4       leo      1136:                        status = read_fdreg(FDC_CS);
1.1       leo      1137:                        if(status & RNF) {
                   1138:                                fd_error = "Recalibrate error";
                   1139:                                /* reset controller */
1.4       leo      1140:                                write_fdreg(FDC_CS, IRUPT);
1.1       leo      1141:                                sc->curtrk = INV_TRK;
                   1142:                                return(X_ERROR);
                   1143:                        }
                   1144:                        sc->curtrk = 0;
1.4       leo      1145:                        if(fd_state == FLP_STAT) {
                   1146:                                if(status & WRI_PRO)
                   1147:                                        sc->flags |= FLPF_WRTPROT;
                   1148:                                break;
                   1149:                        }
1.1       leo      1150:                        return(X_AGAIN);
                   1151:                default:
                   1152:                        fd_error = "Driver error: fd_xfer_ok : Unknown state";
                   1153:                        return(X_FAIL);
                   1154:        }
                   1155:        return(X_OK);
                   1156: }
                   1157:
                   1158: /*
                   1159:  * All timeouts will call this function.
                   1160:  */
                   1161: static void
                   1162: fdmotoroff(sc)
                   1163: struct fd_softc        *sc;
                   1164: {
1.8       leo      1165:        int     sps;
1.1       leo      1166:
                   1167:        /*
                   1168:         * Get at harware interrupt level
                   1169:         */
                   1170:        sps = splbio();
                   1171:
                   1172: #if FLP_DEBUG
1.23      christos 1173:        printf("fdmotoroff, state = 0x%x\n", fd_state);
1.1       leo      1174: #endif
                   1175:
                   1176:        switch(fd_state) {
1.4       leo      1177:                case FLP_STAT :
1.1       leo      1178:                case FLP_XFER :
                   1179:                        /*
                   1180:                         * Timeout during a transfer; cancel transaction
                   1181:                         * set command to 'IRUPT'.
                   1182:                         * A drive-interrupt is simulated to trigger the state
                   1183:                         * machine.
                   1184:                         */
                   1185:                        /*
                   1186:                         * Cancel current transaction
                   1187:                         */
                   1188:                        fd_cmd = IRUPT;
1.8       leo      1189:                        write_fdreg(FDC_CS, IRUPT);
                   1190:                        delay(20);
                   1191:                        (void)read_fdreg(FDC_CS);
                   1192:                        write_fdreg(FDC_CS, RESTORE);
                   1193:                        break;
1.1       leo      1194:
                   1195:                case FLP_MON  :
                   1196:                        /*
                   1197:                         * Turn motor off.
                   1198:                         */
1.12      leo      1199:                        if(selected) {
                   1200:                                int tmp;
                   1201:
1.15      leo      1202:                                st_dmagrab((dma_farg)fdcint, (dma_farg)fdmoff,
                   1203:                                                                sc, &tmp, 0);
1.12      leo      1204:                        }
                   1205:                        else  fd_state = FLP_IDLE;
1.1       leo      1206:                        break;
                   1207:        }
                   1208:        splx(sps);
                   1209: }
                   1210:
                   1211: /*
                   1212:  * min byte count to whats left of the track in question
                   1213:  */
1.10      mycroft  1214: static void
1.1       leo      1215: fdminphys(bp)
                   1216: struct buf     *bp;
                   1217: {
                   1218:        struct fd_softc *sc;
                   1219:        int             sec, toff, tsz;
                   1220:
1.16      thorpej  1221:        if((sc = getsoftc(fd_cd, DISKUNIT(bp->b_dev))) == NULL)
1.9       cgd      1222:                panic("fdminphys: couldn't get softc");
1.1       leo      1223:
                   1224:        sec  = bp->b_blkno % (sc->nsectors * sc->nheads);
                   1225:        toff = sec * SECTOR_SIZE;
                   1226:        tsz  = sc->nsectors * sc->nheads * SECTOR_SIZE;
                   1227:
                   1228: #ifdef FLP_DEBUG
1.24      leo      1229:        printf("fdminphys: before %ld", bp->b_bcount);
1.1       leo      1230: #endif
                   1231:
                   1232:        bp->b_bcount = min(bp->b_bcount, tsz - toff);
                   1233:
                   1234: #ifdef FLP_DEBUG
1.24      leo      1235:        printf(" after %ld\n", bp->b_bcount);
1.1       leo      1236: #endif
                   1237:
1.10      mycroft  1238:        minphys(bp);
1.12      leo      1239: }
                   1240:
                   1241: /*
                   1242:  * Called from fdmotoroff to turn the motor actually off....
                   1243:  * This can't be done in fdmotoroff itself, because exclusive access to the
                   1244:  * DMA controller is needed to read the FDC-status register. The function
                   1245:  * 'fdmoff()' always runs as the result of a 'dmagrab()'.
                   1246:  * We need to test the status-register because we want to be sure that the
                   1247:  * drive motor is really off before deselecting the drive. The FDC only
                   1248:  * turns off the drive motor after having seen 10 index-pulses. You only
                   1249:  * get index-pulses when a drive is selected....This means that if the
                   1250:  * drive is deselected when the motor is still spinning, it will continue
                   1251:  * to spin _even_ when you insert a floppy later on...
                   1252:  */
                   1253: static void
                   1254: fdmoff(fdsoftc)
                   1255: struct fd_softc        *fdsoftc;
                   1256: {
                   1257:        int tmp;
                   1258:
                   1259:        if ((fd_state == FLP_MON) && selected) {
                   1260:                tmp = read_fdreg(FDC_CS);
                   1261:                if (!(tmp & MOTORON)) {
                   1262:                        fddeselect();
                   1263:                        fd_state = FLP_IDLE;
                   1264:                }
1.35      thorpej  1265:                else
                   1266:                        callout_reset(&fdsoftc->sc_motor_ch, 10*FLP_MONDELAY,
                   1267:                            (FPV)fdmotoroff, fdsoftc);
1.12      leo      1268:        }
                   1269:        st_dmafree(fdsoftc, &tmp);
1.1       leo      1270: }
                   1271:
                   1272: /*
1.37      wiz      1273:  * Used to find out wich drives are actually connected. We do this by issuing
1.1       leo      1274:  * is 'RESTORE' command and check if the 'track-0' bit is set. This also works
                   1275:  * if the drive is present but no floppy is inserted.
                   1276:  */
                   1277: static void
                   1278: fdtestdrv(fdsoftc)
                   1279: struct fd_softc        *fdsoftc;
                   1280: {
1.15      leo      1281:        int     status;
1.1       leo      1282:
                   1283:        /*
                   1284:         * Select the right unit and head.
                   1285:         */
1.8       leo      1286:        fdselect(fdsoftc->unit, 0, FLP_DD);
1.1       leo      1287:
1.8       leo      1288:        write_fdreg(FDC_CS, RESTORE|HBIT);
1.1       leo      1289:
                   1290:        /*
                   1291:         * Wait for about 2 seconds.
                   1292:         */
                   1293:        delay(2000000);
                   1294:
1.4       leo      1295:        status = read_fdreg(FDC_CS);
1.8       leo      1296:        if(status & (RNF|BUSY)) {
1.4       leo      1297:                write_fdreg(FDC_CS, IRUPT);     /* reset controller */
1.8       leo      1298:                delay(40);
                   1299:        }
1.1       leo      1300:
                   1301:        if(!(status & LD_T00))
                   1302:                fdsoftc->flags |= FLPF_NOTRESP;
1.8       leo      1303:
                   1304:        fddeselect();
1.1       leo      1305: }
                   1306:
1.26      thorpej  1307: static void
                   1308: fdgetdefaultlabel(sc, lp, part)
                   1309:        struct fd_softc *sc;
                   1310:        struct disklabel *lp;
                   1311:        int part;
1.1       leo      1312: {
                   1313:
                   1314:        bzero(lp, sizeof(struct disklabel));
1.10      mycroft  1315:
1.1       leo      1316:        lp->d_secsize     = SECTOR_SIZE;
                   1317:        lp->d_ntracks     = sc->nheads;
                   1318:        lp->d_nsectors    = sc->nsectors;
                   1319:        lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
                   1320:        lp->d_ncylinders  = sc->nblocks / lp->d_secpercyl;
                   1321:        lp->d_secperunit  = sc->nblocks;
                   1322:
                   1323:        lp->d_type        = DTYPE_FLOPPY;
                   1324:        lp->d_rpm         = 300;        /* good guess I suppose.        */
                   1325:        lp->d_interleave  = 1;          /* FIXME: is this OK?           */
                   1326:        lp->d_bbsize      = 0;
                   1327:        lp->d_sbsize      = 0;
                   1328:        lp->d_npartitions = part + 1;
1.10      mycroft  1329:        lp->d_trkseek     = STEP_DELAY;
1.1       leo      1330:        lp->d_magic       = DISKMAGIC;
                   1331:        lp->d_magic2      = DISKMAGIC;
                   1332:        lp->d_checksum    = dkcksum(lp);
                   1333:        lp->d_partitions[part].p_size   = lp->d_secperunit;
                   1334:        lp->d_partitions[part].p_fstype = FS_UNUSED;
                   1335:        lp->d_partitions[part].p_fsize  = 1024;
                   1336:        lp->d_partitions[part].p_frag   = 8;
1.26      thorpej  1337: }
                   1338:
                   1339: /*
                   1340:  * Build disk label. For now we only create a label from what we know
                   1341:  * from 'sc'.
                   1342:  */
                   1343: static int
                   1344: fdgetdisklabel(sc, dev)
                   1345: struct fd_softc *sc;
                   1346: dev_t                  dev;
                   1347: {
                   1348:        struct disklabel        *lp;
                   1349:        int                     part;
                   1350:
                   1351:        /*
                   1352:         * If we already got one, get out.
                   1353:         */
                   1354:        if(sc->flags & FLPF_HAVELAB)
                   1355:                return(0);
                   1356:
                   1357: #ifdef FLP_DEBUG
                   1358:        printf("fdgetdisklabel()\n");
                   1359: #endif
                   1360:
                   1361:        part = RAW_PART;
                   1362:        lp   = sc->dkdev.dk_label;
                   1363:        fdgetdefaultlabel(sc, lp, part);
1.1       leo      1364:        sc->flags        |= FLPF_HAVELAB;
1.10      mycroft  1365:
1.1       leo      1366:        return(0);
                   1367: }

CVSweb <webmaster@jp.NetBSD.org>