123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771 |
- /*
- * Papa's got a brand new bag on the side.
- */
- #include "all.h"
- #include "io.h"
- #include "mem.h"
- #define DPRINT if(0)print
- typedef struct Floppy Floppy;
- typedef struct Ctlr Ctlr;
- typedef struct Type Type;
- enum
- {
- Pdor= 0x3f2, /* motor port */
- Fintena= 0x8, /* enable floppy interrupt */
- Fena= 0x4, /* 0 == reset controller */
- Pmsr= 0x3f4, /* controller main status port */
- Fready= 0x80, /* ready to be touched */
- Ffrom= 0x40, /* data from controller */
- Fbusy= 0x10, /* operation not over */
- Pdata= 0x3f5, /* controller data port */
- Frecal= 0x7, /* recalibrate cmd */
- Fseek= 0xf, /* seek cmd */
- Fsense= 0x8, /* sense cmd */
- Fread= 0x66, /* read cmd */
- Fwrite= 0x45, /* write cmd */
- Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */
- /* digital input register */
- Pdir= 0x3F7, /* disk changed port (read only) */
- Pdsr= 0x3F7, /* data rate select port (write only) */
- Fchange= 0x80, /* disk has changed */
- DMAmode0= 0xb,
- DMAmode1= 0xc,
- DMAaddr= 0x4,
- DMAtop= 0x81,
- DMAinit= 0xa,
- DMAcount= 0x5,
- Maxfloppy= 4, /* floppies/controller */
- /* sector size encodings */
- S128= 0,
- S256= 1,
- S512= 2,
- S1024= 3,
- /* status 0 byte */
- Floppymask= 3<<0,
- Seekend= 1<<5,
- Codemask= (3<<6)|(3<<3),
- Cmdexec= 1<<6,
- /* status 1 byte */
- Overrun= 0x10,
- };
- #define MOTORBIT(i) (1<<((i)+4))
- /*
- * types of drive (from PC equipment byte)
- */
- enum
- {
- T360kb= 1,
- T1200kb= 2,
- T720kb= 3,
- T1440kb= 4,
- };
- /*
- * floppy types (all MFM encoding)
- */
- struct Type
- {
- char *name;
- int dt; /* compatible drive type */
- int bytes; /* bytes/sector */
- int sectors; /* sectors/track */
- int heads; /* number of heads */
- int steps; /* steps per cylinder */
- int tracks; /* tracks/disk */
- int gpl; /* intersector gap length for read/write */
- int fgpl; /* intersector gap length for format */
- int rate; /* rate code */
- /*
- * these depend on previous entries and are set filled in
- * by floppyinit
- */
- int bcode; /* coded version of bytes for the controller */
- long cap; /* drive capacity in bytes */
- long tsize; /* track size in bytes */
- };
- Type 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, },
- { "5¼DD", T360kb, 512, 9, 2, 1, 40, 0x2A, 0x50, 2, },
- };
- #define NTYPES (sizeof(floppytype)/sizeof(Type))
- /*
- * 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,
- };
- /*
- * a floppy drive
- */
- struct Floppy
- {
- Type *t;
- int dt;
- int dev;
- Timet lasttouched; /* time last touched */
- int cyl; /* current cylinder */
- int confused; /* needs to be recalibrated (or worse) */
- long offset; /* current offset */
- int tcyl; /* target cylinder */
- int thead; /* target head */
- int tsec; /* target sector */
- long len;
- int maxtries;
- };
- /*
- * NEC PD765A controller for 4 floppys
- */
- struct Ctlr
- {
- QLock;
- Rendez;
- Floppy d[Maxfloppy]; /* the floppy drives */
- int rw; /* true if a read or write in progress */
- int seek; /* one bit for each seek in progress */
- uchar stat[8]; /* status of an operation */
- int intr;
- int confused;
- int motor;
- Floppy *selected;
- int rate;
- int cdev;
- uchar *ccache; /* cyclinder cache */
- int ccyl;
- int chead;
- };
- Ctlr fl;
- static int floppysend(int);
- static int floppyrcv(void);
- static int floppyrdstat(int);
- static void floppypos(Floppy*, long);
- static void floppywait(char*);
- static int floppysense(Floppy*);
- static int floppyrecal(Floppy*);
- static void floppyon(Floppy*);
- static long floppyxfer(Floppy*, int, void*, long);
- static void floppyrevive(void);
- static void
- timedsleep(int ms)
- {
- ulong end;
- end = MACHP(0)->ticks + 1 + MS2TK(ms);
- while(MACHP(0)->ticks < end)
- ;
- }
- /*
- * set floppy drive to its default type
- */
- static void
- setdef(Floppy *dp)
- {
- Type *t;
- for(t = floppytype; t < &floppytype[NTYPES]; t++)
- if(dp->dt == t->dt){
- dp->t = t;
- break;
- }
- }
- static void
- floppyintr(Ureg *ur, void *arg)
- {
- USED(ur, arg);
- fl.intr = 1;
- }
- static void
- floppystop(Floppy *dp)
- {
- fl.motor &= ~MOTORBIT(dp->dev);
- outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
- }
- void
- floppyhalt(void)
- {
- Floppy *dp;
- for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++)
- if((fl.motor&MOTORBIT(dp->dev)) && canqlock(&fl)){
- floppystop(dp);
- qunlock(&fl);
- }
- }
- static void
- floppyalarm(Alarm* a, void *arg)
- {
- USED(arg);
- cancel(a);
- wakeup(&fl);
- }
- void
- floppyproc(void)
- {
- Floppy *dp;
- for(;;){
- for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){
- if((fl.motor&MOTORBIT(dp->dev))
- && TK2SEC(MACHP(0)->ticks - dp->lasttouched) > 5
- && canqlock(&fl)){
- if(TK2SEC(MACHP(0)->ticks - dp->lasttouched) > 5)
- floppystop(dp);
- qunlock(&fl);
- }
- }
- alarm(5*1000, floppyalarm, 0);
- sleep(&fl, no, 0);
- }
- }
- int
- floppyinit(void)
- {
- Floppy *dp;
- uchar equip;
- int nfloppy = 0;
- Type *t;
- setvec(Floppyvec, floppyintr, &fl);
- delay(10);
- outb(Pdor, 0);
- delay(1);
- outb(Pdor, Fintena | Fena);
- delay(10);
- /*
- * init dependent parameters
- */
- for(t = floppytype; t < &floppytype[NTYPES]; t++){
- t->cap = t->bytes * t->heads * t->sectors * t->tracks;
- t->bcode = b2c[t->bytes/128];
- t->tsize = t->bytes * t->sectors;
- }
- /*
- * init drive parameters
- */
- for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++){
- dp->cyl = -1;
- dp->dev = dp - fl.d;
- dp->maxtries = 1;
- }
- /*
- * read nvram for types of floppies 0 & 1
- */
- equip = nvramread(0x10);
- if(Maxfloppy > 0){
- fl.d[0].dt = (equip >> 4) & 0xf;
- setdef(&fl.d[0]);
- nfloppy++;
- }
- if(Maxfloppy > 1){
- fl.d[1].dt = equip & 0xf;
- setdef(&fl.d[1]);
- nfloppy++;
- }
- fl.rate = -1;
- fl.motor = 0;
- fl.confused = 1;
- fl.ccyl = -1;
- fl.chead = -1;
- fl.cdev = -1;
- fl.ccache = (uchar*)ialloc(18*2*512, 64*1024);
- if(DMAOK(fl.ccache, 18*2*512) == 0)
- panic("floppy: no memory < 16Mb\n");
- return nfloppy;
- }
- static void
- floppyon(Floppy *dp)
- {
- int alreadyon;
- int tries;
- if(fl.confused)
- floppyrevive();
- dp->lasttouched = MACHP(0)->ticks;
- alreadyon = fl.motor & MOTORBIT(dp->dev);
- fl.motor |= MOTORBIT(dp->dev);
- outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
- /* get motor going */
- if(!alreadyon)
- timedsleep(750);
- /* 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 = MACHP(0)->ticks;
- fl.selected = dp;
- }
- static void
- floppyrevive(void)
- {
- Floppy *dp;
- /*
- * reset the controller if it's confused
- */
- if(fl.confused){
- /* reset controller and turn all motors off */
- fl.intr = 0;
- splhi();
- outb(Pdor, 0);
- delay(1);
- outb(Pdor, Fintena|Fena);
- spllo();
- for(dp = fl.d; dp < &fl.d[Maxfloppy]; dp++)
- dp->confused = 1;
- fl.motor = 0;
- floppywait("revive");
- fl.confused = 0;
- outb(Pdsr, 0);
- }
- }
- static int
- floppysend(int data)
- {
- int tries;
- for(tries = 0; tries < 1000; tries++){
- if((inb(Pmsr)&(Ffrom|Fready)) == Fready){
- outb(Pdata, data);
- return 0;
- }
- microdelay(8);
- }
- return -1;
- }
- static int
- floppyrcv(void)
- {
- int tries;
- uchar c;
- for(tries = 0; tries < 1000; tries++){
- if((inb(Pmsr)&(Ffrom|Fready)) == (Ffrom|Fready))
- return inb(Pdata)&0xff;
- microdelay(8);
- }
- DPRINT("floppyrcv returns -1 status = %ux\n", c);
- return -1;
- }
- static int
- floppyrdstat(int n)
- {
- int i;
- int c;
- for(i = 0; i < n; i++){
- c = floppyrcv();
- if(c < 0)
- return -1;
- fl.stat[i] = c;
- }
- return 0;
- }
- static void
- floppypos(Floppy *dp, long off)
- {
- int lsec;
- int cyl;
- lsec = off/dp->t->bytes;
- dp->tcyl = lsec/(dp->t->sectors*dp->t->heads);
- dp->tsec = (lsec % dp->t->sectors) + 1;
- dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
- /*
- * can't read across cylinder boundaries.
- * if so, decrement the bytes to be read.
- */
- lsec = (off+dp->len)/dp->t->bytes;
- cyl = lsec/(dp->t->sectors*dp->t->heads);
- if(cyl != dp->tcyl){
- dp->len -= (lsec % dp->t->sectors)*dp->t->bytes;
- dp->len -= ((lsec/dp->t->sectors) % dp->t->heads)*dp->t->bytes
- *dp->t->sectors;
- }
- dp->lasttouched = MACHP(0)->ticks;
- fl.intr = 0;
- }
- static void
- floppywait(char *cmd)
- {
- ulong end;
- end = MACHP(0)->ticks + 1 + MS2TK(750);
- while(MACHP(0)->ticks < end && fl.intr == 0)
- ;
- if(m->ticks > end)
- DPRINT("floppy timed out, cmd=%s\n", cmd);
- fl.intr = 0;
- }
- static int
- floppysense(Floppy *dp)
- {
- /*
- * ask for floppy status
- */
- if(floppysend(Fsense) < 0){
- fl.confused = 1;
- return -1;
- }
- if(floppyrdstat(2) < 0){
- fl.confused = 1;
- dp->confused = 1;
- return -1;
- }
- /*
- * make sure it's the right drive
- */
- if((fl.stat[0] & Floppymask) != dp->dev){
- DPRINT("sense failed, %ux %ux\n", fl.stat[0], fl.stat[1]);
- dp->confused = 1;
- return -1;
- }
- return 0;
- }
- static int
- floppyrecal(Floppy *dp)
- {
- fl.intr = 0;
- if(floppysend(Frecal) < 0
- || floppysend(dp - fl.d) < 0){
- DPRINT("recalibrate rejected\n");
- fl.confused = 0;
- return -1;
- }
- floppywait("recal");
- /*
- * get return values
- */
- if(floppysense(dp) < 0)
- return -1;
- /*
- * see what cylinder we got to
- */
- dp->tcyl = 0;
- dp->cyl = fl.stat[1]/dp->t->steps;
- if(dp->cyl != dp->tcyl){
- DPRINT("recalibrate went to wrong cylinder %d\n", dp->cyl);
- dp->confused = 1;
- return -1;
- }
- dp->confused = 0;
- return 0;
- }
- Devsize
- floppyseek(int dev, Devsize off)
- {
- Floppy *dp;
- dp = &fl.d[dev];
- floppyon(dp);
- floppypos(dp, off);
- if(dp->cyl == dp->tcyl){
- dp->offset = off;
- return off;
- }
- /*
- * tell floppy to seek
- */
- if(floppysend(Fseek) < 0
- || floppysend((dp->thead<<2) | dp->dev) < 0
- || floppysend(dp->tcyl * dp->t->steps) < 0){
- DPRINT("seek cmd failed\n");
- fl.confused = 1;
- return -1;
- }
- /*
- * wait for interrupt
- */
- floppywait("seek");
- /*
- * get floppy status
- */
- if(floppysense(dp) < 0)
- return -1;
- /*
- * see if it worked
- */
- if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
- DPRINT("seek failed\n");
- dp->confused = 1;
- return -1;
- }
- /*
- * see what cylinder we got to
- */
- dp->cyl = fl.stat[1]/dp->t->steps;
- if(dp->cyl != dp->tcyl){
- DPRINT("seek went to wrong cylinder %d instead of %d\n",
- dp->cyl, dp->tcyl);
- dp->confused = 1;
- return -1;
- }
- dp->offset = off;
- DPRINT("seek to %ld succeeded\n", dp->offset);
- return dp->offset;
- }
- static long
- floppyxfer(Floppy *dp, int cmd, void *a, long n)
- {
- ulong addr;
- long offset;
- addr = (ulong)a;
- /*
- * dma can't cross 64 k boundaries
- */
- if((addr & 0xffff0000) != ((addr+n) & 0xffff0000))
- n -= (addr+n)&0xffff;
- dp->len = n;
- if(floppyseek(dp->dev, dp->offset) < 0){
- DPRINT("xfer seek failed\n");
- return -1;
- }
- DPRINT("floppy %d tcyl %d, thead %d, tsec %d, addr %lux, n %ld\n",
- dp->dev, dp->tcyl, dp->thead, dp->tsec, addr, n);/**/
- /*
- * set up the dma
- */
- outb(DMAmode1, cmd==Fread ? 0x46 : 0x4a);
- outb(DMAmode0, cmd==Fread ? 0x46 : 0x4a);
- outb(DMAaddr, addr);
- outb(DMAaddr, addr>>8);
- outb(DMAtop, addr>>16);
- outb(DMAcount, n-1);
- outb(DMAcount, (n-1)>>8);
- outb(DMAinit, 2);
- /*
- * tell floppy to go
- */
- cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);
- if(floppysend(cmd) < 0
- || floppysend((dp->thead<<2) | dp->dev) < 0
- || floppysend(dp->tcyl * dp->t->steps) < 0
- || floppysend(dp->thead) < 0
- || floppysend(dp->tsec) < 0
- || floppysend(dp->t->bcode) < 0
- || floppysend(dp->t->sectors) < 0
- || floppysend(dp->t->gpl) < 0
- || floppysend(0xFF) < 0){
- DPRINT("xfer cmd failed\n");
- fl.confused = 1;
- return -1;
- }
- floppywait("xfer");
- /*
- * get status
- */
- if(floppyrdstat(7) < 0){
- DPRINT("xfer status failed\n");
- fl.confused = 1;
- return -1;
- }
- 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]);
- if((fl.stat[0]&Codemask)==Cmdexec && fl.stat[1]==Overrun){
- DPRINT("DMA overrun: retry\n");
- return 0;
- }
- dp->confused = 1;
- return -1;
- }
- offset = (fl.stat[3]/dp->t->steps) * dp->t->heads + fl.stat[4];
- offset = offset*dp->t->sectors + fl.stat[5] - 1;
- offset = offset * c2b[fl.stat[6]];
- if(offset != dp->offset+n){
- DPRINT("new offset %ld instead of %ld\n", offset, dp->offset+dp->len);
- dp->confused = 1;
- return -1;/**/
- }
- dp->offset += dp->len;
- return dp->len;
- }
- Off
- floppyread(int dev, void *a, long n)
- {
- Floppy *dp;
- int tries;
- Off rv, i, nn, offset, sec;
- uchar *aa;
- dp = &fl.d[dev];
- dp->len = n;
- qlock(&fl);
- floppypos(dp, dp->offset);
- offset = dp->offset;
- sec = dp->tsec + (Off)dp->t->sectors*(Off)dp->thead;
- n = dp->len;
- if(fl.ccyl==dp->tcyl && fl.cdev==dev)
- goto out;
- fl.ccyl = -1;
- fl.cdev = dev;
- aa = fl.ccache;
- nn = (Off)dp->t->bytes * (Off)dp->t->sectors * (Off)dp->t->heads;
- dp->offset = dp->tcyl * nn;
- for(rv = 0; rv < nn; rv += i){
- i = 0;
- for(tries = 0; tries < dp->maxtries; tries++){
- i = floppyxfer(dp, Fread, aa+rv, nn-rv);
- if(i > 0)
- break;
- }
- if(tries == dp->maxtries)
- break;
- }
- if(rv != nn){
- dp->confused = 1;
- return -1; // ?!!? no qunlock(&fl)? no "goto out"?
- }
- fl.ccyl = dp->tcyl;
- out:
- memmove(a, fl.ccache + dp->t->bytes*(sec-1), n);
- dp->offset = offset + n;
- dp->maxtries = 3;
- qunlock(&fl);
- return n;
- }
- Off
- floppywrite(int dev, void *a, long n)
- {
- Floppy *dp;
- int tries;
- Off rv, i, offset;
- uchar *aa;
- dp = &fl.d[dev];
- qlock(&fl);
- fl.ccyl = -1;
- fl.cdev = dev;
- dp->len = n;
- offset = dp->offset;
- aa = a;
- if(DMAOK(aa, n) == 0){
- aa = fl.ccache;
- memmove(aa, a, n);
- }
- for(rv = 0; rv < n; rv += i){
- i = 0;
- for(tries = 0; tries < dp->maxtries; tries++){
- floppypos(dp, offset+rv);
- i = floppyxfer(dp, Fwrite, aa+rv, n-rv);
- if(i > 0)
- break;
- }
- if(tries == dp->maxtries)
- break;
- }
- if(rv != n)
- dp->confused = 1;
- dp->offset = offset + rv;
- dp->maxtries = 20;
- qunlock(&fl);
- return rv;
- }
|