1 /*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Don Ahn.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)fd.c 7.3 (Berkeley) 5/25/91
37 */
38
39 /****************************************************************************/
40 /* standalone fd driver */
41 /****************************************************************************/
42 #include "sys/param.h"
43 #include "disklabel.h"
44 #include "fdreg.h"
45 #include "isa_stdports.h"
46 #include "nec765.h"
47 #include "saio.h"
48 #include "machine/inline/io.h"
49
50 #define NUMRETRY 10
51 #define NFD 2
52 #define FDBLK 512
53
54 extern struct disklabel disklabel;
55
56 struct fd_type {
57 int sectrac; /* sectors per track */
58 int secsize; /* size code for sectors */
59 int datalen; /* data len when secsize = 0 */
60 int gap; /* gap len between sectors */
61 int tracks; /* total num of tracks */
62 int size; /* size of disk in sectors */
63 int steptrac; /* steps per cylinder */
64 int trans; /* transfer speed code */
65 };
66
67 struct fd_type fd_types[] = {
68 { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */
69 { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */
70 /* need 720K 3.5in here as well */
71 #ifdef noway
72 { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */
73 { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */
74 #endif
75 };
76
77
78 /* state needed for current transfer */
79 static int probetype;
80 static int fd_type;
81 static int fd_retry;
82 static int fd_status[7];
83
84 static int fdc = IO_FD1; /* floppy disk base */
85
86 /* Make sure DMA buffer doesn't cross 64k boundary */
87 /* char bounce[FDBLK];*/
88 static char *bounce = (char *)0x200000;
89 static int readtrack = -1;
90
91
92 /****************************************************************************/
93 /* fdstrategy */
94 /****************************************************************************/
95 int
fdstrategy(io,func)96 fdstrategy(io,func)
97 register struct iob *io;
98 int func;
99 {
100 char *address;
101 long nblocks,blknum;
102 int unit, iosize;
103
104 #if DEBUG > 2
105 printf("fdstrat ");
106 #endif
107 unit = io->i_unit;
108
109 /*
110 * Set up block calculations.
111 */
112 iosize = io->i_cc / FDBLK;
113 blknum = (unsigned long) io->i_bn * DEV_BSIZE / FDBLK;
114 nblocks = fd_types[fd_type].size /* disklabel.d_secperunit */;
115 if ((blknum + iosize > nblocks) || blknum < 0) {
116 #if DEBUG > 8
117 printf("bn = %d; sectors = %d; type = %d; fssize = %d ",
118 blknum, iosize, fd_type, nblocks);
119 printf("fdstrategy - I/O out of filesystem boundaries\n");
120 #endif
121 return(-1);
122 }
123
124 address = (char *)io->i_ma;
125 while (iosize > 0) {
126 if (fdio(func, unit, blknum, address))
127 return(-1);
128 iosize--;
129 blknum++;
130 address += FDBLK;
131 }
132 return(io->i_cc);
133 }
134
135 static int ccyl = -1;
136
137 int
fdio(func,unit,blknum,address)138 fdio(func, unit, blknum, address)
139 int func,unit,blknum;
140 char *address;
141 {
142 int i,j, cyl, sectrac,sec,head,numretry;
143 struct fd_type *ft;
144 int s;
145
146 #if DEBUG > 1
147 printf("fdio ");
148 #endif
149 ft = &fd_types[fd_type];
150
151 sectrac = ft->sectrac;
152 cyl = blknum / (sectrac*2);
153 sec = blknum % (sectrac * 2);
154 head = sec / sectrac;
155 sec = sec % sectrac + 1;
156 #if DEBUG > 3
157 printf("sec %d hd %d cyl %d ", sec, head, cyl);
158 #endif
159 numretry = NUMRETRY;
160
161 if (func == F_WRITE)
162 bcopy(address, bounce+FDBLK*(sec-1), FDBLK);
163
164 retry:
165 #if DEBUG > 3
166 printf("%x ", inb(fdc+fdsts));
167 #endif
168 if(numretry != NUMRETRY)
169 printf("fdio: bn %d retry\n", blknum);
170 if (ccyl != cyl) {
171 ccyl = -1;
172 /* attempt seek to desired cylinder */
173 out_fdc(NE7CMD_SEEK); out_fdc(unit); out_fdc(cyl);
174
175 if (waitseek(cyl) == 0) {
176 numretry--;
177 recalibrate(unit);
178 if (numretry) goto retry;
179 printf("fdio: seek to cylinder %d failed\n", cyl);
180 #if DEBUG > 3
181 printf("unit %d, type %d, sectrac %d, blknum %d\n",
182 unit,fd_type,sectrac,blknum);
183 #endif
184 return -1;
185 }
186 }
187 ccyl = cyl;
188
189 /* check if in read track buffer to avoid transfer */
190 if (func == F_READ && readtrack == ((cyl<<1)+ head) && sec < 16) {
191 bcopy(bounce + FDBLK*(sec-1), address, FDBLK);
192 return 0;
193 }
194
195 /* set up transfer and issue command */
196 if (func == F_READ && numretry == NUMRETRY && !probetype) {
197 fd_dma(1, (int)bounce, (int)sectrac*FDBLK);
198 readtrack = -1;
199 s = 1;
200 #define NE7CMD_READTRACK 0x62
201 out_fdc(NE7CMD_READTRACK);
202 } else {
203 fd_dma(func == F_READ, (int)bounce + FDBLK*(sec-1), FDBLK);
204 s = sec;
205
206 if (func == F_READ)
207 out_fdc(NE7CMD_READ);
208 else
209 out_fdc(NE7CMD_WRITE);
210 }
211 out_fdc(head << 2 | unit); /* head & unit */
212 out_fdc(cyl); /* track */
213 out_fdc(head);
214 out_fdc(s); /* sector */
215 out_fdc(ft->secsize); /* sector size */
216 out_fdc(sectrac); /* sectors/track */
217 out_fdc(ft->gap); /* gap size */
218 out_fdc(ft->datalen); /* data length */
219
220 waitio('r');
221 #if DEBUG > 3
222 printf("d ");
223 #endif
224 if (fd_status[0] & 0xf8) {
225
226 if (!probetype) {
227 #if DEBUG > 3
228 printf("FD err %lx %lx %lx %lx %lx %lx %lx\n",
229 fd_status[0], fd_status[1], fd_status[2], fd_status[3],
230 fd_status[4], fd_status[5], fd_status[6] );
231 #endif
232 } else
233 return(-1);
234
235 numretry--;
236 recalibrate(unit);
237 if (numretry) goto retry;
238 printf("fdio: i/o error bn %d\n", blknum);
239 return -1;
240 }
241 #if DEBUG > 3
242 printf("e ");
243 #endif
244 if (func == F_READ) {
245 bcopy(bounce+ (FDBLK*(sec-1)), address, FDBLK);
246 if(numretry == NUMRETRY)
247 readtrack = (cyl<<1) + head;
248 }
249 return 0;
250 }
251
252 /*
253 * wait for seek to cylinder to complete. return success.
254 */
255 #define NE7_ST0SE 0x20 /* seek ended */
256 int
waitseek(int cyl)257 waitseek(int cyl) {
258 int attempts, st0, pcn;
259
260 for (attempts = 100000; attempts > 0; attempts--) {
261 /* sense interrupt, get status */
262 out_fdc(NE7CMD_SENSEI);
263 st0 = in_fdc();
264
265 /* controller ready to talk?, if so get present cylinder */
266 if (st0 == -1)
267 continue;
268 pcn = in_fdc();
269 if (pcn == -1)
270 continue;
271
272 /* seek end? */
273 if ((st0 & NE7_ST0SE) == 0)
274 continue;
275
276 /* on cylinder? */
277 if (pcn != cyl)
278 return (0);
279 else
280 return (1);
281 }
282 return (0);
283 }
284
285 /*
286 * Force drive to start of unit and re seek.
287 */
recalibrate(int unit)288 recalibrate(int unit) {
289
290 /* reset head load, head unload, step rate, and DMA mode */
291 out_fdc(NE7CMD_SPECIFY); out_fdc(0xDF); out_fdc(2);
292
293 /* seek to cylinder 0 */
294 out_fdc(NE7CMD_RECAL); out_fdc(unit);
295
296 /* wait for results */
297 (void)waitseek(0);
298
299 /* force a seek on next transfer */
300 ccyl = -1;
301 }
302
303 /****************************************************************************/
304 /* fdc in/out */
305 /****************************************************************************/
306 int
in_fdc()307 in_fdc()
308 {
309 int i;
310 /*int cnt = 100000;*/
311 while (/*cnt-- > 0 &&*/ (i = inb(fdc+fdsts) & 192) != 192) if (i == 128) return -1;
312 /*if(cnt <= 0)
313 return(-1);*/
314 return inb(0x3f5);
315 }
316
waitio(p)317 waitio(p)
318 {
319 char c;
320 int n;
321 int i;
322
323 #if DEBUG > 0
324 printf("w ");
325 #endif
326 n = in_fdc();
327 if (n == -1) return;
328 fd_status[0] = n;
329 #if DEBUG > 1
330 printf("%c%x.", p, n);
331 #endif
332 for(i=1;i<7;i++) {
333 fd_status[i] = in_fdc();
334 #if DEBUG > 2
335 printf("%x.", fd_status[i]);
336 #endif
337 }
338 #if DEBUG > 2
339 printf(" ");
340 #endif
341 }
342
out_fdc(x)343 out_fdc(x)
344 int x;
345 {
346 int r;
347 int cnt=100000;
348 do {
349 if (cnt-- == 0) return(-1);
350 r = (inb(fdc+fdsts) & 192);
351 if (r==128) break;
352 } while (1);
353 outb(0x3f5, x);
354 }
355
356
357 /****************************************************************************/
358 /* fdopen/fdclose */
359 /****************************************************************************/
fdopen(io)360 fdopen(io)
361 register struct iob *io;
362 {
363 int unit, type, i;
364 struct fd_type *ft;
365 char buf[512];
366
367 unit = io->i_unit;
368 io->i_boff = 0; /* no disklabels -- tar/dump wont work */
369 #if DEBUG > 1
370 printf("fdopen %d ", unit);
371 #endif
372 ft = &fd_types[0];
373
374 /* Try a reset, keep motor on */
375 outb(0x3f2,0);
376 for(i=0; i < 100000; i++);
377 outb(0x3f2, unit | (unit ? 32 : 16) );
378 for(i=0; i < 100000; i++);
379 outb(0x3f2, unit | 0xC | (unit ? 32 : 16) );
380 outb(0x3f7, ft->trans);
381
382 recalibrate(unit);
383
384 /*
385 * discover type of floppy
386 */
387 probetype = 1;
388 for (fd_type = 0; fd_type < sizeof(fd_types)/sizeof(fd_types[0]);
389 fd_type++, ft++) {
390 /*for(i=0; i < 100000; i++);
391 outb(0x3f7,ft->trans);
392 for(i=0; i < 100000; i++);*/
393 if (fdio(F_READ, unit, ft->sectrac - 1, buf) >= 0){
394 probetype = 0;
395 return(0);
396 }
397 }
398
399 printf("failed fdopen");
400 return(-1);
401 }
402
403
404 /*
405 * set up DMA read/write operation and virtual address addr for nbytes
406 */
407 int
fd_dma(int read,int addr,int nbytes)408 fd_dma(int read, int addr, int nbytes)
409 {
410 /* Set read/write bytes */
411 if (read) {
412 outb(0xC, 0x46); outb(0xB, 0x46);
413 } else {
414 outb(0xC, 0x4A); outb(0xB, 0x4A);
415 }
416
417 /* Send start address */
418 outb(0x4, addr); outb(0x4, (addr>>8)); outb(0x81, (addr>>16));
419
420 /* Send count */
421 nbytes--;
422 outb(0x5, nbytes); outb(0x5, (nbytes>>8));
423
424 /* set channel 2 */
425 outb(0x0A, 2);
426 }
427