xref: /csrg-svn/sys/i386/isa/fd.c (revision 43594)
1*43594Sdonahn /*-
2*43594Sdonahn  * Copyright (c) 1990 The Regents of the University of California.
3*43594Sdonahn  * All rights reserved.
4*43594Sdonahn  *
5*43594Sdonahn  * This code is derived from software contributed to Berkeley by
6*43594Sdonahn  * Don Ahn.
7*43594Sdonahn  *
8*43594Sdonahn  * %sccs.include.386.c%
9*43594Sdonahn  *
10*43594Sdonahn  *	@(#)fd.c	5.1 (Berkeley) 06/23/90
11*43594Sdonahn  */
12*43594Sdonahn 
13*43594Sdonahn /****************************************************************************/
14*43594Sdonahn /*                               fd driver                                  */
15*43594Sdonahn /****************************************************************************/
16*43594Sdonahn #include "param.h"
17*43594Sdonahn #include "dkbad.h"
18*43594Sdonahn #include "systm.h"
19*43594Sdonahn #include "conf.h"
20*43594Sdonahn #include "file.h"
21*43594Sdonahn #include "dir.h"
22*43594Sdonahn #include "user.h"
23*43594Sdonahn #include "ioctl.h"
24*43594Sdonahn #include "disk.h"
25*43594Sdonahn #include "buf.h"
26*43594Sdonahn #include "vm.h"
27*43594Sdonahn #include "uio.h"
28*43594Sdonahn #include "machine/pte.h"
29*43594Sdonahn #include "machine/device.h"
30*43594Sdonahn #include "icu.h"
31*43594Sdonahn 
32*43594Sdonahn #define NFD 2
33*43594Sdonahn #define	FDUNIT(s)	((s)&1)
34*43594Sdonahn #define	FDTYPE(s)	(((s)>>1)&7)
35*43594Sdonahn #define b_cylin b_resid
36*43594Sdonahn #define FDBLK 512
37*43594Sdonahn #define NUMTYPES 4
38*43594Sdonahn 
39*43594Sdonahn struct fd_type {
40*43594Sdonahn 	int	sectrac;		/* sectors per track         */
41*43594Sdonahn 	int	secsize;		/* size code for sectors     */
42*43594Sdonahn 	int	datalen;		/* data len when secsize = 0 */
43*43594Sdonahn 	int	gap;			/* gap len between sectors   */
44*43594Sdonahn 	int	tracks;			/* total num of tracks       */
45*43594Sdonahn 	int	size;			/* size of disk in sectors   */
46*43594Sdonahn 	int	steptrac;		/* steps per cylinder        */
47*43594Sdonahn 	int	trans;			/* transfer speed code       */
48*43594Sdonahn };
49*43594Sdonahn 
50*43594Sdonahn struct fd_type fd_types[NUMTYPES] = {
51*43594Sdonahn 	{ 18,2,0xFF,0x1B,80,2880,1,0 },	/* 1.44 meg HD 3.5in floppy    */
52*43594Sdonahn 	{ 15,2,0xFF,0x1B,80,2400,1,0 },	/* 1.2 meg HD floppy           */
53*43594Sdonahn 	{ 9,2,0xFF,0x23,40,720,2,1 },	/* 360k floppy in 1.2meg drive */
54*43594Sdonahn 	{ 9,2,0xFF,0x2A,40,720,1,1 },	/* 360k floppy in DD drive     */
55*43594Sdonahn };
56*43594Sdonahn 
57*43594Sdonahn struct fd_u {
58*43594Sdonahn 	int type;		/* Drive type (HD, DD     */
59*43594Sdonahn 	int active;		/* Drive activity boolean */
60*43594Sdonahn 	int motor;		/* Motor on flag          */
61*43594Sdonahn 	int opencnt;		/* Num times open         */
62*43594Sdonahn 	struct buf head;	/* Head of buf chain      */
63*43594Sdonahn 	struct buf rhead;	/* Raw head of buf chain  */
64*43594Sdonahn } fd_unit[NFD];
65*43594Sdonahn 
66*43594Sdonahn extern int hz;
67*43594Sdonahn 
68*43594Sdonahn /* state needed for current transfer */
69*43594Sdonahn static int fd_skip;
70*43594Sdonahn static int fd_state;
71*43594Sdonahn static int fd_retry;
72*43594Sdonahn static int fd_drive;
73*43594Sdonahn static int fd_status[7];
74*43594Sdonahn static char fdrawbuf[FDBLK];
75*43594Sdonahn 
76*43594Sdonahn /* stuff needed for virtual to physical calculations */
77*43594Sdonahn extern char Sysbase;
78*43594Sdonahn static unsigned long sbase = (unsigned long) &Sysbase;
79*43594Sdonahn 
80*43594Sdonahn /****************************************************************************/
81*43594Sdonahn /*                      autoconfiguration stuff                             */
82*43594Sdonahn /****************************************************************************/
83*43594Sdonahn int fdprobe(), fdattach(), fd_turnoff();
84*43594Sdonahn 
85*43594Sdonahn struct	driver fddriver = {
86*43594Sdonahn 	fdprobe, fdattach, "fd",
87*43594Sdonahn };
88*43594Sdonahn 
89*43594Sdonahn fdprobe(dev)
90*43594Sdonahn struct device *dev;
91*43594Sdonahn {
92*43594Sdonahn 	return 1;
93*43594Sdonahn }
94*43594Sdonahn 
95*43594Sdonahn fdattach(dev)
96*43594Sdonahn struct device *dev;
97*43594Sdonahn {
98*43594Sdonahn 	INTREN(IRQ6);
99*43594Sdonahn }
100*43594Sdonahn 
101*43594Sdonahn /****************************************************************************/
102*43594Sdonahn /*                               fdstrategy                                 */
103*43594Sdonahn /****************************************************************************/
104*43594Sdonahn fdstrategy(bp)
105*43594Sdonahn 	register struct buf *bp;	/* IO operation to perform */
106*43594Sdonahn {
107*43594Sdonahn 	register struct buf *dp,*dp0,*dp1;
108*43594Sdonahn 	long nblocks,blknum;
109*43594Sdonahn 	int	unit, type, s;
110*43594Sdonahn 
111*43594Sdonahn 	unit = FDUNIT(minor(bp->b_dev));
112*43594Sdonahn 	type = FDTYPE(minor(bp->b_dev));
113*43594Sdonahn #ifdef FDOTHER
114*43594Sdonahn 	printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n",
115*43594Sdonahn 		unit, bp->b_blkno, bp->b_bcount);
116*43594Sdonahn #endif
117*43594Sdonahn 	if ((unit >= NFD) || (bp->b_blkno < 0)) {
118*43594Sdonahn 		printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n",
119*43594Sdonahn 			unit, bp->b_blkno, bp->b_bcount);
120*43594Sdonahn 		pg("fd:error in fdstrategy");
121*43594Sdonahn 		bp->b_error = EINVAL;
122*43594Sdonahn 		goto bad;
123*43594Sdonahn 	}
124*43594Sdonahn 	/*
125*43594Sdonahn 	 * Set up block calculations.
126*43594Sdonahn 	 */
127*43594Sdonahn 	blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK;
128*43594Sdonahn 	nblocks = fd_types[type].size;
129*43594Sdonahn 	if (blknum + (bp->b_bcount / FDBLK) > nblocks) {
130*43594Sdonahn 		if (blknum == nblocks) bp->b_resid = bp->b_bcount;
131*43594Sdonahn 		else bp->b_error = ENOSPC;
132*43594Sdonahn 		goto bad;
133*43594Sdonahn 	}
134*43594Sdonahn 	bp->b_cylin = blknum / (fd_types[type].sectrac * 2);
135*43594Sdonahn 	bp->b_cylin *= (fd_types[type].steptrac);
136*43594Sdonahn 	dp = &fd_unit[unit].head;
137*43594Sdonahn 	dp0 = &fd_unit[0].head;
138*43594Sdonahn 	dp1 = &fd_unit[1].head;
139*43594Sdonahn 	s = splbio();
140*43594Sdonahn 	disksort(dp, bp);
141*43594Sdonahn 	if ((dp0->b_active == 0)&&(dp1->b_active == 0)) {
142*43594Sdonahn 		dp->b_active = 1;
143*43594Sdonahn 		fd_drive = unit;
144*43594Sdonahn 		untimeout(fd_turnoff,unit);
145*43594Sdonahn 		fdstart(unit);		/* start drive if idle */
146*43594Sdonahn 	}
147*43594Sdonahn 	splx(s);
148*43594Sdonahn 	return;
149*43594Sdonahn 
150*43594Sdonahn bad:
151*43594Sdonahn 	bp->b_flags |= B_ERROR;
152*43594Sdonahn 	biodone(bp);
153*43594Sdonahn }
154*43594Sdonahn 
155*43594Sdonahn /****************************************************************************/
156*43594Sdonahn /*                            motor control stuff                           */
157*43594Sdonahn /****************************************************************************/
158*43594Sdonahn set_motor(unit,reset)
159*43594Sdonahn int unit,reset;
160*43594Sdonahn {
161*43594Sdonahn 	int m0,m1;
162*43594Sdonahn 	m0 = fd_unit[0].motor;
163*43594Sdonahn 	m1 = fd_unit[1].motor;
164*43594Sdonahn 	outb(0x3f2,unit | (reset ? 0 : 0xC)  | (m0 ? 16 : 0) | (m1 ? 32 : 0));
165*43594Sdonahn }
166*43594Sdonahn 
167*43594Sdonahn fd_turnoff(unit)
168*43594Sdonahn int unit;
169*43594Sdonahn {
170*43594Sdonahn 	fd_unit[unit].motor = 0;
171*43594Sdonahn 	if (unit) set_motor(0,0);
172*43594Sdonahn 	else set_motor(1,0);
173*43594Sdonahn }
174*43594Sdonahn 
175*43594Sdonahn fd_turnon(unit)
176*43594Sdonahn int unit;
177*43594Sdonahn {
178*43594Sdonahn 	fd_unit[unit].motor = 1;
179*43594Sdonahn 	set_motor(unit,0);
180*43594Sdonahn }
181*43594Sdonahn 
182*43594Sdonahn /****************************************************************************/
183*43594Sdonahn /*                             fdc in/out                                   */
184*43594Sdonahn /****************************************************************************/
185*43594Sdonahn int
186*43594Sdonahn in_fdc()
187*43594Sdonahn {
188*43594Sdonahn 	int i;
189*43594Sdonahn 	while ((i = inb(0x3f4) & 192) != 192) if (i == 128) return -1;
190*43594Sdonahn 	return inb(0x3f5);
191*43594Sdonahn }
192*43594Sdonahn 
193*43594Sdonahn dump_stat()
194*43594Sdonahn {
195*43594Sdonahn 	int i;
196*43594Sdonahn 	for(i=0;i<7;i++) {
197*43594Sdonahn 		fd_status[i] = in_fdc();
198*43594Sdonahn 		if (fd_status[i] < 0) break;
199*43594Sdonahn 	}
200*43594Sdonahn 	printf("FD bad status :%X %X %X %X %X %X %X\n",
201*43594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
202*43594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
203*43594Sdonahn }
204*43594Sdonahn 
205*43594Sdonahn out_fdc(x)
206*43594Sdonahn int x;
207*43594Sdonahn {
208*43594Sdonahn 	int r,errcnt;
209*43594Sdonahn 	static int maxcnt = 0;
210*43594Sdonahn 	errcnt = 0;
211*43594Sdonahn 	do {
212*43594Sdonahn 		r = (inb(0x3f4) & 192);
213*43594Sdonahn 		if (r==128) break;
214*43594Sdonahn 		if (r==192) {
215*43594Sdonahn 			dump_stat(); /* error: direction. eat up output */
216*43594Sdonahn #ifdef FDOTHER
217*43594Sdonahn 			printf("%X\n",x);
218*43594Sdonahn #endif
219*43594Sdonahn 		}
220*43594Sdonahn 		/* printf("Error r = %d:",r); */
221*43594Sdonahn 		errcnt++;
222*43594Sdonahn 	} while (1);
223*43594Sdonahn 	if (errcnt > maxcnt) {
224*43594Sdonahn 		maxcnt = errcnt;
225*43594Sdonahn #ifdef FDOTHER
226*43594Sdonahn 		printf("New MAX = %d\n",maxcnt);
227*43594Sdonahn #endif
228*43594Sdonahn 	}
229*43594Sdonahn 	outb(0x3f5,x&0xFF);
230*43594Sdonahn }
231*43594Sdonahn 
232*43594Sdonahn /* see if fdc responding */
233*43594Sdonahn int
234*43594Sdonahn check_fdc()
235*43594Sdonahn {
236*43594Sdonahn 	int i;
237*43594Sdonahn 	for(i=0;i<100;i++) {
238*43594Sdonahn 		if (inb(0x3f4)&128) return 0;
239*43594Sdonahn 	}
240*43594Sdonahn 	return 1;
241*43594Sdonahn }
242*43594Sdonahn 
243*43594Sdonahn /****************************************************************************/
244*43594Sdonahn /*                           fdopen/fdclose                                 */
245*43594Sdonahn /****************************************************************************/
246*43594Sdonahn fdopen(dev, flags)
247*43594Sdonahn 	dev_t	dev;
248*43594Sdonahn 	int	flags;
249*43594Sdonahn {
250*43594Sdonahn 	int unit = FDUNIT(minor(dev));
251*43594Sdonahn 	int type = FDTYPE(minor(dev));
252*43594Sdonahn 	int s;
253*43594Sdonahn 
254*43594Sdonahn 	/* check bounds */
255*43594Sdonahn 	if (unit >= NFD) return(ENXIO);
256*43594Sdonahn 	if (type >= NUMTYPES) return(ENXIO);
257*43594Sdonahn 	if (check_fdc()) return(EBUSY);
258*43594Sdonahn 
259*43594Sdonahn 	/* Set proper disk type, only allow one type */
260*43594Sdonahn 	s = splbio();
261*43594Sdonahn 	splx(s);
262*43594Sdonahn 
263*43594Sdonahn 	return 0;
264*43594Sdonahn }
265*43594Sdonahn 
266*43594Sdonahn fdclose(dev)
267*43594Sdonahn 	dev_t dev;
268*43594Sdonahn {
269*43594Sdonahn }
270*43594Sdonahn 
271*43594Sdonahn /****************************************************************************/
272*43594Sdonahn /*                            fdread/fdwrite                                */
273*43594Sdonahn /****************************************************************************/
274*43594Sdonahn /*
275*43594Sdonahn  * Routines to do raw IO for a unit.
276*43594Sdonahn  */
277*43594Sdonahn fdread(dev, uio)			/* character read routine */
278*43594Sdonahn dev_t dev;
279*43594Sdonahn struct uio *uio;
280*43594Sdonahn {
281*43594Sdonahn 	int unit = FDUNIT(minor(dev)) ;
282*43594Sdonahn 	if (unit >= NFD) return(ENXIO);
283*43594Sdonahn 	return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio));
284*43594Sdonahn }
285*43594Sdonahn 
286*43594Sdonahn fdwrite(dev, uio)			/* character write routine */
287*43594Sdonahn dev_t dev;
288*43594Sdonahn struct uio *uio;
289*43594Sdonahn {
290*43594Sdonahn 	int unit = FDUNIT(minor(dev));
291*43594Sdonahn 	if (unit >= NFD) return(ENXIO);
292*43594Sdonahn 	return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio));
293*43594Sdonahn }
294*43594Sdonahn 
295*43594Sdonahn /****************************************************************************/
296*43594Sdonahn /*                                 fdstart                                  */
297*43594Sdonahn /****************************************************************************/
298*43594Sdonahn fdstart(unit)
299*43594Sdonahn int unit;
300*43594Sdonahn {
301*43594Sdonahn 	register struct buf *dp,*bp;
302*43594Sdonahn 	int s;
303*43594Sdonahn 
304*43594Sdonahn 	if (!fd_unit[unit].motor) {
305*43594Sdonahn 		fd_turnon(unit);
306*43594Sdonahn 		/* Wait for 1 sec */
307*43594Sdonahn 		timeout(fdstart,unit,hz);
308*43594Sdonahn 	} else {
309*43594Sdonahn 		s = splbio();
310*43594Sdonahn 		dp = &fd_unit[unit].head;
311*43594Sdonahn 		bp = dp->b_actf;
312*43594Sdonahn 		fd_retry = 0;
313*43594Sdonahn 		fd_state = 1;
314*43594Sdonahn 		fd_skip = 0;
315*43594Sdonahn 		/* Seek necessary, never quite sure where head is at! */
316*43594Sdonahn 		out_fdc(15);	/* Seek function */
317*43594Sdonahn 		out_fdc(unit);	/* Drive number */
318*43594Sdonahn 		out_fdc(bp->b_cylin);
319*43594Sdonahn 		splx(s);
320*43594Sdonahn 	}
321*43594Sdonahn }
322*43594Sdonahn 
323*43594Sdonahn /* XXX temporary */
324*43594Sdonahn kernel_space(x)
325*43594Sdonahn unsigned long x;
326*43594Sdonahn {
327*43594Sdonahn 	if ((x >= sbase) & (x < sbase + 0x800000)) return 1;
328*43594Sdonahn 	else return 0;
329*43594Sdonahn }
330*43594Sdonahn 
331*43594Sdonahn 
332*43594Sdonahn /****************************************************************************/
333*43594Sdonahn /*                                 fd_dma                                   */
334*43594Sdonahn /* set up DMA read/write operation and virtual address addr for nbytes      */
335*43594Sdonahn /****************************************************************************/
336*43594Sdonahn fd_dma(read,addr,nbytes)
337*43594Sdonahn int read;
338*43594Sdonahn unsigned long addr;
339*43594Sdonahn int nbytes;
340*43594Sdonahn {
341*43594Sdonahn 	unsigned long phys;
342*43594Sdonahn 	int s,raw;
343*43594Sdonahn 
344*43594Sdonahn 	if (kernel_space(addr)) raw = 0;
345*43594Sdonahn 	else raw = 1;
346*43594Sdonahn 
347*43594Sdonahn 	/* copy bounce buffer on write */
348*43594Sdonahn 	if (raw && !read) bcopy(addr,fdrawbuf,FDBLK);
349*43594Sdonahn 
350*43594Sdonahn 	/* Set read/write bytes */
351*43594Sdonahn 	if (read) {
352*43594Sdonahn 		outb(0xC,0x46); outb(0xB,0x46);
353*43594Sdonahn 	} else {
354*43594Sdonahn 		outb(0xC,0x4A); outb(0xB,0x4A);
355*43594Sdonahn 	}
356*43594Sdonahn 	/* Send start address */
357*43594Sdonahn 	if (raw) phys = (unsigned long) &fdrawbuf[0];
358*43594Sdonahn 	else phys = addr;
359*43594Sdonahn 	/* translate to physical */
360*43594Sdonahn 	phys = phys - sbase;
361*43594Sdonahn 	outb(0x4,phys & 0xFF);
362*43594Sdonahn 	outb(0x4,(phys>>8) & 0xFF);
363*43594Sdonahn 	outb(0x81,(phys>>16) & 0xFF);
364*43594Sdonahn 	/* Send count */
365*43594Sdonahn 	nbytes--;
366*43594Sdonahn 	outb(0x5,nbytes & 0xFF);
367*43594Sdonahn 	outb(0x5,(nbytes>>8) & 0xFF);
368*43594Sdonahn 	/* set channel 2 */
369*43594Sdonahn 	outb(0x0A,2);
370*43594Sdonahn }
371*43594Sdonahn 
372*43594Sdonahn fd_timeout(x)
373*43594Sdonahn int x;
374*43594Sdonahn {
375*43594Sdonahn 	int i,j;
376*43594Sdonahn 	struct buf *dp,*bp;
377*43594Sdonahn 
378*43594Sdonahn 	dp = &fd_unit[fd_drive].head;
379*43594Sdonahn 	bp = dp->b_actf;
380*43594Sdonahn 
381*43594Sdonahn 	out_fdc(0x4);
382*43594Sdonahn 	out_fdc(fd_drive);
383*43594Sdonahn 	i = in_fdc();
384*43594Sdonahn 	printf("Timeout drive status %X\n",i);
385*43594Sdonahn 
386*43594Sdonahn 	out_fdc(0x8);
387*43594Sdonahn 	i = in_fdc();
388*43594Sdonahn 	j = in_fdc();
389*43594Sdonahn 	printf("ST0 = %X, PCN = %X\n",i,j);
390*43594Sdonahn 
391*43594Sdonahn 	if (bp) badtrans(dp,bp);
392*43594Sdonahn }
393*43594Sdonahn 
394*43594Sdonahn /****************************************************************************/
395*43594Sdonahn /*                                 fdintr                                   */
396*43594Sdonahn /****************************************************************************/
397*43594Sdonahn fdintr(vec)
398*43594Sdonahn int vec;
399*43594Sdonahn {
400*43594Sdonahn 	register struct buf *dp,*bp;
401*43594Sdonahn 	struct buf *dpother;
402*43594Sdonahn 	int read,head,trac,sec,i,s,sectrac;
403*43594Sdonahn 	unsigned long blknum;
404*43594Sdonahn 	struct fd_type *ft;
405*43594Sdonahn 	static int fd_track;
406*43594Sdonahn 
407*43594Sdonahn 	dp = &fd_unit[fd_drive].head;
408*43594Sdonahn 	bp = dp->b_actf;
409*43594Sdonahn 	read = bp->b_flags & B_READ;
410*43594Sdonahn 	ft = &fd_types[FDTYPE(bp->b_dev)];
411*43594Sdonahn 
412*43594Sdonahn 	switch (fd_state) {
413*43594Sdonahn 	case 1 : /* SEEK DONE, START DMA */
414*43594Sdonahn #ifdef FDOTHER
415*43594Sdonahn 		out_fdc(0x8);
416*43594Sdonahn 		i = in_fdc();
417*43594Sdonahn 		sec = in_fdc();
418*43594Sdonahn 		printf("ST0 = %X, PCN = %X:",i,sec);
419*43594Sdonahn #endif
420*43594Sdonahn 		fd_track = bp->b_cylin;
421*43594Sdonahn 		fd_dma(read,bp->b_un.b_addr+fd_skip,FDBLK);
422*43594Sdonahn 		blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
423*43594Sdonahn 			+ fd_skip/FDBLK;
424*43594Sdonahn 		sectrac = ft->sectrac;
425*43594Sdonahn 		sec = blknum %  (sectrac * 2);
426*43594Sdonahn 		head = sec / sectrac;
427*43594Sdonahn 		sec = sec % sectrac + 1;
428*43594Sdonahn 
429*43594Sdonahn 		if (read)  out_fdc(0xE6);	/* READ */
430*43594Sdonahn 		else out_fdc(0xC5);		/* WRITE */
431*43594Sdonahn 		out_fdc(head << 2 | fd_drive);	/* head & unit */
432*43594Sdonahn 		out_fdc(fd_track);		/* track */
433*43594Sdonahn 		out_fdc(head);
434*43594Sdonahn 		out_fdc(sec);			/* sector XXX +1? */
435*43594Sdonahn 		out_fdc(ft->secsize);		/* sector size */
436*43594Sdonahn 		out_fdc(sectrac);		/* sectors/track */
437*43594Sdonahn 		out_fdc(ft->gap);		/* gap size */
438*43594Sdonahn 		out_fdc(ft->datalen);		/* data length */
439*43594Sdonahn 		fd_state = 2;
440*43594Sdonahn 		/* XXX PARANOIA */
441*43594Sdonahn 		untimeout(fd_timeout,2);
442*43594Sdonahn 		timeout(fd_timeout,2,hz);
443*43594Sdonahn 		break;
444*43594Sdonahn 	case 2 : /* IO DONE, post-analyze */
445*43594Sdonahn 		untimeout(fd_timeout,2);
446*43594Sdonahn 		for(i=0;i<7;i++) {
447*43594Sdonahn 			fd_status[i] = in_fdc();
448*43594Sdonahn 		}
449*43594Sdonahn 		if (fd_status[0]&0xF8) {
450*43594Sdonahn #ifdef FDOTHER
451*43594Sdonahn 			printf("status0 err %d:",fd_status[0]);
452*43594Sdonahn #endif
453*43594Sdonahn 			goto retry;
454*43594Sdonahn 		}
455*43594Sdonahn 		if (fd_status[1]){
456*43594Sdonahn 			printf("status1 err %d:",fd_status[0]);
457*43594Sdonahn 			goto retry;
458*43594Sdonahn 		}
459*43594Sdonahn 		if (fd_status[2]){
460*43594Sdonahn 			printf("status2 err %d:",fd_status[0]);
461*43594Sdonahn 			goto retry;
462*43594Sdonahn 		}
463*43594Sdonahn 		/* All OK */
464*43594Sdonahn 		if (!kernel_space(bp->b_un.b_addr+fd_skip)) {
465*43594Sdonahn 			/* RAW transfer */
466*43594Sdonahn 			if (read) bcopy(fdrawbuf,bp->b_un.b_addr+fd_skip,
467*43594Sdonahn 					DEV_BSIZE);
468*43594Sdonahn 		}
469*43594Sdonahn 		fd_skip += FDBLK;
470*43594Sdonahn 		if (fd_skip >= bp->b_bcount) {
471*43594Sdonahn 			/* ALL DONE */
472*43594Sdonahn 			fd_skip = 0;
473*43594Sdonahn 			bp->b_resid = 0;
474*43594Sdonahn 			dp->b_actf = bp->av_forw;
475*43594Sdonahn 			biodone(bp);
476*43594Sdonahn 			nextstate(dp);
477*43594Sdonahn 
478*43594Sdonahn 		} else {
479*43594Sdonahn 			/* set up next transfer */
480*43594Sdonahn 			blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK
481*43594Sdonahn 				+ fd_skip/FDBLK;
482*43594Sdonahn 			fd_state = 1;
483*43594Sdonahn 			bp->b_cylin = (blknum / (ft->sectrac * 2));
484*43594Sdonahn 			bp->b_cylin *= ft->steptrac;
485*43594Sdonahn 			if (bp->b_cylin != fd_track) {
486*43594Sdonahn 				/* SEEK Necessary */
487*43594Sdonahn 				out_fdc(15);	/* Seek function */
488*43594Sdonahn 				out_fdc(fd_drive);/* Drive number */
489*43594Sdonahn 				out_fdc(bp->b_cylin);
490*43594Sdonahn 				break;
491*43594Sdonahn 			} else fdintr();
492*43594Sdonahn 		}
493*43594Sdonahn 		break;
494*43594Sdonahn 	case 3:
495*43594Sdonahn 		/* Seek necessary */
496*43594Sdonahn 		out_fdc(15);	/* Seek function */
497*43594Sdonahn 		out_fdc(fd_drive);/* Drive number */
498*43594Sdonahn 		out_fdc(bp->b_cylin);
499*43594Sdonahn 		fd_state = 1;
500*43594Sdonahn 		break;
501*43594Sdonahn 	case 4:
502*43594Sdonahn 		out_fdc(3); /* specify command */
503*43594Sdonahn 		out_fdc(0xDF);
504*43594Sdonahn 		out_fdc(2);
505*43594Sdonahn 		out_fdc(7);	/* Recalibrate Function */
506*43594Sdonahn 		out_fdc(fd_drive);
507*43594Sdonahn 		fd_state = 3;
508*43594Sdonahn 		break;
509*43594Sdonahn 	default:
510*43594Sdonahn #ifdef FDDEBUG
511*43594Sdonahn 		printf("Unexpected FD int->");
512*43594Sdonahn 		out_fdc(0x8);
513*43594Sdonahn 		i = in_fdc();
514*43594Sdonahn 		sec = in_fdc();
515*43594Sdonahn 		printf("ST0 = %X, PCN = %X\n",i,sec);
516*43594Sdonahn 		out_fdc(0x4A);
517*43594Sdonahn 		out_fdc(fd_drive);
518*43594Sdonahn 		for(i=0;i<7;i++) {
519*43594Sdonahn 			fd_status[i] = in_fdc();
520*43594Sdonahn 		}
521*43594Sdonahn 	printf("intr status :%X %X %X %X %X %X %X ",
522*43594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
523*43594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
524*43594Sdonahn #endif
525*43594Sdonahn 		break;
526*43594Sdonahn 	}
527*43594Sdonahn 	return;
528*43594Sdonahn retry:
529*43594Sdonahn 	switch(fd_retry) {
530*43594Sdonahn 	case 0: case 1:
531*43594Sdonahn 		break;
532*43594Sdonahn 	case 2:
533*43594Sdonahn #ifdef FDDEBUG
534*43594Sdonahn 		printf("**RESET**\n");
535*43594Sdonahn #endif
536*43594Sdonahn 		/* Try a reset, keep motor on */
537*43594Sdonahn 		set_motor(fd_drive,1);
538*43594Sdonahn 		set_motor(fd_drive,0);
539*43594Sdonahn 		outb(0x3f7,ft->trans);
540*43594Sdonahn 		fd_retry++;
541*43594Sdonahn 		fd_state = 4;
542*43594Sdonahn 		return;
543*43594Sdonahn 	case 3: case 4:
544*43594Sdonahn 	case 5: case 6:
545*43594Sdonahn 		break;
546*43594Sdonahn 	default:
547*43594Sdonahn 		printf("FD err %X %X %X %X %X %X %X\n",
548*43594Sdonahn 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
549*43594Sdonahn 		fd_status[4], fd_status[5], fd_status[6] );
550*43594Sdonahn 		badtrans(dp,bp);
551*43594Sdonahn 		return;
552*43594Sdonahn 	}
553*43594Sdonahn 	fd_state = 1;
554*43594Sdonahn 	fd_retry++;
555*43594Sdonahn 	fdintr();
556*43594Sdonahn }
557*43594Sdonahn 
558*43594Sdonahn badtrans(dp,bp)
559*43594Sdonahn struct buf *dp,*bp;
560*43594Sdonahn {
561*43594Sdonahn 
562*43594Sdonahn 	bp->b_flags |= B_ERROR;
563*43594Sdonahn 	bp->b_error = EIO;
564*43594Sdonahn 	bp->b_resid = bp->b_bcount - fd_skip;
565*43594Sdonahn 	dp->b_actf = bp->av_forw;
566*43594Sdonahn 	fd_skip = 0;
567*43594Sdonahn 	biodone(bp);
568*43594Sdonahn 	nextstate(dp);
569*43594Sdonahn 
570*43594Sdonahn }
571*43594Sdonahn 
572*43594Sdonahn /*
573*43594Sdonahn 	nextstate : After a transfer is done, continue processing
574*43594Sdonahn 	requests on the current drive queue.  If empty, go to
575*43594Sdonahn 	the other drives queue.  If that is empty too, timeout
576*43594Sdonahn 	to turn off the current drive in 5 seconds, and go
577*43594Sdonahn 	to state 0 (not expecting any interrupts).
578*43594Sdonahn */
579*43594Sdonahn 
580*43594Sdonahn nextstate(dp)
581*43594Sdonahn struct buf *dp;
582*43594Sdonahn {
583*43594Sdonahn 	struct buf *dpother;
584*43594Sdonahn 
585*43594Sdonahn 	dpother = &fd_unit[fd_drive ? 0 : 1].head;
586*43594Sdonahn 	if (dp->b_actf) fdstart(fd_drive);
587*43594Sdonahn 	else if (dpother->b_actf) {
588*43594Sdonahn 		dp->b_active = 0;
589*43594Sdonahn 		fdstart(fd_drive ? 0 : 1);
590*43594Sdonahn 	} else {
591*43594Sdonahn 		untimeout(fd_turnoff,fd_drive);
592*43594Sdonahn 		timeout(fd_turnoff,fd_drive,5*hz);
593*43594Sdonahn 		fd_state = 0;
594*43594Sdonahn 		dp->b_active = 0;
595*43594Sdonahn 	}
596*43594Sdonahn }
597