143594Sdonahn /*-
2*63364Sbostic * Copyright (c) 1990, 1993
3*63364Sbostic * The Regents of the University of California. All rights reserved.
443594Sdonahn *
543594Sdonahn * This code is derived from software contributed to Berkeley by
643594Sdonahn * Don Ahn.
743594Sdonahn *
849609Swilliam * %sccs.include.redist.c%
943594Sdonahn *
10*63364Sbostic * @(#)fd.c 8.1 (Berkeley) 06/11/93
1143594Sdonahn */
1243594Sdonahn
1349825Sbostic #include "fd.h"
1449825Sbostic #if NFD > 0
1552360Sbostic /*
1652360Sbostic * This driver assumed that NFD == 2. Now it works for NFD == 1 or NFD == 2
1752360Sbostic * It will probably not work for NFD > 2.
1852360Sbostic */
1956513Sbostic #include <sys/param.h>
2056513Sbostic #include <sys/dkbad.h>
2156513Sbostic #include <sys/systm.h>
2256513Sbostic #include <sys/conf.h>
2356513Sbostic #include <sys/file.h>
2456513Sbostic #include <sys/ioctl.h>
2556513Sbostic #include <sys/buf.h>
2656513Sbostic #include <sys/uio.h>
2752360Sbostic
2856513Sbostic #include <i386/isa/isa_device.h>
2956513Sbostic #include <i386/isa/fdreg.h>
3056513Sbostic #include <i386/isa/icu.h>
3143594Sdonahn
3243594Sdonahn #define FDUNIT(s) ((s)&1)
3343594Sdonahn #define FDTYPE(s) (((s)>>1)&7)
3452360Sbostic #define FDMOTOR(u) (fd_unit[(u)].motor ? (1 << (4 + (u))) : 0)
3545533Sbill
3643594Sdonahn #define b_cylin b_resid
3745533Sbill #define b_step b_resid
3843594Sdonahn #define FDBLK 512
3943594Sdonahn #define NUMTYPES 4
4043594Sdonahn
4143594Sdonahn struct fd_type {
4243594Sdonahn int sectrac; /* sectors per track */
4343594Sdonahn int secsize; /* size code for sectors */
4443594Sdonahn int datalen; /* data len when secsize = 0 */
4543594Sdonahn int gap; /* gap len between sectors */
4643594Sdonahn int tracks; /* total num of tracks */
4743594Sdonahn int size; /* size of disk in sectors */
4843594Sdonahn int steptrac; /* steps per cylinder */
4943594Sdonahn int trans; /* transfer speed code */
5043594Sdonahn };
5143594Sdonahn
5243594Sdonahn struct fd_type fd_types[NUMTYPES] = {
5345533Sbill { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */
5443594Sdonahn { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */
5543594Sdonahn { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */
5643594Sdonahn { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */
5743594Sdonahn };
5843594Sdonahn
5943594Sdonahn struct fd_u {
6043594Sdonahn int type; /* Drive type (HD, DD */
6143594Sdonahn int active; /* Drive activity boolean */
6243594Sdonahn int motor; /* Motor on flag */
6343594Sdonahn struct buf head; /* Head of buf chain */
6443594Sdonahn struct buf rhead; /* Raw head of buf chain */
6545533Sbill int reset;
6643594Sdonahn } fd_unit[NFD];
6743594Sdonahn
6845533Sbill
6943594Sdonahn extern int hz;
7043594Sdonahn
7143594Sdonahn /* state needed for current transfer */
7245533Sbill static fdc; /* floppy disk controller io base register */
7345533Sbill int fd_dmachan = 2;
7443594Sdonahn static int fd_skip;
7543594Sdonahn static int fd_state;
7643594Sdonahn static int fd_retry;
7743594Sdonahn static int fd_drive;
7845533Sbill static int fd_track = -1;
7943594Sdonahn static int fd_status[7];
8043594Sdonahn
8145533Sbill /*
8245533Sbill make sure bounce buffer for DMA is aligned since the DMA chip
8345533Sbill doesn't roll over properly over a 64k boundary
8445533Sbill */
8545533Sbill extern struct buf *dma_bounce[];
8643594Sdonahn
8743594Sdonahn /****************************************************************************/
8843594Sdonahn /* autoconfiguration stuff */
8943594Sdonahn /****************************************************************************/
9043594Sdonahn int fdprobe(), fdattach(), fd_turnoff();
9143594Sdonahn
9245533Sbill struct isa_driver fddriver = {
9343594Sdonahn fdprobe, fdattach, "fd",
9443594Sdonahn };
9543594Sdonahn
9643594Sdonahn fdprobe(dev)
9745533Sbill struct isa_device *dev;
9843594Sdonahn {
9943594Sdonahn return 1;
10043594Sdonahn }
10143594Sdonahn
10243594Sdonahn fdattach(dev)
10345533Sbill struct isa_device *dev;
10445533Sbill { int s;
10545533Sbill
10645533Sbill fdc = dev->id_iobase;
10745533Sbill /* Set transfer to 500kbps */
10845533Sbill outb(fdc+fdctl,0);
10945533Sbill fd_turnoff(0);
11045533Sbill }
11145533Sbill
11245533Sbill int
Fdsize(dev)11351729Swilliam Fdsize(dev)
11445533Sbill dev_t dev;
11543594Sdonahn {
11645533Sbill return(2400);
11743594Sdonahn }
11843594Sdonahn
11943594Sdonahn /****************************************************************************/
12043594Sdonahn /* fdstrategy */
12143594Sdonahn /****************************************************************************/
Fdstrategy(bp)12251729Swilliam Fdstrategy(bp)
12343594Sdonahn register struct buf *bp; /* IO operation to perform */
12443594Sdonahn {
12552360Sbostic register struct buf *dp;
12643594Sdonahn long nblocks,blknum;
12745533Sbill int unit, type, s;
12843594Sdonahn
12945533Sbill unit = FDUNIT(minor(bp->b_dev));
13045533Sbill type = FDTYPE(minor(bp->b_dev));
13145533Sbill
13245533Sbill #ifdef FDTEST
13345533Sbill printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|",
13445533Sbill unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr);
13543594Sdonahn #endif
13643594Sdonahn if ((unit >= NFD) || (bp->b_blkno < 0)) {
13743594Sdonahn printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n",
13843594Sdonahn unit, bp->b_blkno, bp->b_bcount);
13943594Sdonahn pg("fd:error in fdstrategy");
14043594Sdonahn bp->b_error = EINVAL;
14145533Sbill bp->b_flags |= B_ERROR;
14243594Sdonahn goto bad;
14343594Sdonahn }
14443594Sdonahn /*
14543594Sdonahn * Set up block calculations.
14643594Sdonahn */
14743594Sdonahn blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
14845533Sbill nblocks = fd_types[type].size;
14943594Sdonahn if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
15045533Sbill if (blknum == nblocks) {
15145533Sbill bp->b_resid = bp->b_bcount;
15245533Sbill } else {
15345533Sbill bp->b_error = ENOSPC;
15445533Sbill bp->b_flags |= B_ERROR;
15545533Sbill }
15652360Sbostic #ifdef FDTEST
15752360Sbostic printf("fdstrat%d, too big\n");
15852360Sbostic #endif
15943594Sdonahn goto bad;
16043594Sdonahn }
16145533Sbill bp->b_cylin = blknum / (fd_types[type].sectrac * 2);
16243594Sdonahn dp = &fd_unit[unit].head;
16345533Sbill dp->b_step = (fd_types[fd_unit[unit].type].steptrac);
16443594Sdonahn s = splbio();
16543594Sdonahn disksort(dp, bp);
16652360Sbostic if ((fd_unit[0].head.b_active == 0)
16752360Sbostic #if NFD > 1
16852360Sbostic && (fd_unit[1].head.b_active == 0)
16952360Sbostic #endif
17052360Sbostic ) {
17145533Sbill #ifdef FDDEBUG
17245533Sbill printf("T|");
17345533Sbill #endif
17443594Sdonahn dp->b_active = 1;
17543594Sdonahn fd_drive = unit;
17645533Sbill fd_track = -1; /* force seek on first xfer */
17743594Sdonahn untimeout(fd_turnoff,unit);
17843594Sdonahn fdstart(unit); /* start drive if idle */
17943594Sdonahn }
18043594Sdonahn splx(s);
18143594Sdonahn return;
18243594Sdonahn
18343594Sdonahn bad:
18443594Sdonahn biodone(bp);
18543594Sdonahn }
18643594Sdonahn
18743594Sdonahn /****************************************************************************/
18843594Sdonahn /* motor control stuff */
18943594Sdonahn /****************************************************************************/
set_motor(unit,reset)19043594Sdonahn set_motor(unit,reset)
19143594Sdonahn int unit,reset;
19243594Sdonahn {
19352360Sbostic outb(fdc+fdout,unit | (reset ? 0 : 0xC) | FDMOTOR(0)
19452360Sbostic #if NFD > 1
19552360Sbostic | FDMOTOR(1)
19652360Sbostic #endif
19752360Sbostic );
19843594Sdonahn }
19943594Sdonahn
fd_turnoff(unit)20043594Sdonahn fd_turnoff(unit)
20143594Sdonahn int unit;
20243594Sdonahn {
20343594Sdonahn fd_unit[unit].motor = 0;
20443594Sdonahn if (unit) set_motor(0,0);
20543594Sdonahn else set_motor(1,0);
20643594Sdonahn }
20743594Sdonahn
fd_turnon(unit)20843594Sdonahn fd_turnon(unit)
20943594Sdonahn int unit;
21043594Sdonahn {
21143594Sdonahn fd_unit[unit].motor = 1;
21243594Sdonahn set_motor(unit,0);
21343594Sdonahn }
21443594Sdonahn
21543594Sdonahn /****************************************************************************/
21643594Sdonahn /* fdc in/out */
21743594Sdonahn /****************************************************************************/
21843594Sdonahn int
in_fdc()21943594Sdonahn in_fdc()
22043594Sdonahn {
22143594Sdonahn int i;
22245533Sbill while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM))
22345533Sbill if (i == NE7_RQM) return -1;
22445533Sbill return inb(fdc+fddata);
22543594Sdonahn }
22643594Sdonahn
dump_stat()22743594Sdonahn dump_stat()
22843594Sdonahn {
22943594Sdonahn int i;
23043594Sdonahn for(i=0;i<7;i++) {
23143594Sdonahn fd_status[i] = in_fdc();
23243594Sdonahn if (fd_status[i] < 0) break;
23343594Sdonahn }
23449878Sbostic printf("FD bad status :%lx %lx %lx %lx %lx %lx %lx\n",
23545533Sbill fd_status[0], fd_status[1], fd_status[2], fd_status[3],
23645533Sbill fd_status[4], fd_status[5], fd_status[6] );
23743594Sdonahn }
23843594Sdonahn
out_fdc(x)23943594Sdonahn out_fdc(x)
24043594Sdonahn int x;
24143594Sdonahn {
24243594Sdonahn int r,errcnt;
24343594Sdonahn static int maxcnt = 0;
24443594Sdonahn errcnt = 0;
24543594Sdonahn do {
24645533Sbill r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM));
24745533Sbill if (r== NE7_RQM) break;
24845533Sbill if (r==(NE7_DIO|NE7_RQM)) {
24943594Sdonahn dump_stat(); /* error: direction. eat up output */
25043594Sdonahn #ifdef FDOTHER
25149878Sbostic printf("%lx\n",x);
25243594Sdonahn #endif
25343594Sdonahn }
25443594Sdonahn /* printf("Error r = %d:",r); */
25543594Sdonahn errcnt++;
25643594Sdonahn } while (1);
25743594Sdonahn if (errcnt > maxcnt) {
25843594Sdonahn maxcnt = errcnt;
25943594Sdonahn #ifdef FDOTHER
26045533Sbill printf("New MAX = %d\n",maxcnt);
26143594Sdonahn #endif
26243594Sdonahn }
26345533Sbill outb(fdc+fddata,x);
26443594Sdonahn }
26543594Sdonahn
26643594Sdonahn /* see if fdc responding */
26743594Sdonahn int
check_fdc()26843594Sdonahn check_fdc()
26943594Sdonahn {
27043594Sdonahn int i;
27143594Sdonahn for(i=0;i<100;i++) {
27245533Sbill if (inb(fdc+fdsts)& NE7_RQM) return 0;
27343594Sdonahn }
27443594Sdonahn return 1;
27543594Sdonahn }
27643594Sdonahn
27743594Sdonahn /****************************************************************************/
27843594Sdonahn /* fdopen/fdclose */
27943594Sdonahn /****************************************************************************/
Fdopen(dev,flags)28049573Swilliam Fdopen(dev, flags)
28143594Sdonahn dev_t dev;
28243594Sdonahn int flags;
28343594Sdonahn {
28445533Sbill int unit = FDUNIT(minor(dev));
28545533Sbill int type = FDTYPE(minor(dev));
28643594Sdonahn int s;
28743594Sdonahn
28852360Sbostic printf("fdopen %x %d %d\n", minor(dev), unit, type);
28943594Sdonahn /* check bounds */
29043594Sdonahn if (unit >= NFD) return(ENXIO);
29143594Sdonahn if (type >= NUMTYPES) return(ENXIO);
29245533Sbill /*
29343594Sdonahn if (check_fdc()) return(EBUSY);
29445533Sbill */
29543594Sdonahn
29643594Sdonahn /* Set proper disk type, only allow one type */
29743594Sdonahn return 0;
29843594Sdonahn }
29943594Sdonahn
Fdclose(dev,flags)30051729Swilliam Fdclose(dev, flags)
30143594Sdonahn dev_t dev;
30243594Sdonahn {
30353640Sbostic return (0);
30443594Sdonahn }
30543594Sdonahn
30643594Sdonahn /****************************************************************************/
30743594Sdonahn /* fdread/fdwrite */
30843594Sdonahn /****************************************************************************/
30943594Sdonahn /*
31043594Sdonahn * Routines to do raw IO for a unit.
31143594Sdonahn */
Fdread(dev,uio)31251729Swilliam Fdread(dev, uio) /* character read routine */
31343594Sdonahn dev_t dev;
31443594Sdonahn struct uio *uio;
31543594Sdonahn {
31645533Sbill int unit = FDUNIT(minor(dev)) ;
31743594Sdonahn if (unit >= NFD) return(ENXIO);
31851729Swilliam return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio));
31943594Sdonahn }
32043594Sdonahn
Fdwrite(dev,uio)32151729Swilliam Fdwrite(dev, uio) /* character write routine */
32243594Sdonahn dev_t dev;
32343594Sdonahn struct uio *uio;
32443594Sdonahn {
32545533Sbill int unit = FDUNIT(minor(dev)) ;
32643594Sdonahn if (unit >= NFD) return(ENXIO);
32751729Swilliam return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio));
32843594Sdonahn }
32943594Sdonahn
33043594Sdonahn /****************************************************************************/
33143594Sdonahn /* fdstart */
33243594Sdonahn /****************************************************************************/
fdstart(unit)33343594Sdonahn fdstart(unit)
33443594Sdonahn int unit;
33543594Sdonahn {
33643594Sdonahn register struct buf *dp,*bp;
33743594Sdonahn int s;
33843594Sdonahn
33945533Sbill #ifdef FDTEST
34052360Sbostic printf("fd%d|",unit);
34145533Sbill #endif
34245533Sbill s = splbio();
34343594Sdonahn if (!fd_unit[unit].motor) {
34443594Sdonahn fd_turnon(unit);
34543594Sdonahn /* Wait for 1 sec */
34643594Sdonahn timeout(fdstart,unit,hz);
34745533Sbill /*DELAY(1000000);*/
34845533Sbill }else
34945533Sbill {
35045533Sbill /* make sure drive is selected as well as on */
35145533Sbill /*set_motor(unit,0);*/
35245533Sbill
35343594Sdonahn dp = &fd_unit[unit].head;
35443594Sdonahn bp = dp->b_actf;
35543594Sdonahn fd_retry = 0;
35645533Sbill if (fd_unit[unit].reset) fd_state = 1;
35745533Sbill else {
35845533Sbill /* DO a RESET */
35945533Sbill fd_unit[unit].reset = 1;
36045533Sbill fd_state = 5;
36145533Sbill }
36243594Sdonahn fd_skip = 0;
36345533Sbill #ifdef FDDEBUG
36445533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
36545533Sbill #endif
36645533Sbill if (bp->b_cylin != fd_track) {
36743594Sdonahn /* Seek necessary, never quite sure where head is at! */
36843594Sdonahn out_fdc(15); /* Seek function */
36943594Sdonahn out_fdc(unit); /* Drive number */
37045533Sbill out_fdc(bp->b_cylin * dp->b_step);
37149573Swilliam } else fdintr(0xff);
37243594Sdonahn }
37345533Sbill splx(s);
37443594Sdonahn }
37543594Sdonahn
fd_timeout(x)37643594Sdonahn fd_timeout(x)
37743594Sdonahn int x;
37843594Sdonahn {
37943594Sdonahn int i,j;
38043594Sdonahn struct buf *dp,*bp;
38143594Sdonahn
38243594Sdonahn dp = &fd_unit[fd_drive].head;
38343594Sdonahn bp = dp->b_actf;
38443594Sdonahn
38543594Sdonahn out_fdc(0x4);
38643594Sdonahn out_fdc(fd_drive);
38743594Sdonahn i = in_fdc();
38849878Sbostic printf("Timeout drive status %lx\n",i);
38943594Sdonahn
39043594Sdonahn out_fdc(0x8);
39143594Sdonahn i = in_fdc();
39243594Sdonahn j = in_fdc();
39349878Sbostic printf("ST0 = %lx, PCN = %lx\n",i,j);
39443594Sdonahn
39543594Sdonahn if (bp) badtrans(dp,bp);
39643594Sdonahn }
39743594Sdonahn
39843594Sdonahn /****************************************************************************/
39943594Sdonahn /* fdintr */
40043594Sdonahn /****************************************************************************/
fdintr(unit)40149573Swilliam fdintr(unit)
40243594Sdonahn {
40343594Sdonahn register struct buf *dp,*bp;
40443594Sdonahn struct buf *dpother;
40545533Sbill int read,head,trac,sec,i,s,sectrac,cyl;
40643594Sdonahn unsigned long blknum;
40743594Sdonahn struct fd_type *ft;
40843594Sdonahn
40945533Sbill #ifdef FDTEST
41049573Swilliam printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive);
41145533Sbill #endif
41245533Sbill
41343594Sdonahn dp = &fd_unit[fd_drive].head;
41443594Sdonahn bp = dp->b_actf;
41543594Sdonahn read = bp->b_flags & B_READ;
41645533Sbill ft = &fd_types[FDTYPE(bp->b_dev)];
41743594Sdonahn
41843594Sdonahn switch (fd_state) {
41943594Sdonahn case 1 : /* SEEK DONE, START DMA */
42045533Sbill /* Make sure seek really happened*/
42149573Swilliam if (unit != 0xff) {
42245533Sbill out_fdc(0x8);
42345533Sbill i = in_fdc();
42445533Sbill cyl = in_fdc();
42545533Sbill if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) {
42649878Sbostic printf("Stray int ST0 = %lx, PCN = %lx:",i,cyl);
42745533Sbill return;
42845533Sbill }
42945533Sbill }
43045533Sbill
43143594Sdonahn fd_track = bp->b_cylin;
43245533Sbill at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan);
43343594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
43443594Sdonahn + fd_skip/FDBLK;
43543594Sdonahn sectrac = ft->sectrac;
43643594Sdonahn sec = blknum % (sectrac * 2);
43743594Sdonahn head = sec / sectrac;
43843594Sdonahn sec = sec % sectrac + 1;
43943594Sdonahn
44043594Sdonahn if (read) out_fdc(0xE6); /* READ */
44143594Sdonahn else out_fdc(0xC5); /* WRITE */
44243594Sdonahn out_fdc(head << 2 | fd_drive); /* head & unit */
44343594Sdonahn out_fdc(fd_track); /* track */
44443594Sdonahn out_fdc(head);
44543594Sdonahn out_fdc(sec); /* sector XXX +1? */
44643594Sdonahn out_fdc(ft->secsize); /* sector size */
44743594Sdonahn out_fdc(sectrac); /* sectors/track */
44843594Sdonahn out_fdc(ft->gap); /* gap size */
44943594Sdonahn out_fdc(ft->datalen); /* data length */
45043594Sdonahn fd_state = 2;
45143594Sdonahn /* XXX PARANOIA */
45243594Sdonahn untimeout(fd_timeout,2);
45343594Sdonahn timeout(fd_timeout,2,hz);
45443594Sdonahn break;
45543594Sdonahn case 2 : /* IO DONE, post-analyze */
45643594Sdonahn untimeout(fd_timeout,2);
45743594Sdonahn for(i=0;i<7;i++) {
45843594Sdonahn fd_status[i] = in_fdc();
45943594Sdonahn }
46043594Sdonahn if (fd_status[0]&0xF8) {
46143594Sdonahn #ifdef FDOTHER
46245533Sbill printf("status0 err %d:",fd_status[0]);
46343594Sdonahn #endif
46443594Sdonahn goto retry;
46543594Sdonahn }
46645533Sbill /*
46743594Sdonahn if (fd_status[1]){
46843594Sdonahn printf("status1 err %d:",fd_status[0]);
46943594Sdonahn goto retry;
47043594Sdonahn }
47143594Sdonahn if (fd_status[2]){
47243594Sdonahn printf("status2 err %d:",fd_status[0]);
47343594Sdonahn goto retry;
47443594Sdonahn }
47545533Sbill */
47643594Sdonahn /* All OK */
47743594Sdonahn if (!kernel_space(bp->b_un.b_addr+fd_skip)) {
47843594Sdonahn /* RAW transfer */
47945533Sbill if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr,
48045533Sbill bp->b_un.b_addr+fd_skip, FDBLK);
48143594Sdonahn }
48243594Sdonahn fd_skip += FDBLK;
48343594Sdonahn if (fd_skip >= bp->b_bcount) {
48445533Sbill #ifdef FDTEST
48545533Sbill printf("DONE %d|", bp->b_blkno);
48645533Sbill #endif
48743594Sdonahn /* ALL DONE */
48843594Sdonahn fd_skip = 0;
48943594Sdonahn bp->b_resid = 0;
49043594Sdonahn dp->b_actf = bp->av_forw;
49143594Sdonahn biodone(bp);
49243594Sdonahn nextstate(dp);
49343594Sdonahn
49443594Sdonahn } else {
49545533Sbill #ifdef FDDEBUG
49645533Sbill printf("next|");
49745533Sbill #endif
49843594Sdonahn /* set up next transfer */
49943594Sdonahn blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
50043594Sdonahn + fd_skip/FDBLK;
50143594Sdonahn fd_state = 1;
50243594Sdonahn bp->b_cylin = (blknum / (ft->sectrac * 2));
50343594Sdonahn if (bp->b_cylin != fd_track) {
50445533Sbill #ifdef FDTEST
50545533Sbill printf("Seek|");
50645533Sbill #endif
50743594Sdonahn /* SEEK Necessary */
50843594Sdonahn out_fdc(15); /* Seek function */
50943594Sdonahn out_fdc(fd_drive);/* Drive number */
51045533Sbill out_fdc(bp->b_cylin * dp->b_step);
51143594Sdonahn break;
51249573Swilliam } else fdintr(0xff);
51343594Sdonahn }
51443594Sdonahn break;
51543594Sdonahn case 3:
51645533Sbill #ifdef FDOTHER
51745533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
51845533Sbill #endif
51943594Sdonahn /* Seek necessary */
52043594Sdonahn out_fdc(15); /* Seek function */
52143594Sdonahn out_fdc(fd_drive);/* Drive number */
52245533Sbill out_fdc(bp->b_cylin * dp->b_step);
52343594Sdonahn fd_state = 1;
52443594Sdonahn break;
52543594Sdonahn case 4:
52643594Sdonahn out_fdc(3); /* specify command */
52743594Sdonahn out_fdc(0xDF);
52843594Sdonahn out_fdc(2);
52943594Sdonahn out_fdc(7); /* Recalibrate Function */
53043594Sdonahn out_fdc(fd_drive);
53143594Sdonahn fd_state = 3;
53243594Sdonahn break;
53345533Sbill case 5:
53445533Sbill #ifdef FDOTHER
53545533Sbill printf("**RESET**\n");
53645533Sbill #endif
53745533Sbill /* Try a reset, keep motor on */
53845533Sbill set_motor(fd_drive,1);
53945533Sbill set_motor(fd_drive,0);
54045533Sbill outb(fdc+fdctl,ft->trans);
54145533Sbill fd_retry++;
54245533Sbill fd_state = 4;
54345533Sbill break;
54443594Sdonahn default:
54543594Sdonahn printf("Unexpected FD int->");
54643594Sdonahn out_fdc(0x8);
54743594Sdonahn i = in_fdc();
54843594Sdonahn sec = in_fdc();
54949878Sbostic printf("ST0 = %lx, PCN = %lx\n",i,sec);
55043594Sdonahn out_fdc(0x4A);
55143594Sdonahn out_fdc(fd_drive);
55243594Sdonahn for(i=0;i<7;i++) {
55343594Sdonahn fd_status[i] = in_fdc();
55443594Sdonahn }
55549878Sbostic printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
55643594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3],
55743594Sdonahn fd_status[4], fd_status[5], fd_status[6] );
55843594Sdonahn break;
55943594Sdonahn }
56043594Sdonahn return;
56143594Sdonahn retry:
56243594Sdonahn switch(fd_retry) {
56343594Sdonahn case 0: case 1:
56445533Sbill case 2: case 3:
56543594Sdonahn break;
56645533Sbill case 4:
56743594Sdonahn fd_retry++;
56845533Sbill fd_state = 5;
56949573Swilliam fdintr(0xff);
57043594Sdonahn return;
57145533Sbill case 5: case 6: case 7:
57243594Sdonahn break;
57343594Sdonahn default:
57449878Sbostic printf("FD err %lx %lx %lx %lx %lx %lx %lx\n",
57543594Sdonahn fd_status[0], fd_status[1], fd_status[2], fd_status[3],
57643594Sdonahn fd_status[4], fd_status[5], fd_status[6] );
57743594Sdonahn badtrans(dp,bp);
57843594Sdonahn return;
57943594Sdonahn }
58043594Sdonahn fd_state = 1;
58143594Sdonahn fd_retry++;
58249573Swilliam fdintr(0xff);
58343594Sdonahn }
58443594Sdonahn
58543594Sdonahn badtrans(dp,bp)
58643594Sdonahn struct buf *dp,*bp;
58743594Sdonahn {
58843594Sdonahn
58943594Sdonahn bp->b_flags |= B_ERROR;
59043594Sdonahn bp->b_error = EIO;
59143594Sdonahn bp->b_resid = bp->b_bcount - fd_skip;
59243594Sdonahn dp->b_actf = bp->av_forw;
59343594Sdonahn fd_skip = 0;
59443594Sdonahn biodone(bp);
59543594Sdonahn nextstate(dp);
59643594Sdonahn
59743594Sdonahn }
59843594Sdonahn
59943594Sdonahn /*
60043594Sdonahn nextstate : After a transfer is done, continue processing
60143594Sdonahn requests on the current drive queue. If empty, go to
60243594Sdonahn the other drives queue. If that is empty too, timeout
60343594Sdonahn to turn off the current drive in 5 seconds, and go
60443594Sdonahn to state 0 (not expecting any interrupts).
60543594Sdonahn */
60643594Sdonahn
60743594Sdonahn nextstate(dp)
60843594Sdonahn struct buf *dp;
60943594Sdonahn {
61043594Sdonahn
61152360Sbostic if (dp->b_actf)
61252360Sbostic fdstart(fd_drive);
61352360Sbostic else {
61452360Sbostic #if NFD > 1
61552360Sbostic struct buf *dpother;
61652360Sbostic
61752360Sbostic dpother = &fd_unit[fd_drive ? 0 : 1].head;
61852360Sbostic
61952360Sbostic if (dpother->b_actf) {
62045533Sbill #ifdef FDTEST
62145533Sbill printf("switch|");
62245533Sbill #endif
62352360Sbostic untimeout(fd_turnoff,fd_drive);
62452360Sbostic timeout(fd_turnoff,fd_drive,5*hz);
62552360Sbostic fd_drive = 1 - fd_drive;
62652360Sbostic dp->b_active = 0;
62752360Sbostic dpother->b_active = 1;
62852360Sbostic fdstart(fd_drive);
62952360Sbostic } else
63052360Sbostic #endif
63152360Sbostic {
63245533Sbill #ifdef FDTEST
63345533Sbill printf("off|");
63445533Sbill #endif
63552360Sbostic untimeout(fd_turnoff,fd_drive);
63652360Sbostic timeout(fd_turnoff,fd_drive,5*hz);
63752360Sbostic fd_state = 0;
63852360Sbostic dp->b_active = 0;
63952360Sbostic }
64043594Sdonahn }
64143594Sdonahn }
64251729Swilliam
Fdioctl()64351729Swilliam Fdioctl() {}
Fddump()64451729Swilliam Fddump() {}
64545533Sbill #endif
646