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