xref: /csrg-svn/sys/i386/isa/fd.c (revision 45533)
1*45533Sbill #include "fd.h"
2*45533Sbill #if NFD > 0
343594Sdonahn /*-
443594Sdonahn  * Copyright (c) 1990 The Regents of the University of California.
543594Sdonahn  * All rights reserved.
643594Sdonahn  *
743594Sdonahn  * This code is derived from software contributed to Berkeley by
843594Sdonahn  * Don Ahn.
943594Sdonahn  *
1043594Sdonahn  * %sccs.include.386.c%
1143594Sdonahn  *
12*45533Sbill  *	@(#)fd.c	5.2 (Berkeley) 11/08/90
1343594Sdonahn  */
1443594Sdonahn 
1543594Sdonahn /****************************************************************************/
1643594Sdonahn /*                               fd driver                                  */
1743594Sdonahn /****************************************************************************/
1843594Sdonahn #include "param.h"
1943594Sdonahn #include "dkbad.h"
2043594Sdonahn #include "systm.h"
2143594Sdonahn #include "conf.h"
2243594Sdonahn #include "file.h"
2343594Sdonahn #include "dir.h"
2443594Sdonahn #include "user.h"
2543594Sdonahn #include "ioctl.h"
2643594Sdonahn #include "disk.h"
2743594Sdonahn #include "buf.h"
2843594Sdonahn #include "vm.h"
2943594Sdonahn #include "uio.h"
3043594Sdonahn #include "machine/pte.h"
31*45533Sbill #include "machine/isa/device.h"
32*45533Sbill #include "machine/isa/fdreg.h"
3343594Sdonahn #include "icu.h"
3443594Sdonahn 
3543594Sdonahn #define	FDUNIT(s)	((s)&1)
3643594Sdonahn #define	FDTYPE(s)	(((s)>>1)&7)
37*45533Sbill 
3843594Sdonahn #define b_cylin b_resid
39*45533Sbill #define b_step b_resid
4043594Sdonahn #define FDBLK 512
4143594Sdonahn #define NUMTYPES 4
4243594Sdonahn 
4343594Sdonahn struct fd_type {
4443594Sdonahn 	int	sectrac;		/* sectors per track         */
4543594Sdonahn 	int	secsize;		/* size code for sectors     */
4643594Sdonahn 	int	datalen;		/* data len when secsize = 0 */
4743594Sdonahn 	int	gap;			/* gap len between sectors   */
4843594Sdonahn 	int	tracks;			/* total num of tracks       */
4943594Sdonahn 	int	size;			/* size of disk in sectors   */
5043594Sdonahn 	int	steptrac;		/* steps per cylinder        */
5143594Sdonahn 	int	trans;			/* transfer speed code       */
5243594Sdonahn };
5343594Sdonahn 
5443594Sdonahn struct fd_type fd_types[NUMTYPES] = {
55*45533Sbill  	{ 18,2,0xFF,0x1B,80,2880,1,0 },	/* 1.44 meg HD 3.5in floppy    */
5643594Sdonahn 	{ 15,2,0xFF,0x1B,80,2400,1,0 },	/* 1.2 meg HD floppy           */
5743594Sdonahn 	{ 9,2,0xFF,0x23,40,720,2,1 },	/* 360k floppy in 1.2meg drive */
5843594Sdonahn 	{ 9,2,0xFF,0x2A,40,720,1,1 },	/* 360k floppy in DD drive     */
5943594Sdonahn };
6043594Sdonahn 
6143594Sdonahn struct fd_u {
6243594Sdonahn 	int type;		/* Drive type (HD, DD     */
6343594Sdonahn 	int active;		/* Drive activity boolean */
6443594Sdonahn 	int motor;		/* Motor on flag          */
6543594Sdonahn 	struct buf head;	/* Head of buf chain      */
6643594Sdonahn 	struct buf rhead;	/* Raw head of buf chain  */
67*45533Sbill 	int reset;
6843594Sdonahn } fd_unit[NFD];
6943594Sdonahn 
70*45533Sbill 
7143594Sdonahn extern int hz;
7243594Sdonahn 
7343594Sdonahn /* state needed for current transfer */
74*45533Sbill static fdc;	/* floppy disk controller io base register */
75*45533Sbill int	fd_dmachan = 2;
7643594Sdonahn static int fd_skip;
7743594Sdonahn static int fd_state;
7843594Sdonahn static int fd_retry;
7943594Sdonahn static int fd_drive;
80*45533Sbill static int fd_track = -1;
8143594Sdonahn static int fd_status[7];
8243594Sdonahn 
83*45533Sbill /*
84*45533Sbill 	make sure bounce buffer for DMA is aligned since the DMA chip
85*45533Sbill 	doesn't roll over properly over a 64k boundary
86*45533Sbill */
87*45533Sbill extern struct buf *dma_bounce[];
8843594Sdonahn 
8943594Sdonahn /****************************************************************************/
9043594Sdonahn /*                      autoconfiguration stuff                             */
9143594Sdonahn /****************************************************************************/
9243594Sdonahn int fdprobe(), fdattach(), fd_turnoff();
9343594Sdonahn 
94*45533Sbill struct	isa_driver fddriver = {
9543594Sdonahn 	fdprobe, fdattach, "fd",
9643594Sdonahn };
9743594Sdonahn 
9843594Sdonahn fdprobe(dev)
99*45533Sbill struct isa_device *dev;
10043594Sdonahn {
10143594Sdonahn 	return 1;
10243594Sdonahn }
10343594Sdonahn 
10443594Sdonahn fdattach(dev)
105*45533Sbill struct isa_device *dev;
106*45533Sbill {	int	s;
107*45533Sbill 
108*45533Sbill 	fdc = dev->id_iobase;
109*45533Sbill 	/* Set transfer to 500kbps */
110*45533Sbill 	outb(fdc+fdctl,0);
111*45533Sbill 	fd_turnoff(0);
112*45533Sbill }
113*45533Sbill 
114*45533Sbill int
115*45533Sbill fdsize(dev)
116*45533Sbill dev_t	dev;
11743594Sdonahn {
118*45533Sbill 	return(2400);
11943594Sdonahn }
12043594Sdonahn 
12143594Sdonahn /****************************************************************************/
12243594Sdonahn /*                               fdstrategy                                 */
12343594Sdonahn /****************************************************************************/
12443594Sdonahn fdstrategy(bp)
12543594Sdonahn 	register struct buf *bp;	/* IO operation to perform */
12643594Sdonahn {
12743594Sdonahn 	register struct buf *dp,*dp0,*dp1;
12843594Sdonahn 	long nblocks,blknum;
129*45533Sbill  	int	unit, type, s;
13043594Sdonahn 
131*45533Sbill  	unit = FDUNIT(minor(bp->b_dev));
132*45533Sbill  	type = FDTYPE(minor(bp->b_dev));
133*45533Sbill 
134*45533Sbill #ifdef FDTEST
135*45533Sbill printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|",
136*45533Sbill 	unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr);
13743594Sdonahn #endif
13843594Sdonahn 	if ((unit >= NFD) || (bp->b_blkno < 0)) {
13943594Sdonahn 		printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n",
14043594Sdonahn 			unit, bp->b_blkno, bp->b_bcount);
14143594Sdonahn 		pg("fd:error in fdstrategy");
14243594Sdonahn 		bp->b_error = EINVAL;
143*45533Sbill 		bp->b_flags |= B_ERROR;
14443594Sdonahn 		goto bad;
14543594Sdonahn 	}
14643594Sdonahn 	/*
14743594Sdonahn 	 * Set up block calculations.
14843594Sdonahn 	 */
14943594Sdonahn 	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
150*45533Sbill  	nblocks = fd_types[type].size;
15143594Sdonahn 	if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
152*45533Sbill 		if (blknum == nblocks) {
153*45533Sbill 			bp->b_resid = bp->b_bcount;
154*45533Sbill 		} else {
155*45533Sbill 			bp->b_error = ENOSPC;
156*45533Sbill 			bp->b_flags |= B_ERROR;
157*45533Sbill 		}
15843594Sdonahn 		goto bad;
15943594Sdonahn 	}
160*45533Sbill  	bp->b_cylin = blknum / (fd_types[type].sectrac * 2);
16143594Sdonahn 	dp = &fd_unit[unit].head;
16243594Sdonahn 	dp0 = &fd_unit[0].head;
16343594Sdonahn 	dp1 = &fd_unit[1].head;
164*45533Sbill 	dp->b_step = (fd_types[fd_unit[unit].type].steptrac);
16543594Sdonahn 	s = splbio();
16643594Sdonahn 	disksort(dp, bp);
16743594Sdonahn 	if ((dp0->b_active == 0)&&(dp1->b_active == 0)) {
168*45533Sbill #ifdef FDDEBUG
169*45533Sbill printf("T|");
170*45533Sbill #endif
17143594Sdonahn 		dp->b_active = 1;
17243594Sdonahn 		fd_drive = unit;
173*45533Sbill 		fd_track = -1;  /* force seek on first xfer */
17443594Sdonahn 		untimeout(fd_turnoff,unit);
17543594Sdonahn 		fdstart(unit);		/* start drive if idle */
17643594Sdonahn 	}
17743594Sdonahn 	splx(s);
17843594Sdonahn 	return;
17943594Sdonahn 
18043594Sdonahn bad:
18143594Sdonahn 	biodone(bp);
18243594Sdonahn }
18343594Sdonahn 
18443594Sdonahn /****************************************************************************/
18543594Sdonahn /*                            motor control stuff                           */
18643594Sdonahn /****************************************************************************/
18743594Sdonahn set_motor(unit,reset)
18843594Sdonahn int unit,reset;
18943594Sdonahn {
19043594Sdonahn 	int m0,m1;
19143594Sdonahn 	m0 = fd_unit[0].motor;
19243594Sdonahn 	m1 = fd_unit[1].motor;
193*45533Sbill 	outb(fdc+fdout,unit | (reset ? 0 : 0xC)  | (m0 ? 16 : 0) | (m1 ? 32 : 0));
19443594Sdonahn }
19543594Sdonahn 
19643594Sdonahn fd_turnoff(unit)
19743594Sdonahn int unit;
19843594Sdonahn {
19943594Sdonahn 	fd_unit[unit].motor = 0;
20043594Sdonahn 	if (unit) set_motor(0,0);
20143594Sdonahn 	else set_motor(1,0);
20243594Sdonahn }
20343594Sdonahn 
20443594Sdonahn fd_turnon(unit)
20543594Sdonahn int unit;
20643594Sdonahn {
20743594Sdonahn 	fd_unit[unit].motor = 1;
20843594Sdonahn 	set_motor(unit,0);
20943594Sdonahn }
21043594Sdonahn 
21143594Sdonahn /****************************************************************************/
21243594Sdonahn /*                             fdc in/out                                   */
21343594Sdonahn /****************************************************************************/
21443594Sdonahn int
21543594Sdonahn in_fdc()
21643594Sdonahn {
21743594Sdonahn 	int i;
218*45533Sbill 	while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM))
219*45533Sbill 		if (i == NE7_RQM) return -1;
220*45533Sbill 	return inb(fdc+fddata);
22143594Sdonahn }
22243594Sdonahn 
22343594Sdonahn dump_stat()
22443594Sdonahn {
22543594Sdonahn 	int i;
22643594Sdonahn 	for(i=0;i<7;i++) {
22743594Sdonahn 		fd_status[i] = in_fdc();
22843594Sdonahn 		if (fd_status[i] < 0) break;
22943594Sdonahn 	}
230*45533Sbill printf("FD bad status :%X %X %X %X %X %X %X\n",
231*45533Sbill 	fd_status[0], fd_status[1], fd_status[2], fd_status[3],
232*45533Sbill 	fd_status[4], fd_status[5], fd_status[6] );
23343594Sdonahn }
23443594Sdonahn 
23543594Sdonahn out_fdc(x)
23643594Sdonahn int x;
23743594Sdonahn {
23843594Sdonahn 	int r,errcnt;
23943594Sdonahn 	static int maxcnt = 0;
24043594Sdonahn 	errcnt = 0;
24143594Sdonahn 	do {
242*45533Sbill 		r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM));
243*45533Sbill 		if (r== NE7_RQM) break;
244*45533Sbill 		if (r==(NE7_DIO|NE7_RQM)) {
24543594Sdonahn 			dump_stat(); /* error: direction. eat up output */
24643594Sdonahn #ifdef FDOTHER
247*45533Sbill printf("%X\n",x);
24843594Sdonahn #endif
24943594Sdonahn 		}
25043594Sdonahn 		/* printf("Error r = %d:",r); */
25143594Sdonahn 		errcnt++;
25243594Sdonahn 	} while (1);
25343594Sdonahn 	if (errcnt > maxcnt) {
25443594Sdonahn 		maxcnt = errcnt;
25543594Sdonahn #ifdef FDOTHER
256*45533Sbill printf("New MAX = %d\n",maxcnt);
25743594Sdonahn #endif
25843594Sdonahn 	}
259*45533Sbill 	outb(fdc+fddata,x);
26043594Sdonahn }
26143594Sdonahn 
26243594Sdonahn /* see if fdc responding */
26343594Sdonahn int
26443594Sdonahn check_fdc()
26543594Sdonahn {
26643594Sdonahn 	int i;
26743594Sdonahn 	for(i=0;i<100;i++) {
268*45533Sbill 		if (inb(fdc+fdsts)& NE7_RQM) return 0;
26943594Sdonahn 	}
27043594Sdonahn 	return 1;
27143594Sdonahn }
27243594Sdonahn 
27343594Sdonahn /****************************************************************************/
27443594Sdonahn /*                           fdopen/fdclose                                 */
27543594Sdonahn /****************************************************************************/
27643594Sdonahn fdopen(dev, flags)
27743594Sdonahn 	dev_t	dev;
27843594Sdonahn 	int	flags;
27943594Sdonahn {
280*45533Sbill  	int unit = FDUNIT(minor(dev));
281*45533Sbill  	int type = FDTYPE(minor(dev));
28243594Sdonahn 	int s;
28343594Sdonahn 
28443594Sdonahn 	/* check bounds */
28543594Sdonahn 	if (unit >= NFD) return(ENXIO);
28643594Sdonahn 	if (type >= NUMTYPES) return(ENXIO);
287*45533Sbill /*
28843594Sdonahn 	if (check_fdc()) return(EBUSY);
289*45533Sbill */
29043594Sdonahn 
29143594Sdonahn 	/* Set proper disk type, only allow one type */
29243594Sdonahn 	return 0;
29343594Sdonahn }
29443594Sdonahn 
29543594Sdonahn fdclose(dev)
29643594Sdonahn 	dev_t dev;
29743594Sdonahn {
29843594Sdonahn }
29943594Sdonahn 
30043594Sdonahn /****************************************************************************/
30143594Sdonahn /*                            fdread/fdwrite                                */
30243594Sdonahn /****************************************************************************/
30343594Sdonahn /*
30443594Sdonahn  * Routines to do raw IO for a unit.
30543594Sdonahn  */
30643594Sdonahn fdread(dev, uio)			/* character read routine */
30743594Sdonahn dev_t dev;
30843594Sdonahn struct uio *uio;
30943594Sdonahn {
310*45533Sbill  	int unit = FDUNIT(minor(dev)) ;
31143594Sdonahn 	if (unit >= NFD) return(ENXIO);
31243594Sdonahn 	return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio));
31343594Sdonahn }
31443594Sdonahn 
31543594Sdonahn fdwrite(dev, uio)			/* character write routine */
31643594Sdonahn dev_t dev;
31743594Sdonahn struct uio *uio;
31843594Sdonahn {
319*45533Sbill  	int unit = FDUNIT(minor(dev)) ;
32043594Sdonahn 	if (unit >= NFD) return(ENXIO);
32143594Sdonahn 	return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio));
32243594Sdonahn }
32343594Sdonahn 
32443594Sdonahn /****************************************************************************/
32543594Sdonahn /*                                 fdstart                                  */
32643594Sdonahn /****************************************************************************/
32743594Sdonahn fdstart(unit)
32843594Sdonahn int unit;
32943594Sdonahn {
33043594Sdonahn 	register struct buf *dp,*bp;
33143594Sdonahn 	int s;
33243594Sdonahn 
333*45533Sbill #ifdef FDTEST
334*45533Sbill printf("st%d|",unit);
335*45533Sbill #endif
336*45533Sbill 	s = splbio();
33743594Sdonahn 	if (!fd_unit[unit].motor) {
33843594Sdonahn 		fd_turnon(unit);
33943594Sdonahn 		/* Wait for 1 sec */
34043594Sdonahn 		timeout(fdstart,unit,hz);
341*45533Sbill 		/*DELAY(1000000);*/
342*45533Sbill 	}else
343*45533Sbill 		 {
344*45533Sbill 		/* make sure drive is selected as well as on */
345*45533Sbill 		/*set_motor(unit,0);*/
346*45533Sbill 
34743594Sdonahn 		dp = &fd_unit[unit].head;
34843594Sdonahn 		bp = dp->b_actf;
34943594Sdonahn 		fd_retry = 0;
350*45533Sbill 		if (fd_unit[unit].reset) fd_state = 1;
351*45533Sbill 		else {
352*45533Sbill 			/* DO a RESET */
353*45533Sbill 			fd_unit[unit].reset = 1;
354*45533Sbill 			fd_state = 5;
355*45533Sbill 		}
35643594Sdonahn 		fd_skip = 0;
357*45533Sbill #ifdef FDDEBUG
358*45533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
359*45533Sbill #endif
360*45533Sbill 		if (bp->b_cylin != fd_track) {
36143594Sdonahn 		/* Seek necessary, never quite sure where head is at! */
36243594Sdonahn 		out_fdc(15);	/* Seek function */
36343594Sdonahn 		out_fdc(unit);	/* Drive number */
364*45533Sbill 		out_fdc(bp->b_cylin * dp->b_step);
365*45533Sbill 		} else fdintr(0);
36643594Sdonahn 	}
367*45533Sbill 	splx(s);
36843594Sdonahn }
36943594Sdonahn 
37043594Sdonahn fd_timeout(x)
37143594Sdonahn int x;
37243594Sdonahn {
37343594Sdonahn 	int i,j;
37443594Sdonahn 	struct buf *dp,*bp;
37543594Sdonahn 
37643594Sdonahn 	dp = &fd_unit[fd_drive].head;
37743594Sdonahn 	bp = dp->b_actf;
37843594Sdonahn 
37943594Sdonahn 	out_fdc(0x4);
38043594Sdonahn 	out_fdc(fd_drive);
38143594Sdonahn 	i = in_fdc();
38243594Sdonahn 	printf("Timeout drive status %X\n",i);
38343594Sdonahn 
38443594Sdonahn 	out_fdc(0x8);
38543594Sdonahn 	i = in_fdc();
38643594Sdonahn 	j = in_fdc();
38743594Sdonahn 	printf("ST0 = %X, PCN = %X\n",i,j);
38843594Sdonahn 
38943594Sdonahn 	if (bp) badtrans(dp,bp);
39043594Sdonahn }
39143594Sdonahn 
39243594Sdonahn /****************************************************************************/
39343594Sdonahn /*                                 fdintr                                   */
39443594Sdonahn /****************************************************************************/
39543594Sdonahn fdintr(vec)
39643594Sdonahn int vec;
39743594Sdonahn {
39843594Sdonahn 	register struct buf *dp,*bp;
39943594Sdonahn 	struct buf *dpother;
400*45533Sbill 	int read,head,trac,sec,i,s,sectrac,cyl;
40143594Sdonahn 	unsigned long blknum;
40243594Sdonahn 	struct fd_type *ft;
40343594Sdonahn 
404*45533Sbill #ifdef FDTEST
405*45533Sbill 	printf("state %d, vec %d, dr %d|",fd_state,vec,fd_drive);
406*45533Sbill #endif
407*45533Sbill 
40843594Sdonahn 	dp = &fd_unit[fd_drive].head;
40943594Sdonahn 	bp = dp->b_actf;
41043594Sdonahn 	read = bp->b_flags & B_READ;
411*45533Sbill  	ft = &fd_types[FDTYPE(bp->b_dev)];
41243594Sdonahn 
41343594Sdonahn 	switch (fd_state) {
41443594Sdonahn 	case 1 : /* SEEK DONE, START DMA */
415*45533Sbill 		/* Make sure seek really happened*/
416*45533Sbill 		if (vec) {
417*45533Sbill 			out_fdc(0x8);
418*45533Sbill 			i = in_fdc();
419*45533Sbill 			cyl = in_fdc();
420*45533Sbill 			if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) {
421*45533Sbill printf("Stray int ST0 = %X, PCN = %X:",i,cyl);
422*45533Sbill 				return;
423*45533Sbill 			}
424*45533Sbill 		}
425*45533Sbill 
42643594Sdonahn 		fd_track = bp->b_cylin;
427*45533Sbill 		at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan);
42843594Sdonahn 		blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
42943594Sdonahn 			+ fd_skip/FDBLK;
43043594Sdonahn 		sectrac = ft->sectrac;
43143594Sdonahn 		sec = blknum %  (sectrac * 2);
43243594Sdonahn 		head = sec / sectrac;
43343594Sdonahn 		sec = sec % sectrac + 1;
43443594Sdonahn 
43543594Sdonahn 		if (read)  out_fdc(0xE6);	/* READ */
43643594Sdonahn 		else out_fdc(0xC5);		/* WRITE */
43743594Sdonahn 		out_fdc(head << 2 | fd_drive);	/* head & unit */
43843594Sdonahn 		out_fdc(fd_track);		/* track */
43943594Sdonahn 		out_fdc(head);
44043594Sdonahn 		out_fdc(sec);			/* sector XXX +1? */
44143594Sdonahn 		out_fdc(ft->secsize);		/* sector size */
44243594Sdonahn 		out_fdc(sectrac);		/* sectors/track */
44343594Sdonahn 		out_fdc(ft->gap);		/* gap size */
44443594Sdonahn 		out_fdc(ft->datalen);		/* data length */
44543594Sdonahn 		fd_state = 2;
44643594Sdonahn 		/* XXX PARANOIA */
44743594Sdonahn 		untimeout(fd_timeout,2);
44843594Sdonahn 		timeout(fd_timeout,2,hz);
44943594Sdonahn 		break;
45043594Sdonahn 	case 2 : /* IO DONE, post-analyze */
45143594Sdonahn 		untimeout(fd_timeout,2);
45243594Sdonahn 		for(i=0;i<7;i++) {
45343594Sdonahn 			fd_status[i] = in_fdc();
45443594Sdonahn 		}
45543594Sdonahn 		if (fd_status[0]&0xF8) {
45643594Sdonahn #ifdef FDOTHER
457*45533Sbill printf("status0 err %d:",fd_status[0]);
45843594Sdonahn #endif
45943594Sdonahn 			goto retry;
46043594Sdonahn 		}
461*45533Sbill /*
46243594Sdonahn 		if (fd_status[1]){
46343594Sdonahn 			printf("status1 err %d:",fd_status[0]);
46443594Sdonahn 			goto retry;
46543594Sdonahn 		}
46643594Sdonahn 		if (fd_status[2]){
46743594Sdonahn 			printf("status2 err %d:",fd_status[0]);
46843594Sdonahn 			goto retry;
46943594Sdonahn 		}
470*45533Sbill */
47143594Sdonahn 		/* All OK */
47243594Sdonahn 		if (!kernel_space(bp->b_un.b_addr+fd_skip)) {
47343594Sdonahn 			/* RAW transfer */
474*45533Sbill 			if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr,
475*45533Sbill 				bp->b_un.b_addr+fd_skip, FDBLK);
47643594Sdonahn 		}
47743594Sdonahn 		fd_skip += FDBLK;
47843594Sdonahn 		if (fd_skip >= bp->b_bcount) {
479*45533Sbill #ifdef FDTEST
480*45533Sbill printf("DONE %d|", bp->b_blkno);
481*45533Sbill #endif
48243594Sdonahn 			/* ALL DONE */
48343594Sdonahn 			fd_skip = 0;
48443594Sdonahn 			bp->b_resid = 0;
48543594Sdonahn 			dp->b_actf = bp->av_forw;
48643594Sdonahn 			biodone(bp);
48743594Sdonahn 			nextstate(dp);
48843594Sdonahn 
48943594Sdonahn 		} else {
490*45533Sbill #ifdef FDDEBUG
491*45533Sbill printf("next|");
492*45533Sbill #endif
49343594Sdonahn 			/* set up next transfer */
49443594Sdonahn 			blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
49543594Sdonahn 				+ fd_skip/FDBLK;
49643594Sdonahn 			fd_state = 1;
49743594Sdonahn 			bp->b_cylin = (blknum / (ft->sectrac * 2));
49843594Sdonahn 			if (bp->b_cylin != fd_track) {
499*45533Sbill #ifdef FDTEST
500*45533Sbill printf("Seek|");
501*45533Sbill #endif
50243594Sdonahn 				/* SEEK Necessary */
50343594Sdonahn 				out_fdc(15);	/* Seek function */
50443594Sdonahn 				out_fdc(fd_drive);/* Drive number */
505*45533Sbill 				out_fdc(bp->b_cylin * dp->b_step);
50643594Sdonahn 				break;
507*45533Sbill 			} else fdintr(0);
50843594Sdonahn 		}
50943594Sdonahn 		break;
51043594Sdonahn 	case 3:
511*45533Sbill #ifdef FDOTHER
512*45533Sbill printf("Seek %d %d\n", bp->b_cylin, dp->b_step);
513*45533Sbill #endif
51443594Sdonahn 		/* Seek necessary */
51543594Sdonahn 		out_fdc(15);	/* Seek function */
51643594Sdonahn 		out_fdc(fd_drive);/* Drive number */
517*45533Sbill 		out_fdc(bp->b_cylin * dp->b_step);
51843594Sdonahn 		fd_state = 1;
51943594Sdonahn 		break;
52043594Sdonahn 	case 4:
52143594Sdonahn 		out_fdc(3); /* specify command */
52243594Sdonahn 		out_fdc(0xDF);
52343594Sdonahn 		out_fdc(2);
52443594Sdonahn 		out_fdc(7);	/* Recalibrate Function */
52543594Sdonahn 		out_fdc(fd_drive);
52643594Sdonahn 		fd_state = 3;
52743594Sdonahn 		break;
528*45533Sbill 	case 5:
529*45533Sbill #ifdef FDOTHER
530*45533Sbill 		printf("**RESET**\n");
531*45533Sbill #endif
532*45533Sbill 		/* Try a reset, keep motor on */
533*45533Sbill 		set_motor(fd_drive,1);
534*45533Sbill 		set_motor(fd_drive,0);
535*45533Sbill 		outb(fdc+fdctl,ft->trans);
536*45533Sbill 		fd_retry++;
537*45533Sbill 		fd_state = 4;
538*45533Sbill 		break;
53943594Sdonahn 	default:
54043594Sdonahn 		printf("Unexpected FD int->");
54143594Sdonahn 		out_fdc(0x8);
54243594Sdonahn 		i = in_fdc();
54343594Sdonahn 		sec = in_fdc();
54443594Sdonahn 		printf("ST0 = %X, PCN = %X\n",i,sec);
54543594Sdonahn 		out_fdc(0x4A);
54643594Sdonahn 		out_fdc(fd_drive);
54743594Sdonahn 		for(i=0;i<7;i++) {
54843594Sdonahn 			fd_status[i] = in_fdc();
54943594Sdonahn 		}
55043594Sdonahn 	printf("intr status :%X %X %X %X %X %X %X ",
55143594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
55243594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
55343594Sdonahn 		break;
55443594Sdonahn 	}
55543594Sdonahn 	return;
55643594Sdonahn retry:
55743594Sdonahn 	switch(fd_retry) {
55843594Sdonahn 	case 0: case 1:
559*45533Sbill 	case 2: case 3:
56043594Sdonahn 		break;
561*45533Sbill 	case 4:
56243594Sdonahn 		fd_retry++;
563*45533Sbill 		fd_state = 5;
564*45533Sbill 		fdintr(0);
56543594Sdonahn 		return;
566*45533Sbill 	case 5: case 6: case 7:
56743594Sdonahn 		break;
56843594Sdonahn 	default:
56943594Sdonahn 		printf("FD err %X %X %X %X %X %X %X\n",
57043594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
57143594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
57243594Sdonahn 		badtrans(dp,bp);
57343594Sdonahn 		return;
57443594Sdonahn 	}
57543594Sdonahn 	fd_state = 1;
57643594Sdonahn 	fd_retry++;
577*45533Sbill 	fdintr(0);
57843594Sdonahn }
57943594Sdonahn 
58043594Sdonahn badtrans(dp,bp)
58143594Sdonahn struct buf *dp,*bp;
58243594Sdonahn {
58343594Sdonahn 
58443594Sdonahn 	bp->b_flags |= B_ERROR;
58543594Sdonahn 	bp->b_error = EIO;
58643594Sdonahn 	bp->b_resid = bp->b_bcount - fd_skip;
58743594Sdonahn 	dp->b_actf = bp->av_forw;
58843594Sdonahn 	fd_skip = 0;
58943594Sdonahn 	biodone(bp);
59043594Sdonahn 	nextstate(dp);
59143594Sdonahn 
59243594Sdonahn }
59343594Sdonahn 
59443594Sdonahn /*
59543594Sdonahn 	nextstate : After a transfer is done, continue processing
59643594Sdonahn 	requests on the current drive queue.  If empty, go to
59743594Sdonahn 	the other drives queue.  If that is empty too, timeout
59843594Sdonahn 	to turn off the current drive in 5 seconds, and go
59943594Sdonahn 	to state 0 (not expecting any interrupts).
60043594Sdonahn */
60143594Sdonahn 
60243594Sdonahn nextstate(dp)
60343594Sdonahn struct buf *dp;
60443594Sdonahn {
60543594Sdonahn 	struct buf *dpother;
60643594Sdonahn 
60743594Sdonahn 	dpother = &fd_unit[fd_drive ? 0 : 1].head;
60843594Sdonahn 	if (dp->b_actf) fdstart(fd_drive);
60943594Sdonahn 	else if (dpother->b_actf) {
610*45533Sbill #ifdef FDTEST
611*45533Sbill printf("switch|");
612*45533Sbill #endif
613*45533Sbill 		untimeout(fd_turnoff,fd_drive);
614*45533Sbill 		timeout(fd_turnoff,fd_drive,5*hz);
615*45533Sbill 		fd_drive = 1 - fd_drive;
61643594Sdonahn 		dp->b_active = 0;
617*45533Sbill 		dpother->b_active = 1;
618*45533Sbill 		fdstart(fd_drive);
61943594Sdonahn 	} else {
620*45533Sbill #ifdef FDTEST
621*45533Sbill printf("off|");
622*45533Sbill #endif
62343594Sdonahn 		untimeout(fd_turnoff,fd_drive);
62443594Sdonahn 		timeout(fd_turnoff,fd_drive,5*hz);
62543594Sdonahn 		fd_state = 0;
62643594Sdonahn 		dp->b_active = 0;
62743594Sdonahn 	}
62843594Sdonahn }
629*45533Sbill #endif
630