xref: /csrg-svn/sys/i386/isa/fd.c (revision 63364)
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