Commit | Line | Data |
---|---|---|
32f56e31 BJ |
1 | #include "fd.h" |
2 | #if NFD > 0 | |
7ff33365 DA |
3 | /*- |
4 | * Copyright (c) 1990 The Regents of the University of California. | |
5 | * All rights reserved. | |
6 | * | |
7 | * This code is derived from software contributed to Berkeley by | |
8 | * Don Ahn. | |
9 | * | |
10 | * %sccs.include.386.c% | |
11 | * | |
8dfab1b8 | 12 | * @(#)fd.c 5.5 (Berkeley) %G% |
7ff33365 DA |
13 | */ |
14 | ||
15 | /****************************************************************************/ | |
16 | /* fd driver */ | |
17 | /****************************************************************************/ | |
18 | #include "param.h" | |
19 | #include "dkbad.h" | |
20 | #include "systm.h" | |
21 | #include "conf.h" | |
22 | #include "file.h" | |
7ff33365 DA |
23 | #include "ioctl.h" |
24 | #include "disk.h" | |
25 | #include "buf.h" | |
7ff33365 | 26 | #include "uio.h" |
8dfab1b8 WN |
27 | #include "i386/isa/isa_device.h" |
28 | #include "i386/isa/fdreg.h" | |
29 | #include "i386/isa/icu.h" | |
7ff33365 | 30 | |
7ff33365 DA |
31 | #define FDUNIT(s) ((s)&1) |
32 | #define FDTYPE(s) (((s)>>1)&7) | |
32f56e31 | 33 | |
7ff33365 | 34 | #define b_cylin b_resid |
32f56e31 | 35 | #define b_step b_resid |
7ff33365 DA |
36 | #define FDBLK 512 |
37 | #define NUMTYPES 4 | |
38 | ||
39 | struct fd_type { | |
40 | int sectrac; /* sectors per track */ | |
41 | int secsize; /* size code for sectors */ | |
42 | int datalen; /* data len when secsize = 0 */ | |
43 | int gap; /* gap len between sectors */ | |
44 | int tracks; /* total num of tracks */ | |
45 | int size; /* size of disk in sectors */ | |
46 | int steptrac; /* steps per cylinder */ | |
47 | int trans; /* transfer speed code */ | |
48 | }; | |
49 | ||
50 | struct fd_type fd_types[NUMTYPES] = { | |
32f56e31 | 51 | { 18,2,0xFF,0x1B,80,2880,1,0 }, /* 1.44 meg HD 3.5in floppy */ |
7ff33365 DA |
52 | { 15,2,0xFF,0x1B,80,2400,1,0 }, /* 1.2 meg HD floppy */ |
53 | { 9,2,0xFF,0x23,40,720,2,1 }, /* 360k floppy in 1.2meg drive */ | |
54 | { 9,2,0xFF,0x2A,40,720,1,1 }, /* 360k floppy in DD drive */ | |
55 | }; | |
56 | ||
57 | struct fd_u { | |
58 | int type; /* Drive type (HD, DD */ | |
59 | int active; /* Drive activity boolean */ | |
60 | int motor; /* Motor on flag */ | |
7ff33365 DA |
61 | struct buf head; /* Head of buf chain */ |
62 | struct buf rhead; /* Raw head of buf chain */ | |
32f56e31 | 63 | int reset; |
7ff33365 DA |
64 | } fd_unit[NFD]; |
65 | ||
32f56e31 | 66 | |
7ff33365 DA |
67 | extern int hz; |
68 | ||
69 | /* state needed for current transfer */ | |
32f56e31 BJ |
70 | static fdc; /* floppy disk controller io base register */ |
71 | int fd_dmachan = 2; | |
7ff33365 DA |
72 | static int fd_skip; |
73 | static int fd_state; | |
74 | static int fd_retry; | |
75 | static int fd_drive; | |
32f56e31 | 76 | static int fd_track = -1; |
7ff33365 | 77 | static int fd_status[7]; |
7ff33365 | 78 | |
32f56e31 BJ |
79 | /* |
80 | make sure bounce buffer for DMA is aligned since the DMA chip | |
81 | doesn't roll over properly over a 64k boundary | |
82 | */ | |
83 | extern struct buf *dma_bounce[]; | |
7ff33365 DA |
84 | |
85 | /****************************************************************************/ | |
86 | /* autoconfiguration stuff */ | |
87 | /****************************************************************************/ | |
88 | int fdprobe(), fdattach(), fd_turnoff(); | |
89 | ||
32f56e31 | 90 | struct isa_driver fddriver = { |
7ff33365 DA |
91 | fdprobe, fdattach, "fd", |
92 | }; | |
93 | ||
94 | fdprobe(dev) | |
32f56e31 | 95 | struct isa_device *dev; |
7ff33365 DA |
96 | { |
97 | return 1; | |
98 | } | |
99 | ||
100 | fdattach(dev) | |
32f56e31 BJ |
101 | struct isa_device *dev; |
102 | { int s; | |
103 | ||
104 | fdc = dev->id_iobase; | |
105 | /* Set transfer to 500kbps */ | |
106 | outb(fdc+fdctl,0); | |
107 | fd_turnoff(0); | |
108 | } | |
109 | ||
110 | int | |
111 | fdsize(dev) | |
112 | dev_t dev; | |
7ff33365 | 113 | { |
32f56e31 | 114 | return(2400); |
7ff33365 DA |
115 | } |
116 | ||
117 | /****************************************************************************/ | |
118 | /* fdstrategy */ | |
119 | /****************************************************************************/ | |
120 | fdstrategy(bp) | |
121 | register struct buf *bp; /* IO operation to perform */ | |
122 | { | |
123 | register struct buf *dp,*dp0,*dp1; | |
124 | long nblocks,blknum; | |
32f56e31 | 125 | int unit, type, s; |
7ff33365 | 126 | |
32f56e31 BJ |
127 | unit = FDUNIT(minor(bp->b_dev)); |
128 | type = FDTYPE(minor(bp->b_dev)); | |
129 | ||
130 | #ifdef FDTEST | |
131 | printf("fdstrat%d, blk = %d, bcount = %d, addr = %x|", | |
132 | unit, bp->b_blkno, bp->b_bcount,bp->b_un.b_addr); | |
7ff33365 DA |
133 | #endif |
134 | if ((unit >= NFD) || (bp->b_blkno < 0)) { | |
135 | printf("fdstrat: unit = %d, blkno = %d, bcount = %d\n", | |
136 | unit, bp->b_blkno, bp->b_bcount); | |
137 | pg("fd:error in fdstrategy"); | |
138 | bp->b_error = EINVAL; | |
32f56e31 | 139 | bp->b_flags |= B_ERROR; |
7ff33365 DA |
140 | goto bad; |
141 | } | |
142 | /* | |
143 | * Set up block calculations. | |
144 | */ | |
145 | blknum = (unsigned long) bp->b_blkno * DEV_BSIZE/FDBLK; | |
32f56e31 | 146 | nblocks = fd_types[type].size; |
7ff33365 | 147 | if (blknum + (bp->b_bcount / FDBLK) > nblocks) { |
32f56e31 BJ |
148 | if (blknum == nblocks) { |
149 | bp->b_resid = bp->b_bcount; | |
150 | } else { | |
151 | bp->b_error = ENOSPC; | |
152 | bp->b_flags |= B_ERROR; | |
153 | } | |
7ff33365 DA |
154 | goto bad; |
155 | } | |
32f56e31 | 156 | bp->b_cylin = blknum / (fd_types[type].sectrac * 2); |
7ff33365 DA |
157 | dp = &fd_unit[unit].head; |
158 | dp0 = &fd_unit[0].head; | |
159 | dp1 = &fd_unit[1].head; | |
32f56e31 | 160 | dp->b_step = (fd_types[fd_unit[unit].type].steptrac); |
7ff33365 DA |
161 | s = splbio(); |
162 | disksort(dp, bp); | |
163 | if ((dp0->b_active == 0)&&(dp1->b_active == 0)) { | |
32f56e31 BJ |
164 | #ifdef FDDEBUG |
165 | printf("T|"); | |
166 | #endif | |
7ff33365 DA |
167 | dp->b_active = 1; |
168 | fd_drive = unit; | |
32f56e31 | 169 | fd_track = -1; /* force seek on first xfer */ |
7ff33365 DA |
170 | untimeout(fd_turnoff,unit); |
171 | fdstart(unit); /* start drive if idle */ | |
172 | } | |
173 | splx(s); | |
174 | return; | |
175 | ||
176 | bad: | |
7ff33365 DA |
177 | biodone(bp); |
178 | } | |
179 | ||
180 | /****************************************************************************/ | |
181 | /* motor control stuff */ | |
182 | /****************************************************************************/ | |
183 | set_motor(unit,reset) | |
184 | int unit,reset; | |
185 | { | |
186 | int m0,m1; | |
187 | m0 = fd_unit[0].motor; | |
188 | m1 = fd_unit[1].motor; | |
32f56e31 | 189 | outb(fdc+fdout,unit | (reset ? 0 : 0xC) | (m0 ? 16 : 0) | (m1 ? 32 : 0)); |
7ff33365 DA |
190 | } |
191 | ||
192 | fd_turnoff(unit) | |
193 | int unit; | |
194 | { | |
195 | fd_unit[unit].motor = 0; | |
196 | if (unit) set_motor(0,0); | |
197 | else set_motor(1,0); | |
198 | } | |
199 | ||
200 | fd_turnon(unit) | |
201 | int unit; | |
202 | { | |
203 | fd_unit[unit].motor = 1; | |
204 | set_motor(unit,0); | |
205 | } | |
206 | ||
207 | /****************************************************************************/ | |
208 | /* fdc in/out */ | |
209 | /****************************************************************************/ | |
210 | int | |
211 | in_fdc() | |
212 | { | |
213 | int i; | |
32f56e31 BJ |
214 | while ((i = inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)) != (NE7_DIO|NE7_RQM)) |
215 | if (i == NE7_RQM) return -1; | |
216 | return inb(fdc+fddata); | |
7ff33365 DA |
217 | } |
218 | ||
219 | dump_stat() | |
220 | { | |
221 | int i; | |
222 | for(i=0;i<7;i++) { | |
223 | fd_status[i] = in_fdc(); | |
224 | if (fd_status[i] < 0) break; | |
225 | } | |
32f56e31 BJ |
226 | printf("FD bad status :%X %X %X %X %X %X %X\n", |
227 | fd_status[0], fd_status[1], fd_status[2], fd_status[3], | |
228 | fd_status[4], fd_status[5], fd_status[6] ); | |
7ff33365 DA |
229 | } |
230 | ||
231 | out_fdc(x) | |
232 | int x; | |
233 | { | |
234 | int r,errcnt; | |
235 | static int maxcnt = 0; | |
236 | errcnt = 0; | |
237 | do { | |
32f56e31 BJ |
238 | r = (inb(fdc+fdsts) & (NE7_DIO|NE7_RQM)); |
239 | if (r== NE7_RQM) break; | |
240 | if (r==(NE7_DIO|NE7_RQM)) { | |
7ff33365 DA |
241 | dump_stat(); /* error: direction. eat up output */ |
242 | #ifdef FDOTHER | |
32f56e31 | 243 | printf("%X\n",x); |
7ff33365 DA |
244 | #endif |
245 | } | |
246 | /* printf("Error r = %d:",r); */ | |
247 | errcnt++; | |
248 | } while (1); | |
249 | if (errcnt > maxcnt) { | |
250 | maxcnt = errcnt; | |
251 | #ifdef FDOTHER | |
32f56e31 | 252 | printf("New MAX = %d\n",maxcnt); |
7ff33365 DA |
253 | #endif |
254 | } | |
32f56e31 | 255 | outb(fdc+fddata,x); |
7ff33365 DA |
256 | } |
257 | ||
258 | /* see if fdc responding */ | |
259 | int | |
260 | check_fdc() | |
261 | { | |
262 | int i; | |
263 | for(i=0;i<100;i++) { | |
32f56e31 | 264 | if (inb(fdc+fdsts)& NE7_RQM) return 0; |
7ff33365 DA |
265 | } |
266 | return 1; | |
267 | } | |
268 | ||
269 | /****************************************************************************/ | |
270 | /* fdopen/fdclose */ | |
271 | /****************************************************************************/ | |
8dfab1b8 | 272 | Fdopen(dev, flags) |
7ff33365 DA |
273 | dev_t dev; |
274 | int flags; | |
275 | { | |
32f56e31 BJ |
276 | int unit = FDUNIT(minor(dev)); |
277 | int type = FDTYPE(minor(dev)); | |
7ff33365 DA |
278 | int s; |
279 | ||
280 | /* check bounds */ | |
281 | if (unit >= NFD) return(ENXIO); | |
282 | if (type >= NUMTYPES) return(ENXIO); | |
32f56e31 | 283 | /* |
7ff33365 | 284 | if (check_fdc()) return(EBUSY); |
32f56e31 | 285 | */ |
7ff33365 DA |
286 | |
287 | /* Set proper disk type, only allow one type */ | |
7ff33365 DA |
288 | return 0; |
289 | } | |
290 | ||
8dfab1b8 | 291 | fdclose(dev, flags) |
7ff33365 DA |
292 | dev_t dev; |
293 | { | |
294 | } | |
295 | ||
296 | /****************************************************************************/ | |
297 | /* fdread/fdwrite */ | |
298 | /****************************************************************************/ | |
299 | /* | |
300 | * Routines to do raw IO for a unit. | |
301 | */ | |
302 | fdread(dev, uio) /* character read routine */ | |
303 | dev_t dev; | |
304 | struct uio *uio; | |
305 | { | |
32f56e31 | 306 | int unit = FDUNIT(minor(dev)) ; |
7ff33365 DA |
307 | if (unit >= NFD) return(ENXIO); |
308 | return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_READ,minphys,uio)); | |
309 | } | |
310 | ||
311 | fdwrite(dev, uio) /* character write routine */ | |
312 | dev_t dev; | |
313 | struct uio *uio; | |
314 | { | |
32f56e31 | 315 | int unit = FDUNIT(minor(dev)) ; |
7ff33365 DA |
316 | if (unit >= NFD) return(ENXIO); |
317 | return(physio(fdstrategy,&fd_unit[unit].rhead,dev,B_WRITE,minphys,uio)); | |
318 | } | |
319 | ||
320 | /****************************************************************************/ | |
321 | /* fdstart */ | |
322 | /****************************************************************************/ | |
323 | fdstart(unit) | |
324 | int unit; | |
325 | { | |
326 | register struct buf *dp,*bp; | |
327 | int s; | |
328 | ||
32f56e31 BJ |
329 | #ifdef FDTEST |
330 | printf("st%d|",unit); | |
331 | #endif | |
332 | s = splbio(); | |
7ff33365 DA |
333 | if (!fd_unit[unit].motor) { |
334 | fd_turnon(unit); | |
335 | /* Wait for 1 sec */ | |
336 | timeout(fdstart,unit,hz); | |
32f56e31 BJ |
337 | /*DELAY(1000000);*/ |
338 | }else | |
339 | { | |
340 | /* make sure drive is selected as well as on */ | |
341 | /*set_motor(unit,0);*/ | |
342 | ||
7ff33365 DA |
343 | dp = &fd_unit[unit].head; |
344 | bp = dp->b_actf; | |
345 | fd_retry = 0; | |
32f56e31 BJ |
346 | if (fd_unit[unit].reset) fd_state = 1; |
347 | else { | |
348 | /* DO a RESET */ | |
349 | fd_unit[unit].reset = 1; | |
350 | fd_state = 5; | |
351 | } | |
7ff33365 | 352 | fd_skip = 0; |
32f56e31 BJ |
353 | #ifdef FDDEBUG |
354 | printf("Seek %d %d\n", bp->b_cylin, dp->b_step); | |
355 | #endif | |
356 | if (bp->b_cylin != fd_track) { | |
7ff33365 DA |
357 | /* Seek necessary, never quite sure where head is at! */ |
358 | out_fdc(15); /* Seek function */ | |
359 | out_fdc(unit); /* Drive number */ | |
32f56e31 | 360 | out_fdc(bp->b_cylin * dp->b_step); |
8dfab1b8 | 361 | } else fdintr(0xff); |
7ff33365 | 362 | } |
32f56e31 | 363 | splx(s); |
7ff33365 DA |
364 | } |
365 | ||
366 | fd_timeout(x) | |
367 | int x; | |
368 | { | |
369 | int i,j; | |
370 | struct buf *dp,*bp; | |
371 | ||
372 | dp = &fd_unit[fd_drive].head; | |
373 | bp = dp->b_actf; | |
374 | ||
375 | out_fdc(0x4); | |
376 | out_fdc(fd_drive); | |
377 | i = in_fdc(); | |
378 | printf("Timeout drive status %X\n",i); | |
379 | ||
380 | out_fdc(0x8); | |
381 | i = in_fdc(); | |
382 | j = in_fdc(); | |
383 | printf("ST0 = %X, PCN = %X\n",i,j); | |
384 | ||
385 | if (bp) badtrans(dp,bp); | |
386 | } | |
387 | ||
388 | /****************************************************************************/ | |
389 | /* fdintr */ | |
390 | /****************************************************************************/ | |
8dfab1b8 | 391 | fdintr(unit) |
7ff33365 DA |
392 | { |
393 | register struct buf *dp,*bp; | |
394 | struct buf *dpother; | |
32f56e31 | 395 | int read,head,trac,sec,i,s,sectrac,cyl; |
7ff33365 DA |
396 | unsigned long blknum; |
397 | struct fd_type *ft; | |
32f56e31 BJ |
398 | |
399 | #ifdef FDTEST | |
8dfab1b8 | 400 | printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive); |
32f56e31 | 401 | #endif |
7ff33365 DA |
402 | |
403 | dp = &fd_unit[fd_drive].head; | |
404 | bp = dp->b_actf; | |
405 | read = bp->b_flags & B_READ; | |
32f56e31 | 406 | ft = &fd_types[FDTYPE(bp->b_dev)]; |
7ff33365 DA |
407 | |
408 | switch (fd_state) { | |
409 | case 1 : /* SEEK DONE, START DMA */ | |
32f56e31 | 410 | /* Make sure seek really happened*/ |
8dfab1b8 | 411 | if (unit != 0xff) { |
32f56e31 BJ |
412 | out_fdc(0x8); |
413 | i = in_fdc(); | |
414 | cyl = in_fdc(); | |
415 | if (!(i&0x20) || (cyl != bp->b_cylin*dp->b_step)) { | |
416 | printf("Stray int ST0 = %X, PCN = %X:",i,cyl); | |
417 | return; | |
418 | } | |
419 | } | |
420 | ||
7ff33365 | 421 | fd_track = bp->b_cylin; |
32f56e31 | 422 | at_dma(read,bp->b_un.b_addr+fd_skip,FDBLK, fd_dmachan); |
7ff33365 DA |
423 | blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK |
424 | + fd_skip/FDBLK; | |
425 | sectrac = ft->sectrac; | |
426 | sec = blknum % (sectrac * 2); | |
427 | head = sec / sectrac; | |
428 | sec = sec % sectrac + 1; | |
429 | ||
430 | if (read) out_fdc(0xE6); /* READ */ | |
431 | else out_fdc(0xC5); /* WRITE */ | |
432 | out_fdc(head << 2 | fd_drive); /* head & unit */ | |
433 | out_fdc(fd_track); /* track */ | |
434 | out_fdc(head); | |
435 | out_fdc(sec); /* sector XXX +1? */ | |
436 | out_fdc(ft->secsize); /* sector size */ | |
437 | out_fdc(sectrac); /* sectors/track */ | |
438 | out_fdc(ft->gap); /* gap size */ | |
439 | out_fdc(ft->datalen); /* data length */ | |
440 | fd_state = 2; | |
441 | /* XXX PARANOIA */ | |
442 | untimeout(fd_timeout,2); | |
443 | timeout(fd_timeout,2,hz); | |
444 | break; | |
445 | case 2 : /* IO DONE, post-analyze */ | |
446 | untimeout(fd_timeout,2); | |
447 | for(i=0;i<7;i++) { | |
448 | fd_status[i] = in_fdc(); | |
449 | } | |
450 | if (fd_status[0]&0xF8) { | |
451 | #ifdef FDOTHER | |
32f56e31 | 452 | printf("status0 err %d:",fd_status[0]); |
7ff33365 DA |
453 | #endif |
454 | goto retry; | |
455 | } | |
32f56e31 | 456 | /* |
7ff33365 DA |
457 | if (fd_status[1]){ |
458 | printf("status1 err %d:",fd_status[0]); | |
459 | goto retry; | |
460 | } | |
461 | if (fd_status[2]){ | |
462 | printf("status2 err %d:",fd_status[0]); | |
463 | goto retry; | |
464 | } | |
32f56e31 | 465 | */ |
7ff33365 DA |
466 | /* All OK */ |
467 | if (!kernel_space(bp->b_un.b_addr+fd_skip)) { | |
468 | /* RAW transfer */ | |
32f56e31 BJ |
469 | if (read) bcopy(dma_bounce[fd_dmachan]->b_un.b_addr, |
470 | bp->b_un.b_addr+fd_skip, FDBLK); | |
7ff33365 DA |
471 | } |
472 | fd_skip += FDBLK; | |
473 | if (fd_skip >= bp->b_bcount) { | |
32f56e31 BJ |
474 | #ifdef FDTEST |
475 | printf("DONE %d|", bp->b_blkno); | |
476 | #endif | |
7ff33365 DA |
477 | /* ALL DONE */ |
478 | fd_skip = 0; | |
479 | bp->b_resid = 0; | |
480 | dp->b_actf = bp->av_forw; | |
481 | biodone(bp); | |
482 | nextstate(dp); | |
483 | ||
484 | } else { | |
32f56e31 BJ |
485 | #ifdef FDDEBUG |
486 | printf("next|"); | |
487 | #endif | |
7ff33365 DA |
488 | /* set up next transfer */ |
489 | blknum = (unsigned long)bp->b_blkno*DEV_BSIZE/FDBLK | |
490 | + fd_skip/FDBLK; | |
491 | fd_state = 1; | |
492 | bp->b_cylin = (blknum / (ft->sectrac * 2)); | |
7ff33365 | 493 | if (bp->b_cylin != fd_track) { |
32f56e31 BJ |
494 | #ifdef FDTEST |
495 | printf("Seek|"); | |
496 | #endif | |
7ff33365 DA |
497 | /* SEEK Necessary */ |
498 | out_fdc(15); /* Seek function */ | |
499 | out_fdc(fd_drive);/* Drive number */ | |
32f56e31 | 500 | out_fdc(bp->b_cylin * dp->b_step); |
7ff33365 | 501 | break; |
8dfab1b8 | 502 | } else fdintr(0xff); |
7ff33365 DA |
503 | } |
504 | break; | |
505 | case 3: | |
32f56e31 BJ |
506 | #ifdef FDOTHER |
507 | printf("Seek %d %d\n", bp->b_cylin, dp->b_step); | |
508 | #endif | |
7ff33365 DA |
509 | /* Seek necessary */ |
510 | out_fdc(15); /* Seek function */ | |
511 | out_fdc(fd_drive);/* Drive number */ | |
32f56e31 | 512 | out_fdc(bp->b_cylin * dp->b_step); |
7ff33365 DA |
513 | fd_state = 1; |
514 | break; | |
515 | case 4: | |
516 | out_fdc(3); /* specify command */ | |
517 | out_fdc(0xDF); | |
518 | out_fdc(2); | |
519 | out_fdc(7); /* Recalibrate Function */ | |
520 | out_fdc(fd_drive); | |
521 | fd_state = 3; | |
522 | break; | |
32f56e31 BJ |
523 | case 5: |
524 | #ifdef FDOTHER | |
525 | printf("**RESET**\n"); | |
526 | #endif | |
527 | /* Try a reset, keep motor on */ | |
528 | set_motor(fd_drive,1); | |
529 | set_motor(fd_drive,0); | |
530 | outb(fdc+fdctl,ft->trans); | |
531 | fd_retry++; | |
532 | fd_state = 4; | |
533 | break; | |
7ff33365 | 534 | default: |
7ff33365 DA |
535 | printf("Unexpected FD int->"); |
536 | out_fdc(0x8); | |
537 | i = in_fdc(); | |
538 | sec = in_fdc(); | |
539 | printf("ST0 = %X, PCN = %X\n",i,sec); | |
540 | out_fdc(0x4A); | |
541 | out_fdc(fd_drive); | |
542 | for(i=0;i<7;i++) { | |
543 | fd_status[i] = in_fdc(); | |
544 | } | |
545 | printf("intr status :%X %X %X %X %X %X %X ", | |
546 | fd_status[0], fd_status[1], fd_status[2], fd_status[3], | |
547 | fd_status[4], fd_status[5], fd_status[6] ); | |
7ff33365 DA |
548 | break; |
549 | } | |
550 | return; | |
551 | retry: | |
552 | switch(fd_retry) { | |
553 | case 0: case 1: | |
32f56e31 | 554 | case 2: case 3: |
7ff33365 | 555 | break; |
32f56e31 | 556 | case 4: |
7ff33365 | 557 | fd_retry++; |
32f56e31 | 558 | fd_state = 5; |
8dfab1b8 | 559 | fdintr(0xff); |
7ff33365 | 560 | return; |
32f56e31 | 561 | case 5: case 6: case 7: |
7ff33365 DA |
562 | break; |
563 | default: | |
564 | printf("FD err %X %X %X %X %X %X %X\n", | |
565 | fd_status[0], fd_status[1], fd_status[2], fd_status[3], | |
566 | fd_status[4], fd_status[5], fd_status[6] ); | |
567 | badtrans(dp,bp); | |
568 | return; | |
569 | } | |
570 | fd_state = 1; | |
571 | fd_retry++; | |
8dfab1b8 | 572 | fdintr(0xff); |
7ff33365 DA |
573 | } |
574 | ||
575 | badtrans(dp,bp) | |
576 | struct buf *dp,*bp; | |
577 | { | |
578 | ||
579 | bp->b_flags |= B_ERROR; | |
580 | bp->b_error = EIO; | |
581 | bp->b_resid = bp->b_bcount - fd_skip; | |
582 | dp->b_actf = bp->av_forw; | |
583 | fd_skip = 0; | |
584 | biodone(bp); | |
585 | nextstate(dp); | |
586 | ||
587 | } | |
588 | ||
589 | /* | |
590 | nextstate : After a transfer is done, continue processing | |
591 | requests on the current drive queue. If empty, go to | |
592 | the other drives queue. If that is empty too, timeout | |
593 | to turn off the current drive in 5 seconds, and go | |
594 | to state 0 (not expecting any interrupts). | |
595 | */ | |
596 | ||
597 | nextstate(dp) | |
598 | struct buf *dp; | |
599 | { | |
600 | struct buf *dpother; | |
601 | ||
602 | dpother = &fd_unit[fd_drive ? 0 : 1].head; | |
603 | if (dp->b_actf) fdstart(fd_drive); | |
604 | else if (dpother->b_actf) { | |
32f56e31 BJ |
605 | #ifdef FDTEST |
606 | printf("switch|"); | |
607 | #endif | |
608 | untimeout(fd_turnoff,fd_drive); | |
609 | timeout(fd_turnoff,fd_drive,5*hz); | |
610 | fd_drive = 1 - fd_drive; | |
7ff33365 | 611 | dp->b_active = 0; |
32f56e31 BJ |
612 | dpother->b_active = 1; |
613 | fdstart(fd_drive); | |
7ff33365 | 614 | } else { |
32f56e31 BJ |
615 | #ifdef FDTEST |
616 | printf("off|"); | |
617 | #endif | |
7ff33365 DA |
618 | untimeout(fd_turnoff,fd_drive); |
619 | timeout(fd_turnoff,fd_drive,5*hz); | |
620 | fd_state = 0; | |
621 | dp->b_active = 0; | |
622 | } | |
623 | } | |
32f56e31 | 624 | #endif |