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