1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087 |
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "io.h"
- #include "../port/error.h"
- #include "floppy.h"
- /* Intel 82077A (8272A compatible) floppy controller */
- /* This module expects the following functions to be defined
- * elsewhere:
- *
- * inb()
- * outb()
- * floppyexec()
- * floppyeject()
- * floppysetup0()
- * floppysetup1()
- * dmainit()
- * dmasetup()
- * dmaend()
- *
- * On DMA systems, floppyexec() should be an empty function;
- * on non-DMA systems, dmaend() should be an empty function;
- * dmasetup() may enforce maximum transfer sizes.
- */
- enum {
- /* file types */
- Qdir= 0,
- Qdata= (1<<2),
- Qctl= (2<<2),
- Qmask= (3<<2),
- DMAchan= 2, /* floppy dma channel */
- };
- #define DPRINT if(floppydebug)print
- int floppydebug = 0;
- /*
- * types of drive (from PC equipment byte)
- */
- enum
- {
- Tnone= 0,
- T360kb= 1,
- T1200kb= 2,
- T720kb= 3,
- T1440kb= 4,
- };
- FType floppytype[] =
- {
- { "3½HD", T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
- { "3½DD", T1440kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
- { "3½DD", T720kb, 512, 9, 2, 1, 80, 0x1B, 0x54, 2, },
- { "5¼HD", T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
- { "5¼DD", T1200kb, 512, 9, 2, 2, 40, 0x2A, 0x50, 1, },
- { "ATT3B1", T1200kb, 512, 8, 2, 2, 48, 0x2A, 0x50, 1, },
- { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
- };
- /*
- * bytes per sector encoding for the controller.
- * - index for b2c is is (bytes per sector/128).
- * - index for c2b is code from b2c
- */
- static int b2c[] =
- {
- [1] 0,
- [2] 1,
- [4] 2,
- [8] 3,
- };
- static int c2b[] =
- {
- 128,
- 256,
- 512,
- 1024,
- };
- FController fl;
- #define MOTORBIT(i) (1<<((i)+4))
- /*
- * predeclared
- */
- static int cmddone(void*);
- static void floppyformat(FDrive*, Cmdbuf*);
- static void floppykproc(void*);
- static void floppypos(FDrive*,long);
- static int floppyrecal(FDrive*);
- static int floppyresult(void);
- static void floppyrevive(void);
- static long floppyseek(FDrive*, long);
- static int floppysense(void);
- static void floppywait(int);
- static long floppyxfer(FDrive*, int, void*, long, long);
- Dirtab floppydir[]={
- ".", {Qdir, 0, QTDIR}, 0, 0550,
- "fd0disk", {Qdata + 0}, 0, 0660,
- "fd0ctl", {Qctl + 0}, 0, 0660,
- "fd1disk", {Qdata + 1}, 0, 0660,
- "fd1ctl", {Qctl + 1}, 0, 0660,
- "fd2disk", {Qdata + 2}, 0, 0660,
- "fd2ctl", {Qctl + 2}, 0, 0660,
- "fd3disk", {Qdata + 3}, 0, 0660,
- "fd3ctl", {Qctl + 3}, 0, 0660,
- };
- #define NFDIR 2 /* directory entries/drive */
- enum
- {
- CMdebug,
- CMnodebug,
- CMeject,
- CMformat,
- CMreset,
- };
- static Cmdtab floppyctlmsg[] =
- {
- CMdebug, "debug", 1,
- CMnodebug, "nodebug", 1,
- CMeject, "eject", 1,
- CMformat, "format", 0,
- CMreset, "reset", 1,
- };
- static void
- fldump(void)
- {
- DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
- inb(Pdor), inb(Pmsr), inb(Pdir));
- }
- /*
- * set floppy drive to its default type
- */
- static void
- floppysetdef(FDrive *dp)
- {
- FType *t;
- for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++)
- if(dp->dt == t->dt){
- dp->t = t;
- floppydir[1+NFDIR*dp->dev].length = dp->t->cap;
- break;
- }
- }
- static void
- floppyreset(void)
- {
- FDrive *dp;
- FType *t;
- ulong maxtsize;
-
- floppysetup0(&fl);
- if(fl.ndrive == 0)
- return;
- /*
- * init dependent parameters
- */
- maxtsize = 0;
- for(t = floppytype; t < &floppytype[nelem(floppytype)]; t++){
- t->cap = t->bytes * t->heads * t->sectors * t->tracks;
- t->bcode = b2c[t->bytes/128];
- t->tsize = t->bytes * t->sectors;
- if(maxtsize < t->tsize)
- maxtsize = t->tsize;
- }
- /*
- * Should check if this fails. Can do so
- * if there is no space <= 16MB for the DMA
- * bounce buffer.
- */
- dmainit(DMAchan, maxtsize);
- /*
- * allocate the drive storage
- */
- fl.d = xalloc(fl.ndrive*sizeof(FDrive));
- fl.selected = fl.d;
- /*
- * stop the motors
- */
- fl.motor = 0;
- delay(10);
- outb(Pdor, fl.motor | Fintena | Fena);
- delay(10);
- /*
- * init drives
- */
- for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
- dp->dev = dp - fl.d;
- dp->dt = T1440kb;
- floppysetdef(dp);
- dp->cyl = -1; /* because we don't know */
- dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);
- dp->ccyl = -1;
- dp->vers = 0;
- }
- /*
- * first operation will recalibrate
- */
- fl.confused = 1;
- floppysetup1(&fl);
- }
- static Chan*
- floppyattach(char *spec)
- {
- static int kstarted;
- if(fl.ndrive == 0)
- error(Enodev);
- if(kstarted == 0){
- /*
- * watchdog to turn off the motors
- */
- kstarted = 1;
- kproc("floppy", floppykproc, 0);
- }
- return devattach('f', spec);
- }
- static Walkqid*
- floppywalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, floppydir, 1+fl.ndrive*NFDIR, devgen);
- }
- static int
- floppystat(Chan *c, uchar *dp, int n)
- {
- return devstat(c, dp, n, floppydir, 1+fl.ndrive*NFDIR, devgen);
- }
- static Chan*
- floppyopen(Chan *c, int omode)
- {
- return devopen(c, omode, floppydir, 1+fl.ndrive*NFDIR, devgen);
- }
- static void
- floppyclose(Chan *)
- {
- }
- static void
- islegal(ulong offset, long n, FDrive *dp)
- {
- if(offset % dp->t->bytes)
- error(Ebadarg);
- if(n % dp->t->bytes)
- error(Ebadarg);
- }
- /*
- * 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);
- }
- static int
- readtrack(FDrive *dp, int cyl, int head)
- {
- int i, nn, sofar;
- ulong pos;
- nn = dp->t->tsize;
- if(dp->ccyl==cyl && dp->chead==head)
- return nn;
- pos = (cyl*dp->t->heads+head) * nn;
- for(sofar = 0; sofar < nn; sofar += i){
- dp->ccyl = -1;
- i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
- if(i <= 0)
- return -1;
- }
- dp->ccyl = cyl;
- dp->chead = head;
- return nn;
- }
- 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;
- }
- 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;
- }
- static void
- floppykproc(void *)
- {
- FDrive *dp;
- while(waserror())
- ;
- for(;;){
- for(dp = fl.d; dp < &fl.d[fl.ndrive]; dp++){
- if((fl.motor&MOTORBIT(dp->dev))
- && TK2SEC(m->ticks - dp->lasttouched) > 5
- && canqlock(&fl)){
- if(TK2SEC(m->ticks - dp->lasttouched) > 5)
- floppyoff(dp);
- qunlock(&fl);
- }
- }
- tsleep(&up->sleep, return0, 0, 1000);
- }
- }
- /*
- * start a floppy drive's motor.
- */
- static int
- floppyon(FDrive *dp)
- {
- int alreadyon;
- int tries;
- if(fl.confused)
- floppyrevive();
- /* start motor and select drive */
- alreadyon = fl.motor & MOTORBIT(dp->dev);
- fl.motor |= MOTORBIT(dp->dev);
- outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
- if(!alreadyon){
- /* wait for drive to spin up */
- tsleep(&up->sleep, return0, 0, 750);
- /* clear any pending interrupts */
- floppysense();
- }
- /* set transfer rate */
- if(fl.rate != dp->t->rate){
- fl.rate = dp->t->rate;
- outb(Pdsr, fl.rate);
- }
- /* get drive to a known cylinder */
- if(dp->confused)
- for(tries = 0; tries < 4; tries++)
- if(floppyrecal(dp) >= 0)
- break;
- dp->lasttouched = m->ticks;
- fl.selected = dp;
- /* return -1 if this didn't work */
- if(dp->confused)
- return -1;
- return 0;
- }
- /*
- * stop the floppy if it hasn't been used in 5 seconds
- */
- static void
- floppyoff(FDrive *dp)
- {
- fl.motor &= ~MOTORBIT(dp->dev);
- outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
- }
- /*
- * 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(8); /* for machine independence */
- }
- outb(Pfdata, fl.cmd[i]);
- }
- 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(8); /* for machine independence */
- }
- fl.stat[i] = inb(Pfdata);
- }
- fl.nstat = sizeof(fl.stat);
- return fl.nstat;
- }
- /*
- * calculate physical address of a logical byte offset into the disk
- *
- * truncate dp->length if it crosses a track boundary
- */
- static void
- floppypos(FDrive *dp, long off)
- {
- int lsec;
- int ltrack;
- int end;
- lsec = off/dp->t->bytes;
- ltrack = lsec/dp->t->sectors;
- dp->tcyl = ltrack/dp->t->heads;
- dp->tsec = (lsec % dp->t->sectors) + 1;
- dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
- /*
- * can't read across track boundaries.
- * if so, decrement the bytes to be read.
- */
- end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
- if(off+dp->len > end)
- dp->len = end - off;
- }
- /*
- * 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;
- }
- static int
- cmddone(void *)
- {
- return fl.ncmd == 0;
- }
- /*
- * Wait for a floppy interrupt. If none occurs in 5 seconds, we
- * may have missed one. This only happens on some portables which
- * do power management behind our backs. Call the interrupt
- * routine to try to clear any conditions.
- */
- static void
- floppywait(int slow)
- {
- tsleep(&fl.r, cmddone, 0, slow ? 5000 : 1000);
- if(!cmddone(0)){
- floppyintr(0);
- fl.confused = 1;
- }
- }
- /*
- * 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;
- }
- /*
- * if the controller or a specific drive is in a confused state,
- * reset it and get back to a known 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();
- }
- }
- /*
- * 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;
- }
- /*
- * 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) */
- tries = 0;
- while(waserror()){
- if(tries++ >= dp->maxtries)
- nexterror();
- DPRINT("floppyxfer: retrying\n");
- }
- dp->len = n;
- if(floppyseek(dp, off) < 0){
- DPRINT("xfer: seek failed\n");
- dp->confused = 1;
- error(Eio);
- }
- /*
- * set up the dma (dp->len may be trimmed)
- */
- if(waserror()){
- dmaend(DMAchan);
- nexterror();
- }
- dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
- if(dp->len < 0)
- error(Eio);
- /*
- * 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)
- error(Eio);
- /* Poll ready bits and transfer data */
- floppyexec((char*)a, dp->len, cmd==Fread);
- /*
- * give bus to DMA, floppyintr() will read result
- */
- floppywait(0);
- dmaend(DMAchan);
- poperror();
- /*
- * check for errors
- */
- if(fl.nstat < 7){
- DPRINT("xfer: confused\n");
- fl.confused = 1;
- error(Eio);
- }
- 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;
- error(Eio);
- }
- /*
- * 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;
- error(Eio);
- }
- poperror();
- dp->lasttouched = m->ticks;
- return dp->len;
- }
- /*
- * 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 void
- floppyintr(Ureg *)
- {
- switch(fl.cmd[0]&~Fmulti){
- case Fread:
- case Fwrite:
- case Fformat:
- case Fdumpreg:
- floppyresult();
- break;
- case Fseek:
- case Frecal:
- default:
- floppysense(); /* to clear interrupt */
- break;
- }
- fl.ncmd = 0;
- wakeup(&fl.r);
- }
- Dev floppydevtab = {
- 'f',
- "floppy",
- floppyreset,
- devinit,
- devshutdown,
- floppyattach,
- floppywalk,
- floppystat,
- floppyopen,
- devcreate,
- floppyclose,
- floppyread,
- devbread,
- floppywrite,
- devbwrite,
- devremove,
- devwstat,
- };
|