xref: /csrg-svn/sys/i386/isa/fd.c (revision 52360)
143594Sdonahn /*-
243594Sdonahn  * Copyright (c) 1990 The Regents of the University of California.
343594Sdonahn  * 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*52360Sbostic  *	@(#)fd.c	7.6 (Berkeley) 02/05/92
1143594Sdonahn  */
1243594Sdonahn 
1349825Sbostic #include "fd.h"
1449825Sbostic #if NFD > 0
15*52360Sbostic /*
16*52360Sbostic  * This driver assumed that NFD == 2. Now it works for NFD == 1 or NFD == 2
17*52360Sbostic  * It will probably not work for NFD > 2.
18*52360Sbostic  */
1943594Sdonahn #include "param.h"
2043594Sdonahn #include "dkbad.h"
2143594Sdonahn #include "systm.h"
2243594Sdonahn #include "conf.h"
2343594Sdonahn #include "file.h"
2443594Sdonahn #include "ioctl.h"
2543594Sdonahn #include "buf.h"
2643594Sdonahn #include "uio.h"
27*52360Sbostic 
2849573Swilliam #include "i386/isa/isa_device.h"
2949573Swilliam #include "i386/isa/fdreg.h"
3049573Swilliam #include "i386/isa/icu.h"
3143594Sdonahn 
3243594Sdonahn #define	FDUNIT(s)	((s)&1)
3343594Sdonahn #define	FDTYPE(s)	(((s)>>1)&7)
34*52360Sbostic #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
11351729Swilliam Fdsize(dev)
11445533Sbill dev_t	dev;
11543594Sdonahn {
11645533Sbill 	return(2400);
11743594Sdonahn }
11843594Sdonahn 
11943594Sdonahn /****************************************************************************/
12043594Sdonahn /*                               fdstrategy                                 */
12143594Sdonahn /****************************************************************************/
12251729Swilliam Fdstrategy(bp)
12343594Sdonahn 	register struct buf *bp;	/* IO operation to perform */
12443594Sdonahn {
125*52360Sbostic 	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 		}
156*52360Sbostic #ifdef FDTEST
157*52360Sbostic printf("fdstrat%d, too big\n");
158*52360Sbostic #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);
166*52360Sbostic 	if ((fd_unit[0].head.b_active == 0)
167*52360Sbostic #if NFD > 1
168*52360Sbostic 	    && (fd_unit[1].head.b_active == 0)
169*52360Sbostic #endif
170*52360Sbostic 	    ) {
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 /****************************************************************************/
19043594Sdonahn set_motor(unit,reset)
19143594Sdonahn int unit,reset;
19243594Sdonahn {
193*52360Sbostic 	outb(fdc+fdout,unit | (reset ? 0 : 0xC)  | FDMOTOR(0)
194*52360Sbostic #if NFD > 1
195*52360Sbostic 	     | FDMOTOR(1)
196*52360Sbostic #endif
197*52360Sbostic 	     );
19843594Sdonahn }
19943594Sdonahn 
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 
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
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 
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 
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
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 /****************************************************************************/
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 
288*52360Sbostic 	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 
30051729Swilliam Fdclose(dev, flags)
30143594Sdonahn 	dev_t dev;
30243594Sdonahn {
30343594Sdonahn }
30443594Sdonahn 
30543594Sdonahn /****************************************************************************/
30643594Sdonahn /*                            fdread/fdwrite                                */
30743594Sdonahn /****************************************************************************/
30843594Sdonahn /*
30943594Sdonahn  * Routines to do raw IO for a unit.
31043594Sdonahn  */
31151729Swilliam Fdread(dev, uio)			/* character read routine */
31243594Sdonahn dev_t dev;
31343594Sdonahn struct uio *uio;
31443594Sdonahn {
31545533Sbill  	int unit = FDUNIT(minor(dev)) ;
31643594Sdonahn 	if (unit >= NFD) return(ENXIO);
31751729Swilliam 	return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio));
31843594Sdonahn }
31943594Sdonahn 
32051729Swilliam Fdwrite(dev, uio)			/* character write routine */
32143594Sdonahn dev_t dev;
32243594Sdonahn struct uio *uio;
32343594Sdonahn {
32445533Sbill  	int unit = FDUNIT(minor(dev)) ;
32543594Sdonahn 	if (unit >= NFD) return(ENXIO);
32651729Swilliam 	return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio));
32743594Sdonahn }
32843594Sdonahn 
32943594Sdonahn /****************************************************************************/
33043594Sdonahn /*                                 fdstart                                  */
33143594Sdonahn /****************************************************************************/
33243594Sdonahn fdstart(unit)
33343594Sdonahn int unit;
33443594Sdonahn {
33543594Sdonahn 	register struct buf *dp,*bp;
33643594Sdonahn 	int s;
33743594Sdonahn 
33845533Sbill #ifdef FDTEST
339*52360Sbostic printf("fd%d|",unit);
34045533Sbill #endif
34145533Sbill 	s = splbio();
34243594Sdonahn 	if (!fd_unit[unit].motor) {
34343594Sdonahn 		fd_turnon(unit);
34443594Sdonahn 		/* Wait for 1 sec */
34543594Sdonahn 		timeout(fdstart,unit,hz);
34645533Sbill 		/*DELAY(1000000);*/
34745533Sbill 	}else
34845533Sbill 		 {
34945533Sbill 		/* make sure drive is selected as well as on */
35045533Sbill 		/*set_motor(unit,0);*/
35145533Sbill 
35243594Sdonahn 		dp = &fd_unit[unit].head;
35343594Sdonahn 		bp = dp->b_actf;
35443594Sdonahn 		fd_retry = 0;
35545533Sbill 		if (fd_unit[unit].reset) fd_state = 1;
35645533Sbill 		else {
35745533Sbill 			/* DO a RESET */
35845533Sbill 			fd_unit[unit].reset = 1;
35945533Sbill 			fd_state = 5;
36045533Sbill 		}
36143594Sdonahn 		fd_skip = 0;
36245533Sbill #ifdef FDDEBUG
36345533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
36445533Sbill #endif
36545533Sbill 		if (bp->b_cylin != fd_track) {
36643594Sdonahn 		/* Seek necessary, never quite sure where head is at! */
36743594Sdonahn 		out_fdc(15);	/* Seek function */
36843594Sdonahn 		out_fdc(unit);	/* Drive number */
36945533Sbill 		out_fdc(bp->b_cylin * dp->b_step);
37049573Swilliam 		} else fdintr(0xff);
37143594Sdonahn 	}
37245533Sbill 	splx(s);
37343594Sdonahn }
37443594Sdonahn 
37543594Sdonahn fd_timeout(x)
37643594Sdonahn int x;
37743594Sdonahn {
37843594Sdonahn 	int i,j;
37943594Sdonahn 	struct buf *dp,*bp;
38043594Sdonahn 
38143594Sdonahn 	dp = &fd_unit[fd_drive].head;
38243594Sdonahn 	bp = dp->b_actf;
38343594Sdonahn 
38443594Sdonahn 	out_fdc(0x4);
38543594Sdonahn 	out_fdc(fd_drive);
38643594Sdonahn 	i = in_fdc();
38749878Sbostic 	printf("Timeout drive status %lx\n",i);
38843594Sdonahn 
38943594Sdonahn 	out_fdc(0x8);
39043594Sdonahn 	i = in_fdc();
39143594Sdonahn 	j = in_fdc();
39249878Sbostic 	printf("ST0 = %lx, PCN = %lx\n",i,j);
39343594Sdonahn 
39443594Sdonahn 	if (bp) badtrans(dp,bp);
39543594Sdonahn }
39643594Sdonahn 
39743594Sdonahn /****************************************************************************/
39843594Sdonahn /*                                 fdintr                                   */
39943594Sdonahn /****************************************************************************/
40049573Swilliam fdintr(unit)
40143594Sdonahn {
40243594Sdonahn 	register struct buf *dp,*bp;
40343594Sdonahn 	struct buf *dpother;
40445533Sbill 	int read,head,trac,sec,i,s,sectrac,cyl;
40543594Sdonahn 	unsigned long blknum;
40643594Sdonahn 	struct fd_type *ft;
40743594Sdonahn 
40845533Sbill #ifdef FDTEST
40949573Swilliam 	printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive);
41045533Sbill #endif
41145533Sbill 
41243594Sdonahn 	dp = &fd_unit[fd_drive].head;
41343594Sdonahn 	bp = dp->b_actf;
41443594Sdonahn 	read = bp->b_flags & B_READ;
41545533Sbill  	ft = &fd_types[FDTYPE(bp->b_dev)];
41643594Sdonahn 
41743594Sdonahn 	switch (fd_state) {
41843594Sdonahn 	case 1 : /* SEEK DONE, START DMA */
41945533Sbill 		/* Make sure seek really happened*/
42049573Swilliam 		if (unit != 0xff) {
42145533Sbill 			out_fdc(0x8);
42245533Sbill 			i = in_fdc();
42345533Sbill 			cyl = in_fdc();
42445533Sbill 			if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) {
42549878Sbostic printf("Stray int ST0 = %lx, PCN = %lx:",i,cyl);
42645533Sbill 				return;
42745533Sbill 			}
42845533Sbill 		}
42945533Sbill 
43043594Sdonahn 		fd_track = bp->b_cylin;
43145533Sbill 		at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan);
43243594Sdonahn 		blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
43343594Sdonahn 			+ fd_skip/FDBLK;
43443594Sdonahn 		sectrac = ft->sectrac;
43543594Sdonahn 		sec = blknum %  (sectrac * 2);
43643594Sdonahn 		head = sec / sectrac;
43743594Sdonahn 		sec = sec % sectrac + 1;
43843594Sdonahn 
43943594Sdonahn 		if (read)  out_fdc(0xE6);	/* READ */
44043594Sdonahn 		else out_fdc(0xC5);		/* WRITE */
44143594Sdonahn 		out_fdc(head << 2 | fd_drive);	/* head & unit */
44243594Sdonahn 		out_fdc(fd_track);		/* track */
44343594Sdonahn 		out_fdc(head);
44443594Sdonahn 		out_fdc(sec);			/* sector XXX +1? */
44543594Sdonahn 		out_fdc(ft->secsize);		/* sector size */
44643594Sdonahn 		out_fdc(sectrac);		/* sectors/track */
44743594Sdonahn 		out_fdc(ft->gap);		/* gap size */
44843594Sdonahn 		out_fdc(ft->datalen);		/* data length */
44943594Sdonahn 		fd_state = 2;
45043594Sdonahn 		/* XXX PARANOIA */
45143594Sdonahn 		untimeout(fd_timeout,2);
45243594Sdonahn 		timeout(fd_timeout,2,hz);
45343594Sdonahn 		break;
45443594Sdonahn 	case 2 : /* IO DONE, post-analyze */
45543594Sdonahn 		untimeout(fd_timeout,2);
45643594Sdonahn 		for(i=0;i<7;i++) {
45743594Sdonahn 			fd_status[i] = in_fdc();
45843594Sdonahn 		}
45943594Sdonahn 		if (fd_status[0]&0xF8) {
46043594Sdonahn #ifdef FDOTHER
46145533Sbill printf("status0 err %d:",fd_status[0]);
46243594Sdonahn #endif
46343594Sdonahn 			goto retry;
46443594Sdonahn 		}
46545533Sbill /*
46643594Sdonahn 		if (fd_status[1]){
46743594Sdonahn 			printf("status1 err %d:",fd_status[0]);
46843594Sdonahn 			goto retry;
46943594Sdonahn 		}
47043594Sdonahn 		if (fd_status[2]){
47143594Sdonahn 			printf("status2 err %d:",fd_status[0]);
47243594Sdonahn 			goto retry;
47343594Sdonahn 		}
47445533Sbill */
47543594Sdonahn 		/* All OK */
47643594Sdonahn 		if (!kernel_space(bp->b_un.b_addr+fd_skip)) {
47743594Sdonahn 			/* RAW transfer */
47845533Sbill 			if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr,
47945533Sbill 				bp->b_un.b_addr+fd_skip, FDBLK);
48043594Sdonahn 		}
48143594Sdonahn 		fd_skip += FDBLK;
48243594Sdonahn 		if (fd_skip >= bp->b_bcount) {
48345533Sbill #ifdef FDTEST
48445533Sbill printf("DONE %d|", bp->b_blkno);
48545533Sbill #endif
48643594Sdonahn 			/* ALL DONE */
48743594Sdonahn 			fd_skip = 0;
48843594Sdonahn 			bp->b_resid = 0;
48943594Sdonahn 			dp->b_actf = bp->av_forw;
49043594Sdonahn 			biodone(bp);
49143594Sdonahn 			nextstate(dp);
49243594Sdonahn 
49343594Sdonahn 		} else {
49445533Sbill #ifdef FDDEBUG
49545533Sbill printf("next|");
49645533Sbill #endif
49743594Sdonahn 			/* set up next transfer */
49843594Sdonahn 			blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
49943594Sdonahn 				+ fd_skip/FDBLK;
50043594Sdonahn 			fd_state = 1;
50143594Sdonahn 			bp->b_cylin = (blknum / (ft->sectrac * 2));
50243594Sdonahn 			if (bp->b_cylin != fd_track) {
50345533Sbill #ifdef FDTEST
50445533Sbill printf("Seek|");
50545533Sbill #endif
50643594Sdonahn 				/* SEEK Necessary */
50743594Sdonahn 				out_fdc(15);	/* Seek function */
50843594Sdonahn 				out_fdc(fd_drive);/* Drive number */
50945533Sbill 				out_fdc(bp->b_cylin * dp->b_step);
51043594Sdonahn 				break;
51149573Swilliam 			} else fdintr(0xff);
51243594Sdonahn 		}
51343594Sdonahn 		break;
51443594Sdonahn 	case 3:
51545533Sbill #ifdef FDOTHER
51645533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
51745533Sbill #endif
51843594Sdonahn 		/* Seek necessary */
51943594Sdonahn 		out_fdc(15);	/* Seek function */
52043594Sdonahn 		out_fdc(fd_drive);/* Drive number */
52145533Sbill 		out_fdc(bp->b_cylin * dp->b_step);
52243594Sdonahn 		fd_state = 1;
52343594Sdonahn 		break;
52443594Sdonahn 	case 4:
52543594Sdonahn 		out_fdc(3); /* specify command */
52643594Sdonahn 		out_fdc(0xDF);
52743594Sdonahn 		out_fdc(2);
52843594Sdonahn 		out_fdc(7);	/* Recalibrate Function */
52943594Sdonahn 		out_fdc(fd_drive);
53043594Sdonahn 		fd_state = 3;
53143594Sdonahn 		break;
53245533Sbill 	case 5:
53345533Sbill #ifdef FDOTHER
53445533Sbill 		printf("**RESET**\n");
53545533Sbill #endif
53645533Sbill 		/* Try a reset, keep motor on */
53745533Sbill 		set_motor(fd_drive,1);
53845533Sbill 		set_motor(fd_drive,0);
53945533Sbill 		outb(fdc+fdctl,ft->trans);
54045533Sbill 		fd_retry++;
54145533Sbill 		fd_state = 4;
54245533Sbill 		break;
54343594Sdonahn 	default:
54443594Sdonahn 		printf("Unexpected FD int->");
54543594Sdonahn 		out_fdc(0x8);
54643594Sdonahn 		i = in_fdc();
54743594Sdonahn 		sec = in_fdc();
54849878Sbostic 		printf("ST0 = %lx, PCN = %lx\n",i,sec);
54943594Sdonahn 		out_fdc(0x4A);
55043594Sdonahn 		out_fdc(fd_drive);
55143594Sdonahn 		for(i=0;i<7;i++) {
55243594Sdonahn 			fd_status[i] = in_fdc();
55343594Sdonahn 		}
55449878Sbostic 	printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
55543594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
55643594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
55743594Sdonahn 		break;
55843594Sdonahn 	}
55943594Sdonahn 	return;
56043594Sdonahn retry:
56143594Sdonahn 	switch(fd_retry) {
56243594Sdonahn 	case 0: case 1:
56345533Sbill 	case 2: case 3:
56443594Sdonahn 		break;
56545533Sbill 	case 4:
56643594Sdonahn 		fd_retry++;
56745533Sbill 		fd_state = 5;
56849573Swilliam 		fdintr(0xff);
56943594Sdonahn 		return;
57045533Sbill 	case 5: case 6: case 7:
57143594Sdonahn 		break;
57243594Sdonahn 	default:
57349878Sbostic 		printf("FD err %lx %lx %lx %lx %lx %lx %lx\n",
57443594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
57543594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
57643594Sdonahn 		badtrans(dp,bp);
57743594Sdonahn 		return;
57843594Sdonahn 	}
57943594Sdonahn 	fd_state = 1;
58043594Sdonahn 	fd_retry++;
58149573Swilliam 	fdintr(0xff);
58243594Sdonahn }
58343594Sdonahn 
58443594Sdonahn badtrans(dp,bp)
58543594Sdonahn struct buf *dp,*bp;
58643594Sdonahn {
58743594Sdonahn 
58843594Sdonahn 	bp->b_flags |= B_ERROR;
58943594Sdonahn 	bp->b_error = EIO;
59043594Sdonahn 	bp->b_resid = bp->b_bcount - fd_skip;
59143594Sdonahn 	dp->b_actf = bp->av_forw;
59243594Sdonahn 	fd_skip = 0;
59343594Sdonahn 	biodone(bp);
59443594Sdonahn 	nextstate(dp);
59543594Sdonahn 
59643594Sdonahn }
59743594Sdonahn 
59843594Sdonahn /*
59943594Sdonahn 	nextstate : After a transfer is done, continue processing
60043594Sdonahn 	requests on the current drive queue.  If empty, go to
60143594Sdonahn 	the other drives queue.  If that is empty too, timeout
60243594Sdonahn 	to turn off the current drive in 5 seconds, and go
60343594Sdonahn 	to state 0 (not expecting any interrupts).
60443594Sdonahn */
60543594Sdonahn 
60643594Sdonahn nextstate(dp)
60743594Sdonahn struct buf *dp;
60843594Sdonahn {
60943594Sdonahn 
610*52360Sbostic 	if (dp->b_actf)
611*52360Sbostic 		fdstart(fd_drive);
612*52360Sbostic 	else {
613*52360Sbostic #if NFD > 1
614*52360Sbostic 		struct buf *dpother;
615*52360Sbostic 
616*52360Sbostic 		dpother = &fd_unit[fd_drive ? 0 : 1].head;
617*52360Sbostic 
618*52360Sbostic 		if (dpother->b_actf) {
61945533Sbill #ifdef FDTEST
62045533Sbill printf("switch|");
62145533Sbill #endif
622*52360Sbostic 			untimeout(fd_turnoff,fd_drive);
623*52360Sbostic 			timeout(fd_turnoff,fd_drive,5*hz);
624*52360Sbostic 			fd_drive = 1 - fd_drive;
625*52360Sbostic 			dp->b_active = 0;
626*52360Sbostic 			dpother->b_active = 1;
627*52360Sbostic 			fdstart(fd_drive);
628*52360Sbostic 		} else
629*52360Sbostic #endif
630*52360Sbostic 		{
63145533Sbill #ifdef FDTEST
63245533Sbill printf("off|");
63345533Sbill #endif
634*52360Sbostic 			untimeout(fd_turnoff,fd_drive);
635*52360Sbostic 			timeout(fd_turnoff,fd_drive,5*hz);
636*52360Sbostic 			fd_state = 0;
637*52360Sbostic 			dp->b_active = 0;
638*52360Sbostic 		}
63943594Sdonahn 	}
64043594Sdonahn }
64151729Swilliam 
64251729Swilliam Fdioctl() {}
64351729Swilliam Fddump() {}
64445533Sbill #endif
645