Home | History | Annotate | Line # | Download | only in dev
fd.c revision 1.2
      1 /*	$NetBSD: fd.c,v 1.2 1995/04/10 08:56:18 mycroft 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 fdsize(dev)
    475 dev_t dev;
    476 {
    477 	return(-1);
    478 }
    479 
    480 int
    481 fdread(dev, uio)
    482 dev_t		dev;
    483 struct uio	*uio;
    484 {
    485 	return(physio(cdevsw[major(dev)].d_strategy, (struct buf *)NULL,
    486 	    dev, B_READ, fdminphys, uio));
    487 }
    488 
    489 int
    490 fdwrite(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_WRITE, fdminphys, uio));
    496 }
    497 
    498 /*
    499  * Called through the dma-dispatcher. So we know we are the only ones
    500  * messing with the floppy-controler.
    501  * Initialize some fields in the fdsoftc for the state-machine and get
    502  * it going.
    503  */
    504 static void
    505 fdstart(sc)
    506 struct fd_softc	*sc;
    507 {
    508 	struct buf	*bp;
    509 
    510 	bp           = sc->bufq.b_actf;
    511 	sc->sector   = bp->b_blkno;	/* Start sector for I/O		*/
    512 	sc->io_data  = bp->b_data;	/* KVA base for I/O		*/
    513 	sc->io_bytes = bp->b_bcount;	/* Transfer size in bytes	*/
    514 	sc->io_dir   = bp->b_flags & B_READ;/* Direction of transfer	*/
    515 	sc->errcnt   = 0;		/* No errors yet		*/
    516 	fd_state     = FLP_XFER;	/* Yes, we're going to transfer	*/
    517 
    518 	/*
    519 	 * Make sure the floppy controller is the correct density mode
    520 	 */
    521 	if(sc->flags & FLPF_ISHD)
    522 		DMA->dma_drvmode |= (FDC_HDSET|FDC_HDSIG);
    523 	else DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG);
    524 	fd_xfer(sc);
    525 }
    526 
    527 /*
    528  * The current transaction is finished (for good or bad). Let go of
    529  * the the dma-resources. Call biodone() to finish the transaction.
    530  * Find a new transaction to work on.
    531  */
    532 static void
    533 fddone(sc)
    534 register struct fd_softc	*sc;
    535 {
    536 	struct buf	*bp, *dp;
    537 	struct fd_softc	*sc1;
    538 	int		i;
    539 
    540 	/*
    541 	 * Lower clock frequency of FDC (better for some old ones).
    542 	 */
    543 	DMA->dma_drvmode &= ~(FDC_HDSET|FDC_HDSIG);
    544 
    545 	dp = &sc->bufq;
    546 	bp = dp->b_actf;
    547 	if(bp == NULL)
    548 		panic("fddone");
    549 	dp->b_actf = bp->b_actf;
    550 
    551 #ifdef FLP_DEBUG
    552 	printf("fddone: unit: %d, buf: %x, resid: %d\n",sc->unit,bp,
    553 							sc->io_bytes);
    554 #endif
    555 	/*
    556 	 * Give others a chance to use the dma.
    557 	 */
    558 	fd_in_dma = 0; dmafree();
    559 
    560 	/*
    561 	 * Finish current transaction.
    562 	 */
    563 	bp->b_resid = sc->io_bytes;
    564 	biodone(bp);
    565 
    566 	if(fd_in_dma)
    567 		return;		/* XXX Is this possible?	*/
    568 
    569 	/*
    570 	 * Find a new transaction on round-robin basis.
    571 	 */
    572 	for(i = sc->unit + 1; ;i++) {
    573 		if(i >= fdcd.cd_ndevs)
    574 			i = 0;
    575 		if((sc1 = fdcd.cd_devs[i]) == NULL)
    576 			continue;
    577 		if(sc1->bufq.b_actf)
    578 			break;
    579 		if(i == sc->unit) {
    580 			timeout((FPV)fdmotoroff, (void*)sc, FLP_MONDELAY);
    581 #ifdef FLP_DEBUG
    582 			printf("fddone: Nothing to do\n");
    583 #endif
    584 			return;	/* No work */
    585 		}
    586 	}
    587 	fd_state = FLP_IDLE;
    588 #ifdef FLP_DEBUG
    589 	printf("fddone: Staring job on unit %d\n", sc1->unit);
    590 #endif
    591 	fd_in_dma = 1; dmagrab(fdcint, fdstart, sc1);
    592 }
    593 
    594 /****************************************************************************
    595  * The following functions assume to be running as a result of a            *
    596  * disk-interrupt (e.q. spl = splbio).				            *
    597  * They form the finit-state machine, the actual driver.                    *
    598  *                                                                          *
    599  *	fdstart()/ --> fd_xfer() -> activate hardware                       *
    600  *  fdopen()          ^                                                     *
    601  *                    |                                                     *
    602  *                    +-- not ready -<------------+                         *
    603  *                                                |                         *
    604  *  fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+                         *
    605  *  h/w interrupt                 |                                         *
    606  *                               \|/                                        *
    607  *                            finished ---> fdone()                         *
    608  *                                                                          *
    609  ****************************************************************************/
    610 static void
    611 fd_xfer(sc)
    612 struct fd_softc	*sc;
    613 {
    614 	register int	head = 0;
    615 	register int	track, sector, hbit;
    616 		 int	i;
    617 		 u_long	phys_addr;
    618 
    619 	if(fd_state != FLP_XFER)
    620 		panic("fd_xfer: wrong state (0x%x)", fd_state);
    621 
    622 	/*
    623 	 * Calculate head/track values
    624 	 */
    625 	track  = sc->sector / sc->nsectors;
    626 	head   = track % sc->nheads;
    627 	track  = track / sc->nheads;
    628 #ifdef FLP_DEBUG
    629 	printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head,track);
    630 #endif
    631 
    632 	/*
    633 	 * Determine if the controller should check spin-up.
    634 	 */
    635 	hbit = motoron ? HBIT : 0;
    636 	motoron = 1;
    637 
    638 	/*
    639 	 * Select the right unit and head.
    640 	 */
    641 	i = (sc->unit ? PA_FLOP1 : PA_FLOP0) | head;
    642 	if(i != selected) {
    643 		selected = i;
    644 		SOUND->sd_selr = YM_IOA;
    645 		SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07);
    646 	}
    647 
    648 	if(sc->curtrk == INV_TRK) {
    649 		/*
    650 		 * Recalibrate, since we lost track of head positioning.
    651 		 * The floppy disk controller has no way of determining its
    652 		 * absolute arm position (track).  Instead, it steps the
    653 		 * arm a track at a time and keeps track of where it
    654 		 * thinks it is (in software).  However, after a SEEK, the
    655 		 * hardware reads information from the diskette telling
    656 		 * where the arm actually is.  If the arm is in the wrong place,
    657 		 * a recalibration is done, which forces the arm to track 0.
    658 		 * This way the controller can get back into sync with reality.
    659 		 */
    660 		dmawdat(FDC_CS, RESTORE|VBIT|hbit, FDC_DELAY);
    661 		fd_cmd = RESTORE;
    662 		timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
    663 
    664 #ifdef FLP_DEBUG
    665 		printf("fd_xfer:Recalibrating drive %d\n", sc->unit);
    666 #endif
    667 		return;
    668 	}
    669 
    670 	dmawdat(FDC_TR, sc->curtrk, FDC_DELAY);
    671 
    672 	/*
    673 	 * Issue a SEEK command on the indicated drive unless the arm is
    674 	 * already positioned on the correct track.
    675 	 */
    676 	if(track != sc->curtrk) {
    677 		sc->curtrk = track;	/* be optimistic */
    678 		dmawdat(FDC_DR, track, FDC_DELAY);
    679 		dmawdat(FDC_CS, SEEK|RATE6|VBIT|hbit, FDC_DELAY);
    680 		timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
    681 		fd_cmd = SEEK;
    682 #ifdef FLP_DEBUG
    683 		printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit);
    684 #endif
    685 		return;
    686 	}
    687 
    688 	/*
    689 	 * The drive is now on the proper track. Read or write 1 block.
    690 	 */
    691 	sector = sc->sector % sc->nsectors;
    692 	sector++;	/* start numbering at 1 */
    693 
    694 	dmawdat(FDC_SR, sector, FDC_DELAY);
    695 
    696 	phys_addr = (u_long)kvtop(sc->io_data);
    697 	if(phys_addr >= FDC_MAX_DMA_AD) {
    698 		/*
    699 		 * We _must_ bounce this address
    700 		 */
    701 		phys_addr = (u_long)kvtop(sc->bounceb);
    702 		if(sc->io_dir == B_WRITE)
    703 			bcopy(sc->io_data, sc->bounceb, SECTOR_SIZE);
    704 		sc->flags |= FLPF_BOUNCE;
    705 	}
    706 	dmaaddr(phys_addr);	/* DMA address setup */
    707 
    708 #ifdef FLP_DEBUG
    709 	printf("fd_xfer:Start io (io_addr:%x)\n", kvtop(sc->io_data));
    710 #endif
    711 
    712 	if(sc->io_dir == B_READ) {
    713 		/* Issue the command */
    714 		dmacomm(FDC | SCREG, 1, 0);
    715 		dmawdat(FDC_CS, F_READ|hbit, FDC_DELAY);
    716 		fd_cmd = F_READ;
    717 	}
    718 	else {
    719 		/* Issue the command */
    720 		dmacomm(WRBIT | FDC | SCREG, 1, FDC_DELAY);
    721 		dmawdat(WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT, FDC_DELAY);
    722 		fd_cmd = F_WRITE;
    723 	}
    724 	timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
    725 }
    726 
    727 /* return values of fd_xfer_ok(): */
    728 #define X_OK			0
    729 #define X_AGAIN			1
    730 #define X_ERROR			2
    731 #define X_FAIL			3
    732 
    733 /*
    734  * Hardware interrupt function.
    735  */
    736 static int
    737 fdcint(sc)
    738 struct fd_softc	*sc;
    739 {
    740 	struct	buf	*bp;
    741 
    742 #ifdef FLP_DEBUG
    743 	printf("fdcint: unit = %d\n", sc->unit);
    744 #endif
    745 
    746 	/*
    747 	 * Cancel timeout (we made it, didn't we)
    748 	 */
    749 	untimeout((FPV)fdmotoroff, (void*)sc);
    750 
    751 	switch(fd_xfer_ok(sc)) {
    752 		case X_ERROR :
    753 			if(++(sc->errcnt) < MAX_ERRORS) {
    754 				/*
    755 				 * Command failed but still retries left.
    756 				 */
    757 				break;
    758 			}
    759 			/* FALL THROUGH */
    760 		case X_FAIL  :
    761 			/*
    762 			 * Non recoverable error. Fall back to motor-on
    763 			 * idle-state.
    764 			 */
    765 			bp = sc->bufq.b_actf;
    766 
    767 			bp->b_error  = EIO;
    768 			bp->b_flags |= B_ERROR;
    769 			fd_state = FLP_MON;
    770 			if(fd_error != NULL) {
    771 				printf("Floppy error: %s\n", fd_error);
    772 				fd_error = NULL;
    773 			}
    774 
    775 			break;
    776 		case X_AGAIN:
    777 			/*
    778 			 * Start next part of state machine.
    779 			 */
    780 			break;
    781 		case X_OK:
    782 			/*
    783 			 * Command ok and finished. Reset error-counter.
    784 			 * If there are no more bytes to transfer fall back
    785 			 * to motor-on idle state.
    786 			 */
    787 			sc->errcnt = 0;
    788 			if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ))
    789 				bcopy(sc->bounceb, sc->io_data, SECTOR_SIZE);
    790 			sc->flags &= ~FLPF_BOUNCE;
    791 
    792 			sc->sector++;
    793 			sc->io_data  += SECTOR_SIZE;
    794 			sc->io_bytes -= SECTOR_SIZE;
    795 			if(sc->io_bytes <= 0)
    796 				fd_state = FLP_MON;
    797 	}
    798 	if(fd_state == FLP_MON)
    799 		fddone(sc);
    800 	else fd_xfer(sc);
    801 }
    802 
    803 /*
    804  * Determine status of last command. Should only be called through
    805  * 'fdcint()'.
    806  * Returns:
    807  *	X_ERROR : Error on command; might succeed next time.
    808  *	X_FAIL  : Error on command; will never succeed.
    809  *	X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete.
    810  *	X_OK	: Command succeeded and is complete.
    811  *
    812  * This function only affects sc->curtrk.
    813  */
    814 static int
    815 fd_xfer_ok(sc)
    816 register struct fd_softc	*sc;
    817 {
    818 	register int	status;
    819 
    820 	switch(fd_cmd) {
    821 		case IRUPT:
    822 			/*
    823 			 * Timeout. Force a recalibrate before we try again.
    824 			 */
    825 			fd_error = "Timeout";
    826 			sc->curtrk = INV_TRK;
    827 			return(X_ERROR);
    828 		case F_READ:
    829 			/*
    830 			 * Test for DMA error
    831 			 */
    832 			status = dmastat(FDC_CS | SCREG, 0);
    833 			if(!(status & DMAOK)) {
    834 				fd_error = "Dma error";
    835 				return(X_ERROR);
    836 			}
    837 			/*
    838 			 * Get controller status and check for errors.
    839 			 */
    840 			status = dmardat(FDC_CS, FDC_DELAY);
    841 			if(status & (RNF | CRCERR | LD_T00)) {
    842 				fd_error = "Read error";
    843 				if(status & RNF)
    844 					sc->curtrk = INV_TRK;
    845 				return(X_ERROR);
    846 			}
    847 			break;
    848 		case F_WRITE:
    849 			/*
    850 			 * Get controller status and check for errors.
    851 			 */
    852 			status = dmardat(WRBIT | FDC_CS, FDC_DELAY);
    853 			if(status & WRI_PRO) {
    854 				fd_error = "Write protected";
    855 				return(X_FAIL);
    856 			}
    857 			if(status & (RNF | CRCERR | LD_T00)) {
    858 				fd_error = "Write error";
    859 				sc->curtrk = INV_TRK;
    860 				return(X_ERROR);
    861 			}
    862 			break;
    863 		case SEEK:
    864 			status = dmardat(FDC_CS, FDC_DELAY);
    865 			if(status & (RNF | CRCERR)) {
    866 				fd_error = "Seek error";
    867 				sc->curtrk = INV_TRK;
    868 				return(X_ERROR);
    869 			}
    870 			return(X_AGAIN);
    871 		case RESTORE:
    872 			/*
    873 			 * Determine if the recalibration succeeded.
    874 			 */
    875 			status = dmardat(FDC_CS, FDC_DELAY);
    876 			if(status & RNF) {
    877 				fd_error = "Recalibrate error";
    878 				/* reset controller */
    879 				dmawdat(FDC_CS, IRUPT, FDC_DELAY);
    880 				sc->curtrk = INV_TRK;
    881 				return(X_ERROR);
    882 			}
    883 			sc->curtrk = 0;
    884 			return(X_AGAIN);
    885 		default:
    886 			fd_error = "Driver error: fd_xfer_ok : Unknown state";
    887 			return(X_FAIL);
    888 	}
    889 	return(X_OK);
    890 }
    891 
    892 /*
    893  * All timeouts will call this function.
    894  */
    895 static void
    896 fdmotoroff(sc)
    897 struct fd_softc	*sc;
    898 {
    899 	int	sps, wrbit;
    900 
    901 	/*
    902 	 * Get at harware interrupt level
    903 	 */
    904 	sps = splbio();
    905 
    906 #if FLP_DEBUG
    907 	printf("fdmotoroff, state = 0x%x\n", fd_state);
    908 #endif
    909 
    910 	switch(fd_state) {
    911 		case FLP_XFER :
    912 			/*
    913 			 * Timeout during a transfer; cancel transaction
    914 			 * set command to 'IRUPT'.
    915 			 * A drive-interrupt is simulated to trigger the state
    916 			 * machine.
    917 			 */
    918 			/*
    919 			 * Cancel current transaction
    920 			 */
    921 			wrbit = (fd_cmd == F_WRITE) ? WRBIT : 0;
    922 			fd_cmd = IRUPT;
    923 			dmawdat(FDC_CS, wrbit|IRUPT, FDC_DELAY);
    924 
    925 			/*
    926 			 * Simulate floppy interrupt.
    927 			 */
    928 			fdcint(sc);
    929 			return;
    930 		case FLP_MON  :
    931 			/*
    932 			 * Turn motor off.
    933 			 */
    934 			if(selected) {
    935 				SOUND->sd_selr = YM_IOA;
    936 				SOUND->sd_wdat = SOUND->sd_rdat | 0x07;
    937 				motoron = selected = 0;
    938 			}
    939 			fd_state = FLP_IDLE;
    940 			break;
    941 	}
    942 	splx(sps);
    943 }
    944 
    945 /*
    946  * min byte count to whats left of the track in question
    947  */
    948 static int
    949 fdminphys(bp)
    950 struct buf	*bp;
    951 {
    952 	struct fd_softc	*sc;
    953 	int		sec, toff, tsz;
    954 
    955 	if((sc = getsoftc(fdcd, DISKUNIT(bp->b_dev))) == NULL)
    956 		return(ENXIO);
    957 
    958 	sec  = bp->b_blkno % (sc->nsectors * sc->nheads);
    959 	toff = sec * SECTOR_SIZE;
    960 	tsz  = sc->nsectors * sc->nheads * SECTOR_SIZE;
    961 
    962 #ifdef FLP_DEBUG
    963 	printf("fdminphys: before %d", bp->b_bcount);
    964 #endif
    965 
    966 	bp->b_bcount = min(bp->b_bcount, tsz - toff);
    967 
    968 #ifdef FLP_DEBUG
    969 	printf(" after %d\n", bp->b_bcount);
    970 #endif
    971 
    972 	return(bp->b_bcount);
    973 }
    974 
    975 /*
    976  * Used to find out wich drives are actually connected. We do this by issueing
    977  * is 'RESTORE' command and check if the 'track-0' bit is set. This also works
    978  * if the drive is present but no floppy is inserted.
    979  */
    980 static void
    981 fdtestdrv(fdsoftc)
    982 struct fd_softc	*fdsoftc;
    983 {
    984 	int		i, status;
    985 
    986 	/*
    987 	 * Select the right unit and head.
    988 	 */
    989 	i = fdsoftc->unit ? PA_FLOP1 : PA_FLOP0;
    990 	if(i != selected) {
    991 		selected = i;
    992 		SOUND->sd_selr = YM_IOA;
    993 		SOUND->sd_wdat = (SOUND->sd_rdat & 0xF8) | (i ^ 0x07);
    994 	}
    995 
    996 	dmawdat(FDC_CS, RESTORE|VBIT|HBIT, FDC_DELAY);
    997 
    998 	/*
    999 	 * Wait for about 2 seconds.
   1000 	 */
   1001 	delay(2000000);
   1002 
   1003 	status = dmardat(FDC_CS, FDC_DELAY);
   1004 	if(status & (RNF|BUSY))
   1005 		dmawdat(FDC_CS, IRUPT, FDC_DELAY);	/* reset controller */
   1006 
   1007 	if(!(status & LD_T00))
   1008 		fdsoftc->flags |= FLPF_NOTRESP;
   1009 }
   1010 
   1011 /*
   1012  * Build disk label. For now we only create a label from what we know
   1013  * from 'sc'.
   1014  */
   1015 static int
   1016 fdgetdisklabel(sc, dev)
   1017 struct fd_softc *sc;
   1018 dev_t			dev;
   1019 {
   1020 	struct disklabel	*lp, *dlp;
   1021 	int			part;
   1022 
   1023 	/*
   1024 	 * If we already got one, get out.
   1025 	 */
   1026 	if(sc->flags & FLPF_HAVELAB)
   1027 		return(0);
   1028 
   1029 #ifdef FLP_DEBUG
   1030 	printf("fdgetdisklabel()\n");
   1031 #endif
   1032 
   1033 	part = DISKPART(dev);
   1034 	lp   = &sc->dkdev.dk_label;
   1035 	bzero(lp, sizeof(struct disklabel));
   1036 
   1037 	lp->d_secsize     = SECTOR_SIZE;
   1038 	lp->d_ntracks     = sc->nheads;
   1039 	lp->d_nsectors    = sc->nsectors;
   1040 	lp->d_secpercyl   = lp->d_ntracks * lp->d_nsectors;
   1041 	lp->d_ncylinders  = sc->nblocks / lp->d_secpercyl;
   1042 	lp->d_secperunit  = sc->nblocks;
   1043 
   1044 	lp->d_type        = DTYPE_FLOPPY;
   1045 	lp->d_rpm         = 300; 	/* good guess I suppose.	*/
   1046 	lp->d_interleave  = 1;		/* FIXME: is this OK?		*/
   1047 	lp->d_bbsize      = 0;
   1048 	lp->d_sbsize      = 0;
   1049 	lp->d_npartitions = part + 1;
   1050 	lp->d_trkseek     = STEP_DELAY;
   1051 	lp->d_magic       = DISKMAGIC;
   1052 	lp->d_magic2      = DISKMAGIC;
   1053 	lp->d_checksum    = dkcksum(lp);
   1054 	lp->d_partitions[part].p_size   = lp->d_secperunit;
   1055 	lp->d_partitions[part].p_fstype = FS_UNUSED;
   1056 	lp->d_partitions[part].p_fsize  = 1024;
   1057 	lp->d_partitions[part].p_frag   = 8;
   1058 	sc->flags        |= FLPF_HAVELAB;
   1059 
   1060 	return(0);
   1061 }
   1062