/* * check if the floppy has been replaced under foot. cause * an error if it has. * * a seek and a read clears the condition. this was determined * experimentally, there has to be a better way. * * if the read fails, cycle through the possible floppy * density till one works or we've cycled through all * possibilities for this drive. */ static void changed(Chan *c, FDrive *dp) { ulong old; FType *start; /* * if floppy has changed or first time through */ if((inb(Pdir)&Fchange) || dp->vers == 0){ DPRINT("changed\n"); fldump(); dp->vers++; start = dp->t; dp->maxtries = 3; /* limit it when we're probing */ /* floppyon will fail if there's a controller but no drive */ dp->confused = 1; /* make floppyon recal */ if(floppyon(dp) < 0) error(Eio); /* seek to the first track */ floppyseek(dp, dp->t->heads*dp->t->tsize); while(waserror()){ /* * if first attempt doesn't reset changed bit, there's * no floppy there */ if(inb(Pdir)&Fchange) nexterror(); while(++dp->t){ if(dp->t == &floppytype[nelem(floppytype)]) dp->t = floppytype; if(dp->dt == dp->t->dt) break; } floppydir[1+NFDIR*dp->dev].length = dp->t->cap; /* floppyon will fail if there's a controller but no drive */ if(floppyon(dp) < 0) error(Eio); DPRINT("changed: trying %s\n", dp->t->name); fldump(); if(dp->t == start) nexterror(); } /* if the read succeeds, we've got the density right */ floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize); poperror(); dp->maxtries = 20; } old = c->qid.vers; c->qid.vers = dp->vers; if(old && old != dp->vers) error(Eio); }
/* * check if the floppy has been replaced under foot. cause * an error if it has. * * a seek and a read clears the condition. this was determined * experimentally, there has to be a better way. * * if the read fails, cycle through the possible floppy * density till one works or we've cycled through all * possibilities for this drive. */ static int changed(FDrive *dp) { FType *start; /* * if floppy has changed or first time through */ if((inb(Pdir)&Fchange) || dp->vers == 0) { DPRINT("changed\n"); fldump(); dp->vers++; floppysetdef(dp); dp->maxtries = 3; start = dp->t; /* flopppyon fails if there's no drive */ dp->confused = 1; /* make floppyon recal */ if(floppyon(dp) < 0) return -1; pcfloppyseek(dp, dp->t->heads*dp->t->tsize); while(floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize) <= 0) { /* * if the xfer attempt doesn't clear the changed bit, * there's no floppy in the drive */ if(inb(Pdir)&Fchange) return -1; while(++dp->t) { if(dp->t == &floppytype[nelem(floppytype)]) dp->t = floppytype; if(dp->dt == dp->t->dt) break; } /* flopppyon fails if there's no drive */ if(floppyon(dp) < 0) return -1; DPRINT("changed: trying %s\n", dp->t->name); fldump(); if(dp->t == start) return -1; } } return 0; }
long floppyread(Fs *fs, void *a, long n) { FDrive *dp; long rv, offset; int sec, head, cyl; long len; uchar *aa; aa = a; dp = &fl.d[fs->dev]; offset = dp->offset; floppyon(dp); if(changed(dp)) return -1; for(rv = 0; rv < n; rv += len) { /* * all xfers come out of the track cache */ dp->len = n - rv; floppypos(dp, offset+rv); cyl = dp->tcyl; head = dp->thead; len = dp->len; sec = dp->tsec; if(readtrack(dp, cyl, head) < 0) break; memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len); } dp->offset = offset+rv; return rv; }
static long floppyread(Chan *c, void *a, long n, vlong off) { FDrive *dp; long rv; int sec, head, cyl; long len; uchar *aa; ulong offset = off; if(c->qid.type & QTDIR) return devdirread(c, a, n, floppydir, 1+fl.ndrive*NFDIR, devgen); rv = 0; dp = &fl.d[c->qid.path & ~Qmask]; switch ((int)(c->qid.path & Qmask)) { case Qdata: islegal(offset, n, dp); aa = a; qlock(&fl); if(waserror()){ qunlock(&fl); nexterror(); } floppyon(dp); changed(c, dp); for(rv = 0; rv < n; rv += len){ /* * all xfers come out of the track cache */ dp->len = n - rv; floppypos(dp, offset+rv); cyl = dp->tcyl; head = dp->thead; len = dp->len; sec = dp->tsec; if(readtrack(dp, cyl, head) < 0) break; memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len); } qunlock(&fl); poperror(); break; case Qctl: return readstr(offset, a, n, dp->t->name); default: panic("floppyread: bad qid"); } return rv; }
/* * 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(); }
static long floppywrite(Chan *c, void *a, long n, vlong off) { FDrive *dp; long rv, i; char *aa = a; Cmdbuf *cb; Cmdtab *ct; ulong offset = off; rv = 0; dp = &fl.d[c->qid.path & ~Qmask]; switch ((int)(c->qid.path & Qmask)) { case Qdata: islegal(offset, n, dp); qlock(&fl); if(waserror()){ qunlock(&fl); nexterror(); } floppyon(dp); changed(c, dp); for(rv = 0; rv < n; rv += i){ floppypos(dp, offset+rv); if(dp->tcyl == dp->ccyl) dp->ccyl = -1; i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv); if(i < 0) break; if(i == 0) error(Eio); } qunlock(&fl); poperror(); break; case Qctl: rv = n; cb = parsecmd(a, n); if(waserror()){ free(cb); nexterror(); } qlock(&fl); if(waserror()){ qunlock(&fl); nexterror(); } ct = lookupcmd(cb, floppyctlmsg, nelem(floppyctlmsg)); switch(ct->index){ case CMeject: floppyeject(dp); break; case CMformat: floppyformat(dp, cb); break; case CMreset: fl.confused = 1; floppyon(dp); break; case CMdebug: floppydebug = 1; break; case CMnodebug: floppydebug = 0; break; } poperror(); qunlock(&fl); poperror(); free(cb); break; default: panic("floppywrite: bad qid"); } return rv; }