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
fdstrategy(io,func)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
fdio(func,unit,blknum,address)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
in_fdc()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
dump_stat()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
set_intr()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
waitio()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
out_fdc(x)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 /****************************************************************************/
fdopen(io)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 /****************************************************************************/
fd_dma(read,addr,nbytes)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