xref: /csrg-svn/sys/i386/isa/fd.c (revision 51729)
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*51729Swilliam  *	@(#)fd.c	7.5 (Berkeley) 11/16/91
1143594Sdonahn  */
1243594Sdonahn 
1349825Sbostic #include "fd.h"
1449825Sbostic #if NFD > 0
1549825Sbostic 
1643594Sdonahn #include "param.h"
1743594Sdonahn #include "dkbad.h"
1843594Sdonahn #include "systm.h"
1943594Sdonahn #include "conf.h"
2043594Sdonahn #include "file.h"
2143594Sdonahn #include "ioctl.h"
2243594Sdonahn #include "buf.h"
2343594Sdonahn #include "uio.h"
2449573Swilliam #include "i386/isa/isa_device.h"
2549573Swilliam #include "i386/isa/fdreg.h"
2649573Swilliam #include "i386/isa/icu.h"
2743594Sdonahn 
2843594Sdonahn #define	FDUNIT(s)	((s)&1)
2943594Sdonahn #define	FDTYPE(s)	(((s)>>1)&7)
3045533Sbill 
3143594Sdonahn #define b_cylin b_resid
3245533Sbill #define b_step b_resid
3343594Sdonahn #define FDBLK 512
3443594Sdonahn #define NUMTYPES 4
3543594Sdonahn 
3643594Sdonahn struct fd_type {
3743594Sdonahn 	int	sectrac;		/* sectors per track         */
3843594Sdonahn 	int	secsize;		/* size code for sectors     */
3943594Sdonahn 	int	datalen;		/* data len when secsize = 0 */
4043594Sdonahn 	int	gap;			/* gap len between sectors   */
4143594Sdonahn 	int	tracks;			/* total num of tracks       */
4243594Sdonahn 	int	size;			/* size of disk in sectors   */
4343594Sdonahn 	int	steptrac;		/* steps per cylinder        */
4443594Sdonahn 	int	trans;			/* transfer speed code       */
4543594Sdonahn };
4643594Sdonahn 
4743594Sdonahn struct fd_type fd_types[NUMTYPES] = {
4845533Sbill  	{ 18,2,0xFF,0x1B,80,2880,1,0 },	/* 1.44 meg HD 3.5in floppy    */
4943594Sdonahn 	{ 15,2,0xFF,0x1B,80,2400,1,0 },	/* 1.2 meg HD floppy           */
5043594Sdonahn 	{ 9,2,0xFF,0x23,40,720,2,1 },	/* 360k floppy in 1.2meg drive */
5143594Sdonahn 	{ 9,2,0xFF,0x2A,40,720,1,1 },	/* 360k floppy in DD drive     */
5243594Sdonahn };
5343594Sdonahn 
5443594Sdonahn struct fd_u {
5543594Sdonahn 	int type;		/* Drive type (HD, DD     */
5643594Sdonahn 	int active;		/* Drive activity boolean */
5743594Sdonahn 	int motor;		/* Motor on flag          */
5843594Sdonahn 	struct buf head;	/* Head of buf chain      */
5943594Sdonahn 	struct buf rhead;	/* Raw head of buf chain  */
6045533Sbill 	int reset;
6143594Sdonahn } fd_unit[NFD];
6243594Sdonahn 
6345533Sbill 
6443594Sdonahn extern int hz;
6543594Sdonahn 
6643594Sdonahn /* state needed for current transfer */
6745533Sbill static fdc;	/* floppy disk controller io base register */
6845533Sbill int	fd_dmachan = 2;
6943594Sdonahn static int fd_skip;
7043594Sdonahn static int fd_state;
7143594Sdonahn static int fd_retry;
7243594Sdonahn static int fd_drive;
7345533Sbill static int fd_track = -1;
7443594Sdonahn static int fd_status[7];
7543594Sdonahn 
7645533Sbill /*
7745533Sbill 	make sure bounce buffer for DMA is aligned since the DMA chip
7845533Sbill 	doesn't roll over properly over a 64k boundary
7945533Sbill */
8045533Sbill extern struct buf *dma_bounce[];
8143594Sdonahn 
8243594Sdonahn /****************************************************************************/
8343594Sdonahn /*                      autoconfiguration stuff                             */
8443594Sdonahn /****************************************************************************/
8543594Sdonahn int fdprobe(), fdattach(), fd_turnoff();
8643594Sdonahn 
8745533Sbill struct	isa_driver fddriver = {
8843594Sdonahn 	fdprobe, fdattach, "fd",
8943594Sdonahn };
9043594Sdonahn 
9143594Sdonahn fdprobe(dev)
9245533Sbill struct isa_device *dev;
9343594Sdonahn {
9443594Sdonahn 	return 1;
9543594Sdonahn }
9643594Sdonahn 
9743594Sdonahn fdattach(dev)
9845533Sbill struct isa_device *dev;
9945533Sbill {	int	s;
10045533Sbill 
10145533Sbill 	fdc = dev->id_iobase;
10245533Sbill 	/* Set transfer to 500kbps */
10345533Sbill 	outb(fdc+fdctl,0);
10445533Sbill 	fd_turnoff(0);
10545533Sbill }
10645533Sbill 
10745533Sbill int
108*51729Swilliam Fdsize(dev)
10945533Sbill dev_t	dev;
11043594Sdonahn {
11145533Sbill 	return(2400);
11243594Sdonahn }
11343594Sdonahn 
11443594Sdonahn /****************************************************************************/
11543594Sdonahn /*                               fdstrategy                                 */
11643594Sdonahn /****************************************************************************/
117*51729Swilliam Fdstrategy(bp)
11843594Sdonahn 	register struct buf *bp;	/* IO operation to perform */
11943594Sdonahn {
12043594Sdonahn 	register struct buf *dp,*dp0,*dp1;
12143594Sdonahn 	long nblocks,blknum;
12245533Sbill  	int	unit, type, s;
12343594Sdonahn 
12445533Sbill  	unit = FDUNIT(minor(bp->b_dev));
12545533Sbill  	type = FDTYPE(minor(bp->b_dev));
12645533Sbill 
12745533Sbill #ifdef FDTEST
12845533Sbill printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|",
12945533Sbill 	unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr);
13043594Sdonahn #endif
13143594Sdonahn 	if ((unit >= NFD) || (bp->b_blkno < 0)) {
13243594Sdonahn 		printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n",
13343594Sdonahn 			unit, bp->b_blkno, bp->b_bcount);
13443594Sdonahn 		pg("fd:error in fdstrategy");
13543594Sdonahn 		bp->b_error = EINVAL;
13645533Sbill 		bp->b_flags |= B_ERROR;
13743594Sdonahn 		goto bad;
13843594Sdonahn 	}
13943594Sdonahn 	/*
14043594Sdonahn 	 * Set up block calculations.
14143594Sdonahn 	 */
14243594Sdonahn 	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
14345533Sbill  	nblocks = fd_types[type].size;
14443594Sdonahn 	if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
14545533Sbill 		if (blknum == nblocks) {
14645533Sbill 			bp->b_resid = bp->b_bcount;
14745533Sbill 		} else {
14845533Sbill 			bp->b_error = ENOSPC;
14945533Sbill 			bp->b_flags |= B_ERROR;
15045533Sbill 		}
15143594Sdonahn 		goto bad;
15243594Sdonahn 	}
15345533Sbill  	bp->b_cylin = blknum / (fd_types[type].sectrac * 2);
15443594Sdonahn 	dp = &fd_unit[unit].head;
15543594Sdonahn 	dp0 = &fd_unit[0].head;
15643594Sdonahn 	dp1 = &fd_unit[1].head;
15745533Sbill 	dp->b_step = (fd_types[fd_unit[unit].type].steptrac);
15843594Sdonahn 	s = splbio();
15943594Sdonahn 	disksort(dp, bp);
16043594Sdonahn 	if ((dp0->b_active == 0)&&(dp1->b_active == 0)) {
16145533Sbill #ifdef FDDEBUG
16245533Sbill printf("T|");
16345533Sbill #endif
16443594Sdonahn 		dp->b_active = 1;
16543594Sdonahn 		fd_drive = unit;
16645533Sbill 		fd_track = -1;  /* force seek on first xfer */
16743594Sdonahn 		untimeout(fd_turnoff,unit);
16843594Sdonahn 		fdstart(unit);		/* start drive if idle */
16943594Sdonahn 	}
17043594Sdonahn 	splx(s);
17143594Sdonahn 	return;
17243594Sdonahn 
17343594Sdonahn bad:
17443594Sdonahn 	biodone(bp);
17543594Sdonahn }
17643594Sdonahn 
17743594Sdonahn /****************************************************************************/
17843594Sdonahn /*                            motor control stuff                           */
17943594Sdonahn /****************************************************************************/
18043594Sdonahn set_motor(unit,reset)
18143594Sdonahn int unit,reset;
18243594Sdonahn {
18343594Sdonahn 	int m0,m1;
18443594Sdonahn 	m0 = fd_unit[0].motor;
18543594Sdonahn 	m1 = fd_unit[1].motor;
18645533Sbill 	outb(fdc+fdout,unit | (reset ? 0 : 0xC)  | (m0 ? 16 : 0) | (m1 ? 32 : 0));
18743594Sdonahn }
18843594Sdonahn 
18943594Sdonahn fd_turnoff(unit)
19043594Sdonahn int unit;
19143594Sdonahn {
19243594Sdonahn 	fd_unit[unit].motor = 0;
19343594Sdonahn 	if (unit) set_motor(0,0);
19443594Sdonahn 	else set_motor(1,0);
19543594Sdonahn }
19643594Sdonahn 
19743594Sdonahn fd_turnon(unit)
19843594Sdonahn int unit;
19943594Sdonahn {
20043594Sdonahn 	fd_unit[unit].motor = 1;
20143594Sdonahn 	set_motor(unit,0);
20243594Sdonahn }
20343594Sdonahn 
20443594Sdonahn /****************************************************************************/
20543594Sdonahn /*                             fdc in/out                                   */
20643594Sdonahn /****************************************************************************/
20743594Sdonahn int
20843594Sdonahn in_fdc()
20943594Sdonahn {
21043594Sdonahn 	int i;
21145533Sbill 	while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM))
21245533Sbill 		if (i == NE7_RQM) return -1;
21345533Sbill 	return inb(fdc+fddata);
21443594Sdonahn }
21543594Sdonahn 
21643594Sdonahn dump_stat()
21743594Sdonahn {
21843594Sdonahn 	int i;
21943594Sdonahn 	for(i=0;i<7;i++) {
22043594Sdonahn 		fd_status[i] = in_fdc();
22143594Sdonahn 		if (fd_status[i] < 0) break;
22243594Sdonahn 	}
22349878Sbostic printf("FD bad status :%lx %lx %lx %lx %lx %lx %lx\n",
22445533Sbill 	fd_status[0], fd_status[1], fd_status[2], fd_status[3],
22545533Sbill 	fd_status[4], fd_status[5], fd_status[6] );
22643594Sdonahn }
22743594Sdonahn 
22843594Sdonahn out_fdc(x)
22943594Sdonahn int x;
23043594Sdonahn {
23143594Sdonahn 	int r,errcnt;
23243594Sdonahn 	static int maxcnt = 0;
23343594Sdonahn 	errcnt = 0;
23443594Sdonahn 	do {
23545533Sbill 		r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM));
23645533Sbill 		if (r== NE7_RQM) break;
23745533Sbill 		if (r==(NE7_DIO|NE7_RQM)) {
23843594Sdonahn 			dump_stat(); /* error: direction. eat up output */
23943594Sdonahn #ifdef FDOTHER
24049878Sbostic printf("%lx\n",x);
24143594Sdonahn #endif
24243594Sdonahn 		}
24343594Sdonahn 		/* printf("Error r = %d:",r); */
24443594Sdonahn 		errcnt++;
24543594Sdonahn 	} while (1);
24643594Sdonahn 	if (errcnt > maxcnt) {
24743594Sdonahn 		maxcnt = errcnt;
24843594Sdonahn #ifdef FDOTHER
24945533Sbill printf("New MAX = %d\n",maxcnt);
25043594Sdonahn #endif
25143594Sdonahn 	}
25245533Sbill 	outb(fdc+fddata,x);
25343594Sdonahn }
25443594Sdonahn 
25543594Sdonahn /* see if fdc responding */
25643594Sdonahn int
25743594Sdonahn check_fdc()
25843594Sdonahn {
25943594Sdonahn 	int i;
26043594Sdonahn 	for(i=0;i<100;i++) {
26145533Sbill 		if (inb(fdc+fdsts)& NE7_RQM) return 0;
26243594Sdonahn 	}
26343594Sdonahn 	return 1;
26443594Sdonahn }
26543594Sdonahn 
26643594Sdonahn /****************************************************************************/
26743594Sdonahn /*                           fdopen/fdclose                                 */
26843594Sdonahn /****************************************************************************/
26949573Swilliam Fdopen(dev, flags)
27043594Sdonahn 	dev_t	dev;
27143594Sdonahn 	int	flags;
27243594Sdonahn {
27345533Sbill  	int unit = FDUNIT(minor(dev));
27445533Sbill  	int type = FDTYPE(minor(dev));
27543594Sdonahn 	int s;
27643594Sdonahn 
27743594Sdonahn 	/* check bounds */
27843594Sdonahn 	if (unit >= NFD) return(ENXIO);
27943594Sdonahn 	if (type >= NUMTYPES) return(ENXIO);
28045533Sbill /*
28143594Sdonahn 	if (check_fdc()) return(EBUSY);
28245533Sbill */
28343594Sdonahn 
28443594Sdonahn 	/* Set proper disk type, only allow one type */
28543594Sdonahn 	return 0;
28643594Sdonahn }
28743594Sdonahn 
288*51729Swilliam Fdclose(dev, flags)
28943594Sdonahn 	dev_t dev;
29043594Sdonahn {
29143594Sdonahn }
29243594Sdonahn 
29343594Sdonahn /****************************************************************************/
29443594Sdonahn /*                            fdread/fdwrite                                */
29543594Sdonahn /****************************************************************************/
29643594Sdonahn /*
29743594Sdonahn  * Routines to do raw IO for a unit.
29843594Sdonahn  */
299*51729Swilliam Fdread(dev, uio)			/* character read routine */
30043594Sdonahn dev_t dev;
30143594Sdonahn struct uio *uio;
30243594Sdonahn {
30345533Sbill  	int unit = FDUNIT(minor(dev)) ;
30443594Sdonahn 	if (unit >= NFD) return(ENXIO);
305*51729Swilliam 	return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio));
30643594Sdonahn }
30743594Sdonahn 
308*51729Swilliam Fdwrite(dev, uio)			/* character write routine */
30943594Sdonahn dev_t dev;
31043594Sdonahn struct uio *uio;
31143594Sdonahn {
31245533Sbill  	int unit = FDUNIT(minor(dev)) ;
31343594Sdonahn 	if (unit >= NFD) return(ENXIO);
314*51729Swilliam 	return(physio(Fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio));
31543594Sdonahn }
31643594Sdonahn 
31743594Sdonahn /****************************************************************************/
31843594Sdonahn /*                                 fdstart                                  */
31943594Sdonahn /****************************************************************************/
32043594Sdonahn fdstart(unit)
32143594Sdonahn int unit;
32243594Sdonahn {
32343594Sdonahn 	register struct buf *dp,*bp;
32443594Sdonahn 	int s;
32543594Sdonahn 
32645533Sbill #ifdef FDTEST
32745533Sbill printf("st%d|",unit);
32845533Sbill #endif
32945533Sbill 	s = splbio();
33043594Sdonahn 	if (!fd_unit[unit].motor) {
33143594Sdonahn 		fd_turnon(unit);
33243594Sdonahn 		/* Wait for 1 sec */
33343594Sdonahn 		timeout(fdstart,unit,hz);
33445533Sbill 		/*DELAY(1000000);*/
33545533Sbill 	}else
33645533Sbill 		 {
33745533Sbill 		/* make sure drive is selected as well as on */
33845533Sbill 		/*set_motor(unit,0);*/
33945533Sbill 
34043594Sdonahn 		dp = &fd_unit[unit].head;
34143594Sdonahn 		bp = dp->b_actf;
34243594Sdonahn 		fd_retry = 0;
34345533Sbill 		if (fd_unit[unit].reset) fd_state = 1;
34445533Sbill 		else {
34545533Sbill 			/* DO a RESET */
34645533Sbill 			fd_unit[unit].reset = 1;
34745533Sbill 			fd_state = 5;
34845533Sbill 		}
34943594Sdonahn 		fd_skip = 0;
35045533Sbill #ifdef FDDEBUG
35145533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
35245533Sbill #endif
35345533Sbill 		if (bp->b_cylin != fd_track) {
35443594Sdonahn 		/* Seek necessary, never quite sure where head is at! */
35543594Sdonahn 		out_fdc(15);	/* Seek function */
35643594Sdonahn 		out_fdc(unit);	/* Drive number */
35745533Sbill 		out_fdc(bp->b_cylin * dp->b_step);
35849573Swilliam 		} else fdintr(0xff);
35943594Sdonahn 	}
36045533Sbill 	splx(s);
36143594Sdonahn }
36243594Sdonahn 
36343594Sdonahn fd_timeout(x)
36443594Sdonahn int x;
36543594Sdonahn {
36643594Sdonahn 	int i,j;
36743594Sdonahn 	struct buf *dp,*bp;
36843594Sdonahn 
36943594Sdonahn 	dp = &fd_unit[fd_drive].head;
37043594Sdonahn 	bp = dp->b_actf;
37143594Sdonahn 
37243594Sdonahn 	out_fdc(0x4);
37343594Sdonahn 	out_fdc(fd_drive);
37443594Sdonahn 	i = in_fdc();
37549878Sbostic 	printf("Timeout drive status %lx\n",i);
37643594Sdonahn 
37743594Sdonahn 	out_fdc(0x8);
37843594Sdonahn 	i = in_fdc();
37943594Sdonahn 	j = in_fdc();
38049878Sbostic 	printf("ST0 = %lx, PCN = %lx\n",i,j);
38143594Sdonahn 
38243594Sdonahn 	if (bp) badtrans(dp,bp);
38343594Sdonahn }
38443594Sdonahn 
38543594Sdonahn /****************************************************************************/
38643594Sdonahn /*                                 fdintr                                   */
38743594Sdonahn /****************************************************************************/
38849573Swilliam fdintr(unit)
38943594Sdonahn {
39043594Sdonahn 	register struct buf *dp,*bp;
39143594Sdonahn 	struct buf *dpother;
39245533Sbill 	int read,head,trac,sec,i,s,sectrac,cyl;
39343594Sdonahn 	unsigned long blknum;
39443594Sdonahn 	struct fd_type *ft;
39543594Sdonahn 
39645533Sbill #ifdef FDTEST
39749573Swilliam 	printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive);
39845533Sbill #endif
39945533Sbill 
40043594Sdonahn 	dp = &fd_unit[fd_drive].head;
40143594Sdonahn 	bp = dp->b_actf;
40243594Sdonahn 	read = bp->b_flags & B_READ;
40345533Sbill  	ft = &fd_types[FDTYPE(bp->b_dev)];
40443594Sdonahn 
40543594Sdonahn 	switch (fd_state) {
40643594Sdonahn 	case 1 : /* SEEK DONE, START DMA */
40745533Sbill 		/* Make sure seek really happened*/
40849573Swilliam 		if (unit != 0xff) {
40945533Sbill 			out_fdc(0x8);
41045533Sbill 			i = in_fdc();
41145533Sbill 			cyl = in_fdc();
41245533Sbill 			if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) {
41349878Sbostic printf("Stray int ST0 = %lx, PCN = %lx:",i,cyl);
41445533Sbill 				return;
41545533Sbill 			}
41645533Sbill 		}
41745533Sbill 
41843594Sdonahn 		fd_track = bp->b_cylin;
41945533Sbill 		at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan);
42043594Sdonahn 		blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
42143594Sdonahn 			+ fd_skip/FDBLK;
42243594Sdonahn 		sectrac = ft->sectrac;
42343594Sdonahn 		sec = blknum %  (sectrac * 2);
42443594Sdonahn 		head = sec / sectrac;
42543594Sdonahn 		sec = sec % sectrac + 1;
42643594Sdonahn 
42743594Sdonahn 		if (read)  out_fdc(0xE6);	/* READ */
42843594Sdonahn 		else out_fdc(0xC5);		/* WRITE */
42943594Sdonahn 		out_fdc(head << 2 | fd_drive);	/* head & unit */
43043594Sdonahn 		out_fdc(fd_track);		/* track */
43143594Sdonahn 		out_fdc(head);
43243594Sdonahn 		out_fdc(sec);			/* sector XXX +1? */
43343594Sdonahn 		out_fdc(ft->secsize);		/* sector size */
43443594Sdonahn 		out_fdc(sectrac);		/* sectors/track */
43543594Sdonahn 		out_fdc(ft->gap);		/* gap size */
43643594Sdonahn 		out_fdc(ft->datalen);		/* data length */
43743594Sdonahn 		fd_state = 2;
43843594Sdonahn 		/* XXX PARANOIA */
43943594Sdonahn 		untimeout(fd_timeout,2);
44043594Sdonahn 		timeout(fd_timeout,2,hz);
44143594Sdonahn 		break;
44243594Sdonahn 	case 2 : /* IO DONE, post-analyze */
44343594Sdonahn 		untimeout(fd_timeout,2);
44443594Sdonahn 		for(i=0;i<7;i++) {
44543594Sdonahn 			fd_status[i] = in_fdc();
44643594Sdonahn 		}
44743594Sdonahn 		if (fd_status[0]&0xF8) {
44843594Sdonahn #ifdef FDOTHER
44945533Sbill printf("status0 err %d:",fd_status[0]);
45043594Sdonahn #endif
45143594Sdonahn 			goto retry;
45243594Sdonahn 		}
45345533Sbill /*
45443594Sdonahn 		if (fd_status[1]){
45543594Sdonahn 			printf("status1 err %d:",fd_status[0]);
45643594Sdonahn 			goto retry;
45743594Sdonahn 		}
45843594Sdonahn 		if (fd_status[2]){
45943594Sdonahn 			printf("status2 err %d:",fd_status[0]);
46043594Sdonahn 			goto retry;
46143594Sdonahn 		}
46245533Sbill */
46343594Sdonahn 		/* All OK */
46443594Sdonahn 		if (!kernel_space(bp->b_un.b_addr+fd_skip)) {
46543594Sdonahn 			/* RAW transfer */
46645533Sbill 			if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr,
46745533Sbill 				bp->b_un.b_addr+fd_skip, FDBLK);
46843594Sdonahn 		}
46943594Sdonahn 		fd_skip += FDBLK;
47043594Sdonahn 		if (fd_skip >= bp->b_bcount) {
47145533Sbill #ifdef FDTEST
47245533Sbill printf("DONE %d|", bp->b_blkno);
47345533Sbill #endif
47443594Sdonahn 			/* ALL DONE */
47543594Sdonahn 			fd_skip = 0;
47643594Sdonahn 			bp->b_resid = 0;
47743594Sdonahn 			dp->b_actf = bp->av_forw;
47843594Sdonahn 			biodone(bp);
47943594Sdonahn 			nextstate(dp);
48043594Sdonahn 
48143594Sdonahn 		} else {
48245533Sbill #ifdef FDDEBUG
48345533Sbill printf("next|");
48445533Sbill #endif
48543594Sdonahn 			/* set up next transfer */
48643594Sdonahn 			blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
48743594Sdonahn 				+ fd_skip/FDBLK;
48843594Sdonahn 			fd_state = 1;
48943594Sdonahn 			bp->b_cylin = (blknum / (ft->sectrac * 2));
49043594Sdonahn 			if (bp->b_cylin != fd_track) {
49145533Sbill #ifdef FDTEST
49245533Sbill printf("Seek|");
49345533Sbill #endif
49443594Sdonahn 				/* SEEK Necessary */
49543594Sdonahn 				out_fdc(15);	/* Seek function */
49643594Sdonahn 				out_fdc(fd_drive);/* Drive number */
49745533Sbill 				out_fdc(bp->b_cylin * dp->b_step);
49843594Sdonahn 				break;
49949573Swilliam 			} else fdintr(0xff);
50043594Sdonahn 		}
50143594Sdonahn 		break;
50243594Sdonahn 	case 3:
50345533Sbill #ifdef FDOTHER
50445533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
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 		fd_state = 1;
51143594Sdonahn 		break;
51243594Sdonahn 	case 4:
51343594Sdonahn 		out_fdc(3); /* specify command */
51443594Sdonahn 		out_fdc(0xDF);
51543594Sdonahn 		out_fdc(2);
51643594Sdonahn 		out_fdc(7);	/* Recalibrate Function */
51743594Sdonahn 		out_fdc(fd_drive);
51843594Sdonahn 		fd_state = 3;
51943594Sdonahn 		break;
52045533Sbill 	case 5:
52145533Sbill #ifdef FDOTHER
52245533Sbill 		printf("**RESET**\n");
52345533Sbill #endif
52445533Sbill 		/* Try a reset, keep motor on */
52545533Sbill 		set_motor(fd_drive,1);
52645533Sbill 		set_motor(fd_drive,0);
52745533Sbill 		outb(fdc+fdctl,ft->trans);
52845533Sbill 		fd_retry++;
52945533Sbill 		fd_state = 4;
53045533Sbill 		break;
53143594Sdonahn 	default:
53243594Sdonahn 		printf("Unexpected FD int->");
53343594Sdonahn 		out_fdc(0x8);
53443594Sdonahn 		i = in_fdc();
53543594Sdonahn 		sec = in_fdc();
53649878Sbostic 		printf("ST0 = %lx, PCN = %lx\n",i,sec);
53743594Sdonahn 		out_fdc(0x4A);
53843594Sdonahn 		out_fdc(fd_drive);
53943594Sdonahn 		for(i=0;i<7;i++) {
54043594Sdonahn 			fd_status[i] = in_fdc();
54143594Sdonahn 		}
54249878Sbostic 	printf("intr status :%lx %lx %lx %lx %lx %lx %lx ",
54343594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
54443594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
54543594Sdonahn 		break;
54643594Sdonahn 	}
54743594Sdonahn 	return;
54843594Sdonahn retry:
54943594Sdonahn 	switch(fd_retry) {
55043594Sdonahn 	case 0: case 1:
55145533Sbill 	case 2: case 3:
55243594Sdonahn 		break;
55345533Sbill 	case 4:
55443594Sdonahn 		fd_retry++;
55545533Sbill 		fd_state = 5;
55649573Swilliam 		fdintr(0xff);
55743594Sdonahn 		return;
55845533Sbill 	case 5: case 6: case 7:
55943594Sdonahn 		break;
56043594Sdonahn 	default:
56149878Sbostic 		printf("FD err %lx %lx %lx %lx %lx %lx %lx\n",
56243594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
56343594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
56443594Sdonahn 		badtrans(dp,bp);
56543594Sdonahn 		return;
56643594Sdonahn 	}
56743594Sdonahn 	fd_state = 1;
56843594Sdonahn 	fd_retry++;
56949573Swilliam 	fdintr(0xff);
57043594Sdonahn }
57143594Sdonahn 
57243594Sdonahn badtrans(dp,bp)
57343594Sdonahn struct buf *dp,*bp;
57443594Sdonahn {
57543594Sdonahn 
57643594Sdonahn 	bp->b_flags |= B_ERROR;
57743594Sdonahn 	bp->b_error = EIO;
57843594Sdonahn 	bp->b_resid = bp->b_bcount - fd_skip;
57943594Sdonahn 	dp->b_actf = bp->av_forw;
58043594Sdonahn 	fd_skip = 0;
58143594Sdonahn 	biodone(bp);
58243594Sdonahn 	nextstate(dp);
58343594Sdonahn 
58443594Sdonahn }
58543594Sdonahn 
58643594Sdonahn /*
58743594Sdonahn 	nextstate : After a transfer is done, continue processing
58843594Sdonahn 	requests on the current drive queue.  If empty, go to
58943594Sdonahn 	the other drives queue.  If that is empty too, timeout
59043594Sdonahn 	to turn off the current drive in 5 seconds, and go
59143594Sdonahn 	to state 0 (not expecting any interrupts).
59243594Sdonahn */
59343594Sdonahn 
59443594Sdonahn nextstate(dp)
59543594Sdonahn struct buf *dp;
59643594Sdonahn {
59743594Sdonahn 	struct buf *dpother;
59843594Sdonahn 
59943594Sdonahn 	dpother = &fd_unit[fd_drive ? 0 : 1].head;
60043594Sdonahn 	if (dp->b_actf) fdstart(fd_drive);
60143594Sdonahn 	else if (dpother->b_actf) {
60245533Sbill #ifdef FDTEST
60345533Sbill printf("switch|");
60445533Sbill #endif
60545533Sbill 		untimeout(fd_turnoff,fd_drive);
60645533Sbill 		timeout(fd_turnoff,fd_drive,5*hz);
60745533Sbill 		fd_drive = 1 - fd_drive;
60843594Sdonahn 		dp->b_active = 0;
60945533Sbill 		dpother->b_active = 1;
61045533Sbill 		fdstart(fd_drive);
61143594Sdonahn 	} else {
61245533Sbill #ifdef FDTEST
61345533Sbill printf("off|");
61445533Sbill #endif
61543594Sdonahn 		untimeout(fd_turnoff,fd_drive);
61643594Sdonahn 		timeout(fd_turnoff,fd_drive,5*hz);
61743594Sdonahn 		fd_state = 0;
61843594Sdonahn 		dp->b_active = 0;
61943594Sdonahn 	}
62043594Sdonahn }
621*51729Swilliam 
622*51729Swilliam Fdioctl() {}
623*51729Swilliam Fddump() {}
62445533Sbill #endif
625