/* * 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; }
/* * get a command result from the floppy * * when the controller goes ready waiting for a command * (instead of sending results), we're done * */ static int floppyresult(void) { int i, s; int tries; /* get the result of the operation */ for(i = 0; i < sizeof(fl.stat); i++) { /* wait for status byte */ for(tries = 0; ; tries++) { s = inb(Pmsr)&(Ffrom|Fready); if(s == Fready) { fl.nstat = i; return fl.nstat; } if(s == (Ffrom|Fready)) break; if(tries > 1000) { DPRINT("floppyresult: %d stats\n", i); fldump(); fl.confused = 1; return -1; } microdelay(1); } fl.stat[i] = inb(Pfdata); } fl.nstat = sizeof(fl.stat); return fl.nstat; }
/* * send a command to the floppy */ static int floppycmd(void) { int i; int tries; fl.nstat = 0; for(i = 0; i < fl.ncmd; i++) { for(tries = 0; ; tries++) { if((inb(Pmsr)&(Ffrom|Fready)) == Fready) break; if(tries > 1000) { DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i); fldump(); /* empty fifo, might have been a bad command */ floppyresult(); return -1; } microdelay(1); } outb(Pfdata, fl.cmd[i]); } return 0; }
/* * if the controller or a specific drive is in a confused state, * reset it and get back to a kown state */ static void floppyrevive(void) { FDrive *dp; /* * reset the controller if it's confused */ if(fl.confused) { DPRINT("floppyrevive in\n"); fldump(); /* reset controller and turn all motors off */ splhi(); fl.ncmd = 1; fl.cmd[0] = 0; outb(Pdor, 0); delay(10); outb(Pdor, Fintena|Fena); delay(10); spllo(); fl.motor = 0; fl.confused = 0; floppywait(0); /* mark all drives in an unknown state */ for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++) dp->confused = 1; /* set rate to a known value */ outb(Pdsr, 0); fl.rate = 0; DPRINT("floppyrevive out\n"); fldump(); } }
/* * 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; }