fd.c revision 1.16 1 /* $NetBSD: fd.c,v 1.16 1996/03/17 01:26:45 thorpej 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/proc.h>
57 #include <sys/device.h>
58 #include <sys/ioctl.h>
59 #include <sys/fcntl.h>
60 #include <sys/conf.h>
61 #include <sys/disklabel.h>
62 #include <sys/disk.h>
63 #include <sys/dkbad.h>
64 #include <atari/atari/device.h>
65 #include <machine/disklabel.h>
66 #include <machine/iomap.h>
67 #include <machine/mfp.h>
68 #include <machine/dma.h>
69 #include <machine/video.h>
70 #include <atari/dev/fdreg.h>
71
72 /*
73 * Be verbose for debugging
74 */
75 /*#define FLP_DEBUG 1 */
76
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 * The density codes
106 */
107 #define FLP_DD 0 /* Double density */
108 #define FLP_HD 1 /* High density */
109
110
111 #define b_block b_resid /* FIXME: this is not the place */
112
113 /*
114 * Global data for all physical floppy devices
115 */
116 static short selected = 0; /* drive/head currently selected*/
117 static short motoron = 0; /* motor is spinning */
118 static short nopens = 0; /* Number of opens executed */
119
120 static short fd_state = FLP_IDLE; /* Current driver state */
121 static int lock_stat= 0; /* dma locking status */
122 static short fd_cmd = 0; /* command being executed */
123 static char *fd_error= NULL; /* error from fd_xfer_ok() */
124
125 /*
126 * Private per device data
127 */
128 struct fd_softc {
129 struct device sc_dv; /* generic device info */
130 struct disk dkdev; /* generic disk info */
131 struct buf bufq; /* queue of buf's */
132 int unit; /* unit for atari controlling hw*/
133 int nheads; /* number of heads in use */
134 int nsectors; /* number of sectors/track */
135 int density; /* density code */
136 int nblocks; /* number of blocks on disk */
137 int curtrk; /* track head positioned on */
138 short flags; /* misc flags */
139 short part; /* Current open partition */
140 int sector; /* logical sector for I/O */
141 caddr_t io_data; /* KVA for data transfer */
142 int io_bytes; /* bytes left for I/O */
143 int io_dir; /* B_READ/B_WRITE */
144 int errcnt; /* current error count */
145 u_char *bounceb; /* Bounce buffer */
146
147 };
148
149 /*
150 * Flags in fd_softc:
151 */
152 #define FLPF_NOTRESP 0x001 /* Unit not responding */
153 #define FLPF_ISOPEN 0x002 /* Unit is open */
154 #define FLPF_SPARE 0x004 /* Not used */
155 #define FLPF_HAVELAB 0x008 /* We have a valid label */
156 #define FLPF_BOUNCE 0x010 /* Now using the bounce buffer */
157 #define FLPF_WRTPROT 0x020 /* Unit is write-protected */
158 #define FLPF_EMPTY 0x040 /* Unit is empty */
159 #define FLPF_INOPEN 0x080 /* Currently being opened */
160 #define FLPF_GETSTAT 0x100 /* Getting unit status */
161
162 struct fd_types {
163 int nheads; /* Heads in use */
164 int nsectors; /* sectors per track */
165 int nblocks; /* number of blocks */
166 int density; /* density code */
167 } fdtypes[NR_TYPES] = {
168 { 1, 9, 720 , FLP_DD }, /* 360 Kb */
169 { 2, 9, 1440 , FLP_DD }, /* 720 Kb */
170 { 2, 18, 2880 , FLP_HD }, /* 1.44 Mb */
171 };
172
173 typedef void (*FPV)();
174
175 /*
176 * {b,c}devsw[] function prototypes
177 */
178 dev_type_open(Fdopen);
179 dev_type_close(fdclose);
180 dev_type_read(fdread);
181 dev_type_write(fdwrite);
182 dev_type_ioctl(fdioctl);
183 dev_type_size(fdsize);
184 dev_type_dump(fddump);
185
186 /*
187 * Private drive functions....
188 */
189 static void fdstart __P((struct fd_softc *));
190 static void fddone __P((struct fd_softc *));
191 static void fdstatus __P((struct fd_softc *));
192 static void fd_xfer __P((struct fd_softc *));
193 static void fdcint __P((struct fd_softc *));
194 static int fd_xfer_ok __P((struct fd_softc *));
195 static void fdmotoroff __P((struct fd_softc *));
196 static void fdminphys __P((struct buf *));
197 static void fdtestdrv __P((struct fd_softc *));
198 static int fdgetdisklabel __P((struct fd_softc *, dev_t));
199 static int fdselect __P((int, int, int));
200 static void fddeselect __P((void));
201 static void fdmoff __P((struct fd_softc *));
202
203 extern __inline__ u_char read_fdreg(u_short regno)
204 {
205 DMA->dma_mode = regno;
206 return(DMA->dma_data);
207 }
208
209 extern __inline__ void write_fdreg(u_short regno, u_short val)
210 {
211 DMA->dma_mode = regno;
212 DMA->dma_data = val;
213 }
214
215 extern __inline__ u_char read_dmastat(void)
216 {
217 DMA->dma_mode = FDC_CS | DMA_SCREG;
218 return(DMA->dma_stat);
219 }
220
221 /*
222 * Autoconfig stuff....
223 */
224 static int fdcmatch __P((struct device *, void *, void *));
225 static int fdcprint __P((void *, char *));
226 static void fdcattach __P((struct device *, struct device *, void *));
227
228 struct cfattach fdc_ca = {
229 sizeof(struct device), fdcmatch, fdcattach
230 };
231
232 struct cfdriver fdc_cd = {
233 NULL, "fdc", DV_DULL, NULL, 0
234 };
235
236 static int
237 fdcmatch(pdp, match, auxp)
238 struct device *pdp;
239 void *match, *auxp;
240 {
241 struct cfdata *cfp = match;
242
243 if(strcmp("fdc", auxp) || cfp->cf_unit != 0)
244 return(0);
245 return(1);
246 }
247
248 static void
249 fdcattach(pdp, dp, auxp)
250 struct device *pdp, *dp;
251 void *auxp;
252 {
253 extern struct cfdriver fd_cd;
254 struct fd_softc fdsoftc;
255 int i, nfound, first_found;
256
257 nfound = first_found = 0;
258 printf("\n");
259 fddeselect();
260 for(i = 0; i < NR_DRIVES; i++) {
261
262 /*
263 * Test if unit is present
264 */
265 fdsoftc.unit = i;
266 fdsoftc.flags = 0;
267 st_dmagrab((dma_farg)fdcint, (dma_farg)fdtestdrv, &fdsoftc,
268 &lock_stat, 0);
269 st_dmafree(&fdsoftc, &lock_stat);
270
271 if(!(fdsoftc.flags & FLPF_NOTRESP)) {
272 if(!nfound)
273 first_found = i;
274 nfound++;
275 config_found(dp, (void*)i, fdcprint);
276 }
277 }
278
279 if(nfound) {
280
281 /*
282 * Make sure motor will be turned of when a floppy is
283 * inserted in the first selected drive.
284 */
285 fdselect(first_found, 0, FLP_DD);
286 fd_state = FLP_MON;
287 timeout((FPV)fdmotoroff, (void*)getsoftc(fd_cd, first_found),
288 FLP_MONDELAY);
289
290 /*
291 * enable disk related interrupts
292 */
293 MFP->mf_ierb |= IB_DINT;
294 MFP->mf_iprb &= ~IB_DINT;
295 MFP->mf_imrb |= IB_DINT;
296 }
297 }
298
299 static int
300 fdcprint(auxp, pnp)
301 void *auxp;
302 char *pnp;
303 {
304 return(UNCONF);
305 }
306
307 static int fdmatch __P((struct device *, void *, void *));
308 static void fdattach __P((struct device *, struct device *, void *));
309 void fdstrategy __P((struct buf *));
310 struct dkdriver fddkdriver = { fdstrategy };
311
312 struct cfattach fd_ca = {
313 sizeof(struct fd_softc), fdmatch, fdattach
314 };
315
316 struct cfdriver fd_cd = {
317 NULL, "fd", DV_DISK, NULL, 0
318 };
319
320 static int
321 fdmatch(pdp, match, auxp)
322 struct device *pdp;
323 void *match, *auxp;
324 {
325 return(1);
326 }
327
328 static void
329 fdattach(pdp, dp, auxp)
330 struct device *pdp, *dp;
331 void *auxp;
332 {
333 struct fd_softc *sc;
334
335 sc = (struct fd_softc *)dp;
336
337 printf("\n");
338
339 /*
340 * Initialize and attach the disk structure.
341 */
342 sc->dkdev.dk_name = sc->sc_dv.dv_xname;
343 sc->dkdev.dk_driver = &fddkdriver;
344 disk_attach(&sc->dkdev);
345 }
346
347 int
348 fdioctl(dev, cmd, addr, flag, p)
349 dev_t dev;
350 u_long cmd;
351 int flag;
352 caddr_t addr;
353 struct proc *p;
354 {
355 struct fd_softc *sc;
356
357 sc = getsoftc(fd_cd, DISKUNIT(dev));
358
359 if((sc->flags & FLPF_HAVELAB) == 0)
360 return(EBADF);
361
362 switch(cmd) {
363 case DIOCSBAD:
364 return(EINVAL);
365 case DIOCGDINFO:
366 *(struct disklabel *)addr = *(sc->dkdev.dk_label);
367 return(0);
368 case DIOCGPART:
369 ((struct partinfo *)addr)->disklab =
370 sc->dkdev.dk_label;
371 ((struct partinfo *)addr)->part =
372 &sc->dkdev.dk_label->d_partitions[DISKPART(dev)];
373 return(0);
374 #ifdef notyet /* XXX LWP */
375 case DIOCSRETRIES:
376 case DIOCSSTEP:
377 case DIOCSDINFO:
378 case DIOCWDINFO:
379 case DIOCWLABEL:
380 #endif /* notyet */
381 }
382 return(ENOTTY);
383 }
384
385 /*
386 * Open the device. If this is the first open on both the floppy devices,
387 * intialize the controller.
388 * Note that partition info on the floppy device is used to distinguise
389 * between 780Kb and 360Kb floppy's.
390 * partition 0: 360Kb
391 * partition 1: 780Kb
392 */
393 int
394 Fdopen(dev, flags, devtype, proc)
395 dev_t dev;
396 int flags, devtype;
397 struct proc *proc;
398 {
399 struct fd_softc *sc;
400 int sps;
401
402 #ifdef FLP_DEBUG
403 printf("Fdopen dev=0x%x\n", dev);
404 #endif
405
406 if(DISKPART(dev) >= NR_TYPES)
407 return(ENXIO);
408
409 if((sc = getsoftc(fd_cd, DISKUNIT(dev))) == NULL)
410 return(ENXIO);
411
412 /*
413 * If no floppy currently open, reset the controller and select
414 * floppy type.
415 */
416 if(!nopens) {
417
418 #ifdef FLP_DEBUG
419 printf("Fdopen device not yet open\n");
420 #endif
421 nopens++;
422 write_fdreg(FDC_CS, IRUPT);
423 delay(40);
424 }
425
426 /*
427 * Sleep while other process is opening the device
428 */
429 sps = splbio();
430 while(sc->flags & FLPF_INOPEN)
431 tsleep((caddr_t)sc, PRIBIO, "Fdopen", 0);
432 splx(sps);
433
434 if(!(sc->flags & FLPF_ISOPEN)) {
435 /*
436 * Initialise some driver values.
437 */
438 int part = DISKPART(dev);
439 void *addr;
440
441 sc->bufq.b_actf = NULL;
442 sc->unit = DISKUNIT(dev);
443 sc->part = part;
444 sc->nheads = fdtypes[part].nheads;
445 sc->nsectors = fdtypes[part].nsectors;
446 sc->nblocks = fdtypes[part].nblocks;
447 sc->density = fdtypes[part].density;
448 sc->curtrk = INV_TRK;
449 sc->sector = 0;
450 sc->errcnt = 0;
451 sc->bounceb = (u_char*)alloc_stmem(SECTOR_SIZE, &addr);
452 if(sc->bounceb == NULL)
453 return(ENOMEM); /* XXX */
454
455 /*
456 * Go get write protect + loaded status
457 */
458 sc->flags |= FLPF_INOPEN|FLPF_GETSTAT;
459 sps = splbio();
460 st_dmagrab((dma_farg)fdcint, (dma_farg)fdstatus, sc,
461 &lock_stat, 0);
462 while(sc->flags & FLPF_GETSTAT)
463 tsleep((caddr_t)sc, PRIBIO, "Fdopen", 0);
464 splx(sps);
465 wakeup((caddr_t)sc);
466
467 if((sc->flags & FLPF_WRTPROT) && (flags & FWRITE)) {
468 sc->flags = 0;
469 return(EPERM);
470 }
471 if(sc->flags & FLPF_EMPTY) {
472 sc->flags = 0;
473 return(ENXIO);
474 }
475 sc->flags &= ~(FLPF_INOPEN|FLPF_GETSTAT);
476 sc->flags |= FLPF_ISOPEN;
477 }
478 else {
479 /*
480 * Multiply opens are granted when accessing the same type of
481 * floppy (eq. the same partition).
482 */
483 if(sc->part != DISKPART(dev))
484 return(ENXIO); /* XXX temporarely out of business */
485 }
486 fdgetdisklabel(sc, dev);
487 #ifdef FLP_DEBUG
488 printf("Fdopen open succeeded on type %d\n", sc->part);
489 #endif
490 return (0);
491 }
492
493 int
494 fdclose(dev, flags, devtype, proc)
495 dev_t dev;
496 int flags, devtype;
497 struct proc *proc;
498 {
499 struct fd_softc *sc;
500
501 sc = getsoftc(fd_cd, DISKUNIT(dev));
502 free_stmem(sc->bounceb);
503 sc->flags = 0;
504 nopens--;
505
506 #ifdef FLP_DEBUG
507 printf("Closed floppy device -- nopens: %d\n", nopens);
508 #endif
509 return(0);
510 }
511
512 void
513 fdstrategy(bp)
514 struct buf *bp;
515 {
516 struct fd_softc *sc;
517 struct disklabel *lp;
518 int sps;
519
520 sc = getsoftc(fd_cd, DISKUNIT(bp->b_dev));
521
522 #ifdef FLP_DEBUG
523 printf("fdstrategy: 0x%x\n", bp);
524 #endif
525
526 /*
527 * check for valid partition and bounds
528 */
529 lp = sc->dkdev.dk_label;
530 if ((sc->flags & FLPF_HAVELAB) == 0) {
531 bp->b_error = EIO;
532 goto bad;
533 }
534 if (bounds_check_with_label(bp, lp, 0) <= 0)
535 goto done;
536
537 if (bp->b_bcount == 0)
538 goto done;
539
540 /*
541 * queue the buf and kick the low level code
542 */
543 sps = splbio();
544 disksort(&sc->bufq, bp);
545 if (!lock_stat) {
546 if (fd_state & FLP_MON)
547 untimeout((FPV)fdmotoroff, (void*)sc);
548 fd_state = FLP_IDLE;
549 st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc,
550 &lock_stat, 0);
551 }
552 splx(sps);
553
554 return;
555 bad:
556 bp->b_flags |= B_ERROR;
557 done:
558 bp->b_resid = bp->b_bcount;
559 biodone(bp);
560 }
561
562 /*
563 * no dumps to floppy disks thank you.
564 */
565 int
566 fddump(dev, blkno, va, size)
567 dev_t dev;
568 daddr_t blkno;
569 caddr_t va;
570 size_t size;
571 {
572 return(ENXIO);
573 }
574
575 /*
576 * no dumps to floppy disks thank you.
577 */
578 int
579 fdsize(dev)
580 dev_t dev;
581 {
582 return(-1);
583 }
584
585 int
586 fdread(dev, uio, flags)
587 dev_t dev;
588 struct uio *uio;
589 int flags;
590 {
591 return(physio(fdstrategy, NULL, dev, B_READ, fdminphys, uio));
592 }
593
594 int
595 fdwrite(dev, uio, flags)
596 dev_t dev;
597 struct uio *uio;
598 int flags;
599 {
600 return(physio(fdstrategy, NULL, dev, B_WRITE, fdminphys, uio));
601 }
602
603 /*
604 * Called through DMA-dispatcher, get status.
605 */
606 static void
607 fdstatus(sc)
608 struct fd_softc *sc;
609 {
610 #ifdef FLP_DEBUG
611 printf("fdstatus\n");
612 #endif
613 sc->errcnt = 0;
614 fd_state = FLP_STAT;
615 fd_xfer(sc);
616 }
617
618 /*
619 * Called through the dma-dispatcher. So we know we are the only ones
620 * messing with the floppy-controler.
621 * Initialize some fields in the fdsoftc for the state-machine and get
622 * it going.
623 */
624 static void
625 fdstart(sc)
626 struct fd_softc *sc;
627 {
628 struct buf *bp;
629
630 bp = sc->bufq.b_actf;
631 sc->sector = bp->b_blkno; /* Start sector for I/O */
632 sc->io_data = bp->b_data; /* KVA base for I/O */
633 sc->io_bytes = bp->b_bcount; /* Transfer size in bytes */
634 sc->io_dir = bp->b_flags & B_READ;/* Direction of transfer */
635 sc->errcnt = 0; /* No errors yet */
636 fd_state = FLP_XFER; /* Yes, we're going to transfer */
637
638 /* Instrumentation. */
639 disk_busy(&sc->dkdev);
640
641 fd_xfer(sc);
642 }
643
644 /*
645 * The current transaction is finished (for good or bad). Let go of
646 * the the dma-resources. Call biodone() to finish the transaction.
647 * Find a new transaction to work on.
648 */
649 static void
650 fddone(sc)
651 register struct fd_softc *sc;
652 {
653 struct buf *bp, *dp;
654 struct fd_softc *sc1;
655 int i, sps;
656
657 /*
658 * Give others a chance to use the dma.
659 */
660 st_dmafree(sc, &lock_stat);
661
662
663 if(fd_state != FLP_STAT) {
664 /*
665 * Finish current transaction.
666 */
667 sps = splbio();
668 dp = &sc->bufq;
669 bp = dp->b_actf;
670 if(bp == NULL)
671 panic("fddone");
672 dp->b_actf = bp->b_actf;
673 splx(sps);
674
675 #ifdef FLP_DEBUG
676 printf("fddone: unit: %d, buf: %x, resid: %d\n",sc->unit,bp,
677 sc->io_bytes);
678 #endif
679 bp->b_resid = sc->io_bytes;
680
681 disk_unbusy(&sc->dkdev, (bp->b_bcount - bp->b_resid));
682
683 biodone(bp);
684 }
685 fd_state = FLP_MON;
686
687 if(lock_stat)
688 return; /* XXX Is this possible? */
689
690 /*
691 * Find a new transaction on round-robin basis.
692 */
693 for(i = sc->unit + 1; ;i++) {
694 if(i >= fd_cd.cd_ndevs)
695 i = 0;
696 if((sc1 = fd_cd.cd_devs[i]) == NULL)
697 continue;
698 if(sc1->bufq.b_actf)
699 break;
700 if(i == sc->unit) {
701 timeout((FPV)fdmotoroff, (void*)sc, FLP_MONDELAY);
702 #ifdef FLP_DEBUG
703 printf("fddone: Nothing to do\n");
704 #endif
705 return; /* No work */
706 }
707 }
708 fd_state = FLP_IDLE;
709 #ifdef FLP_DEBUG
710 printf("fddone: Staring job on unit %d\n", sc1->unit);
711 #endif
712 st_dmagrab((dma_farg)fdcint, (dma_farg)fdstart, sc1, &lock_stat, 0);
713 }
714
715 static int
716 fdselect(drive, head, dense)
717 int drive, head, dense;
718 {
719 int i, sps, spinning;
720 #ifdef FLP_DEBUG
721 printf("fdselect: drive=%d, head=%d, dense=%d\n", drive, head, dense);
722 #endif
723 i = ((drive == 1) ? PA_FLOP1 : PA_FLOP0) | head;
724 spinning = motoron;
725 motoron = 1;
726
727 switch(dense) {
728 case FLP_DD:
729 DMA->dma_drvmode = 0;
730 break;
731 case FLP_HD:
732 DMA->dma_drvmode = (FDC_HDSET|FDC_HDSIG);
733 break;
734 default:
735 panic("fdselect: unknown density code\n");
736 }
737 if(i != selected) {
738 sps = splhigh();
739
740 selected = i;
741 SOUND->sd_selr = YM_IOA;
742 SOUND->sd_wdat = (SOUND->sd_rdat & 0x78) | (i ^ 0x07);
743 splx(sps);
744 }
745 return(spinning);
746 }
747
748 static void
749 fddeselect()
750 {
751 int sps;
752
753 sps = splhigh();
754 SOUND->sd_selr = YM_IOA;
755 SOUND->sd_wdat = SOUND->sd_rdat | 0x07;
756 splx(sps);
757
758 motoron = selected = 0;
759 DMA->dma_drvmode = 0;
760 }
761
762 /****************************************************************************
763 * The following functions assume to be running as a result of a *
764 * disk-interrupt (e.q. spl = splbio). *
765 * They form the finit-state machine, the actual driver. *
766 * *
767 * fdstart()/ --> fd_xfer() -> activate hardware *
768 * fdopen() ^ *
769 * | *
770 * +-- not ready -<------------+ *
771 * | *
772 * fdmotoroff()/ --> fdcint() -> fd_xfer_ok() ---+ *
773 * h/w interrupt | *
774 * \|/ *
775 * finished ---> fdone() *
776 * *
777 ****************************************************************************/
778 static void
779 fd_xfer(sc)
780 struct fd_softc *sc;
781 {
782 register int head;
783 register int track, sector, hbit;
784 u_long phys_addr;
785
786 head = track = 0;
787 switch(fd_state) {
788 case FLP_XFER:
789 /*
790 * Calculate head/track values
791 */
792 track = sc->sector / sc->nsectors;
793 head = track % sc->nheads;
794 track = track / sc->nheads;
795 #ifdef FLP_DEBUG
796 printf("fd_xfer: sector:%d,head:%d,track:%d\n", sc->sector,head,
797 track);
798 #endif
799 break;
800
801 case FLP_STAT:
802 /*
803 * FLP_STAT only wants to recalibrate
804 */
805 sc->curtrk = INV_TRK;
806 break;
807 default:
808 panic("fd_xfer: wrong state (0x%x)", fd_state);
809 }
810
811 /*
812 * Select the drive.
813 */
814 hbit = fdselect(sc->unit, head, sc->density) ? HBIT : 0;
815
816 if(sc->curtrk == INV_TRK) {
817 /*
818 * Recalibrate, since we lost track of head positioning.
819 * The floppy disk controller has no way of determining its
820 * absolute arm position (track). Instead, it steps the
821 * arm a track at a time and keeps track of where it
822 * thinks it is (in software). However, after a SEEK, the
823 * hardware reads information from the diskette telling
824 * where the arm actually is. If the arm is in the wrong place,
825 * a recalibration is done, which forces the arm to track 0.
826 * This way the controller can get back into sync with reality.
827 */
828 fd_cmd = RESTORE;
829 write_fdreg(FDC_CS, RESTORE|VBIT|hbit);
830 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
831
832 #ifdef FLP_DEBUG
833 printf("fd_xfer:Recalibrating drive %d\n", sc->unit);
834 #endif
835 return;
836 }
837
838 write_fdreg(FDC_TR, sc->curtrk);
839
840 /*
841 * Issue a SEEK command on the indicated drive unless the arm is
842 * already positioned on the correct track.
843 */
844 if(track != sc->curtrk) {
845 sc->curtrk = track; /* be optimistic */
846 write_fdreg(FDC_DR, track);
847 write_fdreg(FDC_CS, SEEK|RATE6|VBIT|hbit);
848 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
849 fd_cmd = SEEK;
850 #ifdef FLP_DEBUG
851 printf("fd_xfer:Seek to track %d on drive %d\n",track,sc->unit);
852 #endif
853 return;
854 }
855
856 /*
857 * The drive is now on the proper track. Read or write 1 block.
858 */
859 sector = sc->sector % sc->nsectors;
860 sector++; /* start numbering at 1 */
861
862 write_fdreg(FDC_SR, sector);
863
864 phys_addr = (u_long)kvtop(sc->io_data);
865 if(phys_addr >= FDC_MAX_DMA_AD) {
866 /*
867 * We _must_ bounce this address
868 */
869 phys_addr = (u_long)kvtop(sc->bounceb);
870 if(sc->io_dir == B_WRITE)
871 bcopy(sc->io_data, sc->bounceb, SECTOR_SIZE);
872 sc->flags |= FLPF_BOUNCE;
873 }
874 st_dmaaddr_set((caddr_t)phys_addr); /* DMA address setup */
875
876 #ifdef FLP_DEBUG
877 printf("fd_xfer:Start io (io_addr:%x)\n", kvtop(sc->io_data));
878 #endif
879
880 if(sc->io_dir == B_READ) {
881 /* Issue the command */
882 st_dmacomm(DMA_FDC | DMA_SCREG, 1);
883 write_fdreg(FDC_CS, F_READ|hbit);
884 fd_cmd = F_READ;
885 }
886 else {
887 /* Issue the command */
888 st_dmacomm(DMA_WRBIT | DMA_FDC | DMA_SCREG, 1);
889 write_fdreg(DMA_WRBIT | FDC_CS, F_WRITE|hbit|EBIT|PBIT);
890 fd_cmd = F_WRITE;
891 }
892 timeout((FPV)fdmotoroff, (void*)sc, FLP_XFERDELAY);
893 }
894
895 /* return values of fd_xfer_ok(): */
896 #define X_OK 0
897 #define X_AGAIN 1
898 #define X_ERROR 2
899 #define X_FAIL 3
900
901 /*
902 * Hardware interrupt function.
903 */
904 static void
905 fdcint(sc)
906 struct fd_softc *sc;
907 {
908 struct buf *bp;
909
910 #ifdef FLP_DEBUG
911 printf("fdcint: unit = %d\n", sc->unit);
912 #endif
913
914 /*
915 * Cancel timeout (we made it, didn't we)
916 */
917 untimeout((FPV)fdmotoroff, (void*)sc);
918
919 switch(fd_xfer_ok(sc)) {
920 case X_ERROR :
921 if(++(sc->errcnt) < MAX_ERRORS) {
922 /*
923 * Command failed but still retries left.
924 */
925 break;
926 }
927 /* FALL THROUGH */
928 case X_FAIL :
929 /*
930 * Non recoverable error. Fall back to motor-on
931 * idle-state.
932 */
933 if(fd_error != NULL) {
934 printf("Floppy error: %s\n", fd_error);
935 fd_error = NULL;
936 }
937
938 if(fd_state == FLP_STAT) {
939 sc->flags |= FLPF_EMPTY;
940 sc->flags &= ~FLPF_GETSTAT;
941 wakeup((caddr_t)sc);
942 fddone(sc);
943 return;
944 }
945
946 bp = sc->bufq.b_actf;
947
948 bp->b_error = EIO;
949 bp->b_flags |= B_ERROR;
950 fd_state = FLP_MON;
951
952 break;
953 case X_AGAIN:
954 /*
955 * Start next part of state machine.
956 */
957 break;
958 case X_OK:
959 /*
960 * Command ok and finished. Reset error-counter.
961 * If there are no more bytes to transfer fall back
962 * to motor-on idle state.
963 */
964 sc->errcnt = 0;
965
966 if(fd_state == FLP_STAT) {
967 sc->flags &= ~FLPF_GETSTAT;
968 wakeup((caddr_t)sc);
969 fddone(sc);
970 return;
971 }
972
973 if((sc->flags & FLPF_BOUNCE) && (sc->io_dir == B_READ))
974 bcopy(sc->bounceb, sc->io_data, SECTOR_SIZE);
975 sc->flags &= ~FLPF_BOUNCE;
976
977 sc->sector++;
978 sc->io_data += SECTOR_SIZE;
979 sc->io_bytes -= SECTOR_SIZE;
980 if(sc->io_bytes <= 0)
981 fd_state = FLP_MON;
982 }
983 if(fd_state == FLP_MON)
984 fddone(sc);
985 else fd_xfer(sc);
986 }
987
988 /*
989 * Determine status of last command. Should only be called through
990 * 'fdcint()'.
991 * Returns:
992 * X_ERROR : Error on command; might succeed next time.
993 * X_FAIL : Error on command; will never succeed.
994 * X_AGAIN : Part of a command succeeded, call 'fd_xfer()' to complete.
995 * X_OK : Command succeeded and is complete.
996 *
997 * This function only affects sc->curtrk.
998 */
999 static int
1000 fd_xfer_ok(sc)
1001 register struct fd_softc *sc;
1002 {
1003 register int status;
1004
1005 #ifdef FLP_DEBUG
1006 printf("fd_xfer_ok: cmd: 0x%x, state: 0x%x\n", fd_cmd, fd_state);
1007 #endif
1008 switch(fd_cmd) {
1009 case IRUPT:
1010 /*
1011 * Timeout. Force a recalibrate before we try again.
1012 */
1013 status = read_fdreg(FDC_CS);
1014
1015 fd_error = "Timeout";
1016 sc->curtrk = INV_TRK;
1017 return(X_ERROR);
1018 case F_READ:
1019 /*
1020 * Test for DMA error
1021 */
1022 status = read_dmastat();
1023 if(!(status & DMAOK)) {
1024 fd_error = "Dma error";
1025 return(X_ERROR);
1026 }
1027 /*
1028 * Get controller status and check for errors.
1029 */
1030 status = read_fdreg(FDC_CS);
1031 if(status & (RNF | CRCERR | LD_T00)) {
1032 fd_error = "Read error";
1033 if(status & RNF)
1034 sc->curtrk = INV_TRK;
1035 return(X_ERROR);
1036 }
1037 break;
1038 case F_WRITE:
1039 /*
1040 * Test for DMA error
1041 */
1042 status = read_dmastat();
1043 if(!(status & DMAOK)) {
1044 fd_error = "Dma error";
1045 return(X_ERROR);
1046 }
1047 /*
1048 * Get controller status and check for errors.
1049 */
1050 status = read_fdreg(FDC_CS);
1051 if(status & WRI_PRO) {
1052 fd_error = "Write protected";
1053 return(X_FAIL);
1054 }
1055 if(status & (RNF | CRCERR | LD_T00)) {
1056 fd_error = "Write error";
1057 sc->curtrk = INV_TRK;
1058 return(X_ERROR);
1059 }
1060 break;
1061 case SEEK:
1062 status = read_fdreg(FDC_CS);
1063 if(status & (RNF | CRCERR)) {
1064 fd_error = "Seek error";
1065 sc->curtrk = INV_TRK;
1066 return(X_ERROR);
1067 }
1068 return(X_AGAIN);
1069 case RESTORE:
1070 /*
1071 * Determine if the recalibration succeeded.
1072 */
1073 status = read_fdreg(FDC_CS);
1074 if(status & RNF) {
1075 fd_error = "Recalibrate error";
1076 /* reset controller */
1077 write_fdreg(FDC_CS, IRUPT);
1078 sc->curtrk = INV_TRK;
1079 return(X_ERROR);
1080 }
1081 sc->curtrk = 0;
1082 if(fd_state == FLP_STAT) {
1083 if(status & WRI_PRO)
1084 sc->flags |= FLPF_WRTPROT;
1085 break;
1086 }
1087 return(X_AGAIN);
1088 default:
1089 fd_error = "Driver error: fd_xfer_ok : Unknown state";
1090 return(X_FAIL);
1091 }
1092 return(X_OK);
1093 }
1094
1095 /*
1096 * All timeouts will call this function.
1097 */
1098 static void
1099 fdmotoroff(sc)
1100 struct fd_softc *sc;
1101 {
1102 int sps;
1103
1104 /*
1105 * Get at harware interrupt level
1106 */
1107 sps = splbio();
1108
1109 #if FLP_DEBUG
1110 printf("fdmotoroff, state = 0x%x\n", fd_state);
1111 #endif
1112
1113 switch(fd_state) {
1114 case FLP_STAT :
1115 case FLP_XFER :
1116 /*
1117 * Timeout during a transfer; cancel transaction
1118 * set command to 'IRUPT'.
1119 * A drive-interrupt is simulated to trigger the state
1120 * machine.
1121 */
1122 /*
1123 * Cancel current transaction
1124 */
1125 fd_cmd = IRUPT;
1126 write_fdreg(FDC_CS, IRUPT);
1127 delay(20);
1128 (void)read_fdreg(FDC_CS);
1129 write_fdreg(FDC_CS, RESTORE);
1130 break;
1131
1132 case FLP_MON :
1133 /*
1134 * Turn motor off.
1135 */
1136 if(selected) {
1137 int tmp;
1138
1139 st_dmagrab((dma_farg)fdcint, (dma_farg)fdmoff,
1140 sc, &tmp, 0);
1141 }
1142 else fd_state = FLP_IDLE;
1143 break;
1144 }
1145 splx(sps);
1146 }
1147
1148 /*
1149 * min byte count to whats left of the track in question
1150 */
1151 static void
1152 fdminphys(bp)
1153 struct buf *bp;
1154 {
1155 struct fd_softc *sc;
1156 int sec, toff, tsz;
1157
1158 if((sc = getsoftc(fd_cd, DISKUNIT(bp->b_dev))) == NULL)
1159 panic("fdminphys: couldn't get softc");
1160
1161 sec = bp->b_blkno % (sc->nsectors * sc->nheads);
1162 toff = sec * SECTOR_SIZE;
1163 tsz = sc->nsectors * sc->nheads * SECTOR_SIZE;
1164
1165 #ifdef FLP_DEBUG
1166 printf("fdminphys: before %d", bp->b_bcount);
1167 #endif
1168
1169 bp->b_bcount = min(bp->b_bcount, tsz - toff);
1170
1171 #ifdef FLP_DEBUG
1172 printf(" after %d\n", bp->b_bcount);
1173 #endif
1174
1175 minphys(bp);
1176 }
1177
1178 /*
1179 * Called from fdmotoroff to turn the motor actually off....
1180 * This can't be done in fdmotoroff itself, because exclusive access to the
1181 * DMA controller is needed to read the FDC-status register. The function
1182 * 'fdmoff()' always runs as the result of a 'dmagrab()'.
1183 * We need to test the status-register because we want to be sure that the
1184 * drive motor is really off before deselecting the drive. The FDC only
1185 * turns off the drive motor after having seen 10 index-pulses. You only
1186 * get index-pulses when a drive is selected....This means that if the
1187 * drive is deselected when the motor is still spinning, it will continue
1188 * to spin _even_ when you insert a floppy later on...
1189 */
1190 static void
1191 fdmoff(fdsoftc)
1192 struct fd_softc *fdsoftc;
1193 {
1194 int tmp;
1195
1196 if ((fd_state == FLP_MON) && selected) {
1197 tmp = read_fdreg(FDC_CS);
1198 if (!(tmp & MOTORON)) {
1199 fddeselect();
1200 fd_state = FLP_IDLE;
1201 }
1202 else timeout((FPV)fdmotoroff, (void*)fdsoftc, 10*FLP_MONDELAY);
1203 }
1204 st_dmafree(fdsoftc, &tmp);
1205 }
1206
1207 /*
1208 * Used to find out wich drives are actually connected. We do this by issueing
1209 * is 'RESTORE' command and check if the 'track-0' bit is set. This also works
1210 * if the drive is present but no floppy is inserted.
1211 */
1212 static void
1213 fdtestdrv(fdsoftc)
1214 struct fd_softc *fdsoftc;
1215 {
1216 int status;
1217
1218 /*
1219 * Select the right unit and head.
1220 */
1221 fdselect(fdsoftc->unit, 0, FLP_DD);
1222
1223 write_fdreg(FDC_CS, RESTORE|HBIT);
1224
1225 /*
1226 * Wait for about 2 seconds.
1227 */
1228 delay(2000000);
1229
1230 status = read_fdreg(FDC_CS);
1231 if(status & (RNF|BUSY)) {
1232 write_fdreg(FDC_CS, IRUPT); /* reset controller */
1233 delay(40);
1234 }
1235
1236 if(!(status & LD_T00))
1237 fdsoftc->flags |= FLPF_NOTRESP;
1238
1239 fddeselect();
1240 }
1241
1242 /*
1243 * Build disk label. For now we only create a label from what we know
1244 * from 'sc'.
1245 */
1246 static int
1247 fdgetdisklabel(sc, dev)
1248 struct fd_softc *sc;
1249 dev_t dev;
1250 {
1251 struct disklabel *lp;
1252 int part;
1253
1254 /*
1255 * If we already got one, get out.
1256 */
1257 if(sc->flags & FLPF_HAVELAB)
1258 return(0);
1259
1260 #ifdef FLP_DEBUG
1261 printf("fdgetdisklabel()\n");
1262 #endif
1263
1264 part = DISKPART(dev);
1265 lp = sc->dkdev.dk_label;
1266 bzero(lp, sizeof(struct disklabel));
1267
1268 lp->d_secsize = SECTOR_SIZE;
1269 lp->d_ntracks = sc->nheads;
1270 lp->d_nsectors = sc->nsectors;
1271 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
1272 lp->d_ncylinders = sc->nblocks / lp->d_secpercyl;
1273 lp->d_secperunit = sc->nblocks;
1274
1275 lp->d_type = DTYPE_FLOPPY;
1276 lp->d_rpm = 300; /* good guess I suppose. */
1277 lp->d_interleave = 1; /* FIXME: is this OK? */
1278 lp->d_bbsize = 0;
1279 lp->d_sbsize = 0;
1280 lp->d_npartitions = part + 1;
1281 lp->d_trkseek = STEP_DELAY;
1282 lp->d_magic = DISKMAGIC;
1283 lp->d_magic2 = DISKMAGIC;
1284 lp->d_checksum = dkcksum(lp);
1285 lp->d_partitions[part].p_size = lp->d_secperunit;
1286 lp->d_partitions[part].p_fstype = FS_UNUSED;
1287 lp->d_partitions[part].p_fsize = 1024;
1288 lp->d_partitions[part].p_frag = 8;
1289 sc->flags |= FLPF_HAVELAB;
1290
1291 return(0);
1292 }
1293