#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h" #include "pcmcia.h" #define DPRINT if(0)print typedef struct Drive Drive;typedef struct Ident Ident;typedef struct Controller Controller;typedef struct Partition Partition;typedef struct Repl Repl; enum{ /* ports */ Pbase= 0x1F0, Pdata= 0, /* data port (16 bits) */ Perror= 1, /* error port (read) */ Pprecomp= 1, /* buffer mode port (write) */ Pcount= 2, /* sector count port */ Psector= 3, /* sector number port */ Pcyllsb= 4, /* least significant byte cylinder # */ Pcylmsb= 5, /* most significant byte cylinder # */ Pdh= 6, /* drive/head port */ Pstatus= 7, /* status port (read) */ Sbusy= (1<<7), Sready= (1<<6), Sdrq= (1<<3), Serr= (1<<0), Pcmd= 7, /* cmd port (write) */ /* commands */ Crecal= 0x10, Cread= 0x20, Cwrite= 0x30, Cident= 0xEC, Cident2= 0xFF, /* pseudo command for post Cident interrupt */ Csetbuf= 0xEF, Cinitparam= 0x91, /* conner specific commands */ Cstandby= 0xE2, Cidle= 0xE1, Cpowerdown= 0xE3, /* disk states */ Sspinning, Sstandby, Sidle, Spowerdown, /* something we have to or into the drive/head reg */ DHmagic= 0xA0, /* file types */ Qdir= 0, Maxxfer= BY2PG, /* maximum transfer size/cmd */ Npart= 8+2, /* 8 sub partitions, disk, and partition */ Nrepl= 64, /* maximum replacement blocks */};#define PART(x) ((x)&0xF)#define DRIVE(x) (((x)>>4)&0x7)#define MKQID(d,p) (((d)<<4) | (p)) struct Partition{ ulong start; ulong end; char name[NAMELEN+1];}; struct Repl{ Partition *p; int nrepl; ulong blk[Nrepl];}; #define PARTMAGIC "plan9 partitions"#define REPLMAGIC "block replacements" /* * an ata drive */struct Drive{ QLock; Controller *cp; int drive; int confused; /* needs to be recalibrated (or worse) */ int online; int npart; /* number of real partitions */ Partition p[Npart]; Repl repl; ulong usetime; int state; char vol[NAMELEN]; ulong cap; /* total bytes */ int bytes; /* bytes/sector */ int sectors; /* sectors/track */ int heads; /* heads/cyl */ long cyl; /* cylinders/drive */ char lba; /* true if drive has logical block addressing */ char multi; /* non-zero if drive does multiple block xfers */}; /* * a controller for 2 drives */struct Controller{ QLock; /* exclusive access to the controller */ ISAConf; /* interface to pcmspecial */ Lock reglock; /* exclusive access to the registers */ int confused; /* needs to be recalibrated (or worse) */ ulong pbase; /* base port (copied from ISAConf) */ /* * current operation */ int cmd; /* current command */ int lastcmd; /* debugging info */ Rendez r; /* wait here for command termination */ char *buf; /* xfer buffer */ int nsecs; /* length of transfer (sectors) */ int sofar; /* sectors transferred so far */ int status; int error; Drive *dp; /* drive being accessed */}; Controller *atac;Drive *ata;static char* ataerr;static int nhard;static int spindowntime; static void ataintr(Ureg*, void*);static long ataxfer(Drive*, Partition*, int, long, long, char*);static void ataident(Drive*);static void atasetbuf(Drive*, int);static void ataparams(Drive*);static void atapart(Drive*);static int ataprobe(Drive*, int, int, int); static intatagen(Chan *c, Dirtab*, int, int s, Dir *dirp){ Qid qid; int drive; Drive *dp; Partition *pp; ulong l; qid.vers = 0; drive = s/Npart; s = s % Npart; if(drive >= nhard) return -1; dp = &ata[drive]; if(dp->online == 0 || s >= dp->npart) return 0; pp = &dp->p[s]; sprint(up->genbuf, "%s%s", dp->vol, pp->name); qid.path = MKQID(drive, s); l = (pp->end - pp->start) * dp->bytes; devdir(c, qid, up->genbuf, l, eve, 0660, dirp); return 1;} static voidatainit(void){ Drive *dp; Controller *cp; uchar equip; int pcmslot; if (atac) return; /* already done */ equip = 0x10; /* hard coded */ print("ata init\n"); cp = malloc(sizeof(*cp)); if (!cp) error(Enomem); cp->port = Pbase; cp->irq = 14; if((pcmslot = pcmspecial("SunDisk", cp)) < 0) { print("No ATA card\n"); free(cp); ataerr = Enoifc; return; } ata = malloc(2 * sizeof(*ata)); if(ata == nil) { pcmspecialclose(pcmslot); free(cp); error(Enomem); } atac = cp; cp->buf = 0; cp->lastcmd = cp->cmd; cp->cmd = 0; cp->pbase = cp->port; pcmintrenable(pcmslot, ataintr, cp); dp = ata; if(equip & 0xf0){ dp->drive = 0; dp->online = 0; dp->cp = cp; dp++; } if((equip & 0x0f)){ dp->drive = 1; dp->online = 0; dp->cp = cp; dp++; } nhard = dp - ata; spindowntime = 1;} /* * Get the characteristics of each drive. Mark unresponsive ones * off line. */static Chan*ataattach(char *spec){ Drive *dp; atainit(); if (!ata) error(ataerr ? ataerr : Enoifc); for(dp = ata; dp < &ata[nhard]; dp++){ if(waserror()){ dp->online = 0; qunlock(dp); continue; } qlock(dp); if(!dp->online){ /* * Make sure ataclock() doesn't * interfere. */ dp->usetime = m->ticks; ataparams(dp); dp->online = 1; atasetbuf(dp, 1); } /* * read Plan 9 partition table */ atapart(dp); qunlock(dp); poperror(); } return devattach('H', spec);} static intatawalk(Chan *c, char *name){ return devwalk(c, name, 0, 0, atagen);} static voidatastat(Chan *c, char *dp){ devstat(c, dp, 0, 0, atagen);} static Chan*ataopen(Chan *c, int omode){ return devopen(c, omode, 0, 0, atagen);} static voidataclose(Chan *c){ Drive *d; Partition *p; if(c->mode != OWRITE && c->mode != ORDWR) return; d = &ata[DRIVE(c->qid.path)]; p = &d->p[PART(c->qid.path)]; if(strcmp(p->name, "partition") != 0) return; if(waserror()){ qunlock(d); nexterror(); } qlock(d); atapart(d); qunlock(d); poperror();} static longataread(Chan *c, void *a, long n, vlong offset){ Drive *dp; long rv, i; int skip; uchar *aa = a; Partition *pp; char *buf; if(c->qid.path == CHDIR) return devdirread(c, a, n, 0, 0, atagen); buf = smalloc(Maxxfer); if(waserror()){ free(buf); nexterror(); } dp = &ata[DRIVE(c->qid.path)]; pp = &dp->p[PART(c->qid.path)]; skip = offset % dp->bytes; for(rv = 0; rv < n; rv += i){ i = ataxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf); if(i == 0) break; i -= skip; if(i > n - rv) i = n - rv; memmove(aa+rv, buf + skip, i); skip = 0; } free(buf); poperror(); return rv;} static longatawrite(Chan *c, void *a, long n, vlong offset){ Drive *dp; long rv, i, partial; uchar *aa = a; Partition *pp; char *buf; if(c->qid.path == CHDIR) error(Eisdir); dp = &ata[DRIVE(c->qid.path)]; pp = &dp->p[PART(c->qid.path)]; buf = smalloc(Maxxfer); if(waserror()){ free(buf); nexterror(); } /* * if not starting on a sector boundary, * read in the first sector before writing * it out. */ partial = offset % dp->bytes; if(partial){ ataxfer(dp, pp, Cread, offset-partial, dp->bytes, buf); if(partial+n > dp->bytes) rv = dp->bytes - partial; else rv = n; memmove(buf+partial, aa, rv); ataxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf); } else rv = 0; /* * write out the full sectors */ partial = (n - rv) % dp->bytes; n -= partial; for(; rv < n; rv += i){ i = n - rv; if(i > Maxxfer) i = Maxxfer; memmove(buf, aa+rv, i); i = ataxfer(dp, pp, Cwrite, offset+rv, i, buf); if(i == 0) break; } /* * if not ending on a sector boundary, * read in the last sector before writing * it out. */ if(partial){ ataxfer(dp, pp, Cread, offset+rv, dp->bytes, buf); memmove(buf, aa+rv, partial); ataxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf); rv += partial; } free(buf); poperror(); return rv;} /* * did an interrupt happen? */static intcmddone(void *a){ Controller *cp = a; return cp->cmd == 0;} /* * Wait for the controller to be ready to accept a command. * This is protected from intereference by ataclock() by * setting dp->usetime before it is called. */static voidcmdreadywait(Drive *dp){ long start; int period; Controller *cp = dp->cp; /* give it 2 seconds to spin down and up */ if(dp->state == Sspinning) period = 10; else period = 2000; start = m->ticks; while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready) if(TK2MS(m->ticks - start) > period){ DPRINT("cmdreadywait failed\n"); error(Eio); }} static voidatarepl(Drive *dp, long bblk){ int i; if(dp->repl.p == 0) return; for(i = 0; i < dp->repl.nrepl; i++){ if(dp->repl.blk[i] == bblk) DPRINT("found bblk %ld at offset %ld\n", bblk, i); }} static voidatasleep(Controller *cp, int ms){ tsleep(&cp->r, cmddone, cp, ms); if(cp->cmd && cp->cmd != Cident2){ DPRINT("ata: cmd 0x%uX timeout, status=%lux\n", cp->cmd, inb(cp->pbase+Pstatus)); error("ata drive timeout"); }} /* * transfer a number of sectors. ataintr will perform all the iterative * parts.Lines 1–500 of 1194. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "pcmcia.h" #define DPRINT if(0)print typedef struct Drive Drive; typedef struct Ident Ident; typedef struct Controller Controller; typedef struct Partition Partition; typedef struct Repl Repl; enum { /* ports */ Pbase= 0x1F0, Pdata= 0, /* data port (16 bits) */ Perror= 1, /* error port (read) */ Pprecomp= 1, /* buffer mode port (write) */ Pcount= 2, /* sector count port */ Psector= 3, /* sector number port */ Pcyllsb= 4, /* least significant byte cylinder # */ Pcylmsb= 5, /* most significant byte cylinder # */ Pdh= 6, /* drive/head port */ Pstatus= 7, /* status port (read) */ Sbusy= (1<<7), Sready= (1<<6), Sdrq= (1<<3), Serr= (1<<0), Pcmd= 7, /* cmd port (write) */ /* commands */ Crecal= 0x10, Cread= 0x20, Cwrite= 0x30, Cident= 0xEC, Cident2= 0xFF, /* pseudo command for post Cident interrupt */ Csetbuf= 0xEF, Cinitparam= 0x91, /* conner specific commands */ Cstandby= 0xE2, Cidle= 0xE1, Cpowerdown= 0xE3, /* disk states */ Sspinning, Sstandby, Sidle, Spowerdown, /* something we have to or into the drive/head reg */ DHmagic= 0xA0, /* file types */ Qdir= 0, Maxxfer= BY2PG, /* maximum transfer size/cmd */ Npart= 8+2, /* 8 sub partitions, disk, and partition */ Nrepl= 64, /* maximum replacement blocks */ }; #define PART(x) ((x)&0xF) #define DRIVE(x) (((x)>>4)&0x7) #define MKQID(d,p) (((d)<<4) | (p)) struct Partition { ulong start; ulong end; char name[NAMELEN+1]; }; struct Repl { Partition *p; int nrepl; ulong blk[Nrepl]; }; #define PARTMAGIC "plan9 partitions" #define REPLMAGIC "block replacements" /* * an ata drive */ struct Drive { QLock; Controller *cp; int drive; int confused; /* needs to be recalibrated (or worse) */ int online; int npart; /* number of real partitions */ Partition p[Npart]; Repl repl; ulong usetime; int state; char vol[NAMELEN]; ulong cap; /* total bytes */ int bytes; /* bytes/sector */ int sectors; /* sectors/track */ int heads; /* heads/cyl */ long cyl; /* cylinders/drive */ char lba; /* true if drive has logical block addressing */ char multi; /* non-zero if drive does multiple block xfers */ }; /* * a controller for 2 drives */ struct Controller { QLock; /* exclusive access to the controller */ ISAConf; /* interface to pcmspecial */ Lock reglock; /* exclusive access to the registers */ int confused; /* needs to be recalibrated (or worse) */ ulong pbase; /* base port (copied from ISAConf) */ /* * current operation */ int cmd; /* current command */ int lastcmd; /* debugging info */ Rendez r; /* wait here for command termination */ char *buf; /* xfer buffer */ int nsecs; /* length of transfer (sectors) */ int sofar; /* sectors transferred so far */ int status; int error; Drive *dp; /* drive being accessed */ }; Controller *atac; Drive *ata; static char* ataerr; static int nhard; static int spindowntime; static void ataintr(Ureg*, void*); static long ataxfer(Drive*, Partition*, int, long, long, char*); static void ataident(Drive*); static void atasetbuf(Drive*, int); static void ataparams(Drive*); static void atapart(Drive*); static int ataprobe(Drive*, int, int, int); static int atagen(Chan *c, Dirtab*, int, int s, Dir *dirp) { Qid qid; int drive; Drive *dp; Partition *pp; ulong l; qid.vers = 0; drive = s/Npart; s = s % Npart; if(drive >= nhard) return -1; dp = &ata[drive]; if(dp->online == 0 || s >= dp->npart) return 0; pp = &dp->p[s]; sprint(up->genbuf, "%s%s", dp->vol, pp->name); qid.path = MKQID(drive, s); l = (pp->end - pp->start) * dp->bytes; devdir(c, qid, up->genbuf, l, eve, 0660, dirp); return 1; } static void atainit(void) { Drive *dp; Controller *cp; uchar equip; int pcmslot; if (atac) return; /* already done */ equip = 0x10; /* hard coded */ print("ata init\n"); cp = malloc(sizeof(*cp)); if (!cp) error(Enomem); cp->port = Pbase; cp->irq = 14; if((pcmslot = pcmspecial("SunDisk", cp)) < 0) { print("No ATA card\n"); free(cp); ataerr = Enoifc; return; } ata = malloc(2 * sizeof(*ata)); if(ata == nil) { pcmspecialclose(pcmslot); free(cp); error(Enomem); } atac = cp; cp->buf = 0; cp->lastcmd = cp->cmd; cp->cmd = 0; cp->pbase = cp->port; pcmintrenable(pcmslot, ataintr, cp); dp = ata; if(equip & 0xf0){ dp->drive = 0; dp->online = 0; dp->cp = cp; dp++; } if((equip & 0x0f)){ dp->drive = 1; dp->online = 0; dp->cp = cp; dp++; } nhard = dp - ata; spindowntime = 1; } /* * Get the characteristics of each drive. Mark unresponsive ones * off line. */ static Chan* ataattach(char *spec) { Drive *dp; atainit(); if (!ata) error(ataerr ? ataerr : Enoifc); for(dp = ata; dp < &ata[nhard]; dp++){ if(waserror()){ dp->online = 0; qunlock(dp); continue; } qlock(dp); if(!dp->online){ /* * Make sure ataclock() doesn't * interfere. */ dp->usetime = m->ticks; ataparams(dp); dp->online = 1; atasetbuf(dp, 1); } /* * read Plan 9 partition table */ atapart(dp); qunlock(dp); poperror(); } return devattach('H', spec); } static int atawalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, atagen); } static void atastat(Chan *c, char *dp) { devstat(c, dp, 0, 0, atagen); } static Chan* ataopen(Chan *c, int omode) { return devopen(c, omode, 0, 0, atagen); } static void ataclose(Chan *c) { Drive *d; Partition *p; if(c->mode != OWRITE && c->mode != ORDWR) return; d = &ata[DRIVE(c->qid.path)]; p = &d->p[PART(c->qid.path)]; if(strcmp(p->name, "partition") != 0) return; if(waserror()){ qunlock(d); nexterror(); } qlock(d); atapart(d); qunlock(d); poperror(); } static long ataread(Chan *c, void *a, long n, vlong offset) { Drive *dp; long rv, i; int skip; uchar *aa = a; Partition *pp; char *buf; if(c->qid.path == CHDIR) return devdirread(c, a, n, 0, 0, atagen); buf = smalloc(Maxxfer); if(waserror()){ free(buf); nexterror(); } dp = &ata[DRIVE(c->qid.path)]; pp = &dp->p[PART(c->qid.path)]; skip = offset % dp->bytes; for(rv = 0; rv < n; rv += i){ i = ataxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf); if(i == 0) break; i -= skip; if(i > n - rv) i = n - rv; memmove(aa+rv, buf + skip, i); skip = 0; } free(buf); poperror(); return rv; } static long atawrite(Chan *c, void *a, long n, vlong offset) { Drive *dp; long rv, i, partial; uchar *aa = a; Partition *pp; char *buf; if(c->qid.path == CHDIR) error(Eisdir); dp = &ata[DRIVE(c->qid.path)]; pp = &dp->p[PART(c->qid.path)]; buf = smalloc(Maxxfer); if(waserror()){ free(buf); nexterror(); } /* * if not starting on a sector boundary, * read in the first sector before writing * it out. */ partial = offset % dp->bytes; if(partial){ ataxfer(dp, pp, Cread, offset-partial, dp->bytes, buf); if(partial+n > dp->bytes) rv = dp->bytes - partial; else rv = n; memmove(buf+partial, aa, rv); ataxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf); } else rv = 0; /* * write out the full sectors */ partial = (n - rv) % dp->bytes; n -= partial; for(; rv < n; rv += i){ i = n - rv; if(i > Maxxfer) i = Maxxfer; memmove(buf, aa+rv, i); i = ataxfer(dp, pp, Cwrite, offset+rv, i, buf); if(i == 0) break; } /* * if not ending on a sector boundary, * read in the last sector before writing * it out. */ if(partial){ ataxfer(dp, pp, Cread, offset+rv, dp->bytes, buf); memmove(buf, aa+rv, partial); ataxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf); rv += partial; } free(buf); poperror(); return rv; } /* * did an interrupt happen? */ static int cmddone(void *a) { Controller *cp = a; return cp->cmd == 0; } /* * Wait for the controller to be ready to accept a command. * This is protected from intereference by ataclock() by * setting dp->usetime before it is called. */ static void cmdreadywait(Drive *dp) { long start; int period; Controller *cp = dp->cp; /* give it 2 seconds to spin down and up */ if(dp->state == Sspinning) period = 10; else period = 2000; start = m->ticks; while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready) if(TK2MS(m->ticks - start) > period){ DPRINT("cmdreadywait failed\n"); error(Eio); } } static void atarepl(Drive *dp, long bblk) { int i; if(dp->repl.p == 0) return; for(i = 0; i < dp->repl.nrepl; i++){ if(dp->repl.blk[i] == bblk) DPRINT("found bblk %ld at offset %ld\n", bblk, i); } } static void atasleep(Controller *cp, int ms) { tsleep(&cp->r, cmddone, cp, ms); if(cp->cmd && cp->cmd != Cident2){ DPRINT("ata: cmd 0x%uX timeout, status=%lux\n", cp->cmd, inb(cp->pbase+Pstatus)); error("ata drive timeout"); } } /* * transfer a number of sectors. ataintr will perform all the iterative * parts.