xref: /csrg-svn/sys/i386/stand/fd.c (revision 48819)
1*48819Swilliam /*-
2*48819Swilliam  * Copyright (c) 1990 The Regents of the University of California.
3*48819Swilliam  * All rights reserved.
4*48819Swilliam  *
5*48819Swilliam  * This code is derived from software contributed to Berkeley by
6*48819Swilliam  * Don Ahn.
7*48819Swilliam  *
8*48819Swilliam  * %sccs.include.redist.c%
9*48819Swilliam  *
10*48819Swilliam  *	@(#)fd.c	7.1 (Berkeley) 04/28/91
11*48819Swilliam  */
12*48819Swilliam 
13*48819Swilliam /****************************************************************************/
14*48819Swilliam /*                        standalone fd driver                               */
15*48819Swilliam /****************************************************************************/
16*48819Swilliam #include "param.h"
17*48819Swilliam #include "dkbad.h"
18*48819Swilliam #include "i386/isa/disk.h"
19*48819Swilliam #include "i386/isa/fdreg.h"
20*48819Swilliam #include "i386/isa/isa.h"
21*48819Swilliam #include "saio.h"
22*48819Swilliam 
23*48819Swilliam #define NUMRETRY 10
24*48819Swilliam /*#define FDDEBUG*/
25*48819Swilliam 
26*48819Swilliam #define NFD 2
27*48819Swilliam #define FDBLK 512
28*48819Swilliam #define NUMTYPES 4
29*48819Swilliam 
30*48819Swilliam struct fd_type {
31*48819Swilliam 	int	sectrac;		/* sectors per track         */
32*48819Swilliam 	int	secsize;		/* size code for sectors     */
33*48819Swilliam 	int	datalen;		/* data len when secsize = 0 */
34*48819Swilliam 	int	gap;			/* gap len between sectors   */
35*48819Swilliam 	int	tracks;			/* total num of tracks       */
36*48819Swilliam 	int	size;			/* size of disk in sectors   */
37*48819Swilliam 	int	steptrac;		/* steps per cylinder        */
38*48819Swilliam 	int	trans;			/* transfer speed code       */
39*48819Swilliam };
40*48819Swilliam 
41*48819Swilliam struct fd_type fd_types[NUMTYPES] = {
42*48819Swilliam  	{ 18,2,0xFF,0x1B,80,2880,1,0 },	/* 1.44 meg HD 3.5in floppy    */
43*48819Swilliam 	{ 15,2,0xFF,0x1B,80,2400,1,0 },	/* 1.2 meg HD floppy           */
44*48819Swilliam 	{ 9,2,0xFF,0x23,40,720,2,1 },	/* 360k floppy in 1.2meg drive */
45*48819Swilliam 	{ 9,2,0xFF,0x2A,40,720,1,1 },	/* 360k floppy in DD drive     */
46*48819Swilliam };
47*48819Swilliam 
48*48819Swilliam 
49*48819Swilliam /* state needed for current transfer */
50*48819Swilliam static int fd_type;
51*48819Swilliam static int fd_motor;
52*48819Swilliam static int fd_retry;
53*48819Swilliam static int fd_drive;
54*48819Swilliam static int fd_status[7];
55*48819Swilliam 
56*48819Swilliam static int fdc = IO_FD1;	/* floppy disk base */
57*48819Swilliam 
58*48819Swilliam /* Make sure DMA buffer doesn't cross 64k boundary */
59*48819Swilliam char bounce[FDBLK];
60*48819Swilliam 
61*48819Swilliam 
62*48819Swilliam /****************************************************************************/
63*48819Swilliam /*                               fdstrategy                                 */
64*48819Swilliam /****************************************************************************/
65*48819Swilliam int
66*48819Swilliam fdstrategy(io,func)
67*48819Swilliam register struct iob *io;
68*48819Swilliam int func;
69*48819Swilliam {
70*48819Swilliam 	char *address;
71*48819Swilliam 	long nblocks,blknum;
72*48819Swilliam  	int unit, iosize;
73*48819Swilliam 
74*48819Swilliam #ifdef FDDEBUG
75*48819Swilliam printf("fdstrat ");
76*48819Swilliam #endif
77*48819Swilliam 	unit = io->i_unit;
78*48819Swilliam 	fd_type = io->i_part;
79*48819Swilliam 
80*48819Swilliam 	/*
81*48819Swilliam 	 * Set up block calculations.
82*48819Swilliam 	 */
83*48819Swilliam         iosize = io->i_cc / FDBLK;
84*48819Swilliam 	blknum = (unsigned long) io->i_bn * DEV_BSIZE / FDBLK;
85*48819Swilliam  	nblocks = fd_types[fd_type].size;
86*48819Swilliam 	if ((blknum + iosize > nblocks) || blknum < 0) {
87*48819Swilliam #ifndef SMALL
88*48819Swilliam 		printf("bn = %d; sectors = %d; type = %d; fssize = %d ",
89*48819Swilliam 			blknum, iosize, fd_type, nblocks);
90*48819Swilliam                 printf("fdstrategy - I/O out of filesystem boundaries\n");
91*48819Swilliam #endif
92*48819Swilliam 		return(-1);
93*48819Swilliam 	}
94*48819Swilliam 
95*48819Swilliam 	address = io->i_ma;
96*48819Swilliam         while (iosize > 0) {
97*48819Swilliam                 if (fdio(func, unit, blknum, address))
98*48819Swilliam                         return(-1);
99*48819Swilliam 		iosize--;
100*48819Swilliam 		blknum++;
101*48819Swilliam                 address += FDBLK;
102*48819Swilliam         }
103*48819Swilliam         return(io->i_cc);
104*48819Swilliam }
105*48819Swilliam 
106*48819Swilliam int
107*48819Swilliam fdio(func, unit, blknum, address)
108*48819Swilliam int func,unit,blknum;
109*48819Swilliam char *address;
110*48819Swilliam {
111*48819Swilliam 	int i,j,cyl,sectrac,sec,head,numretry;
112*48819Swilliam 	struct fd_type *ft;
113*48819Swilliam 
114*48819Swilliam  	ft = &fd_types[fd_type];
115*48819Swilliam #ifdef FDDEBUG
116*48819Swilliam printf("fdio ");
117*48819Swilliam #endif
118*48819Swilliam 
119*48819Swilliam  	sectrac = ft->sectrac;
120*48819Swilliam 	cyl = blknum / (2 * sectrac);
121*48819Swilliam 	numretry = NUMRETRY;
122*48819Swilliam 
123*48819Swilliam 	if (func == WRITE) bcopy(address,bounce,FDBLK);
124*48819Swilliam 
125*48819Swilliam retry:
126*48819Swilliam 	out_fdc(15);	/* Seek function */
127*48819Swilliam 	out_fdc(unit);	/* Drive number */
128*48819Swilliam 	out_fdc(cyl);
129*48819Swilliam 
130*48819Swilliam 	waitio();
131*48819Swilliam 
132*48819Swilliam 	out_fdc(0x8);
133*48819Swilliam 	i = in_fdc(); j = in_fdc();
134*48819Swilliam 	if (!(i&0x20) || (cyl != j)) {
135*48819Swilliam 		numretry--;
136*48819Swilliam 		if (numretry) goto retry;
137*48819Swilliam #ifndef SMALL
138*48819Swilliam 		printf("Seek error %d, req = %d, at = %d\n",i,cyl,j);
139*48819Swilliam 		printf("unit %d, type %d, sectrac %d, blknum %d\n",
140*48819Swilliam 			unit,fd_type,sectrac,blknum);
141*48819Swilliam #endif
142*48819Swilliam 		return -1;
143*48819Swilliam 	}
144*48819Swilliam 
145*48819Swilliam 	/* set up transfer */
146*48819Swilliam 	fd_dma(func == READ,bounce,FDBLK);
147*48819Swilliam 	sec = blknum %  (sectrac * 2);
148*48819Swilliam 	head = sec / sectrac;
149*48819Swilliam 	sec = sec % sectrac + 1;
150*48819Swilliam #ifdef FDDEBUG
151*48819Swilliam 	printf("sec %d hd %d cyl %d ", sec, head, cyl);
152*48819Swilliam #endif
153*48819Swilliam 
154*48819Swilliam 	if (func == READ)  out_fdc(0xE6);/* READ */
155*48819Swilliam 	else out_fdc(0xC5);		/* WRITE */
156*48819Swilliam 	out_fdc(head << 2 | fd_drive);	/* head & unit */
157*48819Swilliam 	out_fdc(cyl);			/* track */
158*48819Swilliam 	out_fdc(head);
159*48819Swilliam 	out_fdc(sec);			/* sector XXX +1? */
160*48819Swilliam 	out_fdc(ft->secsize);		/* sector size */
161*48819Swilliam 	out_fdc(sectrac);		/* sectors/track */
162*48819Swilliam 	out_fdc(ft->gap);		/* gap size */
163*48819Swilliam 	out_fdc(ft->datalen);		/* data length */
164*48819Swilliam 
165*48819Swilliam 	waitio();
166*48819Swilliam 
167*48819Swilliam 	for(i=0;i<7;i++) {
168*48819Swilliam 		fd_status[i] = in_fdc();
169*48819Swilliam 	}
170*48819Swilliam 	if (fd_status[0]&0xF8) {
171*48819Swilliam 		numretry--;
172*48819Swilliam 		if (numretry) goto retry;
173*48819Swilliam #ifndef SMALL
174*48819Swilliam 		printf("FD err %X %X %X %X %X %X %X\n",
175*48819Swilliam 		fd_status[0], fd_status[1], fd_status[2], fd_status[3],
176*48819Swilliam 		fd_status[4], fd_status[5], fd_status[6] );
177*48819Swilliam #endif
178*48819Swilliam 		return -1;
179*48819Swilliam 	}
180*48819Swilliam 	if (func == READ) bcopy(bounce,address,FDBLK);
181*48819Swilliam 	return 0;
182*48819Swilliam }
183*48819Swilliam 
184*48819Swilliam /****************************************************************************/
185*48819Swilliam /*                             fdc in/out                                   */
186*48819Swilliam /****************************************************************************/
187*48819Swilliam int
188*48819Swilliam in_fdc()
189*48819Swilliam {
190*48819Swilliam 	int i;
191*48819Swilliam 	while ((i = inb(fdc+fdsts) & 192) != 192) if (i == 128) return -1;
192*48819Swilliam 	return inb(0x3f5);
193*48819Swilliam }
194*48819Swilliam 
195*48819Swilliam dump_stat()
196*48819Swilliam {
197*48819Swilliam 	int i;
198*48819Swilliam 	for(i=0;i<7;i++) {
199*48819Swilliam 		fd_status[i] = in_fdc();
200*48819Swilliam 		if (fd_status[i] < 0) break;
201*48819Swilliam 	}
202*48819Swilliam #ifdef FDDEBUGx
203*48819Swilliam printf("FD bad status :%X %X %X %X %X %X %X\n",
204*48819Swilliam 	fd_status[0], fd_status[1], fd_status[2], fd_status[3],
205*48819Swilliam 	fd_status[4], fd_status[5], fd_status[6] );
206*48819Swilliam #endif
207*48819Swilliam }
208*48819Swilliam 
209*48819Swilliam set_intr()
210*48819Swilliam {
211*48819Swilliam 	/* initialize 8259's */
212*48819Swilliam 	outb(0x20,0x11);
213*48819Swilliam 	outb(0x21,32);
214*48819Swilliam 	outb(0x21,4);
215*48819Swilliam 	outb(0x21,1);
216*48819Swilliam 	outb(0x21,0x0f); /* turn on int 6 */
217*48819Swilliam 
218*48819Swilliam /*
219*48819Swilliam 	outb(0xa0,0x11);
220*48819Swilliam 	outb(0xa1,40);
221*48819Swilliam 	outb(0xa1,2);
222*48819Swilliam 	outb(0xa1,1);
223*48819Swilliam 	outb(0xa1,0xff); */
224*48819Swilliam 
225*48819Swilliam }
226*48819Swilliam 
227*48819Swilliam 
228*48819Swilliam 
229*48819Swilliam waitio()
230*48819Swilliam {
231*48819Swilliam char c;
232*48819Swilliam int n;
233*48819Swilliam 
234*48819Swilliam 	do
235*48819Swilliam 		outb(0x20,0xc); /* read polled interrupt */
236*48819Swilliam 	while ((c=inb(0x20))&0x7f != 6); /* wait for int */
237*48819Swilliam 	outb(0x20,0x20);
238*48819Swilliam }
239*48819Swilliam 
240*48819Swilliam out_fdc(x)
241*48819Swilliam int x;
242*48819Swilliam {
243*48819Swilliam 	int r;
244*48819Swilliam 	do {
245*48819Swilliam 		r = (inb(fdc+fdsts) & 192);
246*48819Swilliam 		if (r==128) break;
247*48819Swilliam 		if (r==192) {
248*48819Swilliam 			dump_stat(); /* error: direction. eat up output */
249*48819Swilliam 		}
250*48819Swilliam 	} while (1);
251*48819Swilliam 	outb(0x3f5,x&0xFF);
252*48819Swilliam }
253*48819Swilliam 
254*48819Swilliam 
255*48819Swilliam /****************************************************************************/
256*48819Swilliam /*                           fdopen/fdclose                                 */
257*48819Swilliam /****************************************************************************/
258*48819Swilliam fdopen(io)
259*48819Swilliam 	register struct iob *io;
260*48819Swilliam {
261*48819Swilliam 	int unit, type, i;
262*48819Swilliam 	struct fd_type *ft;
263*48819Swilliam 
264*48819Swilliam 	unit = io->i_unit;
265*48819Swilliam 	type = io->i_part;
266*48819Swilliam 	io->i_boff = 0;		/* no disklabels -- tar/dump wont work */
267*48819Swilliam #ifdef FDDEBUG
268*48819Swilliam 	printf("fdopen %d %d ", unit, type);
269*48819Swilliam #endif
270*48819Swilliam  	ft = &fd_types[type];
271*48819Swilliam 	fd_drive = unit;
272*48819Swilliam 
273*48819Swilliam 	set_intr(); /* init intr cont */
274*48819Swilliam 
275*48819Swilliam 	/* Try a reset, keep motor on */
276*48819Swilliam 	outb(0x3f2,0);
277*48819Swilliam 	for(i=0; i < 100000; i++);
278*48819Swilliam 	outb(0x3f2,unit | (unit  ? 32 : 16) );
279*48819Swilliam 	for(i=0; i < 100000; i++);
280*48819Swilliam 	outb(0x3f2,unit | 0xC | (unit  ? 32 : 16) );
281*48819Swilliam 	outb(0x3f7,ft->trans);
282*48819Swilliam 	fd_motor = 1;
283*48819Swilliam 
284*48819Swilliam 	waitio();
285*48819Swilliam 
286*48819Swilliam 	out_fdc(3); /* specify command */
287*48819Swilliam 	out_fdc(0xDF);
288*48819Swilliam 	out_fdc(2);
289*48819Swilliam 
290*48819Swilliam 	out_fdc(7);	/* Recalibrate Function */
291*48819Swilliam 	out_fdc(unit);
292*48819Swilliam 
293*48819Swilliam 	waitio();
294*48819Swilliam 	return(0);
295*48819Swilliam }
296*48819Swilliam 
297*48819Swilliam 
298*48819Swilliam /****************************************************************************/
299*48819Swilliam /*                                 fd_dma                                   */
300*48819Swilliam /* set up DMA read/write operation and virtual address addr for nbytes      */
301*48819Swilliam /****************************************************************************/
302*48819Swilliam fd_dma(read,addr,nbytes)
303*48819Swilliam int read;
304*48819Swilliam unsigned long addr;
305*48819Swilliam int nbytes;
306*48819Swilliam {
307*48819Swilliam 	/* Set read/write bytes */
308*48819Swilliam 	if (read) {
309*48819Swilliam 		outb(0xC,0x46); outb(0xB,0x46);
310*48819Swilliam 	} else {
311*48819Swilliam 		outb(0xC,0x4A); outb(0xB,0x4A);
312*48819Swilliam 	}
313*48819Swilliam 	/* Send start address */
314*48819Swilliam 	outb(0x4,addr & 0xFF);
315*48819Swilliam 	outb(0x4,(addr>>8) & 0xFF);
316*48819Swilliam 	outb(0x81,(addr>>16) & 0xFF);
317*48819Swilliam 	/* Send count */
318*48819Swilliam 	nbytes--;
319*48819Swilliam 	outb(0x5,nbytes & 0xFF);
320*48819Swilliam 	outb(0x5,(nbytes>>8) & 0xFF);
321*48819Swilliam 	/* set channel 2 */
322*48819Swilliam 	outb(0x0A,2);
323*48819Swilliam }
324*48819Swilliam 
325