/* * seek to the target cylinder * * interrupt, no results */ static vlong pcfloppyseek(FDrive *dp, vlong off) { floppypos(dp, off); if(dp->cyl == dp->tcyl) { dp->offset = off; return off; } dp->cyl = -1; fl.ncmd = 0; fl.cmd[fl.ncmd++] = Fseek; fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps; if(floppycmd() < 0) return -1; floppywait(1); if(fl.nstat < 2) { DPRINT("seek: confused\n"); fl.confused = 1; return -1; } if((fl.stat[0] & (Codemask|Seekend)) != Seekend) { DPRINT("seek: failed\n"); dp->confused = 1; return -1; } dp->cyl = dp->tcyl; dp->offset = off; DPRINT("seek to %d succeeded\n", dp->offset); return dp->offset; }
/* * we've lost the floppy position, go to cylinder 0. */ static int floppyrecal(FDrive *dp) { dp->ccyl = -1; dp->cyl = -1; fl.ncmd = 0; fl.cmd[fl.ncmd++] = Frecal; fl.cmd[fl.ncmd++] = dp->dev; if(floppycmd() < 0) return -1; floppywait(1); if(fl.nstat < 2) { DPRINT("recalibrate: confused %ux\n", inb(Pmsr)); fl.confused = 1; return -1; } if((fl.stat[0] & (Codemask|Seekend)) != Seekend) { DPRINT("recalibrate: failed\n"); dp->confused = 1; return -1; } dp->cyl = fl.stat[1]; if(dp->cyl != 0) { DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl); dp->cyl = -1; dp->confused = 1; return -1; } dp->confused = 0; return 0; }
/* * seek to the target cylinder * * interrupt, no results */ static long floppyseek(FDrive *dp, long off) { floppypos(dp, off); if(dp->cyl == dp->tcyl) return dp->tcyl; dp->cyl = -1; fl.ncmd = 0; fl.cmd[fl.ncmd++] = Fseek; fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps; if(floppycmd() < 0) return -1; floppywait(1); if(fl.nstat < 2){ DPRINT("seek: confused\n"); fl.confused = 1; return -1; } if((fl.stat[0] & (Codemask|Seekend)) != Seekend){ DPRINT("seek: failed\n"); dp->confused = 1; return -1; } dp->cyl = dp->tcyl; return dp->tcyl; }
/* * get the interrupt cause from the floppy. */ static int floppysense(void) { fl.ncmd = 0; fl.cmd[fl.ncmd++] = Fsense; if(floppycmd() < 0) return -1; if(floppyresult() < 2) { DPRINT("can't read sense response\n"); fldump(); fl.confused = 1; return -1; } return 0; }
/* * read or write to floppy. try up to three times. */ static long floppyxfer(FDrive *dp, int cmd, void *a, long off, long n) { long offset; int tries; if(off >= dp->t->cap) return 0; if(off + n > dp->t->cap) n = dp->t->cap - off; /* retry on error (until it gets ridiculous) */ for(tries = 0; tries < dp->maxtries; tries++) { dp->len = n; if(pcfloppyseek(dp, off) < 0) { DPRINT("xfer: seek failed\n"); dp->confused = 1; continue; } /* * set up the dma (dp->len may be trimmed) */ dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread); if(dp->len < 0) { buggery: dmaend(DMAchan); continue; } /* * start operation */ fl.ncmd = 0; fl.cmd[fl.ncmd++] = cmd | (dp->t->heads > 1 ? Fmulti : 0); fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; fl.cmd[fl.ncmd++] = dp->tcyl; fl.cmd[fl.ncmd++] = dp->thead; fl.cmd[fl.ncmd++] = dp->tsec; fl.cmd[fl.ncmd++] = dp->t->bcode; fl.cmd[fl.ncmd++] = dp->t->sectors; fl.cmd[fl.ncmd++] = dp->t->gpl; fl.cmd[fl.ncmd++] = 0xFF; if(floppycmd() < 0) goto buggery; /* * give bus to DMA, floppyintr() will read result */ floppywait(0); dmaend(DMAchan); /* * check for errors */ if(fl.nstat < 7) { DPRINT("xfer: confused\n"); fl.confused = 1; continue; } if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]) { DPRINT("xfer: failed %ux %ux %ux\n", fl.stat[0], fl.stat[1], fl.stat[2]); DPRINT("offset %lud len %ld\n", off, dp->len); if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun) { DPRINT("DMA overrun: retry\n"); } else dp->confused = 1; continue; } /* * check for correct cylinder */ offset = fl.stat[3] * dp->t->heads + fl.stat[4]; offset = offset*dp->t->sectors + fl.stat[5] - 1; offset = offset * c2b[fl.stat[6]]; if(offset != off+dp->len) { DPRINT("xfer: ends on wrong cyl\n"); dp->confused = 1; continue; } dp->lasttouched = m->ticks; dp->maxtries = 20; return dp->len; } return -1; }
/* * format a track */ static void floppyformat(FDrive *dp, Cmdbuf *cb) { int cyl, h, sec; ulong track; uchar *buf, *bp; FType *t; /* * set the type */ if(cb->nf == 2){ for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){ if(strcmp(cb->f[1], t->name)==0 && t->dt==dp->dt){ dp->t = t; floppydir[1+NFDIR*dp->dev].length = dp->t->cap; break; } } if(t >= &floppytype[nelem(floppytype)]) error(Ebadarg); } else if(cb->nf == 1){ floppysetdef(dp); t = dp->t; } else { cmderror(cb, "invalid floppy format command"); SET(t); } /* * buffer for per track info */ buf = smalloc(t->sectors*4); if(waserror()){ free(buf); nexterror(); } /* force a recalibrate to cylinder 0 */ dp->confused = 1; if(!waserror()){ floppyon(dp); poperror(); } /* * format a track at time */ for(track = 0; track < t->tracks*t->heads; track++){ cyl = track/t->heads; h = track % t->heads; /* * seek to track, ignore errors */ floppyseek(dp, track*t->tsize); dp->cyl = cyl; dp->confused = 0; /* * set up the dma (dp->len may be trimmed) */ bp = buf; for(sec = 1; sec <= t->sectors; sec++){ *bp++ = cyl; *bp++ = h; *bp++ = sec; *bp++ = t->bcode; } if(waserror()){ dmaend(DMAchan); nexterror(); } if(dmasetup(DMAchan, buf, bp-buf, 0) < 0) error(Eio); /* * start operation */ fl.ncmd = 0; fl.cmd[fl.ncmd++] = Fformat; fl.cmd[fl.ncmd++] = (h<<2) | dp->dev; fl.cmd[fl.ncmd++] = t->bcode; fl.cmd[fl.ncmd++] = t->sectors; fl.cmd[fl.ncmd++] = t->fgpl; fl.cmd[fl.ncmd++] = 0x5a; if(floppycmd() < 0) error(Eio); /* Poll ready bits and transfer data */ floppyexec((char *)buf, bp-buf, 0); /* * give bus to DMA, floppyintr() will read result */ floppywait(1); dmaend(DMAchan); poperror(); /* * check for errors */ if(fl.nstat < 7){ DPRINT("format: confused\n"); fl.confused = 1; error(Eio); } if((fl.stat[0]&Codemask)!=0 || fl.stat[1]|| fl.stat[2]){ DPRINT("format: failed %ux %ux %ux\n", fl.stat[0], fl.stat[1], fl.stat[2]); dp->confused = 1; error(Eio); } } free(buf); dp->confused = 1; poperror(); }