lint
[unix-history] / usr / src / sys / i386 / stand / fd.c
CommitLineData
40118d23
WN
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 * %sccs.include.redist.c%
9 *
38a01dbe 10 * @(#)fd.c 7.4 (Berkeley) %G%
40118d23
WN
11 */
12
13/****************************************************************************/
14/* standalone fd driver */
15/****************************************************************************/
38a01dbe
KB
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>
40118d23
WN
23
24#define NUMRETRY 10
25/*#define FDDEBUG*/
26
27#define NFD 2
28#define FDBLK 512
29#define NUMTYPES 4
30
31struct 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
42struct 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 */
51static int fd_type;
52static int fd_motor;
53static int fd_retry;
54static int fd_drive;
55static int fd_status[7];
56
57static int fdc = IO_FD1; /* floppy disk base */
58
59/* Make sure DMA buffer doesn't cross 64k boundary */
60char bounce[FDBLK];
61
62
63/****************************************************************************/
64/* fdstrategy */
65/****************************************************************************/
66int
67fdstrategy(io,func)
68register struct iob *io;
69int func;
70{
71 char *address;
72 long nblocks,blknum;
73 int unit, iosize;
74
75#ifdef FDDEBUG
76printf("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
107int
108fdio(func, unit, blknum, address)
109int func,unit,blknum;
110char *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
117printf("fdio ");
118#endif
119
120 sectrac = ft->sectrac;
121 cyl = blknum / (2 * sectrac);
122 numretry = NUMRETRY;
123
e698f3b5 124 if (func == F_WRITE) bcopy(address,bounce,FDBLK);
40118d23
WN
125
126retry:
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 */
e698f3b5 147 fd_dma(func == F_READ, bounce, FDBLK);
40118d23
WN
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
e698f3b5 155 if (func == F_READ) out_fdc(0xE6);/* READ */
40118d23
WN
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
d7070096 175 printf("FD err %lx %lx %lx %lx %lx %lx %lx\n",
40118d23
WN
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 }
e698f3b5 181 if (func == F_READ) bcopy(bounce,address,FDBLK);
40118d23
WN
182 return 0;
183}
184
185/****************************************************************************/
186/* fdc in/out */
187/****************************************************************************/
188int
189in_fdc()
190{
191 int i;
192 while ((i = inb(fdc+fdsts) & 192) != 192) if (i == 128) return -1;
193 return inb(0x3f5);
194}
195
196dump_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
d7070096 204printf("FD bad status :%lx %lx %lx %lx %lx %lx %lx\n",
40118d23
WN
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
210set_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
230waitio()
231{
232char c;
233int 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
241out_fdc(x)
242int 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/****************************************************************************/
259fdopen(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/****************************************************************************/
303fd_dma(read,addr,nbytes)
304int read;
305unsigned long addr;
306int 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