2 #include "../port/lib.h"
7 #include "../port/error.h"
11 /* Intel 82077A (8272A compatible) floppy controller */
13 /* This module expects the following functions to be defined
26 * On DMA systems, floppyexec() should be an empty function;
27 * on non-DMA systems, dmaend() should be an empty function;
28 * dmasetup() may enforce maximum transfer sizes.
38 DMAchan= 2, /* floppy dma channel */
41 #define DPRINT if(floppydebug)print
45 * types of drive (from PC equipment byte)
58 { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
59 { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
60 { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
61 { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
62 { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
63 { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
64 { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
68 * bytes per sector encoding for the controller.
69 * - index for b2c is is (bytes per sector/128).
70 * - index for c2b is code from b2c
89 #define MOTORBIT(i) (1<<((i)+4))
94 static int cmddone(void*);
95 static void floppyformat(FDrive*, Cmdbuf*);
96 static void floppykproc(void*);
97 static void floppypos(FDrive*,long);
98 static int floppyrecal(FDrive*);
99 static int floppyresult(void);
100 static void floppyrevive(void);
101 static long floppyseek(FDrive*, long);
102 static int floppysense(void);
103 static void floppywait(int);
104 static long floppyxfer(FDrive*, int, void*, long, long);
107 ".", {Qdir, 0, QTDIR}, 0, 0550,
108 "fd0disk", {Qdata + 0}, 0, 0660,
109 "fd0ctl", {Qctl + 0}, 0, 0660,
110 "fd1disk", {Qdata + 1}, 0, 0660,
111 "fd1ctl", {Qctl + 1}, 0, 0660,
112 "fd2disk", {Qdata + 2}, 0, 0660,
113 "fd2ctl", {Qctl + 2}, 0, 0660,
114 "fd3disk", {Qdata + 3}, 0, 0660,
115 "fd3ctl", {Qctl + 3}, 0, 0660,
117 #define NFDIR 2 /* directory entries/drive */
128 static Cmdtab floppyctlmsg[] =
131 CMnodebug, "nodebug", 1,
133 CMformat, "format", 0,
140 DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
141 inb(Pdor), inb(Pmsr), inb(Pdir));
145 * set floppy drive to its default type
148 floppysetdef(FDrive *dp)
153 for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)
158 floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
174 * init dependent parameters
177 for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
178 t->cap = t->bytes * t->heads * t->sectors * t->tracks;
179 t->bcode = b2c[t->bytes/128];
180 t->tsize = t->bytes * t->sectors;
181 if(maxtsize < t->tsize)
186 * Can fail if there is no space <= 16MB for the DMA
189 if(dmainit(DMAchan, maxtsize)){
190 print("floppy: dmainit failed\n");
196 * allocate the drive storage
198 fl.d = xalloc(fl.ndrive*sizeof(FDrive));
201 print("floppy: can't allocate memory\n");
211 outb(Pdor, fl.motor | Fintena | Fena);
217 for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
221 dp->cyl = -1; /* because we don't know */
222 dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);
228 * first operation will recalibrate
236 floppyattach(char *spec)
245 * watchdog to turn off the motors
248 kproc("floppy", floppykproc, 0);
250 return devattach('f', spec);
254 floppywalk(Chan *c, Chan *nc, char **name, int nname)
256 return devwalk(c, nc, name, nname, floppydir, 1+fl.ndrive*NFDIR, devgen);
260 floppystat(Chan *c, uchar *dp, int n)
262 return devstat(c, dp, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
266 floppyopen(Chan *c, int omode)
268 return devopen(c, omode, floppydir, 1+fl.ndrive*NFDIR, devgen);
277 islegal(ulong offset, long n, FDrive *dp)
279 if(offset % dp->t->bytes)
286 * check if the floppy has been replaced under foot. cause
287 * an error if it has.
289 * a seek and a read clears the condition. this was determined
290 * experimentally, there has to be a better way.
292 * if the read fails, cycle through the possible floppy
293 * density till one works or we've cycled through all
294 * possibilities for this drive.
297 changed(Chan *c, FDrive *dp)
303 * if floppy has changed or first time through
305 if((inb(Pdir)&Fchange) || dp->vers == 0){
310 dp->maxtries = 3; /* limit it when we're probing */
312 /* floppyon will fail if there's a controller but no drive */
313 dp->confused = 1; /* make floppyon recal */
317 /* seek to the first track */
318 floppyseek(dp, dp->t->heads*dp->t->tsize);
321 * if first attempt doesn't reset changed bit, there's
324 if(inb(Pdir)&Fchange)
328 if(dp->t >= &floppytype[nelem(floppytype)])
330 if(dp->t == start || dp->dt == dp->t->dt)
333 floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
335 /* floppyon will fail if there's a controller but no drive */
341 DPRINT("changed: trying %s\n", dp->t->name);
345 /* if the read succeeds, we've got the density right */
346 floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);
352 c->qid.vers = dp->vers;
353 if(old && old != dp->vers)
358 readtrack(FDrive *dp, int cyl, int head)
364 if(dp->ccyl==cyl && dp->chead==head)
366 pos = (cyl*dp->t->heads+head) * nn;
367 for(sofar = 0; sofar < nn; sofar += i){
369 i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
379 floppyread(Chan *c, void *a, long n, vlong off)
388 if(c->qid.type & QTDIR)
389 return devdirread(c, a, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
392 dp = &fl.d[c->qid.path & ~Qmask];
393 switch ((int)(c->qid.path & Qmask)) {
395 islegal(offset, n, dp);
405 for(rv = 0; rv < n; rv += len){
407 * all xfers come out of the track cache
410 floppypos(dp, offset+rv);
415 if(readtrack(dp, cyl, head) < 0)
417 memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
424 return readstr(offset, a, n, dp->t->name);
426 panic("floppyread: bad qid");
433 floppywrite(Chan *c, void *a, long n, vlong off)
443 dp = &fl.d[c->qid.path & ~Qmask];
444 switch ((int)(c->qid.path & Qmask)) {
446 islegal(offset, n, dp);
454 for(rv = 0; rv < n; rv += i){
455 floppypos(dp, offset+rv);
456 if(dp->tcyl == dp->ccyl)
458 i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv);
479 ct = lookupcmd(cb, floppyctlmsg, nelem(floppyctlmsg));
485 floppyformat(dp, cb);
504 panic("floppywrite: bad qid");
518 for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
519 if((fl.motor&MOTORBIT(dp->dev))
520 && TK2SEC(m->ticks - dp->lasttouched) > 5
522 if(TK2SEC(m->ticks - dp->lasttouched) > 5)
527 tsleep(&up->sleep, return0, 0, 1000);
532 * start a floppy drive's motor.
543 /* start motor and select drive */
544 alreadyon = fl.motor & MOTORBIT(dp->dev);
545 fl.motor |= MOTORBIT(dp->dev);
546 outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
548 /* wait for drive to spin up */
549 tsleep(&up->sleep, return0, 0, 750);
551 /* clear any pending interrupts */
555 /* set transfer rate */
556 if(fl.rate != dp->t->rate){
557 fl.rate = dp->t->rate;
561 /* get drive to a known cylinder */
563 for(tries = 0; tries < 4; tries++)
564 if(floppyrecal(dp) >= 0)
566 dp->lasttouched = m->ticks;
569 /* return -1 if this didn't work */
576 * stop the floppy if it hasn't been used in 5 seconds
579 floppyoff(FDrive *dp)
581 fl.motor &= ~MOTORBIT(dp->dev);
582 outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
586 * send a command to the floppy
595 for(i = 0; i < fl.ncmd; i++){
596 for(tries = 0; ; tries++){
597 if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
600 DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
603 /* empty fifo, might have been a bad command */
607 microdelay(8); /* for machine independence */
609 outb(Pfdata, fl.cmd[i]);
615 * get a command result from the floppy
617 * when the controller goes ready waiting for a command
618 * (instead of sending results), we're done
627 /* get the result of the operation */
628 for(i = 0; i < sizeof(fl.stat); i++){
629 /* wait for status byte */
630 for(tries = 0; ; tries++){
631 s = inb(Pmsr)&(Ffrom|Fready);
636 if(s == (Ffrom|Fready))
639 DPRINT("floppyresult: %d stats\n", i);
644 microdelay(8); /* for machine independence */
646 fl.stat[i] = inb(Pfdata);
648 fl.nstat = sizeof(fl.stat);
653 * calculate physical address of a logical byte offset into the disk
655 * truncate dp->length if it crosses a track boundary
658 floppypos(FDrive *dp, long off)
664 lsec = off/dp->t->bytes;
665 ltrack = lsec/dp->t->sectors;
666 dp->tcyl = ltrack/dp->t->heads;
667 dp->tsec = (lsec % dp->t->sectors) + 1;
668 dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
671 * can't read across track boundaries.
672 * if so, decrement the bytes to be read.
674 end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
675 if(off+dp->len > end)
680 * get the interrupt cause from the floppy.
686 fl.cmd[fl.ncmd++] = Fsense;
689 if(floppyresult() < 2){
690 DPRINT("can't read sense response\n");
705 * Wait for a floppy interrupt. If none occurs in 5 seconds, we
706 * may have missed one. This only happens on some portables which
707 * do power management behind our backs. Call the interrupt
708 * routine to try to clear any conditions.
713 tsleep(&fl.r, cmddone, 0, slow ? 5000 : 1000);
721 * we've lost the floppy position, go to cylinder 0.
724 floppyrecal(FDrive *dp)
730 fl.cmd[fl.ncmd++] = Frecal;
731 fl.cmd[fl.ncmd++] = dp->dev;
736 DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
740 if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
741 DPRINT("recalibrate: failed\n");
745 dp->cyl = fl.stat[1];
747 DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);
758 * if the controller or a specific drive is in a confused state,
759 * reset it and get back to a known state
767 * reset the controller if it's confused
770 DPRINT("floppyrevive in\n");
773 /* reset controller and turn all motors off */
779 outb(Pdor, Fintena|Fena);
786 /* mark all drives in an unknown state */
787 for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++)
790 /* set rate to a known value */
794 DPRINT("floppyrevive out\n");
800 * seek to the target cylinder
802 * interrupt, no results
805 floppyseek(FDrive *dp, long off)
808 if(dp->cyl == dp->tcyl)
813 fl.cmd[fl.ncmd++] = Fseek;
814 fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
815 fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
820 DPRINT("seek: confused\n");
824 if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
825 DPRINT("seek: failed\n");
835 * read or write to floppy. try up to three times.
838 floppyxfer(FDrive *dp, int cmd, void *a, long off, long n)
843 if(off >= dp->t->cap)
845 if(off + n > dp->t->cap)
846 n = dp->t->cap - off;
848 /* retry on error (until it gets ridiculous) */
851 if(tries++ >= dp->maxtries)
853 DPRINT("floppyxfer: retrying\n");
857 if(floppyseek(dp, off) < 0){
858 DPRINT("xfer: seek failed\n");
864 * set up the dma (dp->len may be trimmed)
870 dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread ? DMAREAD : DMAWRITE);
878 fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0);
879 fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
880 fl.cmd[fl.ncmd++] = dp->tcyl;
881 fl.cmd[fl.ncmd++] = dp->thead;
882 fl.cmd[fl.ncmd++] = dp->tsec;
883 fl.cmd[fl.ncmd++] = dp->t->bcode;
884 fl.cmd[fl.ncmd++] = dp->t->sectors;
885 fl.cmd[fl.ncmd++] = dp->t->gpl;
886 fl.cmd[fl.ncmd++] = 0xFF;
890 /* Poll ready bits and transfer data */
891 floppyexec((char*)a, dp->len, cmd==Fread);
894 * give bus to DMA, floppyintr() will read result
904 DPRINT("xfer: confused\n");
908 if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
909 DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0],
910 fl.stat[1], fl.stat[2]);
911 DPRINT("offset %lud len %ld\n", off, dp->len);
912 if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){
913 DPRINT("DMA overrun: retry\n");
920 * check for correct cylinder
922 offset = fl.stat[3] * dp->t->heads + fl.stat[4];
923 offset = offset*dp->t->sectors + fl.stat[5] - 1;
924 offset = offset * c2b[fl.stat[6]];
925 if(offset != off+dp->len){
926 DPRINT("xfer: ends on wrong cyl\n");
932 dp->lasttouched = m->ticks;
940 floppyformat(FDrive *dp, Cmdbuf *cb)
951 for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
952 if(strcmp(cb->f[1], t->name)==0 && t->dt==dp->dt){
954 floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
958 if(t >= &floppytype[nelem(floppytype)])
960 } else if(cb->nf == 1){
964 cmderror(cb, "invalid floppy format command");
969 * buffer for per track info
971 buf = smalloc(t->sectors*4);
977 /* force a recalibrate to cylinder 0 */
985 * format a track at time
987 for(track = 0; track < t->tracks*t->heads; track++){
988 cyl = track/t->heads;
989 h = track % t->heads;
992 * seek to track, ignore errors
994 floppyseek(dp, track*t->tsize);
999 * set up the dma (dp->len may be trimmed)
1002 for(sec = 1; sec <= t->sectors; sec++){
1012 if(dmasetup(DMAchan, buf, bp-buf, DMAWRITE) < 0)
1019 fl.cmd[fl.ncmd++] = Fformat;
1020 fl.cmd[fl.ncmd++] = (h<<2) | dp->dev;
1021 fl.cmd[fl.ncmd++] = t->bcode;
1022 fl.cmd[fl.ncmd++] = t->sectors;
1023 fl.cmd[fl.ncmd++] = t->fgpl;
1024 fl.cmd[fl.ncmd++] = 0x5a;
1028 /* Poll ready bits and transfer data */
1029 floppyexec((char *)buf, bp-buf, 0);
1032 * give bus to DMA, floppyintr() will read result
1042 DPRINT("format: confused\n");
1046 if((fl.stat[0]&Codemask)!=0 || fl.stat[1]|| fl.stat[2]){
1047 DPRINT("format: failed %ux %ux %ux\n",
1048 fl.stat[0], fl.stat[1], fl.stat[2]);
1061 switch(fl.cmd[0]&~Fmulti){
1071 floppysense(); /* to clear interrupt */
1078 Dev floppydevtab = {