#include "all.h"#include "io.h"#include "mem.h" #define DEBUG 0#define DPRINT if(DEBUG)print#define IDEBUG 0#define IDPRINT if(IDEBUG)print typedef struct Drive Drive;typedef struct Ident Ident;typedef struct Controller Controller; enum{ /* ports */ Pbase0= 0x1F0, /* primary */ Pbase1= 0x170, /* secondary */ Pbase2= 0x1E8, /* tertiary */ Pbase3= 0x168, /* quaternary */ Pdata= 0, /* data port (16 bits) */ Perror= 1, /* error port (read) */ Eabort= (1<<2), Pfeature= 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 */ DHmagic= 0xA0, DHslave= 0x10, 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, Cpktcmd= 0xA0, Cidentd= 0xA1, Ctur= 0x00, Creqsense= 0x03, Ccapacity= 0x25, Cread2= 0x28, Cwrite2= 0x2A, ATAtimo= 6000, /* ms to wait for things to complete */ ATAPItimo= 10000, NCtlr= 4, NDrive= NCtlr*2, Maxloop= 1000000,}; /* * ident sector from drive. this is from ANSI X3.221-1994 */struct Ident{ ushort config; /* general configuration info */ ushort cyls; /* # of cylinders (default) */ ushort reserved0; ushort heads; /* # of heads (default) */ ushort b2t; /* unformatted bytes/track */ ushort b2s; /* unformated bytes/sector */ ushort s2t; /* sectors/track (default) */ ushort reserved1[3];/* 10 */ ushort serial[10]; /* serial number */ ushort type; /* buffer type */ ushort bsize; /* buffer size/512 */ ushort ecc; /* ecc bytes returned by read long */ ushort firm[4]; /* firmware revision */ ushort model[20]; /* model number *//* 47 */ ushort s2i; /* number of sectors/interrupt */ ushort dwtf; /* double word transfer flag */ ushort capabilities; ushort reserved2; ushort piomode; ushort dmamode; ushort cvalid; /* (cvald&1) if next 4 words are valid */ ushort ccyls; /* current # cylinders */ ushort cheads; /* current # heads */ ushort cs2t; /* current sectors/track */ ushort ccap[2]; /* current capacity in sectors */ ushort cs2i; /* current number of sectors/interrupt *//* 60 */ ushort lbasecs[2]; /* # LBA user addressable sectors */ ushort dmasingle; ushort dmadouble;/* 64 */ ushort reserved3[64]; ushort vendor[32]; /* vendor specific */ ushort reserved4[96];}; enum { Maxxfer = 16*1024, /* maximum transfer size/cmd */ Npart = 8+2, /* 8 sub partitions, disk, and partition */}; typedef struct { ulong start; ulong end; char name[NAMELEN+1];} Partition; typedef struct { int online; int npart; /* number of real partitions */ Partition p[Npart]; ulong offset; Partition *current; /* current partition */ ulong cap; /* total sectors */ 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 */} Disc; /* * an ata drive */struct Drive{ Controller *cp; uchar driveno; uchar dh; uchar atapi; /* ATAPI */ uchar drqintr; /* ATAPI */ ulong vers; /* ATAPI */ int partok; Disc;}; /* * a controller for 2 drives */struct Controller{ int pbase; /* base port */ uchar ctlrno; /* * current operation */ int cmd; /* current command */ uchar cmdblk[12]; /* ATAPI */ int len; /* ATAPI */ int count; /* ATAPI */ uchar lastcmd; /* debugging info */ uchar *buf; /* xfer buffer */ int tcyl; /* target cylinder */ int thead; /* target head */ int tsec; /* target sector */ int tbyte; /* target byte */ int nsecs; /* length of transfer (sectors) */ int sofar; /* sectors transferred so far */ int status; int error; Drive *dp; /* drive being accessed */}; static int atactlrmask;static Controller *atactlr[NCtlr];static int atadrivemask;static Drive *atadrive[NDrive];static int pbase[NCtlr] = { Pbase0, Pbase1, Pbase2, Pbase3,};static int defirq[NCtlr] = { 14, 15, 0, 0,}; static void ataintr(Ureg*, void*);static long ataxfer(Drive*, Partition*, int, ulong, long);static int ataident(Drive*);static Drive* atapart(Drive*);static int ataparams(Drive*);static void atarecal(Drive*);static int ataprobe(Drive*, int, int, int);static Drive* atapipart(Drive*);static void atapiintr(Controller*);static long atapiio(Drive*, long); static voidatactlrprobe(int ctlrno, int irq){ Controller *ctlr; Drive *drive; int driveno, port; if(atactlrmask & (1<<ctlrno)) return; atactlrmask |= 1<<ctlrno; port = pbase[ctlrno]; outb(port+Pdh, DHmagic); delay(1); if((inb(port+Pdh) & 0xFF) != DHmagic){ DPRINT("ata%d: DHmagic not ok\n", ctlrno); return; } DPRINT("ata%d: DHmagic ok\n", ctlrno); atactlr[ctlrno] = ialloc(sizeof(Controller), 0); ctlr = atactlr[ctlrno]; ctlr->pbase = port; ctlr->ctlrno = ctlrno; ctlr->buf = ialloc(Maxxfer, 0); inb(ctlr->pbase+Pstatus); setvec(irq, ataintr, ctlr); driveno = ctlrno*2; atadrive[driveno] = ialloc(sizeof(Drive), 0); drive = atadrive[driveno]; drive->cp = ctlr; drive->driveno = driveno; drive->dh = DHmagic; driveno++; atadrive[driveno] = ialloc(sizeof(Drive), 0); drive = atadrive[driveno]; drive->cp = ctlr; drive->driveno = driveno; drive->dh = DHmagic|DHslave;} static Drive*atadriveprobe(int driveno){ Drive *drive; int ctlrno; ISAConf isa; ctlrno = driveno/2; if(atactlr[ctlrno] == 0){ if(atactlrmask & (1<<ctlrno)) return 0; memset(&isa, 0, sizeof(ISAConf)); if(isaconfig("ata", ctlrno, &isa) == 0) return 0; if(ctlrno && isa.irq) atactlrprobe(ctlrno, Int0vec+isa.irq); if(atactlr[ctlrno] == 0) return 0; } drive = atadrive[driveno]; if(drive->online == 0){ if(atadrivemask & (1<<driveno)) return 0; atadrivemask |= 1<<driveno; if(ataparams(drive)) return 0; if(drive->lba) print("hd%d: LBA %lud sectors\n", drive->driveno, drive->cap); else print("hd%d: CHS %ld/%d/%d %lud sectors\n", drive->driveno, drive->cyl, drive->heads, drive->sectors, drive->cap); drive->online = 1; } return atapart(drive);} intatainit(void){ ISAConf isa; int ctlrno; for(ctlrno = 0; ctlrno < NCtlr; ctlrno++){ memset(&isa, 0, sizeof(ISAConf)); if(isaconfig("ata", ctlrno, &isa) == 0 && ctlrno > 1) continue; if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0) continue; atactlrprobe(ctlrno, Int0vec+isa.irq); } DPRINT("atainit: mask 0x%ux 0x%ux\n", atactlrmask, atadrivemask); return 0xFF;} longataseek(int driveno, long offset){ Drive *drive; if((drive = atadriveprobe(driveno)) == 0) return -1; drive->offset = offset; return offset;} /* * did an interrupt happen? */static voidatawait(Controller *cp, int timo){ ulong start; int x; x = spllo(); start = m->ticks; while(TK2MS(m->ticks - start) < timo){ if(cp->cmd == 0) break; if(cp->cmd == Cident2 && TK2MS(m->ticks - start) >= 1000) break; } if(TK2MS(m->ticks - start) >= timo){ DPRINT("atawait timed out 0x%ux\n", inb(cp->pbase+Pstatus)); ataintr(0, cp); } splx(x);} intsetatapart(int driveno, char *p){ Partition *pp; Drive *dp; if((dp = atadriveprobe(driveno)) == 0) return 0; for(pp = dp->p; pp < &dp->p[dp->npart]; pp++) if(strcmp(pp->name, p) == 0){ dp->current = pp; return 1; } return 0;} longataread(int driveno, void *a, long n){ Drive *dp; long rv, i; int skip; uchar *aa = a; Partition *pp; Controller *cp; if((dp = atadriveprobe(driveno)) == 0) return 0; pp = dp->current; if(pp == 0) return -1; cp = dp->cp; skip = dp->offset % dp->bytes; for(rv = 0; rv < n; rv += i){ i = ataxfer(dp, pp, Cread, dp->offset+rv-skip, n-rv+skip); if(i == 0) break; if(i < 0) return -1; i -= skip; if(i > n - rv) i = n - rv; memmove(aa+rv, cp->buf + skip, i); skip = 0; } dp->offset += rv; return rv;} longatawrite(int driveno, void *a, long n){ Drive *dp; long rv, i, partial; uchar *aa = a; Partition *pp; Controller *cp; if((dp = atadriveprobe(driveno)) == 0) return 0; pp = dp->current; if(pp == 0) return -1; cp = dp->cp; /* * if not starting on a sector boundary, * read in the first sector before writing * it out. */ partial = dp->offset % dp->bytes; if(partial){ ataxfer(dp, pp, Cread, dp->offset-partial, dp->bytes); if(partial+n > dp->bytes) rv = dp->bytes - partial; else rv = n; memmove(cp->buf+partial, aa, rv); if(ataxfer(dp, pp, Cwrite, dp->offset-partial, dp->bytes) < 0) return -1; } 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(cp->buf, aa+rv, i); i = ataxfer(dp, pp, Cwrite, dp->offset+rv, i); if(i == 0) break; if(i < 0) return -1; } /* * if not ending on a sector boundary, * read in the last sector before writing * it out. */ if(partial){ if(ataxfer(dp, pp, Cread, dp->offset+rv, dp->bytes) < 0) return -1; memmove(cp->buf, aa+rv, partial); if(ataxfer(dp, pp, Cwrite, dp->offset+rv, dp->bytes) < 0) return -1; rv += partial; } dp->offset += rv; return rv;} /* * wait for the controller to be ready to accept a command */static intcmdreadywait(Drive *drive){ ulong end; uchar dh, status; Controller *ctlr; ctlr = drive->cp; end = m->ticks+MS2TK(10)+1; dh = (inb(ctlr->pbase+Pdh) & DHslave)^(drive->dh & DHslave); status = 0; while(m->ticks < end){ status = inb(ctlr->pbase+Pstatus); if(status & Sbusy) continue; if(dh){ outb(ctlr->pbase+Pdh, drive->dh); dh = 0; continue; } if(drive->atapi || (status & Sready)) return 0; } USED(status); DPRINT("hd%d: cmdreadywait failed 0x%ux\n", drive->driveno, status); outb(ctlr->pbase+Pdh, DHmagic); return -1;} /* * transfer a number of sectors. ataintr will perform all the iterative * parts. */static longataxfer(Drive *dp, Partition *pp, int cmd, ulong start, long len)Lines 1–500 of 1135. Load more
#include "all.h" #include "io.h" #include "mem.h" #define DEBUG 0 #define DPRINT if(DEBUG)print #define IDEBUG 0 #define IDPRINT if(IDEBUG)print typedef struct Drive Drive; typedef struct Ident Ident; typedef struct Controller Controller; enum { /* ports */ Pbase0= 0x1F0, /* primary */ Pbase1= 0x170, /* secondary */ Pbase2= 0x1E8, /* tertiary */ Pbase3= 0x168, /* quaternary */ Pdata= 0, /* data port (16 bits) */ Perror= 1, /* error port (read) */ Eabort= (1<<2), Pfeature= 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 */ DHmagic= 0xA0, DHslave= 0x10, 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, Cpktcmd= 0xA0, Cidentd= 0xA1, Ctur= 0x00, Creqsense= 0x03, Ccapacity= 0x25, Cread2= 0x28, Cwrite2= 0x2A, ATAtimo= 6000, /* ms to wait for things to complete */ ATAPItimo= 10000, NCtlr= 4, NDrive= NCtlr*2, Maxloop= 1000000, }; /* * ident sector from drive. this is from ANSI X3.221-1994 */ struct Ident { ushort config; /* general configuration info */ ushort cyls; /* # of cylinders (default) */ ushort reserved0; ushort heads; /* # of heads (default) */ ushort b2t; /* unformatted bytes/track */ ushort b2s; /* unformated bytes/sector */ ushort s2t; /* sectors/track (default) */ ushort reserved1[3]; /* 10 */ ushort serial[10]; /* serial number */ ushort type; /* buffer type */ ushort bsize; /* buffer size/512 */ ushort ecc; /* ecc bytes returned by read long */ ushort firm[4]; /* firmware revision */ ushort model[20]; /* model number */ /* 47 */ ushort s2i; /* number of sectors/interrupt */ ushort dwtf; /* double word transfer flag */ ushort capabilities; ushort reserved2; ushort piomode; ushort dmamode; ushort cvalid; /* (cvald&1) if next 4 words are valid */ ushort ccyls; /* current # cylinders */ ushort cheads; /* current # heads */ ushort cs2t; /* current sectors/track */ ushort ccap[2]; /* current capacity in sectors */ ushort cs2i; /* current number of sectors/interrupt */ /* 60 */ ushort lbasecs[2]; /* # LBA user addressable sectors */ ushort dmasingle; ushort dmadouble; /* 64 */ ushort reserved3[64]; ushort vendor[32]; /* vendor specific */ ushort reserved4[96]; }; enum { Maxxfer = 16*1024, /* maximum transfer size/cmd */ Npart = 8+2, /* 8 sub partitions, disk, and partition */ }; typedef struct { ulong start; ulong end; char name[NAMELEN+1]; } Partition; typedef struct { int online; int npart; /* number of real partitions */ Partition p[Npart]; ulong offset; Partition *current; /* current partition */ ulong cap; /* total sectors */ 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 */ } Disc; /* * an ata drive */ struct Drive { Controller *cp; uchar driveno; uchar dh; uchar atapi; /* ATAPI */ uchar drqintr; /* ATAPI */ ulong vers; /* ATAPI */ int partok; Disc; }; /* * a controller for 2 drives */ struct Controller { int pbase; /* base port */ uchar ctlrno; /* * current operation */ int cmd; /* current command */ uchar cmdblk[12]; /* ATAPI */ int len; /* ATAPI */ int count; /* ATAPI */ uchar lastcmd; /* debugging info */ uchar *buf; /* xfer buffer */ int tcyl; /* target cylinder */ int thead; /* target head */ int tsec; /* target sector */ int tbyte; /* target byte */ int nsecs; /* length of transfer (sectors) */ int sofar; /* sectors transferred so far */ int status; int error; Drive *dp; /* drive being accessed */ }; static int atactlrmask; static Controller *atactlr[NCtlr]; static int atadrivemask; static Drive *atadrive[NDrive]; static int pbase[NCtlr] = { Pbase0, Pbase1, Pbase2, Pbase3, }; static int defirq[NCtlr] = { 14, 15, 0, 0, }; static void ataintr(Ureg*, void*); static long ataxfer(Drive*, Partition*, int, ulong, long); static int ataident(Drive*); static Drive* atapart(Drive*); static int ataparams(Drive*); static void atarecal(Drive*); static int ataprobe(Drive*, int, int, int); static Drive* atapipart(Drive*); static void atapiintr(Controller*); static long atapiio(Drive*, long); static void atactlrprobe(int ctlrno, int irq) { Controller *ctlr; Drive *drive; int driveno, port; if(atactlrmask & (1<<ctlrno)) return; atactlrmask |= 1<<ctlrno; port = pbase[ctlrno]; outb(port+Pdh, DHmagic); delay(1); if((inb(port+Pdh) & 0xFF) != DHmagic){ DPRINT("ata%d: DHmagic not ok\n", ctlrno); return; } DPRINT("ata%d: DHmagic ok\n", ctlrno); atactlr[ctlrno] = ialloc(sizeof(Controller), 0); ctlr = atactlr[ctlrno]; ctlr->pbase = port; ctlr->ctlrno = ctlrno; ctlr->buf = ialloc(Maxxfer, 0); inb(ctlr->pbase+Pstatus); setvec(irq, ataintr, ctlr); driveno = ctlrno*2; atadrive[driveno] = ialloc(sizeof(Drive), 0); drive = atadrive[driveno]; drive->cp = ctlr; drive->driveno = driveno; drive->dh = DHmagic; driveno++; atadrive[driveno] = ialloc(sizeof(Drive), 0); drive = atadrive[driveno]; drive->cp = ctlr; drive->driveno = driveno; drive->dh = DHmagic|DHslave; } static Drive* atadriveprobe(int driveno) { Drive *drive; int ctlrno; ISAConf isa; ctlrno = driveno/2; if(atactlr[ctlrno] == 0){ if(atactlrmask & (1<<ctlrno)) return 0; memset(&isa, 0, sizeof(ISAConf)); if(isaconfig("ata", ctlrno, &isa) == 0) return 0; if(ctlrno && isa.irq) atactlrprobe(ctlrno, Int0vec+isa.irq); if(atactlr[ctlrno] == 0) return 0; } drive = atadrive[driveno]; if(drive->online == 0){ if(atadrivemask & (1<<driveno)) return 0; atadrivemask |= 1<<driveno; if(ataparams(drive)) return 0; if(drive->lba) print("hd%d: LBA %lud sectors\n", drive->driveno, drive->cap); else print("hd%d: CHS %ld/%d/%d %lud sectors\n", drive->driveno, drive->cyl, drive->heads, drive->sectors, drive->cap); drive->online = 1; } return atapart(drive); } int atainit(void) { ISAConf isa; int ctlrno; for(ctlrno = 0; ctlrno < NCtlr; ctlrno++){ memset(&isa, 0, sizeof(ISAConf)); if(isaconfig("ata", ctlrno, &isa) == 0 && ctlrno > 1) continue; if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0) continue; atactlrprobe(ctlrno, Int0vec+isa.irq); } DPRINT("atainit: mask 0x%ux 0x%ux\n", atactlrmask, atadrivemask); return 0xFF; } long ataseek(int driveno, long offset) { Drive *drive; if((drive = atadriveprobe(driveno)) == 0) return -1; drive->offset = offset; return offset; } /* * did an interrupt happen? */ static void atawait(Controller *cp, int timo) { ulong start; int x; x = spllo(); start = m->ticks; while(TK2MS(m->ticks - start) < timo){ if(cp->cmd == 0) break; if(cp->cmd == Cident2 && TK2MS(m->ticks - start) >= 1000) break; } if(TK2MS(m->ticks - start) >= timo){ DPRINT("atawait timed out 0x%ux\n", inb(cp->pbase+Pstatus)); ataintr(0, cp); } splx(x); } int setatapart(int driveno, char *p) { Partition *pp; Drive *dp; if((dp = atadriveprobe(driveno)) == 0) return 0; for(pp = dp->p; pp < &dp->p[dp->npart]; pp++) if(strcmp(pp->name, p) == 0){ dp->current = pp; return 1; } return 0; } long ataread(int driveno, void *a, long n) { Drive *dp; long rv, i; int skip; uchar *aa = a; Partition *pp; Controller *cp; if((dp = atadriveprobe(driveno)) == 0) return 0; pp = dp->current; if(pp == 0) return -1; cp = dp->cp; skip = dp->offset % dp->bytes; for(rv = 0; rv < n; rv += i){ i = ataxfer(dp, pp, Cread, dp->offset+rv-skip, n-rv+skip); if(i == 0) break; if(i < 0) return -1; i -= skip; if(i > n - rv) i = n - rv; memmove(aa+rv, cp->buf + skip, i); skip = 0; } dp->offset += rv; return rv; } long atawrite(int driveno, void *a, long n) { Drive *dp; long rv, i, partial; uchar *aa = a; Partition *pp; Controller *cp; if((dp = atadriveprobe(driveno)) == 0) return 0; pp = dp->current; if(pp == 0) return -1; cp = dp->cp; /* * if not starting on a sector boundary, * read in the first sector before writing * it out. */ partial = dp->offset % dp->bytes; if(partial){ ataxfer(dp, pp, Cread, dp->offset-partial, dp->bytes); if(partial+n > dp->bytes) rv = dp->bytes - partial; else rv = n; memmove(cp->buf+partial, aa, rv); if(ataxfer(dp, pp, Cwrite, dp->offset-partial, dp->bytes) < 0) return -1; } 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(cp->buf, aa+rv, i); i = ataxfer(dp, pp, Cwrite, dp->offset+rv, i); if(i == 0) break; if(i < 0) return -1; } /* * if not ending on a sector boundary, * read in the last sector before writing * it out. */ if(partial){ if(ataxfer(dp, pp, Cread, dp->offset+rv, dp->bytes) < 0) return -1; memmove(cp->buf, aa+rv, partial); if(ataxfer(dp, pp, Cwrite, dp->offset+rv, dp->bytes) < 0) return -1; rv += partial; } dp->offset += rv; return rv; } /* * wait for the controller to be ready to accept a command */ static int cmdreadywait(Drive *drive) { ulong end; uchar dh, status; Controller *ctlr; ctlr = drive->cp; end = m->ticks+MS2TK(10)+1; dh = (inb(ctlr->pbase+Pdh) & DHslave)^(drive->dh & DHslave); status = 0; while(m->ticks < end){ status = inb(ctlr->pbase+Pstatus); if(status & Sbusy) continue; if(dh){ outb(ctlr->pbase+Pdh, drive->dh); dh = 0; continue; } if(drive->atapi || (status & Sready)) return 0; } USED(status); DPRINT("hd%d: cmdreadywait failed 0x%ux\n", drive->driveno, status); outb(ctlr->pbase+Pdh, DHmagic); return -1; } /* * transfer a number of sectors. ataintr will perform all the iterative * parts. */ static long ataxfer(Drive *dp, Partition *pp, int cmd, ulong start, long len)