Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.3
      1 /*	$NetBSD: fd.c,v 1.3 1995/04/16 14:56:25 leo Exp $	*/
      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 
     51 #include	<sys/param.h>
     52 #include	<sys/systm.h>
     53 #include	<sys/kernel.h>
     54 #include	<sys/malloc.h>
     55 #include	<sys/buf.h>
     56 #include	<sys/device.h>
     57 #include	<sys/ioctl.h>
     58 #include	<sys/fcntl.h>
     59 #include	<sys/conf.h>
     60 #include	<sys/disklabel.h>
     61 #include	<sys/disk.h>
     62 #include	<sys/dkbad.h>
     63 #include	<atari/atari/device.h>
     64 #include	<machine/disklabel.h>
     65 #include	<machine/iomap.h>
     66 #include	<machine/mfp.h>
     67 #include	<machine/dma.h>
     68 #include	<machine/video.h>
     69 #include	<atari/dev/fdreg.h>
     70 
     71 /*
     72  * Be verbose for debugging
     73  */
     74 /*#define FLP_DEBUG		1 */
     75 
     76 #define	FDC_DELAY	64	/* for dma[rw]dat()			*/
     77 #define	FDC_MAX_DMA_AD	0x1000000	/* No DMA possible beyond	*/
     78 
     79 /* Parameters for the disk drive. */
     80 #define SECTOR_SIZE	512	/* physical sector size in bytes	*/
     81 #define NR_DRIVES	2	/* maximum number of drives		*/
     82 #define NR_TYPES	3	/* number of diskette/drive combinations*/
     83 #define MAX_ERRORS	10	/* how often to try rd/wt before quitting*/
     84 #define STEP_DELAY	6000	/* 6ms (6000us) delay after stepping	*/
     85 
     86 
     87 #define	INV_TRK		32000	/* Should fit in unsigned short		*/
     88 #define	INV_PART	NR_TYPES
     89 
     90 /*
     91  * Driver states
     92  */
     93 #define	FLP_IDLE	0x00	/* floppy is idle			*/
     94 #define	FLP_MON		0x01	/* idle with motor on			*/
     95 #define	FLP_STAT	0x02	/* determine floppy status		*/
     96 #define	FLP_XFER	0x04	/* read/write data from floppy		*/
     97 
     98 /*
     99  * Timer delay's
    100  */
    101 #define	FLP_MONDELAY	(3 * hz)	/* motor-on delay		*/
    102 #define	FLP_XFERDELAY	(2 * hz)	/* timeout on transfer		*/
    103 
    104 
    105 #define	b_block		b_resid		/* FIXME: this is not the place	*/
    106 
    107 /*
    108  * Global data for all physical floppy devices
    109  */
    110 static short	selected = 0;		/* drive/head currently selected*/
    111 static short	motoron  = 0;		/* motor is spinning		*/
    112 static short	nopens   = 0;		/* Number of opens executed	*/
    113 
    114 static short	fd_state = FLP_IDLE;/* Current driver state		*/
    115 static short	fd_in_dma= 0;		/* 1: dmagrab() called		*/
    116 static short	fd_cmd   = 0;		/* command being executed	*/
    117 static char	*fd_error= NULL;	/* error from fd_xfer_ok()	*/
    118 
    119 /*
    120  * Private per device data
    121  */
    122 struct fd_softc {
    123 	struct dkdevice dkdev;
    124 	struct buf	bufq;		/* queue of buf's		*/
    125 	int		unit;		/* unit for atari controlling hw*/
    126 	int		nheads;		/* number of heads in use	*/
    127 	int		nsectors;	/* number of sectors/track	*/
    128 	int		nblocks;	/* number of blocks on disk	*/
    129 	int		curtrk;		/* track head positioned on	*/
    130 	short		flags;		/* misc flags			*/
    131 	short		part;		/* Current open partition	*/
    132 	int		sector;		/* logical sector for I/O	*/
    133 	caddr_t		io_data;	/* KVA for data transfer	*/
    134 	int		io_bytes;	/* bytes left for I/O		*/
    135 	int		io_dir;		/* B_READ/B_WRITE		*/
    136 	int		errcnt;		/* current error count		*/
    137 	u_char		*bounceb;	/* Bounce buffer		*/
    138 
    139 };
    140 
    141 /*
    142  * Flags in fd_softc:
    143  */
    144 #define FLPF_NOTRESP	0x01		/* Unit not responding		*/
    145 #define FLPF_ISOPEN	0x02		/* Unit is open			*/
    146 #define FLPF_ISHD	0x04		/* Use High Density		*/
    147 #define FLPF_HAVELAB	0x08		/* We have a valid label	*/
    148 #define FLPF_BOUNCE	0x10		/* Now using the  bounce buffer	*/
    149 
    150 struct fd_types {
    151 	int		nheads;		/* Heads in use			*/
    152 	int		nsectors;	/* sectors per track		*/
    153 	int		nblocks;	/* number of blocks		*/
    154 } fdtypes[NR_TYPES] = {
    155 		{ 1,  9,  720 },	/* 360  Kb	*/
    156 		{ 2,  9, 1440 },	/* 720  Kb	*/
    157 		{ 1, 18, 2880 },	/* 1.44 Mb	*/
    158 };
    159 
    160 typedef void	(*FPV)();
    161 
    162 /*
    163  * Private drive functions....
    164  */
    165 static void	fdstart __P((struct fd_softc *));
    166 static void	fddone __P((struct fd_softc *));
    167 static void	fd_xfer __P((struct fd_softc *));
    168 static int	fdcint __P((struct fd_softc *));
    169 static int	fd_xfer_ok __P((struct fd_softc *));
    170 static void	fdmotoroff __P((struct fd_softc *));
    171 static int	fdminphys __P((struct buf *));
    172 static void	fdtestdrv __P((struct fd_softc *));
    173 static int	fdgetdisklabel __P((struct fd_softc *, dev_t));
    174 
    175 /*
    176  * Autoconfig stuff....
    177  */
    178 static int	fdcmatch __P((struct device *, struct cfdata *, void *));
    179 static int	fdcprint __P((void *, char *));
    180 static void	fdcattach __P((struct device *, struct device *, void *));
    181 
    182 struct cfdriver fdccd = {
    183 	NULL, "fdc", (cfmatch_t)fdcmatch, fdcattach, DV_DULL,
    184 	sizeof(struct device), NULL, 0 };
    185 
    186 static int
    187 fdcmatch(pdp, cfp, auxp)
    188 struct device	*pdp;
    189 struct cfdata	*cfp;
    190 void		*auxp;
    191 {
    192 	if(strcmp("fdc", auxp) || cfp->cf_unit != 0)
    193 		return(0);
    194 	return(1);
    195 }
    196 
    197 static void
    198 fdcattach(pdp, dp, auxp)
    199 struct device	*pdp, *dp;
    200 void		*auxp;
    201 {
    202 	struct fd_softc	fdsoftc;
    203 	int		i, nfound = 0;
    204 
    205 	printf("\n");
    206 	for(i = 0; i < NR_DRIVES; i++) {
    207 
    208 		/*
    209 		 * Test if unit is present
    210 		 */
    211 		fdsoftc.unit  = i;
    212 		fdsoftc.flags = 0;
    213 		dmagrab(fdcint, fdtestdrv, &fdsoftc);
    214 		dmafree();
    215 
    216 		if(!(fdsoftc.flags & FLPF_NOTRESP)) {
    217 			nfound++;
    218 			config_found(dp, (void*)i, fdcprint);
    219 		}
    220 	}
    221 
    222 	if(nfound) {
    223 		/*
    224 		 * enable disk related interrupts
    225 		 */
    226 		MFP->mf_ierb  |= IB_DINT;
    227 		MFP->mf_iprb  &= ~IB_DINT;
    228 		MFP->mf_imrb  |= IB_DINT;
    229 	}
    230 }
    231 
    232 static int
    233 fdcprint(auxp, pnp)
    234 void	*auxp;
    235 char	*pnp;
    236 {
    237 	return(UNCONF);
    238 }
    239 
    240 static int	fdmatch __P((struct device *, struct cfdata *, void *));
    241 static void	fdattach __P((struct device *, struct device *, void *));
    242 	   void fdstrategy __P((struct buf *));
    243 struct dkdriver fddkdriver = { fdstrategy };
    244 
    245 struct cfdriver fdcd = {
    246 	NULL, "fd", (cfmatch_t)fdmatch, fdattach, DV_DISK,
    247 	sizeof(struct fd_softc), NULL, 0 };
    248 
    249 static int
    250 fdmatch(pdp, cfp, auxp)
    251 struct device	*pdp;
    252 struct cfdata	*cfp;
    253 void		*auxp;
    254 {
    255 	int	unit = (int)auxp;
    256 	return(1);
    257 }
    258 
    259 static void
    260 fdattach(pdp, dp, auxp)
    261 struct device	*pdp, *dp;
    262 void		*auxp;
    263 {
    264 	struct fd_softc	*sc;
    265 
    266 	sc = (struct fd_softc *)dp;
    267 
    268 	printf("\n");
    269 
    270 	sc->dkdev.dk_driver = &fddkdriver;
    271 }
    272 
    273 fdioctl(dev, cmd, addr, flag, p)
    274 dev_t		dev;
    275 u_long		cmd;
    276 int		flag;
    277 caddr_t		addr;
    278 struct proc	*p;
    279 {
    280 	struct fd_softc *sc;
    281 	void		*data;
    282 
    283 	sc = getsoftc(fdcd, DISKUNIT(dev));
    284 
    285 	if((sc->flags & FLPF_HAVELAB) == 0)
    286 		return(EBADF);
    287 
    288 	switch(cmd) {
    289 		case DIOCSBAD:
    290 			return(EINVAL);
    291 		case DIOCGDINFO:
    292 			*(struct disklabel *)addr = sc->dkdev.dk_label;
    293 			return(0);
    294 		case DIOCGPART:
    295 			((struct partinfo *)addr)->disklab =
    296 				&sc->dkdev.dk_label;
    297 			((struct partinfo *)addr)->part =
    298 				&sc->dkdev.dk_label.d_partitions[DISKPART(dev)];
    299 			return(0);
    300 #ifdef notyet /* XXX LWP */
    301 		case DIOCSRETRIES:
    302 		case DIOCSSTEP:
    303 		case DIOCSDINFO:
    304 		case DIOCWDINFO:
    305 		case DIOCWLABEL:
    306 #endif /* notyet */
    307 		default:
    308 			return(ENOTTY);
    309 	}
    310 }
    311 
    312 /*
    313  * Open the device. If this is the first open on both the floppy devices,
    314  * intialize the controller.
    315  * Note that partition info on the floppy device is used to distinguise
    316  * between 780Kb and 360Kb floppy's.
    317  *	partition 0: 360Kb
    318  *	partition 1: 780Kb
    319  */
    320 Fdopen(dev, flags, devtype, proc)
    321 dev_t		dev;
    322 int		flags, devtype;
    323 struct proc	*proc;
    324 {
    325 	struct fd_softc	*sc;
    326 	int		sps;
    327 
    328 #ifdef FLP_DEBUG
    329 	printf("Fdopen dev=0x%x\n", dev);
    330 #endif
    331 
    332 	if(DISKPART(dev) >= NR_TYPES)
    333 		return(ENXIO);
    334 
    335 	if((sc = getsoftc(fdcd, DISKUNIT(dev))) == NULL)
    336 		return(ENXIO);
    337 
    338 	/*
    339 	 * If no floppy currently open, reset the controller and select
    340 	 * floppy type.
    341 	 */
    342 	if(!nopens) {
    343 
    344 #ifdef FLP_DEBUG
    345 		printf("Fdopen device not yet open\n");
    346 #endif
    347 		nopens++;
    348 		dmawdat(FDC_CS, IRUPT, FDC_DELAY);
    349 	}
    350 
    351 	if(!(sc->flags & FLPF_ISOPEN)) {
    352 		/*
    353 		 * Initialise some driver values.
    354 		 */
    355 		int	part = DISKPART(dev);
    356 		void	*addr;
    357 
    358 		sc->bufq.b_actf = NULL;
    359 		sc->unit        = DISKUNIT(dev);
    360 		sc->part        = part;
    361 		sc->nheads	= fdtypes[part].nheads;
    362 		sc->nsectors	= fdtypes[part].nsectors;
    363 		sc->nblocks     = fdtypes[part].nblocks;
    364 		sc->curtrk	= INV_TRK;
    365 		sc->sector	= 0;
    366 		sc->errcnt	= 0;
    367 		sc->bounceb	= (u_char*)alloc_stmem(SECTOR_SIZE, &addr);
    368 		if(sc->bounceb == NULL)
    369 			return(ENOMEM); /* XXX */
    370 		if(sc->nsectors > 9) /* XXX */
    371 			sc->flags |= FLPF_ISHD;
    372 
    373 		sc->flags	= FLPF_ISOPEN;
    374 	}
    375 	else {
    376 		/*
    377 		 * Multiply opens are granted when accessing the same type of
    378 		 * floppy (eq. the same partition).
    379 		 */
    380 		if(sc->part != DISKPART(dev))
    381 			return(ENXIO);	/* XXX temporarely out of business */
    382 	}
    383 	fdgetdisklabel(sc, dev);
    384 #ifdef FLP_DEBUG
    385 	printf("Fdopen open succeeded on type %d\n", sc->part);
    386 #endif
    387 }
    388 
    389 fdclose(dev, flags, devtype, proc)
    390 dev_t		dev;
    391 int		flags, devtype;
    392 struct proc	*proc;
    393 {
    394 	struct fd_softc	*sc;
    395 
    396 	sc = getsoftc(fdcd, DISKUNIT(dev));
    397 	free_stmem(sc->bounceb);
    398 	sc->flags = 0;
    399 	nopens--;
    400 
    401 #ifdef FLP_DEBUG
    402 	printf("Closed floppy device -- nopens: %d\n", nopens);
    403 #endif
    404 }
    405 
    406 void
    407 fdstrategy(bp)
    408 struct buf	*bp;
    409 {
    410 	struct fd_softc	*sc;
    411 	int		sps, nblocks;
    412 
    413 	sc   = getsoftc(fdcd, DISKUNIT(bp->b_dev));
    414 
    415 #ifdef FLP_DEBUG
    416 	printf("fdstrategy: 0x%x\n", bp);
    417 #endif
    418 
    419 	/*
    420 	 * check for valid partition and bounds
    421 	 */
    422 	nblocks = (bp->b_bcount + SECTOR_SIZE - 1) / SECTOR_SIZE;
    423 	if((bp->b_blkno < 0) || ((bp->b_blkno + nblocks) >= sc->nblocks)) {
    424 		if((bp->b_blkno == sc->nblocks) && (bp->b_flags & B_READ)) {
    425 			/*
    426 			 * Read 1 block beyond, return EOF
    427 			 */
    428 			bp->b_resid = bp->b_bcount;
    429 			goto done;
    430 		}
    431 		/*
    432 		 * Try to limit the size of the transaction, adjust count
    433 		 * if we succeed.
    434 		 */
    435 		nblocks = sc->nblocks - bp->b_blkno;
    436 		if((nblocks <= 0) || (bp->b_blkno < 0)) {
    437 			bp->b_error  = EINVAL;
    438 			bp->b_flags |= B_ERROR;
    439 			goto done;
    440 		}
    441 		bp->b_bcount = nblocks * SECTOR_SIZE;
    442 	}
    443 	if(bp->b_bcount == 0)
    444 		goto done;
    445 
    446 	/*
    447 	 * Set order info for disksort
    448 	 */
    449 	bp->b_block = bp->b_blkno / (sc->nsectors * sc->nheads);
    450 
    451 	/*
    452 	 * queue the buf and kick the low level code
    453 	 */
    454 	sps = splbio();
    455 	disksort(&sc->bufq, bp);
    456 	if(!fd_in_dma) {
    457 		if(fd_state & FLP_MON)
    458 			untimeout((FPV)fdmotoroff, (void*)sc);
    459 		fd_state = FLP_IDLE;
    460 		fd_in_dma = 1; dmagrab(fdcint, fdstart, sc);
    461 	}
    462 	splx(sps);
    463 
    464 	return;
    465 done:
    466 	bp->b_resid = bp->b_bcount;
    467 	biodone(bp);
    468 }
    469 
    470 /*
    471  * no dumps to floppy disks thank you.
    472  */
    473 int
    474 fddump(dev_t dev)
    475 {
    476 	return(ENXIO);
    477 }
    478 
    479 /*
    480  * no dumps to floppy disks thank you.
    481  */
    482 int
    483 fdsize(dev)
    484 dev_t dev;
    485 {
    486 	return(-1);
    487 }
    488 
    489 int
    490 fdread(dev, uio)
    491 dev_t		dev;
    492 struct uio	*uio;
    493 {
    494 	return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
    495 	    dev, B_READ, fdminphys, uio));
    496 }
    497 
    498 int
    499 fdwrite(dev, uio)
    500 dev_t		dev;
    501 struct uio	*uio;
    502 {
    503 	return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
    504 	    dev, B_WRITE, fdminphys, uio));
    505 }
    506 
    507 /*
    508  * Called through the dma-dispatcher. So we know we are the only ones
    509  * messing with the floppy-controler.
    510  * Initialize some fields in the fdsoftc for the state-machine and get
    511  * it going.
    512  */
    513 static void
    514 fdstart(sc)
    515 struct fd_softc	*sc;
    516 {
    517 	struct buf	*bp;
    518 
    519 	bp           = sc->bufq.b_actf;
    520 	sc->sector   = bp->b_blkno;	/* Start sector for I/O		*/
    521 	sc->io_data  = bp->b_data;	/* KVA base for I/O		*/
    522 	sc->io_bytes = bp->b_bcount;	/* Transfer size in bytes	*/
    523 	sc->io_dir   = bp->b_flags & B_READ;/* Direction of transfer	*/
    524 	sc->errcnt   = 0;		/* No errors yet		*/
    525 	fd_state     = FLP_XFER;	/* Yes, we're going to transfer	*/
    526 
    527 	/*
    528 	 * Make sure the floppy controller is the correct density mode
    529 	 */
    530 	if(sc->flags & FLPF_ISHD)
    531 		DMA->dma_drvmode |= (FDC_HDSET|FDC_HDSIG);
    532 	else DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG);
    533 	fd_xfer(sc);
    534 }
    535 
    536 /*
    537  * The current transaction is finished (for good or bad). Let go of
    538  * the the dma-resources. Call biodone() to finish the transaction.
    539  * Find a new transaction to work on.
    540  */
    541 static void
    542 fddone(sc)
    543 register struct fd_softc	*sc;
    544 {
    545 	struct buf	*bp, *dp;
    546 	struct fd_softc	*sc1;
    547 	int		i;
    548 
    549 	/*
    550 	 * Lower clock frequency of FDC (better for some old ones).
    551 	 */
    552 	DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG);
    553 
    554 	dp = &sc->bufq;
    555 	bp = dp->b_actf;
    556 	if(bp == NULL)
    557 		panic("fddone");
    558 	dp->b_actf = bp->b_actf;
    559 
    560 #ifdef FLP_DEBUG
    561 	printf("fddone: unit: %d, buf: %x, resid: %d\n",sc->unit,bp,
    562 							sc->io_bytes);
    563 #endif
    564 	/*
    565 	 * Give others a chance to use the dma.
    566 	 */
    567 	fd_in_dma = 0; dmafree();
    568 
    569 	/*
    570 	 * Finish current transaction.
    571 	 */
    572 	bp->b_resid = sc->io_bytes;
    573 	biodone(bp);
    574 
    575 	if(fd_in_dma)
    576 		return;		/* XXX Is this possible?	*/
    577 
    578 	/*
    579 	 * Find a new transaction on round-robin basis.
    580 	 */
    581 	for(i = sc->unit + 1; ;i++) {
    582 		if(i >= fdcd.cd_ndevs)
    583 			i = 0;
    584 		if((sc1 = fdcd.cd_devs[i]) == NULL)
    585 			continue;
    586 		if(sc1->bufq.b_actf)
    587 			break;
    588 		if(i == sc->unit) {
    589 			timeout((FPV)fdmotoroff, (void*)sc, FLP_MONDELAY);
    590 #ifdef FLP_DEBUG
    591 			printf("fddone: Nothing to do\n");
    592 #endif
    593 			return;	/* No work */
    594 		}
    595 	}
    596 	fd_state = FLP_IDLE;
    597 #ifdef FLP_DEBUG
    598 	printf("fddone: Staring job on unit %d\n", sc1->unit);
    599 #endif
    600 	fd_in_dma = 1; dmagrab(fdcint, fdstart, sc1);
    601 }
    602 
    603 /****************************************************************************
    604  * The following functions assume to be running as a result of a            *
    605  * disk-interrupt (e.q. spl = splbio).				            *
    606  * They form the finit-state machine, the actual driver.                    *
    607  *                                                                          *
    608  *	fdstart()/ --> fd_xfer() -> activate hardware                       *
    609  *  fdopen()          ^                                                     *
    610  *                    |                                                     *
    611  *                    +-- not ready -<------------+                         *
    612  *                                                |                         *
    613  *  fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+                         *
    614  *  h/w interrupt                 |                                         *
    615  *                               \|/                                        *
    616  *                            finished ---> fdone()                         *
    617  *                                                                          *
    618  ****************************************************************************/
    619 static void
    620 fd_xfer(sc)
    621 struct fd_softc	*sc;
    622 {
    623 	register int	head = 0;
    624 	register int	track, sector, hbit;
    625 		 int	i;
    626 		 u_long	phys_addr;
    627 
    628 	if(fd_state != FLP_XFER)
    629 		panic("fd_xfer: wrong state (0x%x)", fd_state);
    630 
    631 	/*
    632 	 * Calculate head/track values
    633 	 */
    634 	track  = sc->sector / sc->nsectors;
    635 	head   = track % sc->nheads;
    636 	track  = track / sc->nheads;
    637 #ifdef FLP_DEBUG
    638 	printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head,track);
    639 #endif
    640 
    641 	/*
    642 	 * Determine if the controller should check spin-up.
    643 	 */
    644 	hbit = motoron ? HBIT : 0;
    645 	motoron = 1;
    646 
    647 	/*
    648 	 * Select the right unit and head.
    649 	 */
    650 	i = (sc->unit ? PA_FLOP1 : PA_FLOP0) | head;
    651 	if(i != selected) {
    652 		selected = i;
    653 		SOUND->sd_selr = YM_IOA;
    654 		SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07);
    655 	}
    656 
    657 	if(sc->curtrk == INV_TRK) {
    658 		/*
    659 		 * Recalibrate, since we lost track of head positioning.
    660 		 * The floppy disk controller has no way of determining its
    661 		 * absolute arm position (track).  Instead, it steps the
    662 		 * arm a track at a time and keeps track of where it
    663 		 * thinks it is (in software).  However, after a SEEK, the
    664 		 * hardware reads information from the diskette telling
    665 		 * where the arm actually is.  If the arm is in the wrong place,
    666 		 * a recalibration is done, which forces the arm to track 0.
    667 		 * This way the controller can get back into sync with reality.
    668 		 */
    669 		dmawdat(FDC_CS, RESTORE|VBIT|hbit, FDC_DELAY);
    670 		fd_cmd = RESTORE;
    671 		timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
    672 
    673 #ifdef FLP_DEBUG
    674 		printf("fd_xfer:Recalibrating drive %d\n", sc->unit);
    675 #endif
    676 		return;
    677 	}
    678 
    679 	dmawdat(FDC_TR, sc->curtrk, FDC_DELAY);
    680 
    681 	/*
    682 	 * Issue a SEEK command on the indicated drive unless the arm is
    683 	 * already positioned on the correct track.
    684 	 */
    685 	if(track != sc->curtrk) {
    686 		sc->curtrk = track;	/* be optimistic */
    687 		dmawdat(FDC_DR, track, FDC_DELAY);
    688 		dmawdat(FDC_CS, SEEK|RATE6|VBIT|hbit, FDC_DELAY);
    689 		timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
    690 		fd_cmd = SEEK;
    691 #ifdef FLP_DEBUG
    692 		printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit);
    693 #endif
    694 		return;
    695 	}
    696 
    697 	/*
    698 	 * The drive is now on the proper track. Read or write 1 block.
    699 	 */
    700 	sector = sc->sector % sc->nsectors;
    701 	sector++;	/* start numbering at 1 */
    702 
    703 	dmawdat(FDC_SR, sector, FDC_DELAY);
    704 
    705 	phys_addr = (u_long)kvtop(sc->io_data);
    706 	if(phys_addr >= FDC_MAX_DMA_AD) {
    707 		/*
    708 		 * We _must_ bounce this address
    709 		 */
    710 		phys_addr = (u_long)kvtop(sc->bounceb);
    711 		if(sc->io_dir == B_WRITE)
    712 			bcopy(sc->io_data, sc->bounceb, SECTOR_SIZE);
    713 		sc->flags |= FLPF_BOUNCE;
    714 	}
    715 	dmaaddr(phys_addr);	/* DMA address setup */
    716 
    717 #ifdef FLP_DEBUG
    718 	printf("fd_xfer:Start io (io_addr:%x)\n", kvtop(sc->io_data));
    719 #endif
    720 
    721 	if(sc->io_dir == B_READ) {
    722 		/* Issue the command */
    723 		dmacomm(FDC | SCREG, 1, 0);
    724 		dmawdat(FDC_CS, F_READ|hbit, FDC_DELAY);
    725 		fd_cmd = F_READ;
    726 	}
    727 	else {
    728 		/* Issue the command */
    729 		dmacomm(WRBIT | FDC | SCREG, 1, FDC_DELAY);
    730 		dmawdat(WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT, FDC_DELAY);
    731 		fd_cmd = F_WRITE;
    732 	}
    733 	timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
    734 }
    735 
    736 /* return values of fd_xfer_ok(): */
    737 #define X_OK			0
    738 #define X_AGAIN			1
    739 #define X_ERROR			2
    740 #define X_FAIL			3
    741 
    742 /*
    743  * Hardware interrupt function.
    744  */
    745 static int
    746 fdcint(sc)
    747 struct fd_softc	*sc;
    748 {
    749 	struct	buf	*bp;
    750 
    751 #ifdef FLP_DEBUG
    752 	printf("fdcint: unit = %d\n", sc->unit);
    753 #endif
    754 
    755 	/*
    756 	 * Cancel timeout (we made it, didn't we)
    757 	 */
    758 	untimeout((FPV)fdmotoroff, (void*)sc);
    759 
    760 	switch(fd_xfer_ok(sc)) {
    761 		case X_ERROR :
    762 			if(++(sc->errcnt) < MAX_ERRORS) {
    763 				/*
    764 				 * Command failed but still retries left.
    765 				 */
    766 				break;
    767 			}
    768 			/* FALL THROUGH */
    769 		case X_FAIL  :
    770 			/*
    771 			 * Non recoverable error. Fall back to motor-on
    772 			 * idle-state.
    773 			 */
    774 			bp = sc->bufq.b_actf;
    775 
    776 			bp->b_error  = EIO;
    777 			bp->b_flags |= B_ERROR;
    778 			fd_state = FLP_MON;
    779 			if(fd_error != NULL) {
    780 				printf("Floppy error: %s\n", fd_error);
    781 				fd_error = NULL;
    782 			}
    783 
    784 			break;
    785 		case X_AGAIN:
    786 			/*
    787 			 * Start next part of state machine.
    788 			 */
    789 			break;
    790 		case X_OK:
    791 			/*
    792 			 * Command ok and finished. Reset error-counter.
    793 			 * If there are no more bytes to transfer fall back
    794 			 * to motor-on idle state.
    795 			 */
    796 			sc->errcnt = 0;
    797 			if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ))
    798 				bcopy(sc->bounceb, sc->io_data, SECTOR_SIZE);
    799 			sc->flags &= ~FLPF_BOUNCE;
    800 
    801 			sc->sector++;
    802 			sc->io_data  += SECTOR_SIZE;
    803 			sc->io_bytes -= SECTOR_SIZE;
    804 			if(sc->io_bytes <= 0)
    805 				fd_state = FLP_MON;
    806 	}
    807 	if(fd_state == FLP_MON)
    808 		fddone(sc);
    809 	else fd_xfer(sc);
    810 }
    811 
    812 /*
    813  * Determine status of last command. Should only be called through
    814  * 'fdcint()'.
    815  * Returns:
    816  *	X_ERROR : Error on command; might succeed next time.
    817  *	X_FAIL  : Error on command; will never succeed.
    818  *	X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete.
    819  *	X_OK	: Command succeeded and is complete.
    820  *
    821  * This function only affects sc->curtrk.
    822  */
    823 static int
    824 fd_xfer_ok(sc)
    825 register struct fd_softc	*sc;
    826 {
    827 	register int	status;
    828 
    829 	switch(fd_cmd) {
    830 		case IRUPT:
    831 			/*
    832 			 * Timeout. Force a recalibrate before we try again.
    833 			 */
    834 			fd_error = "Timeout";
    835 			sc->curtrk = INV_TRK;
    836 			return(X_ERROR);
    837 		case F_READ:
    838 			/*
    839 			 * Test for DMA error
    840 			 */
    841 			status = dmastat(FDC_CS | SCREG, 0);
    842 			if(!(status & DMAOK)) {
    843 				fd_error = "Dma error";
    844 				return(X_ERROR);
    845 			}
    846 			/*
    847 			 * Get controller status and check for errors.
    848 			 */
    849 			status = dmardat(FDC_CS, FDC_DELAY);
    850 			if(status & (RNF | CRCERR | LD_T00)) {
    851 				fd_error = "Read error";
    852 				if(status & RNF)
    853 					sc->curtrk = INV_TRK;
    854 				return(X_ERROR);
    855 			}
    856 			break;
    857 		case F_WRITE:
    858 			/*
    859 			 * Get controller status and check for errors.
    860 			 */
    861 			status = dmardat(WRBIT | FDC_CS, FDC_DELAY);
    862 			if(status & WRI_PRO) {
    863 				fd_error = "Write protected";
    864 				return(X_FAIL);
    865 			}
    866 			if(status & (RNF | CRCERR | LD_T00)) {
    867 				fd_error = "Write error";
    868 				sc->curtrk = INV_TRK;
    869 				return(X_ERROR);
    870 			}
    871 			break;
    872 		case SEEK:
    873 			status = dmardat(FDC_CS, FDC_DELAY);
    874 			if(status & (RNF | CRCERR)) {
    875 				fd_error = "Seek error";
    876 				sc->curtrk = INV_TRK;
    877 				return(X_ERROR);
    878 			}
    879 			return(X_AGAIN);
    880 		case RESTORE:
    881 			/*
    882 			 * Determine if the recalibration succeeded.
    883 			 */
    884 			status = dmardat(FDC_CS, FDC_DELAY);
    885 			if(status & RNF) {
    886 				fd_error = "Recalibrate error";
    887 				/* reset controller */
    888 				dmawdat(FDC_CS, IRUPT, FDC_DELAY);
    889 				sc->curtrk = INV_TRK;
    890 				return(X_ERROR);
    891 			}
    892 			sc->curtrk = 0;
    893 			return(X_AGAIN);
    894 		default:
    895 			fd_error = "Driver error: fd_xfer_ok : Unknown state";
    896 			return(X_FAIL);
    897 	}
    898 	return(X_OK);
    899 }
    900 
    901 /*
    902  * All timeouts will call this function.
    903  */
    904 static void
    905 fdmotoroff(sc)
    906 struct fd_softc	*sc;
    907 {
    908 	int	sps, wrbit;
    909 
    910 	/*
    911 	 * Get at harware interrupt level
    912 	 */
    913 	sps = splbio();
    914 
    915 #if FLP_DEBUG
    916 	printf("fdmotoroff, state = 0x%x\n", fd_state);
    917 #endif
    918 
    919 	switch(fd_state) {
    920 		case FLP_XFER :
    921 			/*
    922 			 * Timeout during a transfer; cancel transaction
    923 			 * set command to 'IRUPT'.
    924 			 * A drive-interrupt is simulated to trigger the state
    925 			 * machine.
    926 			 */
    927 			/*
    928 			 * Cancel current transaction
    929 			 */
    930 			wrbit = (fd_cmd == F_WRITE) ? WRBIT : 0;
    931 			fd_cmd = IRUPT;
    932 			dmawdat(FDC_CS, wrbit|IRUPT, FDC_DELAY);
    933 
    934 			/*
    935 			 * Simulate floppy interrupt.
    936 			 */
    937 			fdcint(sc);
    938 			return;
    939 		case FLP_MON  :
    940 			/*
    941 			 * Turn motor off.
    942 			 */
    943 			if(selected) {
    944 				SOUND->sd_selr = YM_IOA;
    945 				SOUND->sd_wdat = SOUND->sd_rdat | 0x07;
    946 				motoron = selected = 0;
    947 			}
    948 			fd_state = FLP_IDLE;
    949 			break;
    950 	}
    951 	splx(sps);
    952 }
    953 
    954 /*
    955  * min byte count to whats left of the track in question
    956  */
    957 static int
    958 fdminphys(bp)
    959 struct buf	*bp;
    960 {
    961 	struct fd_softc	*sc;
    962 	int		sec, toff, tsz;
    963 
    964 	if((sc = getsoftc(fdcd, DISKUNIT(bp->b_dev))) == NULL)
    965 		return(ENXIO);
    966 
    967 	sec  = bp->b_blkno % (sc->nsectors * sc->nheads);
    968 	toff = sec * SECTOR_SIZE;
    969 	tsz  = sc->nsectors * sc->nheads * SECTOR_SIZE;
    970 
    971 #ifdef FLP_DEBUG
    972 	printf("fdminphys: before %d", bp->b_bcount);
    973 #endif
    974 
    975 	bp->b_bcount = min(bp->b_bcount, tsz - toff);
    976 
    977 #ifdef FLP_DEBUG
    978 	printf(" after %d\n", bp->b_bcount);
    979 #endif
    980 
    981 	return(bp->b_bcount);
    982 }
    983 
    984 /*
    985  * Used to find out wich drives are actually connected. We do this by issueing
    986  * is 'RESTORE' command and check if the 'track-0' bit is set. This also works
    987  * if the drive is present but no floppy is inserted.
    988  */
    989 static void
    990 fdtestdrv(fdsoftc)
    991 struct fd_softc	*fdsoftc;
    992 {
    993 	int		i, status;
    994 
    995 	/*
    996 	 * Select the right unit and head.
    997 	 */
    998 	i = fdsoftc->unit ? PA_FLOP1 : PA_FLOP0;
    999 	if(i != selected) {
   1000 		selected = i;
   1001 		SOUND->sd_selr = YM_IOA;
   1002 		SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07);
   1003 	}
   1004 
   1005 	dmawdat(FDC_CS, RESTORE|VBIT|HBIT, FDC_DELAY);
   1006 
   1007 	/*
   1008 	 * Wait for about 2 seconds.
   1009 	 */
   1010 	delay(2000000);
   1011 
   1012 	status = dmardat(FDC_CS, FDC_DELAY);
   1013 	if(status & (RNF|BUSY))
   1014 		dmawdat(FDC_CS, IRUPT, FDC_DELAY);	/* reset controller */
   1015 
   1016 	if(!(status & LD_T00))
   1017 		fdsoftc->flags |= FLPF_NOTRESP;
   1018 }
   1019 
   1020 /*
   1021  * Build disk label. For now we only create a label from what we know
   1022  * from 'sc'.
   1023  */
   1024 static int
   1025 fdgetdisklabel(sc, dev)
   1026 struct fd_softc *sc;
   1027 dev_t			dev;
   1028 {
   1029 	struct disklabel	*lp, *dlp;
   1030 	int			part;
   1031 
   1032 	/*
   1033 	 * If we already got one, get out.
   1034 	 */
   1035 	if(sc->flags & FLPF_HAVELAB)
   1036 		return(0);
   1037 
   1038 #ifdef FLP_DEBUG
   1039 	printf("fdgetdisklabel()\n");
   1040 #endif
   1041 
   1042 	part = DISKPART(dev);
   1043 	lp   = &sc->dkdev.dk_label;
   1044 	bzero(lp, sizeof(struct disklabel));
   1045 
   1046 	lp->d_secsize     = SECTOR_SIZE;
   1047 	lp->d_ntracks     = sc->nheads;
   1048 	lp->d_nsectors    = sc->nsectors;
   1049 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1050 	lp->d_ncylinders  = sc->nblocks / lp->d_secpercyl;
   1051 	lp->d_secperunit  = sc->nblocks;
   1052 
   1053 	lp->d_type        = DTYPE_FLOPPY;
   1054 	lp->d_rpm         = 300; 	/* good guess I suppose.	*/
   1055 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1056 	lp->d_bbsize      = 0;
   1057 	lp->d_sbsize      = 0;
   1058 	lp->d_npartitions = part + 1;
   1059 	lp->d_trkseek     = STEP_DELAY;
   1060 	lp->d_magic       = DISKMAGIC;
   1061 	lp->d_magic2      = DISKMAGIC;
   1062 	lp->d_checksum    = dkcksum(lp);
   1063 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1064 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1065 	lp->d_partitions[part].p_fsize  = 1024;
   1066 	lp->d_partitions[part].p_frag   = 8;
   1067 	sc->flags        |= FLPF_HAVELAB;
   1068 
   1069 	return(0);
   1070 }
   1071