xref: /netbsd-src/sys/arch/atari/dev/fd.c (revision ce0bb6e8d2e560ecacbe865a848624f94498063b)
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