## diffname pc/devata.c 1995/0213 ## diff -e /dev/null /n/fornaxdump/1995/0213/sys/src/brazil/pc/devata.c 0a #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "devtab.h" #define DPRINT if(1)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, /* 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 */ Lock; /* exclusive access to the registers */ int confused; /* needs to be recalibrated (or worse) */ int pbase; /* base port */ /* * 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 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 *tab, long ntab, long s, Dir *dirp) { Qid qid; int drive; char name[NAMELEN+4]; Drive *dp; Partition *pp; ulong l; USED(tab, ntab); qid.vers = 0; drive = s/Npart; s = s % Npart; if(drive >= conf.nhard) return -1; dp = &ata[drive]; if(s >= dp->npart) return 0; pp = &dp->p[s]; sprint(name, "%s%s", dp->vol, pp->name); name[NAMELEN] = 0; qid.path = MKQID(drive, s); l = (pp->end - pp->start) * dp->bytes; devdir(c, qid, name, l, eve, 0660, dirp); return 1; } /* * we assume drives 0 and 1 are on the first controller, 2 and 3 on the * second, etc. */ void atareset(void) { Drive *dp; Controller *cp; int drive; uchar equip; char *p; ata = xalloc(conf.nhard * sizeof(Drive)); atac = xalloc(((conf.nhard+1)/2) * sizeof(Controller)); /* * read nvram for number of ata drives (2 max) */ equip = nvramread(0x12); if(conf.nhard > 0 && (equip>>4) == 0) conf.nhard = 0; if(conf.nhard > 1 && (equip&0xf) == 0) conf.nhard = 1; if(conf.nhard > 2) conf.nhard = 2; for(drive = 0; drive < conf.nhard; drive++){ dp = &ata[drive]; cp = &atac[drive/2]; dp->drive = drive&1; dp->online = 0; dp->cp = cp; if((drive&1) == 0){ cp->buf = 0; cp->lastcmd = cp->cmd; cp->cmd = 0; cp->pbase = Pbase; setvec(Hardvec, ataintr, 0); } } if(conf.nhard && (p = getconf("spindowntime"))) spindowntime = atoi(p); } void atainit(void) { } /* * Get the characteristics of each drive. Mark unresponsive ones * off line. */ Chan* ataattach(char *spec) { Drive *dp; for(dp = ata; dp < &ata[conf.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); } Chan* ataclone(Chan *c, Chan *nc) { return devclone(c, nc); } int atawalk(Chan *c, char *name) { return devwalk(c, name, 0, 0, atagen); } void atastat(Chan *c, char *dp) { devstat(c, dp, 0, 0, atagen); } Chan* ataopen(Chan *c, int omode) { return devopen(c, omode, 0, 0, atagen); } void atacreate(Chan *c, char *name, int omode, ulong perm) { USED(c, name, omode, perm); error(Eperm); } 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(); } void ataremove(Chan *c) { USED(c); error(Eperm); } void atawstat(Chan *c, char *dp) { USED(c, dp); error(Eperm); } long ataread(Chan *c, void *a, long n, ulong 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; } Block* atabread(Chan *c, long n, ulong offset) { return devbread(c, n, offset); } long atawrite(Chan *c, void *a, long n, ulong 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; } long atabwrite(Chan *c, Block *bp, ulong offset) { return devbwrite(c, bp, offset); } /* * 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); } } /* * transfer a number of sectors. ataintr will perform all the iterative * parts. */ static long ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf) { Controller *cp; long lblk; int cyl, sec, head; int loop, stat; if(dp->online == 0) error(Eio); /* * cut transfer size down to disk buffer size */ start = start / dp->bytes; if(len > Maxxfer) len = Maxxfer; len = (len + dp->bytes - 1) / dp->bytes; if(len == 0) return 0; /* * calculate physical address */ lblk = start + pp->start; if(lblk >= pp->end) return 0; if(lblk+len > pp->end) len = pp->end - lblk; if(dp->lba){ sec = lblk & 0xff; cyl = (lblk>>8) & 0xffff; head = (lblk>>24) & 0xf; } else { cyl = lblk/(dp->sectors*dp->heads); sec = (lblk % dp->sectors) + 1; head = ((lblk/dp->sectors) % dp->heads); } cp = dp->cp; qlock(cp); if(waserror()){ cp->buf = 0; qunlock(cp); nexterror(); } /* * Make sure hardclock() doesn't * interfere. */ dp->usetime = m->ticks; cmdreadywait(dp); ilock(cp); cp->sofar = 0; cp->buf = buf; cp->nsecs = len; cp->cmd = cmd; cp->dp = dp; cp->status = 0; outb(cp->pbase+Pcount, cp->nsecs); outb(cp->pbase+Psector, sec); outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | (dp->lba<<6) | head); outb(cp->pbase+Pcyllsb, cyl); outb(cp->pbase+Pcylmsb, cyl>>8); outb(cp->pbase+Pcmd, cmd); if(cmd == Cwrite){ loop = 0; while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0) if(++loop > 10000) panic("ataxfer"); outss(cp->pbase+Pdata, cp->buf, dp->bytes/2); } else stat = 0; iunlock(cp); if(stat & Serr) error(Eio); /* * wait for command to complete. if we get a note, * remember it but keep waiting to let the disk finish * the current command. */ loop = 0; while(waserror()){ DPRINT("interrupted ataxfer\n"); if(loop++ > 10){ print("ata disk error\n"); nexterror(); } } sleep(&cp->r, cmddone, cp); dp->state = Sspinning; dp->usetime = m->ticks; poperror(); if(loop) nexterror(); if(cp->status & Serr){ DPRINT("hd%d err: lblk %ld status %lux, err %lux\n", dp-ata, lblk, cp->status, cp->error); DPRINT("\tcyl %d, sec %d, head %d\n", cyl, sec, head); DPRINT("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar); atarepl(dp, lblk+cp->sofar); error(Eio); } cp->buf = 0; len = cp->sofar*dp->bytes; qunlock(cp); poperror(); return len; } /* * set read ahead mode */ static void atasetbuf(Drive *dp, int on) { Controller *cp = dp->cp; qlock(cp); if(waserror()){ qunlock(cp); nexterror(); } cmdreadywait(dp); ilock(cp); cp->cmd = Csetbuf; outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55); /* read look ahead */ outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4)); outb(cp->pbase+Pcmd, Csetbuf); iunlock(cp); sleep(&cp->r, cmddone, cp); /* if(cp->status & Serr) DPRINT("hd%d setbuf err: status %lux, err %lux\n", dp-ata, cp->status, cp->error);/**/ poperror(); qunlock(cp); } /* * 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]; }; /* * get parameters from the drive */ static void ataident(Drive *dp) { Controller *cp; char *buf; Ident *ip; char id[21]; cp = dp->cp; buf = smalloc(Maxxfer); qlock(cp); if(waserror()){ qunlock(cp); nexterror(); } cmdreadywait(dp); ilock(cp); cp->nsecs = 1; cp->sofar = 0; cp->cmd = Cident; cp->dp = dp; cp->buf = buf; outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4)); outb(cp->pbase+Pcmd, Cident); iunlock(cp); sleep(&cp->r, cmddone, cp); if(cp->status & Serr){ DPRINT("bad disk ident status\n"); error(Eio); } ip = (Ident*)buf; /* * this function appears to respond with an extra interrupt after * the ident information is read, except on the safari. The following * delay gives this extra interrupt a chance to happen while we are quiet. * Otherwise, the interrupt may come during a subsequent read or write, * causing a panic and much confusion. */ if (cp->cmd == Cident2) tsleep(&cp->r, return0, 0, 10); memmove(id, ip->model, sizeof(id)-1); id[sizeof(id)-1] = 0; if(ip->capabilities & (1<<9)){ dp->lba = 1; dp->sectors = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); dp->cap = dp->bytes * dp->sectors; print("ata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors); } else { dp->lba = 0; /* use default (unformatted) settings */ dp->cyl = ip->cyls; dp->heads = ip->heads; dp->sectors = ip->s2t; print("ata%d model %s with default %d cyl %d head %d sec\n", dp->drive, id, dp->cyl, dp->heads, dp->sectors); if(ip->cvalid&(1<<0)){ /* use current settings */ dp->cyl = ip->ccyls; dp->heads = ip->cheads; dp->sectors = ip->cs2t; print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, dp->heads, dp->sectors); } dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; } cp->lastcmd = cp->cmd; cp->cmd = 0; cp->buf = 0; free(buf); poperror(); qunlock(cp); } /* * probe the given sector to see if it exists */ static int ataprobe(Drive *dp, int cyl, int sec, int head) { Controller *cp; char *buf; int rv; cp = dp->cp; buf = smalloc(Maxxfer); qlock(cp); if(waserror()){ free(buf); qunlock(cp); nexterror(); } cmdreadywait(dp); ilock(cp); cp->cmd = Cread; cp->dp = dp; cp->status = 0; cp->nsecs = 1; cp->sofar = 0; outb(cp->pbase+Pcount, 1); outb(cp->pbase+Psector, sec+1); outb(cp->pbase+Pdh, 0x20 | head | (dp->drive<<4)); outb(cp->pbase+Pcyllsb, cyl); outb(cp->pbase+Pcylmsb, cyl>>8); outb(cp->pbase+Pcmd, Cread); iunlock(cp); sleep(&cp->r, cmddone, cp); if(cp->status & Serr) rv = -1; else rv = 0; cp->buf = 0; free(buf); poperror(); qunlock(cp); return rv; } /* * figure out the drive parameters */ static void ataparams(Drive *dp) { int i, hi, lo; /* * first try the easy way, ask the drive and make sure it * isn't lying. */ dp->bytes = 512; ataident(dp); if(dp->lba){ i = dp->sectors - 1; if(ataprobe(dp, (i>>8)&0xffff, i&0xff, (i>>24)&0xf) == 0) return; } else { if(ataprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0) return; } /* * the drive lied, determine parameters by seeing which ones * work to read sectors. */ print("ata%d lied. probing...\n", dp->drive); dp->lba = 0; for(i = 0; i < 32; i++) if(ataprobe(dp, 0, 0, i) < 0) break; dp->heads = i; for(i = 0; i < 128; i++) if(ataprobe(dp, 0, i, 0) < 0) break; dp->sectors = i; for(i = 512; ; i += 512) if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0) break; lo = i - 512; hi = i; for(; hi-lo > 1;){ i = lo + (hi - lo)/2; if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0) hi = i; else lo = i; } dp->cyl = lo + 1; dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; } /* * Read block replacement table. * The table is just ascii block numbers. */ static void atareplinit(Drive *dp) { char *line[Nrepl+1]; char *field[1]; ulong n; int i; char *buf; /* * check the partition is big enough */ if(dp->repl.p->end - dp->repl.p->start < Nrepl+1){ dp->repl.p = 0; return; } buf = smalloc(Maxxfer); if(waserror()){ free(buf); nexterror(); } /* * read replacement table from disk, null terminate */ ataxfer(dp, dp->repl.p, Cread, 0, dp->bytes, buf); buf[dp->bytes-1] = 0; /* * parse replacement table. */ n = getfields(buf, line, Nrepl+1, "\n"); if(strncmp(line[0], REPLMAGIC, sizeof(REPLMAGIC)-1)){ dp->repl.p = 0; } else { for(dp->repl.nrepl = 0, i = 1; i < n; i++, dp->repl.nrepl++){ if(getfields(line[i], field, 1, " ") != 1) break; dp->repl.blk[dp->repl.nrepl] = strtoul(field[0], 0, 0); if(dp->repl.blk[dp->repl.nrepl] <= 0) break; } } free(buf); poperror(); } /* * read partition table. The partition table is just ascii strings. */ static void atapart(Drive *dp) { Partition *pp; char *line[Npart+1]; char *field[3]; ulong n; int i; char *buf; sprint(dp->vol, "hd%d", dp - ata); /* * we always have a partition for the whole disk * and one for the partition table */ pp = &dp->p[0]; strcpy(pp->name, "disk"); pp->start = 0; pp->end = dp->cap / dp->bytes; pp++; strcpy(pp->name, "partition"); pp->start = dp->p[0].end - 1; pp->end = dp->p[0].end; dp->npart = 2; /* * initialise the bad-block replacement info */ dp->repl.p = 0; buf = smalloc(Maxxfer); if(waserror()){ free(buf); nexterror(); } /* * read last sector from disk, null terminate. This used * to be the sector we used for the partition tables. * However, this sector is special on some PC's so we've * started to use the second last sector as the partition * table instead. To avoid reconfiguring all our old systems * we first look to see if there is a valid partition * table in the last sector. If so, we use it. Otherwise * we switch to the second last. */ ataxfer(dp, pp, Cread, 0, dp->bytes, buf); buf[dp->bytes-1] = 0; n = getfields(buf, line, Npart+1, "\n"); if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ dp->p[0].end--; dp->p[1].start--; dp->p[1].end--; ataxfer(dp, pp, Cread, 0, dp->bytes, buf); buf[dp->bytes-1] = 0; n = getfields(buf, line, Npart+1, "\n"); } /* * parse partition table. */ if(n && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ for(i = 1; i < n; i++){ pp++; switch(getfields(line[i], field, 3, " ")) { case 2: if(strcmp(field[0], "unit") == 0) strncpy(dp->vol, field[1], NAMELEN); break; case 3: strncpy(pp->name, field[0], NAMELEN); if(strncmp(pp->name, "repl", NAMELEN) == 0) dp->repl.p = pp; pp->start = strtoul(field[1], 0, 0); pp->end = strtoul(field[2], 0, 0); if(pp->start > pp->end || pp->start >= dp->p[0].end) break; dp->npart++; } } } free(buf); poperror(); if(dp->repl.p) atareplinit(dp); } /* * we get an interrupt for every sector transferred */ static void ataintr(Ureg *ur, void *arg) { Controller *cp; Drive *dp; long loop; char *addr; USED(ur, arg); /* * BUG!! if there is ever more than one controller, we need a way to * distinguish which interrupted (use arg). */ cp = &atac[0]; dp = cp->dp; ilock(cp); loop = 0; while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ if(++loop > 100) { DPRINT("cmd=%lux status=%lux\n", cp->cmd, inb(cp->pbase+Pstatus)); panic("ataintr: wait busy"); } } switch(cp->cmd){ case Cwrite: if(cp->status & Serr){ cp->lastcmd = cp->cmd; cp->cmd = 0; cp->error = inb(cp->pbase+Perror); wakeup(&cp->r); break; } cp->sofar++; if(cp->sofar < cp->nsecs){ loop = 0; while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0) if(++loop > 100) { DPRINT("cmd=%lux status=%lux\n", cp->cmd, inb(cp->pbase+Pstatus)); panic("ataintr: write"); } addr = cp->buf; if(addr){ addr += cp->sofar*dp->bytes; outss(cp->pbase+Pdata, addr, dp->bytes/2); } } else{ cp->lastcmd = cp->cmd; cp->cmd = 0; wakeup(&cp->r); } break; case Cread: case Cident: loop = 0; while((cp->status & (Serr|Sdrq)) == 0){ if(++loop > 10000) { DPRINT("cmd=%lux status=%lux\n", cp->cmd, inb(cp->pbase+Pstatus)); panic("ataintr: read/ident"); } cp->status = inb(cp->pbase+Pstatus); } if(cp->status & Serr){ cp->lastcmd = cp->cmd; cp->cmd = 0; cp->error = inb(cp->pbase+Perror); wakeup(&cp->r); break; } addr = cp->buf; if(addr){ addr += cp->sofar*dp->bytes; inss(cp->pbase+Pdata, addr, dp->bytes/2); } cp->sofar++; if(cp->sofar > cp->nsecs) print("ataintr %d %d\n", cp->sofar, cp->nsecs); if(cp->sofar >= cp->nsecs){ cp->lastcmd = cp->cmd; if (cp->cmd == Cread) cp->cmd = 0; else cp->cmd = Cident2; wakeup(&cp->r); } break; case Cinitparam: case Csetbuf: case Cidle: case Cstandby: case Cpowerdown: cp->lastcmd = cp->cmd; cp->cmd = 0; wakeup(&cp->r); break; case Cident2: cp->lastcmd = cp->cmd; cp->cmd = 0; break; default: print("weird disk interrupt, cmd=%.2ux, lastcmd= %.2ux status=%.2ux\n", cp->cmd, cp->lastcmd, cp->status); break; } iunlock(cp); } void hardclock(void) { int drive; Drive *dp; Controller *cp; int diff; if(spindowntime <= 0) return; for(drive = 0; drive < conf.nhard; drive++){ dp = &ata[drive]; cp = dp->cp; diff = TK2SEC(m->ticks - dp->usetime); if((dp->state == Sspinning) && (diff >= spindowntime)){ ilock(cp); cp->cmd = Cstandby; outb(cp->pbase+Pcount, 0); outb(cp->pbase+Pdh, 0x20 | (dp->drive<<4) | 0); outb(cp->pbase+Pcmd, cp->cmd); iunlock(cp); dp->state = Sstandby; } } } . ## diffname pc/devata.c 1995/0214 ## diff -e /n/fornaxdump/1995/0213/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/0214/sys/src/brazil/pc/devata.c 1180c iunlock(&cp->reglock); . 1175c ilock(&cp->reglock); . 1155c iunlock(&cp->reglock); . 1061c ilock(&cp->reglock); . 828c iunlock(&cp->reglock); . 815c ilock(&cp->reglock); . 738c iunlock(&cp->reglock); . 730c ilock(&cp->reglock); . 654c iunlock(&cp->reglock); . 649c ilock(&cp->reglock); . 592c iunlock(&cp->reglock); . 569c ilock(&cp->reglock); . 121c Lock reglock; /* exclusive access to the registers */ . ## diffname pc/devata.c 1995/0215 ## diff -e /n/fornaxdump/1995/0214/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/0215/sys/src/brazil/pc/devata.c 1178c outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | 0); . 1105c if(++loop > Maxloop) { . 1085c if(++loop > Maxloop) { . 1065c if(++loop > Maxloop) { . 1040a enum { Maxloop= 10000, }; . 871c print("ata%d probing...\n", dp->drive); . 860c if(ataprobe(dp, (i>>8)&0xffff, (i&0xff)-1, (i>>24)&0xf) == 0) . 824c outb(cp->pbase+Pdh, DHmagic | head | (dp->lba<<6) | (dp->drive<<4)); . 781,782c /*print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, dp->heads, dp->sectors);/**/ . 773,774c /*print("\nata%d model %s with default %d cyl %d head %d sec\n", dp->drive, id, dp->cyl, dp->heads, dp->sectors);/**/ . 764,765c print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors); . 736c outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); . 652c outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); . 579c outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | (dp->lba<<6) | head); . 222a if((equip & 0x0f)){ dp->drive = 1; dp->online = 0; dp->cp = cp; dp++; } conf.nhard = dp - ata; . 215,221c dp++; . 209,212c ata = xalloc(2 * sizeof(Drive)); atac = xalloc(sizeof(Controller)); cp = atac; cp->buf = 0; cp->lastcmd = cp->cmd; cp->cmd = 0; cp->pbase = Pbase; setvec(Hardvec, ataintr, 0); dp = ata; if(equip & 0xf0){ dp->drive = 0; . 202,207c if(equip == 0) equip = 0x10; /* the Globalyst 250 lies */ . 195,200d 191d 182,185d 170c if(dp->online == 0 || s >= dp->npart) . 57a /* something we have to or into the drive/head reg */ DHmagic= 0xA0, . 11c #define DPRINT if(0)print . ## diffname pc/devata.c 1995/0222 ## diff -e /n/fornaxdump/1995/0215/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/0222/sys/src/brazil/pc/devata.c 762c /*print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors);/**/ . ## diffname pc/devata.c 1995/0726 ## diff -e /n/fornaxdump/1995/0222/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/0726/sys/src/brazil/pc/devata.c 295d 293c atacreate(Chan*, char*, int, ulong) . ## diffname pc/devata.c 1995/0728 ## diff -e /n/fornaxdump/1995/0726/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/0728/sys/src/brazil/pc/devata.c 1122a } else { /* old drives/controllers hang unless the buffer is emptied */ for(loop = dp->bytes/2; --loop >= 0;) ins(cp->pbase+Pdata); . 815a cp->buf = buf; . ## diffname pc/devata.c 1995/0818 ## diff -e /n/fornaxdump/1995/0728/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/0818/sys/src/brazil/pc/devata.c 1124,1127d 1109c cp->status |= Serr; break; . 1106,1107c if(++loop > Maxloop){ print("ataintr: read/ident cmd=%lux status=%lux\n", . 1089,1090d 1086,1087c if(++loop > Maxloop) panic("ataintr: write cmd=%lux status=%lux\n", . 1069,1070d 1066,1067c if(++loop > Maxloop) panic("ataintr: wait busy cmd=%lux status=%lux", . 1039c Maxloop= 1000000, . 867d 826c atasleep(cp); . 759c dp->sectors = lbasecs; . 757c lbasecs = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); if((ip->capabilities & (1<<9)) && (lbasecs & 0xf0000000) == 0){ . 752c tsleep(&cp->r, return0, 0, Hardtimeout); . 737c atasleep(cp); . 715a ulong lbasecs; . 653c atasleep(cp); . 607c atasleep(cp); . 550a /*print("ataxfer cyl %d sec %d head %d\n", cyl, sec, head);/**/ . 507a static void atasleep(Controller *cp) { tsleep(&cp->r, cmddone, cp, Hardtimeout); if(cp->cmd && cp->cmd != Cident2){ DPRINT("hard drive timeout\n"); error("ata drive timeout"); } } . 294a USED(c, name, omode, perm); . 293c atacreate(Chan *c, char *name, int omode, ulong perm) . 204,205c cp->pbase = Pbase0; setvec(ATAvec0, ataintr, 0); . 66a Hardtimeout= 4000, /* disk access timeout */ . 22c Pbase0= 0x1F0, Pbase1= 0x170, . ## diffname pc/devata.c 1995/0908 ## diff -e /n/fornaxdump/1995/0818/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/0908/sys/src/brazil/pc/devata.c 892c for(i = 0; i < 64; i++) . 888c for(i = 0; i < 16; i++) . ## diffname pc/devata.c 1995/1206 ## diff -e /n/fornaxdump/1995/0908/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/1206/sys/src/brazil/pc/devata.c 1199a } } static int isatapi(Drive *dp) { Controller *cp; cp = dp->cp; outb(cp->pbase+Pdh, dp->dh); DPRINT("%s: isatapi %d\n", dp->vol, dp->atapi); if(dp->atapi){ outb(cp->pbase+Pcmd, 0x08); delay(20); } dp->atapi = 0; dp->bytes = 512; microdelay(1); if(inb(cp->pbase+Pstatus)){ DPRINT("%s: isatapi status %ux\n", dp->vol, inb(cp->pbase+Pstatus)); return 0; } if(inb(cp->pbase+Pcylmsb) != 0xEB || inb(cp->pbase+Pcyllsb) != 0x14){ DPRINT("%s: isatapi cyl %ux %ux\n", dp->vol, inb(cp->pbase+Pcylmsb), inb(cp->pbase+Pcyllsb)); return 0; } dp->atapi = 1; sprint(dp->vol, "atapi%d", dp->driveno); dp->spindown = 0; spindownmask &= ~(1<driveno); return 1; } static void atapiexec(Drive *dp) { Controller *cp; int loop; cp = dp->cp; if(cmdreadywait(dp)){ error(Eio); } ILOCK(&cp->reglock); cp->nsecs = 1; cp->sofar = 0; cp->error = 0; cp->cmd = Cpktcmd; outb(cp->pbase+Pcount, 0); outb(cp->pbase+Psector, 0); outb(cp->pbase+Pfeature, 0); outb(cp->pbase+Pcyllsb, cp->len); outb(cp->pbase+Pcylmsb, cp->len>>8); outb(cp->pbase+Pdh, dp->dh); outb(cp->pbase+Pcmd, cp->cmd); if(dp->drqintr == 0){ microdelay(1); for(loop = 0; (inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0; loop++){ if(loop < 10000) continue; panic("%s: cmddrqwait: cmd=%lux status=%lux\n", dp->vol, cp->cmd, inb(cp->pbase+Pstatus)); } outss(cp->pbase+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2); } IUNLOCK(&cp->reglock); loop = 0; while(waserror()){ DPRINT("%s: interrupted atapiexec\n", dp->vol); if(loop++ > 10){ print("%s: disk error\n", dp->vol); nexterror(); } } atasleep(cp); poperror(); if(loop) nexterror(); if(cp->status & Serr){ DPRINT("%s: Bad packet command %ux\n", dp->vol, cp->error); error(Eio); } } static long atapiio(Drive *dp, char *a, ulong len, ulong offset) { ulong bn, n, o, m; Controller *cp; uchar *buf; int retrycount; cp = dp->cp; buf = smalloc(Maxxfer); qlock(cp->ctlrlock); retrycount = 1; retry: if(waserror()){ dp->partok = 0; if((cp->status & Serr) && (cp->error & 0xF0) == 0x60){ dp->vers++; if(retrycount){ retrycount--; goto retry; } } cp->dp = 0; free(buf); qunlock(cp->ctlrlock); nexterror(); } cp->buf = buf; cp->dp = dp; cp->len = dp->bytes; n = len; while(n > 0){ bn = offset / dp->bytes; if(offset > dp->cap-dp->bytes) break; o = offset % dp->bytes; m = dp->bytes - o; if(m > n) m = n; memset(cp->cmdblk, 0, 12); cp->cmdblk[0] = Cread2; cp->cmdblk[2] = bn >> 24; cp->cmdblk[3] = bn >> 16; cp->cmdblk[4] = bn >> 8; cp->cmdblk[5] = bn; cp->cmdblk[7] = 0; cp->cmdblk[8] = 1; atapiexec(dp); if(cp->count != dp->bytes){ print("short read\n"); break; } memmove(a, cp->buf + o, m); n -= m; offset += m; a += m; } poperror(); free(buf); cp->dp = 0; qunlock(cp->ctlrlock); return len-n; } static long atapirwio(Chan *c, char *a, ulong len, ulong offset) { Drive *dp; ulong vers; long rv; dp = atadrive[DRIVE(c->qid.path)]; qlock(dp); if(waserror()){ qunlock(dp); nexterror(); } vers = c->qid.vers; c->qid.vers = dp->vers; if(vers && vers != dp->vers) error(Eio); rv = atapiio(dp, a, len, offset); poperror(); qunlock(dp); return rv; } static void atapipart(Drive *dp) { Controller *cp; uchar *buf, err; Partition *pp; int retrycount; cp = dp->cp; pp = &dp->p[0]; strcpy(pp->name, "disk"); pp->start = 0; pp->end = 0; dp->npart = 1; buf = smalloc(Maxxfer); qlock(cp->ctlrlock); retrycount = 1; retry: if(waserror()){ if((cp->status & Serr) && (cp->error & 0xF0) == 0x60){ dp->vers++; if(retrycount){ retrycount--; goto retry; } } cp->dp = 0; free(buf); if((cp->status & Serr) && (cp->error & 0xF0) == 0x20) err = cp->error; else err = 0; qunlock(cp->ctlrlock); if(err == 0x20) return; nexterror(); } cp->buf = buf; cp->dp = dp; cp->len = 8; cp->count = 0; memset(cp->cmdblk, 0, sizeof(cp->cmdblk)); cp->cmdblk[0] = Ccapacity; atapiexec(dp); if(cp->count != 8){ print("cmd=%2.2uX, lastcmd=%2.2uX ", cp->cmd, cp->lastcmd); print("cdsize count %d, status 0x%2.2uX, error 0x%2.2uX\n", cp->count, cp->status, cp->error); error(Eio); } dp->lbasecs = (cp->buf[0]<<24)|(cp->buf[1]<<16)|(cp->buf[2]<<8)|cp->buf[3]; dp->cap = dp->lbasecs*dp->bytes; cp->dp = 0; free(cp->buf); poperror(); qunlock(cp->ctlrlock); pp->end = dp->cap / dp->bytes; dp->partok = 1; } static void atapiintr(Controller *cp) { uchar cause; int count, loop, pbase; uchar *addr; pbase = cp->pbase; cause = inb(pbase+Pcount) & 0x03; DPRINT("%s: atapiintr %uX\n", cp->dp->vol, cause); switch(cause){ case 0: /* data out */ cp->status |= Serr; /*FALLTHROUGH*/ case 1: /* command */ if(cp->status & Serr){ cp->lastcmd = cp->cmd; cp->cmd = 0; cp->error = inb(pbase+Perror); wakeup(&cp->r); break; } outss(pbase+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2); break; case 2: /* data in */ addr = cp->buf; if(addr == 0){ cp->lastcmd = cp->cmd; cp->cmd = 0; if(cp->status & Serr) cp->error = inb(pbase+Perror); wakeup(&cp->r); break; } loop = 0; while((cp->status & (Serr|Sdrq)) == 0){ if(++loop > Maxloop){ cp->status |= Serr; break; } cp->status = inb(pbase+Pstatus); } if(cp->status & Serr){ cp->lastcmd = cp->cmd; cp->cmd = 0; cp->error = inb(pbase+Perror); print("%s: Cpktcmd status=%uX, error=%uX\n", cp->dp->vol, cp->status, cp->error); wakeup(&cp->r); break; } count = inb(pbase+Pcyllsb)|(inb(pbase+Pcylmsb)<<8); if (count > Maxxfer) count = Maxxfer; inss(pbase+Pdata, addr, count/2); cp->count = count; cp->lastcmd = cp->cmd; break; case 3: /* status */ cp->lastcmd = cp->cmd; cp->cmd = 0; if(cp->status & Serr) cp->error = inb(cp->pbase+Perror); wakeup(&cp->r); break; . 1197c IUNLOCK(&cp->reglock); . 1195c outb(cp->pbase+Pdh, dp->dh); . 1191,1192c if((dp->state == Sspinning) && (diff >= dp->spindown)){ DPRINT("%s: spindown\n", dp->vol); ILOCK(&cp->reglock); . 1186,1187c for(driveno = 0; driveno < NDrive && mask; driveno++){ mask &= ~(1<reglock); . 1167,1168c if(cp->cmd == 0 && cp->lastcmd == Cpktcmd && cp->cmdblk[0] == Ccapacity) break; if(cp->status & Serr) cp->error = inb(cp->pbase+Perror); print("%s: weird interrupt, cmd=%.2ux, lastcmd=%.2ux, ", dp->vol, cp->cmd, cp->lastcmd); print("status=%.2ux, error=%.2ux, count=%.2ux\n", cp->ctlrno, cp->error, inb(cp->pbase+Pcount)); . 1165a case Cpktcmd: atapiintr(cp); break; . 1157c case Cedd: . 1153,1155c case Cfeature: . 1149a else if(cp->cmd == Cident && (cp->status & Sready) == 0) cp->cmd = Cident2; else cp->cmd = 0; inb(cp->pbase+Pstatus); DPRINT("status %uX, alt %uX\n", inb(cp->pbase+Pstatus), inb(cp->pbase+0x206)); . 1146,1148c if(cp->cmd == Cidentd) . 1143c print("%s: intr %d %d\n", dp->vol, cp->sofar, cp->nsecs); . 1122,1123c print("%s: read/ident cmd=%lux status=%lux\n", dp->vol, cp->cmd, inb(cp->pbase+Pstatus)); . 1118a case Cidentd: . 1104,1105c panic("%s: write cmd=%lux status=%lux\n", dp->vol, cp->cmd, inb(cp->pbase+Pstatus)); . 1085,1087c if(++loop > Maxloop){ print("ata%d: cmd=%lux, lastcmd=%lux status=%lux\n", cp->ctlrno, cp->cmd, cp->lastcmd, inb(cp->pbase+Pstatus)); panic("%s: wait busy\n", dp->vol); } . 1081,1082d 1074,1079c ILOCK(&cp->reglock); . 1072c cp = arg; if((dp = cp->dp) == 0 && cp->cmd != Cedd) return; . 1069,1070c int loop; uchar *addr; . 1065c ataintr(Ureg*, void* arg) . 1051a dp->partok = 1; . 1048a dp->npart = pp - dp->p; . 1032,1046d 1030a if(getfields(line[i], field, 3, " ") != 3) break; if(pp >= &dp->p[Npart]) break; strncpy(pp->name, field[0], NAMELEN); if(strncmp(pp->name, "repl", NAMELEN) == 0) dp->repl.p = pp; pp->start = strtoul(field[1], 0, 0); pp->end = strtoul(field[2], 0, 0); if(pp->start > pp->end || pp->start >= dp->p[0].end) break; . 1029c if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ . 1024a else{ strcpy((char*)buf, p); n = getfields((char*)buf, line, Npart+1, "\n"); } . 1023c n = getfields((char*)buf, line, Npart+1, "\n"); if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ dp->p[0].end--; dp->p[1].start--; dp->p[1].end--; ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); buf[dp->bytes-1] = 0; n = getfields((char*)buf, line, Npart+1, "\n"); } . 1014,1021c sprint(namebuf, "%spartition", dp->vol); if((p = getconf(namebuf)) == 0){ /* * read last sector from disk, null terminate. This used * to be the sector we used for the partition tables. * However, this sector is special on some PC's so we've * started to use the second last sector as the partition * table instead. To avoid reconfiguring all our old systems * we first look to see if there is a valid partition * table in the last sector. If so, we use it. Otherwise * we switch to the second last. */ ataxfer(dp, &dp->p[1], Cread, 0, dp->bytes, buf); . 1005,1012c * Check if the partitions are described in plan9.ini. * If not, read the disc. . 1003a . 999a DPRINT("%s: atapart error\n", dp->vol); . 990a pp++; . 978a if(dp->partok) return; . 977c DPRINT("%s: partok %d\n", dp->vol, dp->partok); . 975c uchar *buf; . 972c char *field[3], namebuf[NAMELEN], *p; . 948c n = getfields((char*)buf, line, Nrepl+1, "\n"); . 923c uchar *buf; . 909a DPRINT("%s: probed: %d/%d/%d CHS %d bytes\n", dp->vol, dp->cyl, dp->heads, dp->sectors, dp->cap); if(dp->cyl == 0 || dp->heads == 0 || dp->sectors == 0) error(Eio); . 875c i = dp->lbasecs - 1; . 873a if(dp->atapi) return; . 856c qunlock(cp->ctlrlock); . 852a cp->dp = 0; . 849a } . 848c if(cp->status & Serr){ DPRINT("%s: probe err: status %lux, err %lux\n", dp->vol, cp->status, cp->error); . 844c IUNLOCK(&cp->reglock); . 840c outb(cp->pbase+Pdh, dp->dh | (dp->lba<<6) | head); . 830c ILOCK(&cp->reglock); . 828c if(cmdreadywait(dp)){ error(Eio); } . 824c qunlock(cp->ctlrlock); . 822a cp->dp = 0; . 821c qlock(cp->ctlrlock); . 816c uchar *buf; . 806c qunlock(cp->ctlrlock); . 801,802c if(cp->cmd){ cp->lastcmd = cp->cmd; cp->cmd = 0; } cp->dp = 0; . 784,798c dp->lbasecs = 0; . 779,781c dp->lbasecs = lbasecs; dp->cap = dp->bytes * dp->lbasecs; DPRINT("%s: LBA: %s %d sectors %d bytes\n", dp->vol, id, dp->lbasecs, dp->cap); . 775a DPRINT("%s: config 0x%uX capabilities 0x%uX\n", dp->vol, ip->config, ip->capabilities); if(dp->atapi){ dp->bytes = 2048; if((ip->config & 0x0060) == 0x0020) dp->drqintr = 1; } if(dp->spindown && (ip->capabilities & (1<<13))) dp->spindown /= 5; /* use default (unformatted) settings */ dp->cyl = ip->cyls; dp->heads = ip->heads; dp->sectors = ip->s2t; DPRINT("%s: %s %d/%d/%d CHS %d bytes\n", dp->vol, id, dp->cyl, dp->heads, dp->sectors, dp->cap); if(ip->cvalid&(1<<0)){ /* use current settings */ dp->cyl = ip->ccyls; dp->heads = ip->cheads; dp->sectors = ip->cs2t; DPRINT("%s: changed to %d cyl %d head %d sec\n", dp->vol, dp->cyl, dp->heads, dp->sectors); } . 758c DPRINT("%s: bad disk ident status\n", dp->vol); if(dp->atapi == 0 && (cp->error & Eabort)){ dp->atapi = 1; if(isatapi(dp)){ cmd = Cidentd; goto retryatapi; } } . 751,753c outb(cp->pbase+Pdh, dp->dh); outb(cp->pbase+Pcmd, cmd); IUNLOCK(&cp->reglock); . 748c cp->cmd = cmd; . 745c retryatapi: ILOCK(&cp->reglock); . 743c if(dp->atapi || isatapi(dp)) cmd = Cidentd; else{ cmd = Cident; if(cmdreadywait(dp)){ dp->atapi = 1; if(isatapi(dp) == 0) error(Eio); cmd = Cidentd; } } . 739c cp->dp = 0; free(buf); qunlock(cp->ctlrlock); . 737c qlock(cp->ctlrlock); . 733a uchar cmd; . 730c uchar *buf; . 677c qunlock(cp->ctlrlock); . 675a cp->dp = 0; . 672,674c if(cp->status & Serr) DPRINT("%s: setbuf err: status %lux, err %lux\n", dp->vol, cp->status, cp->error); . 663,668c ILOCK(&cp->reglock); cp->cmd = Cfeature; cp->dp = dp; outb(cp->pbase+Pfeature, arg); outb(cp->pbase+Pdh, dp->dh); outb(cp->pbase+Pcmd, Cfeature); IUNLOCK(&cp->reglock); . 661c if(cmdreadywait(dp)){ error(Eio); } . 657c cp->dp = 0; qunlock(cp->ctlrlock); . 655c if(dp->atapi) return; qlock(cp->ctlrlock); . 651c atafeature(Drive *dp, uchar arg) . 641c qunlock(cp->ctlrlock); . 638a cp->dp = 0; . 632,633c DPRINT("%s err: lblk %ld status %lux, err %lux\n", dp->vol, lblk, cp->status, cp->error); . 626a dp->state = Sspinning; . 625d 620c print("%s: disk error\n", dp->vol); . 618c DPRINT("%s: interrupted ataxfer\n", dp->vol); . 606c IUNLOCK(&cp->reglock); . 602c panic("%s: ataxfer", dp->vol); . 599a microdelay(1); . 593c outb(cp->pbase+Pdh, dp->dh | (dp->lba<<6) | head); . 583c ILOCK(&cp->reglock); . 576,581c if(cmdreadywait(dp)){ error(Eio); } . 572c qunlock(cp->ctlrlock); . 570a cp->dp = 0; . 569c qlock(cp->ctlrlock); . 566c XPRINT("%s: ataxfer cyl %d sec %d head %d len %d\n", dp->vol, cyl, sec, head, len); . 528c ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, uchar *buf) . 517c DPRINT("ata%d: cmd 0x%uX timeout\n", cp->ctlrno, cp->cmd); . 508c DPRINT("%s: found bblk %ld at offset %ld\n", dp->vol, bblk, i); . 491,496c if(dp->atapi) ready = 0; else ready = Sready; return atactlrwait(dp->cp, dp->dh, ready, ticks); . 489c ticks = MS2TK(2000); . 487c ticks = MS2TK(10); . 485a dp->usetime = m->ticks; . 481,483c ulong ticks; uchar ready; . 478c static int . 475,476d 399a . 398c dp = atadrive[DRIVE(c->qid.path)]; if(dp->atapi) error(Eperm); . 393c uchar *buf; . 359,361d 352a dp = atadrive[DRIVE(c->qid.path)]; if(dp->atapi){ if(dp->online == 0) error(Eio); if(waserror()){ qunlock(dp); nexterror(); } qlock(dp); if(dp->partok == 0) atapipart(dp); qunlock(dp); poperror(); return atapirwio(c, a, n, offset); } pp = &dp->p[PART(c->qid.path)]; . 348c uchar *buf; . 336d 334c atawstat(Chan*, char*) . 329d 327c ataremove(Chan*) . 320,322c qlock(dp); dp->partok = 0; atapart(dp); qunlock(dp); . 317c qunlock(dp); . 311,312c dp = atadrive[DRIVE(c->qid.path)]; p = &dp->p[PART(c->qid.path)]; . 305c Drive *dp; . 298d 296c atacreate(Chan*, char*, int, ulong) . 264c if(dp->partok == 0){ if(dp->atapi) atapipart(dp); else atapart(dp); } . 258c atafeature(dp, 0xAA); /* read look ahead */ . 251,255d 243c DPRINT("ataattach\n"); qlock(&ataprobelock); if(ataprobedone == 0){ atactlrreset(); ataprobedone = 1; } qunlock(&ataprobelock); for(driveno = 0; driveno < NDrive; driveno++){ if((dp = atadrive[driveno]) == 0) continue; . 240a int driveno; . 229a atareset(void) { } void . 225,226c for(i = 0; i < isa.nopt; i++){ DPRINT("ata%d: opt %s\n", ctlrno, isa.opt[i]); if(strncmp(isa.opt[i], "spindown", 8) == 0){ if(isa.opt[i][9] != '=') continue; if(isa.opt[i][8] == '0') slave = 0; else if(isa.opt[i][8] == '1') slave = 1; else continue; driveno = ctlrno*2+slave; if(atadrive[driveno] == 0) continue; if((spindown = strtol(&isa.opt[i][10], 0, 0)) == 0) continue; if(spindown < (Hardtimeout+2000)/1000) spindown = (Hardtimeout+2000)/1000; atadrive[driveno]->spindown = spindown; spindownmask |= (1<noatapi = 1; } } . 223c DPRINT("ata%d: DHmagic ok\n", ctlrno); if((ctlr = xalloc(sizeof(Controller))) == 0) return -1; ctlr->pbase = port; ctlr->ctlrno = ctlrno; ctlr->lastcmd = 0xFF; /* * Attempt to check the existence of drives on the controller * by issuing a 'check device diagnostics' command. * Issuing a device reset here would possibly destroy any BIOS * drive remapping and, anyway, some controllers (Vibra16) don't * seem to implement the control-block registers. * Unfortunately the vector must be set at this point as the Cedd * command will generate an interrupt, which means the ataintr routine * will be left on the interrupt call chain even if there are no * drives found. * At least one controller/ATAPI-drive combination doesn't respond * to the Edd (Micronics M54Li + Sanyo CDR-XXX) so let's check for the * ATAPI signature straight off. If we find it there will be no probe * done for a slave. Tough. */ atapi = 0; mask = 0; status = inb(port+Pstatus); DPRINT("ata%d: ATAPI %uX %uX %uX\n", ctlrno, status, inb(port+Pcylmsb), inb(port+Pcyllsb)); if(status == 0 && inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){ DPRINT("ata%d: ATAPI ok\n", ctlrno); setvec(irq, ataintr, ctlr); atapi |= 0x01; mask |= 0x01; goto skipedd; } if(atactlrwait(ctlr, DHmagic, 0, MS2TK(1)) || waserror()){ xfree(ctlr); return -1; } setvec(irq, ataintr, ctlr); ctlr->cmd = Cedd; outb(port+Pcmd, Cedd); atasleep(ctlr); poperror(); /* * The diagnostic returns a code in the error register, good * status is bits 6-0 == 0x01. * The existence of the slave is more difficult to determine, * different generations of controllers may respond in different * ways. The standards here offer little light but only more and * more heat: * 1) the slave must be done and have dropped Sbusy by now (six * seconds for the master, 5 seconds for the slave). If it * hasn't, then it has either failed or the controller is * broken in some way (e.g. Vibra16 returns status of 0xFF); * 2) theory says the status of a non-existent slave should be 0. * Of course, it's valid for all the bits to be 0 for a slave * that exists too... * 3) a valid ATAPI drive can have status 0 and the ATAPI signature * in the cylinder registers after reset. Of course, if the drive * has been messed about by the BIOS or some other O/S then the * signature may be gone. */ error = inb(port+Perror); DPRINT("ata%d: master diag error %ux\n", ctlr->ctlrno, error); if((error & ~0x80) == 0x01) mask |= 0x01; outb(port+Pdh, DHmagic|DHslave); microdelay(1); status = inb(port+Pstatus); error = inb(port+Perror); DPRINT("ata%d: slave diag status %ux, error %ux\n", ctlr->ctlrno, status, error); if(status && (status & (Sbusy|Serr)) == 0 && (error & ~0x80) == 0x01) mask |= 0x02; else if(status == 0 && inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){ atapi |= 0x02; mask |= 0x02; } skipedd: if(mask == 0){ xfree(ctlr); return -1; } atactlr[ctlrno] = ctlr; if(have640b >= 0 && (ctlrno & 0x01)) ctlr->ctlrlock = &atactlrlock[ctlrno-1]; else ctlr->ctlrlock = &atactlrlock[ctlrno]; if(mask & 0x01) atadrivealloc(ctlr, ctlrno*2, atapi & 0x01); if(mask & 0x02) atadrivealloc(ctlr, ctlrno*2+1, atapi & 0x02); return 0; } void atactlrreset(void) { int ctlrno, driveno, i, slave, spindown; ISAConf isa; cmd640b(); rz1000(); for(ctlrno = 0; ctlrno < NCtlr; ctlrno++){ memset(&isa, 0, sizeof(ISAConf)); if(isaconfig("ata", ctlrno, &isa) == 0 && ctlrno) continue; if(isa.irq == 0 && (isa.irq = defirq[ctlrno]) == 0) continue; if(atactlrprobe(ctlrno, Int0vec+isa.irq)) continue; . 217,221c drive->cp = ctlr; drive->driveno = driveno; sprint(drive->vol, "hd%d", drive->driveno); drive->dh = DHmagic; if(driveno & 0x01) drive->dh |= DHslave; drive->vers = 1; if(atapi) drive->atapi = 1; atadrive[driveno] = drive; } static int atactlrprobe(int ctlrno, int irq) { Controller *ctlr; int atapi, mask, port; uchar error, status; /* * Check the existence of a controller by verifying a sensible * value can be written to and read from the drive/head register. * We define the primary/secondary/tertiary and quaternary controller * port addresses to be at fixed values. * If it's OK, allocate and initialise a Controller structure. */ port = pbase[ctlrno]; outb(port+Pdh, DHmagic); microdelay(1); if((inb(port+Pdh) & 0xFF) != DHmagic){ DPRINT("ata%d: DHmagic not ok\n", ctlrno); return -1; . 210,215c static int atactlrwait(Controller* ctlr, uchar pdh, uchar ready, ulong ticks) { int port; uchar dh, status; port = ctlr->pbase; dh = (inb(port+Pdh) & DHslave)^(pdh & DHslave); ticks += m->ticks+1; do{ status = inb(port+Pstatus); if(status & Sbusy) continue; if(dh){ outb(port+Pdh, pdh); dh = 0; continue; } if((status & ready) == ready) return 0; }while(m->ticks < ticks); DPRINT("ata%d: ctlrwait failed %uX\n", ctlr->ctlrno, status); outb(port+Pdh, DHmagic); return 1; } static void atadrivealloc(Controller* ctlr, int driveno, int atapi) { Drive *drive; if((drive = xalloc(sizeof(Drive))) == 0){ DPRINT("ata%d: can't xalloc drive0\n", ctlr->ctlrno); return; . 203,208c /* * Look for PC-Tech RZ1000 controllers and turn off prefetch. * This is overkill, but cheap. */ pcicfg = malloc(sizeof(PCIcfg)); pcicfg->vid = 0x1042; pcicfg->did = 0; devno = 0; while((devno = pcimatch(0, devno, pcicfg)) != -1){ if(pcicfg->did != 0x1000 && pcicfg->did != 0x1001) continue; pcicfgr(0, devno-1, 0, 0x40, &r40, sizeof(r40)); r40 &= ~0x2000; pcicfgw(0, devno-1, 0, 0x40, &r40, sizeof(r40)); } free(pcicfg); } . 200,201c static void rz1000(void) { PCIcfg* pcicfg; ulong r40; int devno; . 196,198c /* * Look for CMD640B dual PCI controllers. Amongst other * bugs only one of the controllers can be active at a time. * Unfortunately there's no way to tell which pair of * controllers this is, so if one is found then all controller * pairs are synchronised. */ pcicfg = malloc(sizeof(PCIcfg)); pcicfg->vid = 0x1095; pcicfg->did = 0x0640; devno = 0; while((devno = pcimatch(0, devno, pcicfg)) != -1){ have640b = devno-1; /* * If one is found, make sure read-ahead is disabled on all * drives and that the 2nd controller is enabled: * reg 0x51: bit 7 - drive 1 read ahead disable * bit 6 - drive 0 read ahead disable * bit 3 - 2nd controller enable * reg 0x57: bit 3 - drive 1 read ahead disable * bit 2 - drive 0 read ahead disable * Doing byte-writes to PCI configuration space is not in the * spec... */ pcicfgr(0, have640b, 0, 0x50, r50, sizeof(r50)); r50[0x01] |= 0xC8; pcicfgw8(0, have640b, 0, 0x51, &r50[0x01], sizeof(r50[0x01])); r50[0x07] |= 0x0C; pcicfgw8(0, have640b, 0, 0x57, &r50[0x07], sizeof(r50[0x07])); } free(pcicfg); } . 191,194c PCIcfg* pcicfg; uchar r50[12]; int devno; extern void pcicfgw8(int, int, int, int, void*, int); . 188,189c static void cmd640b(void) . 174c if(atadrive[drive] == 0) return 0; dp = atadrive[drive]; . 172c if(drive >= NDrive) . 168d 159c atagen(Chan *c, Dirtab*, long, long s, Dir *dirp) . 157a static int isatapi(Drive*); static long atapirwio(Chan*, char*, ulong, ulong); static void atapipart(Drive*); static void atapiintr(Controller*); . 156a static void atasleep(Controller*); . 153c static void atafeature(Drive*, uchar); . 151c static long ataxfer(Drive*, Partition*, int, long, long, uchar*); . 146,148c static QLock ataprobelock; static int ataprobedone; static Controller *atactlr[NCtlr]; static QLock atactlrlock[NCtlr]; static Drive *atadrive[NDrive]; static int spindownmask; static int have640b = -1; static int pbase[NCtlr] = { Pbase0, Pbase1, Pbase2, Pbase3, }; static int defirq[NCtlr] = { 14, 15, 0, 0, }; . 141,143c Drive* dp; /* drive being accessed */ . 138c uchar cmd; /* current command */ uchar cmdblk[12]; /* ATAPI */ int len; /* ATAPI */ int count; /* ATAPI */ uchar lastcmd; /* debugging info */ uchar status; uchar error; uchar* buf; /* xfer buffer */ . 135,136d 130a uchar ctlrno; uchar noatapi; . 129d 125c QLock* ctlrlock; /* exclusive access to the controller */ . 116,117c uchar lba; /* true if drive has logical block addressing */ uchar multi; /* true if drive can do multiple block xfers (unused) */ uchar drqintr; /* ATAPI */ ulong vers; /* ATAPI */ int spindown; . 114a ulong lbasecs; . 103a int partok; . 100,102c uchar driveno; uchar dh; /* DHmagic|Am-I-A-Slave */ uchar atapi; uchar online; . 70a . 69c Hardtimeout= 30000, /* disk access timeout (ms) */ NCtlr= 4, NDrive= NCtlr*2, . 66c Npart= 20+2, /* 8 sub partitions, disk, and partition */ . 59,61d 56,57d 52a Cpktcmd= 0xA0, Cidentd= 0xA1, Ccapacity= 0x25, Cread2= 0x28, . 50,51d 48d 44,46c Cident2= 0xFE, /* pseudo command for post Cident interrupt */ Cfeature= 0xEF, . 42a Cedd= 0x90, /* execute device diagnostics */ . 40c Cfirst= 0xFF, /* pseudo command for initialisation */ . 34a Sdf= (1<<5), . 31a DHmagic= 0xA0, DHslave= 0x10, . 26c Eabort= (1<<2), Pfeature= 1, /* buffer mode port (write) */ . 22,23c Pbase0= 0x1F0, /* primary */ Pbase1= 0x170, /* secondary */ Pbase2= 0x1E8, /* tertiary */ Pbase3= 0x168, /* quaternary */ . 11a #define XPRINT if(0)print #define ILOCK(x) #define IUNLOCK(x) . 0a /* * This has gotten a bit messy with the addition of multiple controller * and ATAPI support; needs a rewrite before adding any 'ctl' functions. */ . ## diffname pc/devata.c 1995/1208 ## diff -e /n/fornaxdump/1995/1206/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/1208/sys/src/brazil/pc/devata.c 1820c err = cp->error & 0xF0; . 1807c retrycount = 2; . 1708c retrycount = 2; . 1691c DPRINT("%s: Bad packet command %ux, error %ux\n", dp->vol, cp->cmdblk[0], cp->error); . 1617,1619c outb(cp->pbase+Pcmd, 0x08); if(atactlrwait(dp->cp, DHmagic, 0, MS2TK(100))){ DPRINT("%s: isatapi ctlrwait status %ux\n", dp->vol, inb(cp->pbase+Pstatus)); return 0; . 1544,1545d 1540a #else if(cp->cmd != Cread && (cp->status & (Sbusy|Sready)) != Sready) cp->cmd = Cident2; #endif /* notdef */ . 1536a #ifdef notdef . 1154c XPRINT("%s: LBA: %s %d sectors %d bytes\n", . 1145c XPRINT("%s: changed to %d cyl %d head %d sec\n", . 1137c XPRINT("%s: %s %d/%d/%d CHS %d bytes\n", . 1099,1100c if(cp->error & Eabort){ . 1094a DPRINT("%s: ident command %ux sent\n", dp->vol, cmd); . 1072,1083c cmd = Cident; . 403a DPRINT("ata%d: Cedd status %ux/%ux/%ux\n", ctlrno, inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); . 387c * to the Cedd (Micronics M54Li + Sanyo CRD-254P) so let's check for the . 343a } . 342c if(atapi){ sprint(drive->vol, "atapi%d", drive->driveno); . 79c Hardtimeout= 6000, /* disk access timeout (ms) */ . ## diffname pc/devata.c 1995/1209 ## diff -e /n/fornaxdump/1995/1208/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/1209/sys/src/brazil/pc/devata.c 1682c atasleep(cp, Hardtimeout); . 1533,1538d 1530,1531c if(cp->cmd != Cread) . 1206c atasleep(cp, Hardtimeout); . 1089c atasleep(cp, 1000); . 999c atasleep(cp, Hardtimeout); . 945c atasleep(cp, Hardtimeout); . 837c tsleep(&cp->r, cmddone, cp, ms); . 835c atasleep(Controller *cp, int ms) . 414c atasleep(ctlr, Hardtimeout); . 193c static void atasleep(Controller*, int); . ## diffname pc/devata.c 1995/1218 ## diff -e /n/fornaxdump/1995/1209/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/1218/sys/src/brazil/pc/devata.c 1405a if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ dp->p[0].end--; dp->p[1].start--; dp->p[1].end--; } . 1402a } else{ . 1399c if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ . 1396c ataxfer(dp, &dp->p[0], Cread, dp->p[0].end-1, dp->bytes, buf); . 1392,1394c * we still check if there is a valid partition table in * the last sector if none is found in the second last. . 1387,1388c * Read second last sector from disk, null terminate. * The last sector used to hold the partition tables. . ## diffname pc/devata.c 1995/1219 ## diff -e /n/fornaxdump/1995/1218/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/1219/sys/src/brazil/pc/devata.c 1411a else print("ok%d|", dp->p[1].start); . 1410a print("nok%d|", dp->p[1].start); . 1403a print("r%d|", dp->p[1].start); . 1401a print("OK%d|", dp->p[1].start); . 1395c print("R%d|", dp->p[0].end-2); ataxfer(dp, &dp->p[0], Cread, dp->p[0].end-2, dp->bytes, buf); . ## diffname pc/devata.c 1995/1221 ## diff -e /n/fornaxdump/1995/1219/sys/src/brazil/pc/devata.c /n/fornaxdump/1995/1221/sys/src/brazil/pc/devata.c 1410,1416c if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)) i = 1; } if(i){ dp->p[0].end--; dp->p[1].start--; dp->p[1].end--; . 1406d 1399,1404c if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0) i = 1; . 1395,1396c i = 0; ataxfer(dp, &dp->p[0], Cread, (dp->p[0].end-2)*dp->bytes, dp->bytes, buf); . ## diffname pc/devata.c 1996/0112 ## diff -e /n/fornaxdump/1995/1221/sys/src/brazil/pc/devata.c /n/fornaxdump/1996/0112/sys/src/brazil/pc/devata.c 1826a cp->len = 18; cp->count = 0; memset(cp->cmdblk, 0, sizeof(cp->cmdblk)); cp->cmdblk[0] = Creqsense; cp->cmdblk[4] = 18; atapiexec(dp); if(cp->count != 18){ print("cmd=%2.2uX, lastcmd=%2.2uX ", cp->cmd, cp->lastcmd); print("cdsize count %d, status 0x%2.2uX, error 0x%2.2uX\n", cp->count, cp->status, cp->error); error(Eio); } . 1805a DPRINT("atapipart: cmd %uX error %uX\n", cp->cmd, cp->error); . 1076c if(dp->atapi) cmd = Cidentd; else cmd = Cident; . 64a Ctur= 0x00, Creqsense= 0x03, . ## diffname pc/devata.c 1996/0210 ## diff -e /n/fornaxdump/1996/0112/sys/src/brazil/pc/devata.c /n/fornaxdump/1996/0210/sys/src/brazil/pc/devata.c 1094c if(cmd == Cident) atasleep(cp, 3000); else atasleep(cp, 30000); . 517,518c else if(strcmp(isa.opt[i], "reset") == 0) atactlr[ctlrno]->resetok = 1; . 450,452c else if(status == 0){ msb = inb(port+Pcylmsb); lsb = inb(port+Pcyllsb); DPRINT("ata%d: ATAPI slave %uX %uX %uX\n", ctlrno, status, inb(port+Pcylmsb), inb(port+Pcyllsb)); if(msb == 0xEB && lsb == 0x14){ atapi |= 0x02; mask |= 0x02; } . 408,409c DPRINT("ata%d: Cedd status %ux/%ux/%ux\n", ctlrno, inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); . 394a if(ctlr->resetok){ outb(port+Pctrl, Srst|nIEN); microdelay(1); outb(port+Pctrl, 0); if(atactlrwait(ctlr, DHmagic, 0, 100)){ DPRINT("ata%d: Srst status %ux/%ux/%ux\n", ctlrno, inb(port+Pstatus), inb(port+Pcylmsb), inb(port+Pcyllsb)); xfree(ctlr); } } . 385c * seem to implement the control-block registers; do it if requested. . 379a . 357c uchar error, status, msb, lsb; . 155c uchar resetok; . 51a Pctrl= 0x206, /* device control, alternate status */ nIEN= (1<<1), Srst= (1<<2), . ## diffname pc/devata.c 1996/0215 ## diff -e /n/fornaxdump/1996/0210/sys/src/brazil/pc/devata.c /n/fornaxdump/1996/0215/sys/src/brazil/pc/devata.c 1119c atasleep(cp, 10000); . 404c if(atactlrwait(ctlr, DHmagic, 0, MS2TK(20)){ . 402c delay(10); . ## diffname pc/devata.c 1996/0216 ## diff -e /n/fornaxdump/1996/0215/sys/src/brazil/pc/devata.c /n/fornaxdump/1996/0216/sys/src/brazil/pc/devata.c 404c if(atactlrwait(ctlr, DHmagic, 0, MS2TK(20))){ . ## diffname pc/devata.c 1996/0223 ## diff -e /n/fornaxdump/1996/0216/sys/src/brazil/pc/devata.c /n/fornaxdump/1996/0223/sys/src/brazil/pc/devata.c 13d ## diffname pc/devata.c 1996/0315 ## diff -e /n/fornaxdump/1996/0223/sys/src/brazil/pc/devata.c /n/fornaxdump/1996/0315/sys/src/brazil/pc/devata.c 1453c if(parsefields(line[i], field, 3, " ") != 3) . 1445c n = parsefields((char*)buf, line, Npart+1, "\n"); . 1433c n = parsefields((char*)buf, line, Npart+1, "\n"); . 1427c n = parsefields((char*)buf, line, Npart+1, "\n"); . 1352c if(parsefields(line[i], field, 1, " ") != 1) . 1347c n = parsefields((char*)buf, line, Nrepl+1, "\n"); . ## diffname pc/devata.c 1996/0803 ## diff -e /n/fornaxdump/1996/0315/sys/src/brazil/pc/devata.c /n/fornaxdump/1996/0803/sys/src/brazil/pc/devata.c 642a if(dp == 0) return; . ## diffname pc/devata.c 1996/1225 ## diff -e /n/fornaxdump/1996/0803/sys/src/brazil/pc/devata.c /n/fornaxdump/1996/1225/sys/src/brazil/pc/devata.c 206c atagen(Chan *c, Dirtab*, int, int s, Dir *dirp) . ## diffname pc/devata.c 1997/0327 ## diff -e /n/fornaxdump/1996/1225/sys/src/brazil/pc/devata.c /n/emeliedump/1997/0327/sys/src/brazil/pc/devata.c 1964a Dev atadevtab = { devreset, devinit, ataattach, devclone, atawalk, atastat, ataopen, devcreate, ataclose, ataread, devbread, atawrite, devbwrite, devremove, devwstat, }; . 1604,1605c static void ataclock(void) . 805,810d 726,732c static long . 663,674d 660,661c static long ataread(Chan* c, void* a, long n, ulong offset) . 630,635d 628c ataclose(Chan* c) . 621,622c static Chan* ataopen(Chan* c, int omode) . 615,616c static void atastat(Chan* c, char* dp) . 606,611d 603,604c static int atawalk(Chan* c, char* name) . 558,559c static Chan* ataattach(char* spec) . 549,553d 544,546c if(spindownmask) addclock0link(ataclock); . 542d 512c if(atactlrprobe(ctlrno, VectorPIC+isa.irq)) . 496c static void . 483c if(have640b && (ctlrno & 0x01)) . 428c intrenable(irq, ataintr, ctlr, ctlr->tbdf); . 417c intrenable(irq, ataintr, ctlr, ctlr->tbdf); . 380a ctlr->tbdf = BUSUNKNOWN; . 300d 296,298c r = pcicfgr32(p, 0x40); r &= ~0x2000; pcicfgw32(p, 0x40, r); . 289,294c p = 0; while(p = pcimatch(p, 0x1042, 0)){ if(p->did != 0x1000 && p->did != 0x1001) . 281,283c Pcidev *p; ulong r; . 275d 269,273c r = pcicfgr8(p, 0x51); r |= 0xC8; pcicfgw8(p, 0x51, r); r = pcicfgr8(p, 0x57); r |= 0x0C; pcicfgw8(p, 0x57, r); . 266,267d 252,257c p = 0; while(p = pcimatch(p, 0x1095, 0x0640)){ have640b++; . 240,243c Pcidev *p; int r; . 206c atagen(Chan* c, Dirtab*, int, int s, Dir* dirp) . 198a static void ataclock(void); . 183c static int have640b; . 157a int tbdf; . ## diffname pc/devata.c 1997/0408 ## diff -e /n/emeliedump/1997/0327/sys/src/brazil/pc/devata.c /n/emeliedump/1997/0408/sys/src/brazil/pc/devata.c 1914a 'H', "ata", . ## diffname pc/devata.c 1997/0812 ## diff -e /n/emeliedump/1997/0408/sys/src/brazil/pc/devata.c /n/emeliedump/1997/0812/sys/src/brazil/pc/devata.c 823c ataxfer(Drive *dp, Partition *pp, int cmd, ulong start, long len, uchar *buf) . 193c static long ataxfer(Drive*, Partition*, int, ulong, long, uchar*); . ## diffname pc/devata.c 1997/0815 ## diff -e /n/emeliedump/1997/0812/sys/src/brazil/pc/devata.c /n/emeliedump/1997/0815/sys/src/brazil/pc/devata.c 531a if(atactlrprobe(ctlrno, VectorPIC+isa.irq, resetok)) continue; if(spindown == 0 || atadrive[driveno] == 0) continue; atadrive[driveno]->spindown = spindown; spindownmask |= (1<vol, dp->lbasecs, dp->bytes, dp->cap); . 1833a dp->bytes = (cp->buf[4]<<24)|(cp->buf[5]<<16)|(cp->buf[6]<<8)|cp->buf[7]; . 1820a { int i; for(i = 0; i < 18; i++) print("%2.2uX ", buf[i]); print("\n"); } . 14,15c #define DPRINT if(1)print #define XPRINT if(1)print . ## diffname pc/devata.c 1998/0106 ## diff -e /n/emeliedump/1997/1230/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0106/sys/src/brazil/pc/devata.c 1839a if(dp->bytes > 2048 && dp->bytes <= 2352) dp->bytes = 2048; . 448a atapislave: . 411c // goto skipedd; goto atapislave; . 14,15c #define DPRINT if(0)print #define XPRINT if(0)print . ## diffname pc/devata.c 1998/0115 ## diff -e /n/emeliedump/1998/0106/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0115/sys/src/brazil/pc/devata.c 1823,1827d ## diffname pc/devata.c 1998/0219 ## diff -e /n/emeliedump/1998/0115/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0219/sys/src/brazil/pc/devata.c 1907c if(cause == 0) outss(pbase+Pdata, addr, count/2); else inss(pbase+Pdata, addr, count/2); . 1876a case 0: /* data out */ . 1863,1865d 1760c rv = atapiio(dp, a, len, offset, cmd); . 1742c atapirwio(Chan *c, uchar *a, ulong len, ulong offset, int cmd) . 1735c if(cmd == Cread2) free(buf); . 1717c cp->cmdblk[0] = cmd; . 1703c if(cmd == Cread2) cp->buf = buf; else cp->buf = a; . 1698c if(cmd == Cread2) free(buf); . 1684c if(cmd == Cread2) buf = smalloc(Maxxfer); else buf = 0; . 1675c atapiio(Drive *dp, uchar *a, ulong len, ulong offset, int cmd) . 1103a if((ip->config & 0x1F00) == 0x0000) dp->atapi = 2; . 752c if(dp->atapi) atapirwio(c, buf, dp->bytes, offset+rv, Cwrite2); else ataxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf); . 750c if(dp->atapi) atapirwio(c, buf, dp->bytes, offset+rv, Cread2); else ataxfer(dp, pp, Cread, offset+rv, dp->bytes, buf); . 739c if(dp->atapi) i = atapirwio(c, buf, i, offset+rv, Cwrite2); else i = ataxfer(dp, pp, Cwrite, offset+rv, i, buf); . 725c if(dp->atapi) atapirwio(c, buf, dp->bytes, offset-partial, Cwrite2); else ataxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf); . 719c if(dp->atapi) atapirwio(c, buf, dp->bytes, offset-partial, Cread2); else ataxfer(dp, pp, Cread, offset-partial, dp->bytes, buf); . 702,703c if(dp->atapi){ if(dp->online == 0 || dp->atapi == 1) error(Eio); if(waserror()){ qunlock(dp); nexterror(); } qlock(dp); if(dp->partok == 0) atapipart(dp); qunlock(dp); poperror(); } . 661c return atapirwio(c, a, n, offset, Cread2); . 456c if((status & ~0x02) && (status & (Sbusy|Serr)) == 0 && (error & ~0x80) == 0x01) . 446c DPRINT("ata%d: master diag status %uX, error %ux\n", ctlr->ctlrno, inb(port+Pstatus), error); . 443a * When checking status, mask off the IDX bit. . 411,412c goto atapislave; . 403d 202c static long atapirwio(Chan*, uchar*, ulong, ulong, int); . 71a Cwrite2= 0x2A, . 13,15c #define DEBUG 0 #define DPRINT if(DEBUG)print #define XPRINT if(DEBUG)print . ## diffname pc/devata.c 1998/0319 ## diff -e /n/emeliedump/1998/0219/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0319/sys/src/brazil/pc/devata.c 697a ulong offset = off; . 691c atawrite(Chan *c, void *a, long n, vlong off) . 644a ulong offset = off; . 637c ataread(Chan* c, void* a, long n, vlong off) . ## diffname pc/devata.c 1998/0327 ## diff -e /n/emeliedump/1998/0319/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0327/sys/src/brazil/pc/devata.c 1799c rv = atapiio(dp, a, len, off, cmd); . 1781c atapirwio(Chan *c, uchar *a, ulong len, vlong off, int cmd) . 1769c off += m; . 1750c o = off % dp->bytes; . 1747,1748c bn = off / dp->bytes; if(off > dp->cap-dp->bytes) . 1720a . 1706c atapiio(Drive *dp, uchar *a, ulong len, vlong off, int cmd) . 1288,1290c dp->cap = (vlong)dp->bytes * dp->cyl * dp->heads * dp->sectors; DPRINT("%s: probed: %d/%d/%d CHS %lld bytes\n", dp->vol, dp->cyl, dp->heads, dp->sectors, dp->cap); . 1165c dp->cap = (vlong)dp->bytes * dp->cyl * dp->heads * dp->sectors; . 1159,1161c dp->cap = (vlong)dp->bytes * dp->lbasecs; XPRINT("%s: LBA: %s %d sectors %lld bytes\n", dp->vol, id, dp->lbasecs, dp->cap); . 1143,1144c XPRINT("%s: %s %d/%d/%d CHS %lld bytes\n", dp->vol, id, dp->cyl, dp->heads, dp->sectors, dp->cap); . 893c XPRINT("%s: ataxfer cyl %d sec %d head %d len %d\n", dp->vol, cyl, sec, head, len); . 868c start = off / dp->bytes; . 860a ulong start; . 855c ataxfer(Drive *dp, Partition *pp, int cmd, vlong off, long len, uchar *buf) . 835c DPRINT("%s: found bblk %ld at offset %ld\n", dp->vol, bblk, i); . 781c ataxfer(dp, pp, Cwrite, off+rv, dp->bytes, buf); . 779c atapirwio(c, buf, dp->bytes, off+rv, Cwrite2); . 776c ataxfer(dp, pp, Cread, off+rv, dp->bytes, buf); . 774c atapirwio(c, buf, dp->bytes, off+rv, Cread2); . 762c i = ataxfer(dp, pp, Cwrite, off+rv, i, buf); . 760c i = atapirwio(c, buf, i, off+rv, Cwrite2); . 745c ataxfer(dp, pp, Cwrite, off-partial, dp->bytes, buf); . 743c atapirwio(c, buf, dp->bytes, off-partial, Cwrite2); . 736c ataxfer(dp, pp, Cread, off-partial, dp->bytes, buf); . 734c atapirwio(c, buf, dp->bytes, off-partial, Cread2); . 731c partial = off % dp->bytes; . 699d 675c i = ataxfer(dp, pp, Cread, off+rv-skip, n-rv+skip, buf); . 673c skip = off % dp->bytes; . 663c return atapirwio(c, a, n, off, Cread2); . 645d 234c l = (pp->end - pp->start) * (vlong)dp->bytes; . 215c vlong l; . 203c static long atapirwio(Chan*, uchar*, ulong, vlong, int); . 193c static long ataxfer(Drive*, Partition*, int, vlong, long, uchar*); . 133c vlong cap; /* total bytes */ . ## diffname pc/devata.c 1998/0331 ## diff -e /n/emeliedump/1998/0327/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0331/sys/src/brazil/pc/devata.c 1413c ataxfer(dp, &dp->p[0], Cread, (dp->p[0].end-2)* (vlong)dp->bytes, dp->bytes, buf); . 419c if(once) intrenable(irq, ataintr, ctlr, ctlr->tbdf); . 415a if(once){ once = 0; ctlr->cmd = 0; goto retry; } . 408c if(once) intrenable(irq, ataintr, ctlr, ctlr->tbdf); . 406c if(/*status == 0 &&*/ inb(port+Pcylmsb) == 0xEB && inb(port+Pcyllsb) == 0x14){ . 401a once = 1; retry: . 349c int atapi, mask, once, port; . ## diffname pc/devata.c 1998/0501 ## diff -e /n/emeliedump/1998/0331/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0501/sys/src/brazil/pc/devata.c 1782c if(cmd == Cread2) memmove(a, cp->buf + o, m); else cp->buf += m; . ## diffname pc/devata.c 1998/0510 ## diff -e /n/emeliedump/1998/0501/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0510/sys/src/brazil/pc/devata.c 1845c DPRINT("atapipart: cmd %uX error %uX\n", cp->cmdblk[0], cp->error); . 1739a atapireqsense(dp); . 1737a DPRINT("atapiio: cmd %uX error %uX\n", cp->cmdblk[0], cp->error); . 1718a static void atapireqsense(Drive* dp) { Controller *cp; uchar *buf; cp = dp->cp; buf = smalloc(Maxxfer); cp->buf = buf; cp->dp = dp; if(waserror()){ free(buf); return; } cp->len = 18; cp->count = 0; memset(cp->cmdblk, 0, sizeof(cp->cmdblk)); cp->cmdblk[0] = Creqsense; cp->cmdblk[4] = 18; atapiexec(dp); if(cp->count != 18){ print("cmd=%2.2uX, lastcmd=%2.2uX ", cp->cmd, cp->lastcmd); print("cdsize count %d, status 0x%2.2uX, error 0x%2.2uX\n", cp->count, cp->status, cp->error); } poperror(); free(buf); } . 1178a XPRINT("%s: %s %d/%d/%d CHS %lld bytes\n", dp->vol, id, dp->cyl, dp->heads, dp->sectors, dp->cap); . 1153,1155d 13,17c #define DEBUG 0 #define DPRINT if(DEBUG)print #define XPRINT if(DEBUG)print #define ILOCK(x) ilock(x) #define IUNLOCK(x) iunlock(x) . 3a * The register locking needs looked at. . ## diffname pc/devata.c 1998/0516 ## diff -e /n/emeliedump/1998/0510/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0516/sys/src/brazil/pc/devata.c 2001,2003c inss(pbase+Pdata, cp->buf+cp->count, count/2); cp->count += count; . 1999c outss(pbase+Pdata, cp->buf+cp->count, count/2); . 1996,1997c if(cp->count+count > Maxxfer) panic("hd%d: count %d, already %d\n", count, cp->count); . 1969,1970c if(cp->buf == 0){ . 1949d 1918d 1916a cp->nsecs = 1; . 1905d 1903a cp->nsecs = 1; . 1831c poperror(); return len; . 1829a cp->buf = 0; len = cp->count; . 1796,1828c memset(cp->cmdblk, 0, 12); cp->cmdblk[0] = cmd; cp->cmdblk[2] = start>>24; cp->cmdblk[3] = start>>16; cp->cmdblk[4] = start>>8; cp->cmdblk[5] = start; cp->cmdblk[7] = cp->nsecs>>8; cp->cmdblk[8] = cp->nsecs; atapiexec(dp); if(cp->count != cp->len) print("short read\n"); . 1794d 1789,1792c cp->buf = buf; cp->nsecs = len; cp->len = len*dp->bytes; cp->cmd = cmd; . 1783,1784c cp->buf = 0; . 1763,1766c cp = dp->cp; . 1761c /* * cut transfer size down to disk buffer size */ start = off / dp->bytes; if(len > Maxxfer) len = Maxxfer; len = (len + dp->bytes - 1) / dp->bytes; if(len == 0) return 0; . 1758d 1756c ulong start; . 1754c atapiio(Drive *dp, uchar *buf, ulong len, vlong off, int cmd) . 1738d 1736a cp->nsecs = 1; . 1677c cp->count = 0; . 684c if(dp->atapi) i = atapirwio(c, buf, n-rv+skip, off+rv-skip, Cread2); else i = ataxfer(dp, pp, Cread, off+rv-skip, n-rv+skip, buf); . 672d ## diffname pc/devata.c 1998/0825 ## diff -e /n/emeliedump/1998/0516/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0825/sys/src/brazil/pc/devata.c 1919c DPRINT("%s: atapipart secs %lud, bytes %ud, cap %lld\n", . 1542c print("%s: read/ident cmd=%ux status=%ux\n", . 1503c print("ata%d: cmd=%ux, lastcmd=%ux status=%ux\n", . 1304c DPRINT("%s: probed: %ld/%d/%d CHS %lld bytes\n", . 1237c DPRINT("%s: probe err: status %ux, err %ux\n", . 1179c XPRINT("%s: %s %ld/%d/%d CHS %lld bytes\n", . 1171c XPRINT("%s: LBA: %s %lud sectors %lld bytes\n", . 1162c XPRINT("%s: changed to %ld cyl %d head %d sec\n", . 1020c DPRINT("%s: setbuf err: status %ux, err %ux\n", . 971c DPRINT("%s err: lblk %ld status %ux, err %ux\n", . 905c XPRINT("%s: ataxfer cyl %d sec %d head %d len %ld\n", . 845c DPRINT("%s: found bblk %ld at offset %d\n", . ## diffname pc/devata.c 1998/0831 ## diff -e /n/emeliedump/1998/0825/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0831/sys/src/brazil/pc/devata.c 1860a if(dp->atapi == 1) { /* cd-rom */ dp->npart = CDmax; pp = &dp->p[CDcmd]; strcpy(pp->name, "cmd"); pp->start = pp->end = 0; pp = &dp->p[CDdata]; strcpy(pp->name, "data"); pp->start = pp->end = 0; } . 1711c atasleep(cp, Atapitimeout); . 1674a print("cmdreadywait fails"); . 1589c if(cp->cmd == 0 && cp->lastcmd == Cpktcmd) . 722,726d 720c poperror(); break; case CDcmd: if(n != 12) error(Ebadarg); acmd = &dp->atapicmd; qlock(acmd); acmd->pid = up->pid; memmove(acmd->cmdblk, a, n); return n; case CDdata: error(Egreg); . 716,718c switch(PART(c->qid.path)) { case CDdisk: if(dp->online == 0 || dp->atapi == 1) error(Eio); if(waserror()){ qunlock(dp); nexterror(); } qlock(dp); if(dp->partok == 0) atapipart(dp); . 709a Atapicmd *acmd; . 667,671d 665c poperror(); break; case CDcmd: acmd = &dp->atapicmd; if(n < 4) error(Ebadarg); if(canqlock(acmd)) { qunlock(acmd); error(Egreg); } if(acmd->pid != up->pid) error(Egreg); n = 4; *aa++ = 0; *aa++ = 0; *aa++ = acmd->error; *aa = acmd->status; qunlock(acmd); return n; case CDdata: acmd = &dp->atapicmd; if(canqlock(acmd)) { qunlock(acmd); error(Egreg); } if(acmd->pid != up->pid) error(Egreg); if(n > Maxxfer) error(Ebadarg); cp = dp->cp; qlock(cp->ctlrlock); cp->len = 0; cp->buf = 0; cp->dp = dp; if(waserror()) { if(cp->buf) free(cp->buf); cp->buf = 0; cp->dp = 0; acmd->status = cp->status; acmd->error = cp->error; qunlock(cp->ctlrlock); nexterror(); } if(n) cp->buf = smalloc(Maxxfer); cp->len = n; memmove(cp->cmdblk, acmd->cmdblk, sizeof cp->cmdblk); atapiexec(dp); memmove(a, cp->buf, cp->count); poperror(); if(cp->buf) free(cp->buf); acmd->status = cp->status; acmd->error = cp->error; n = cp->count; qunlock(cp->ctlrlock); return n; . 661,663c switch(PART(c->qid.path)){ case CDdisk: if(dp->online == 0) error(Eio); if(waserror()){ qunlock(dp); nexterror(); } qlock(dp); if(dp->partok == 0) atapipart(dp); . 654a Atapicmd *acmd; Controller *cp; . 631a if(dp->atapi == 1 && strcmp(p->name, "cmd") == 0) { acmd = &dp->atapicmd; if(canqlock(acmd)) { qunlock(acmd); return; } if(acmd->pid == up->pid) qunlock(acmd); return; } . 623a Atapicmd *acmd; . 206a static void atapiexec(Drive*); . 146a Atapicmd atapicmd; . 113a * the result of the last user-invoked atapi cmd */ struct Atapicmd { QLock; int pid; ushort status; ushort error; uchar cmdblk[12]; }; /* . 89a /* cd files */ CDdisk = 0, CDcmd, CDdata, CDmax, . 87c Atapitimeout= 10000, /* disk access timeout (ms) */ . 24a typedef struct Atapicmd Atapicmd; . ## diffname pc/devata.c 1998/0910 ## diff -e /n/emeliedump/1998/0831/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0910/sys/src/brazil/pc/devata.c 559c if(atactlrprobe(ctlrno, isa.irq, resetok)) . ## diffname pc/devata.c 1998/0922 ## diff -e /n/emeliedump/1998/0910/sys/src/brazil/pc/devata.c /n/emeliedump/1998/0922/sys/src/brazil/pc/devata.c 2030c print("cmd=0x%2.2uX, lastcmd=0x%2.2uX ", cp->cmd, cp->lastcmd); . 2018c print("cmd=0x%2.2uX, lastcmd=0x%2.2uX ", cp->cmd, cp->lastcmd); . 1988c DPRINT("atapipart: cmd 0x%uX error 0x%uX\n", cp->cmdblk[0], cp->error); . 1828c DPRINT("%s: Bad packet command 0x%ux, error 0x%ux\n", dp->vol, cp->cmdblk[0], cp->error); . ## diffname pc/devata.c 1998/1006 ## diff -e /n/emeliedump/1998/0922/sys/src/brazil/pc/devata.c /n/emeliedump/1998/1006/sys/src/brazil/pc/devata.c 1615c panic("ata%d: wait busy\n", cp->ctlrno); . 397d ## diffname pc/devata.c 1998/1007 ## diff -e /n/emeliedump/1998/1006/sys/src/brazil/pc/devata.c /n/emeliedump/1998/1007/sys/src/brazil/pc/devata.c 2095c print("%s: Cpktcmd status=0x%uX, error=0x%uX\n", . 2088a microdelay(1); . 2059c DPRINT("%s: atapiintr 0x%uX\n", cp->dp->vol, cause); . 1889c DPRINT("atapiio: cmd 0x%uX error 0x%uX\n", cp->cmdblk[0], cp->error); . 1827c DPRINT("%s: Bad packet command 0x%uX, error 0x%uX\n", . 1803a microdelay(1); . 1764c DPRINT("%s: isatapi cyl 0x%uX 0x%uX\n", . 1760c DPRINT("%s: isatapi status 0x%uX\n", dp->vol, inb(cp->pbase+Pstatus)); . 1753c DPRINT("%s: isatapi ctlrwait status 0x%uX\n", dp->vol, inb(cp->pbase+Pstatus)); . 1690a DPRINT("Cident2\n"); . 1675,1677c //if(cp->cmd != Cread) // cp->cmd = Cident2; //else . 1655a microdelay(1); . 1651c print("%s: read/ident cmd=0x%uX status=0x%uX\n", . 1633a microdelay(1); } . 1630c while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0){ . 1615a microdelay(1); . 1614c panic("%s: wait busy\n", dp->vol); . 1612c print("ata%d: cmd=0x%uX, lastcmd=0x%uX status=0x%uX\n", . 1346c DPRINT("%s: probe err: status 0x%uX, err 0x%uX\n", . 1243,1244c //if (cp->cmd == Cident2) // tsleep(&cp->r, return0, 0, Hardtimeout); . 1218c DPRINT("%s: ident command 0x%uX sent\n", dp->vol, cmd); . 1129c DPRINT("%s: setbuf err: status 0x%uX, err 0x%uX\n", . 1080c DPRINT("%s err: lblk %ld status 0x%uX, err 0x%uX\n", . 1050a } . 1048c while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0){ microdelay(1); . 565c DPRINT("ata%d: opt spindownmask 0x%uX\n", ctlrno, spindownmask); . 500c //skipedd: . 492c DPRINT("ata%d: ATAPI slave 0x%uX 0x%uX 0x%uX\n", ctlrno, status, . 486c DPRINT("ata%d: slave diag status 0x%uX, error 0x%uX\n", ctlr->ctlrno, status, error); . 476c DPRINT("ata%d: master diag status 0x%uX, error 0x%uX\n", . 438c DPRINT("ata%d: Cedd status 0x%uX/0x%uX/0x%uX\n", ctlrno, . 427c DPRINT("ata%d: ATAPI 0x%uX 0x%uX 0x%uX\n", ctlrno, status, . 417c DPRINT("ata%d: Srst status 0x%uX/0x%uX/0x%uX\n", ctlrno, . 396a . 386c DPRINT("ata%d: DHmagic not ok == 0x%uX\n", ctlrno, status); . 338c DPRINT("ata%d: ctlrwait failed 0x%uX\n", ctlr->ctlrno, status); . ## diffname pc/devata.c 1998/1101 ## diff -e /n/emeliedump/1998/1007/sys/src/brazil/pc/devata.c /n/emeliedump/1998/1101/sys/src/brazil/pc/devata.c 427a status = inb(port+Pstatus); . 420a return -1; . 397d ## diffname pc/devata.c 1998/1126 ## diff -e /n/emeliedump/1998/1101/sys/src/brazil/pc/devata.c /n/emeliedump/1998/1126/sys/src/brazil/pc/devata.c 2136c atareset, . 2126c cp->error = inb(cp->cmdport+Perror); . 2118c inss(cmdport+Pdata, cp->buf+cp->count, count/2); . 2116c outss(cmdport+Pdata, cp->buf+cp->count, count/2); . 2112c count = inb(cmdport+Pcyllsb)|(inb(cmdport+Pcylmsb)<<8); . 2106c cp->error = inb(cmdport+Perror); . 2101c cp->status = inb(cmdport+Pstatus); . 2090c cp->error = inb(cmdport+Perror); . 2081c outss(cmdport+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2); . 2077c cp->error = inb(cmdport+Perror); . 2068,2069c cmdport = cp->cmdport; cause = inb(cmdport+Pcount) & 0x03; . 2066c int count, loop, cmdport; . 1820c outss(cp->cmdport+Pdata, cp->cmdblk, sizeof(cp->cmdblk)/2); . 1818c dp->vol, cp->cmd, inb(cp->cmdport+Pstatus)); . 1813c for(loop = 0; (inb(cp->cmdport+Pstatus) & (Serr|Sdrq)) == 0; loop++){ . 1803,1809c outb(cp->cmdport+Pcount, 0); outb(cp->cmdport+Psector, 0); outb(cp->cmdport+Pfeature, 0); outb(cp->cmdport+Pcyllsb, cp->len); outb(cp->cmdport+Pcylmsb, cp->len>>8); outb(cp->cmdport+Pdh, dp->dh); outb(cp->cmdport+Pcmd, cp->cmd); . 1775c dp->vol, inb(cp->cmdport+Pcylmsb), inb(cp->cmdport+Pcyllsb)); . 1773c if(inb(cp->cmdport+Pcylmsb) != 0xEB || inb(cp->cmdport+Pcyllsb) != 0x14){ . 1769,1770c if(inb(cp->cmdport+Pstatus)){ DPRINT("%s: isatapi status 0x%uX\n", dp->vol, inb(cp->cmdport+Pstatus)); . 1763c DPRINT("%s: isatapi ctlrwait status 0x%uX\n", dp->vol, inb(cp->cmdport+Pstatus)); . 1761c outb(cp->cmdport+Pcmd, 0x08); . 1759c outb(cp->cmdport+Pdh, dp->dh); . 1744,1746c outb(cp->cmdport+Pcount, 0); outb(cp->cmdport+Pdh, dp->dh); outb(cp->cmdport+Pcmd, cp->cmd); . 1715c cp->ctlrno, cp->error, inb(cp->cmdport+Pcount)); . 1711c cp->error = inb(cp->cmdport+Perror); . 1688c inb(cp->cmdport+Pstatus); . 1677c inss(cp->cmdport+Pdata, addr, dp->bytes/2); . 1670c cp->error = inb(cp->cmdport+Perror); . 1665c cp->status = inb(cp->cmdport+Pstatus); . 1660c dp->vol, cp->cmd, inb(cp->cmdport+Pstatus)); . 1645c outss(cp->cmdport+Pdata, addr, dp->bytes/2); . 1639c dp->vol, cp->cmd, inb(cp->cmdport+Pstatus)); . 1636c while(((cp->status = inb(cp->cmdport+Pstatus)) & Sdrq) == 0){ . 1629c cp->error = inb(cp->cmdport+Perror); . 1618c cp->ctlrno, cp->cmd, cp->lastcmd, inb(cp->cmdport+Pstatus)); . 1615c while((cp->status = inb(cp->cmdport+Pstatus)) & Sbusy){ . 1340,1345c outb(cp->cmdport+Pcount, 1); outb(cp->cmdport+Psector, sec+1); outb(cp->cmdport+Pdh, dp->dh | (dp->lba<<6) | head); outb(cp->cmdport+Pcyllsb, cyl); outb(cp->cmdport+Pcylmsb, cyl>>8); outb(cp->cmdport+Pcmd, Cread); . 1276,1277c XPRINT("%s: %d/%d/%d changed to %ld/%d/%d CHS\n", dp->vol, ip->cyls, ip->heads, ip->s2t, dp->cyl, dp->heads, dp->sectors); . 1219,1220c outb(cp->cmdport+Pdh, dp->dh); outb(cp->cmdport+Pcmd, cmd); . 1126,1128c outb(cp->cmdport+Pfeature, arg); outb(cp->cmdport+Pdh, dp->dh); outb(cp->cmdport+Pcmd, Cfeature); . 1056c outss(cp->cmdport+Pdata, cp->buf, dp->bytes/2); . 1051c while((stat = inb(cp->cmdport+Pstatus) & (Serr|Sdrq)) == 0){ . 1041,1046c outb(cp->cmdport+Pcount, cp->nsecs); outb(cp->cmdport+Psector, sec); outb(cp->cmdport+Pdh, dp->dh | (dp->lba<<6) | head); outb(cp->cmdport+Pcyllsb, cyl); outb(cp->cmdport+Pcylmsb, cyl>>8); outb(cp->cmdport+Pcmd, cmd); . 562a ctlrno++; . 561c if(atactlrprobe(ctlrno, devp, isa.irq, resetok)) . 557c else if(cistrcmp(isa.opt[i], "reset") == 0) . 542c if(cistrncmp(isa.opt[i], "spindown", 8) == 0){ . 536c if(isa.irq == 0 && (isa.irq = devp->irq) == 0) . 534c isaconfig("ata", ctlrno, &isa); if(isa.port && isa.port != devp->cmdport) . 529,532c ctlrno = 0; for(devno = 0; devno < natadev; devno++){ devp = &atadev[devno]; . 527a Atadev *devp; . 526c int ctlrno, devno, driveno, i, resetok, slave, spindown; . 519a print("#H%d: cmdport 0x%uX ctlport 0x%uX irq %d mask 0x%uX atapi 0x%uX\n", ctlrno, cmdport, ctlport, irq, mask, atapi); intrenable(irq, ataintr, ctlr, ctlr->tbdf); inb(cmdport+Pstatus); outb(ctlport+Pctl, 0); if(devp->ienable) devp->ienable(devp); . 503c //skipslave: . 501a outb(cmdport+Pdh, DHmagic); . 496c inb(cmdport+Pcylmsb), inb(cmdport+Pcyllsb)); . 493,494c msb = inb(cmdport+Pcylmsb); lsb = inb(cmdport+Pcyllsb); . 486,487c status = inb(cmdport+Pstatus); error = inb(cmdport+Perror); . 484c outb(cmdport+Pdh, DHmagic|DHslave); . 479c ctlr->ctlrno, inb(cmdport+Pstatus), error); . 477c error = inb(cmdport+Perror); . 453,455c outb(cmdport+Pcmd, Cedd); microdelay(1); status = inb(cmdport+Pstatus); if(!(status & Sbusy)){ DPRINT("ata%d: !busy 1 0x%uX\n", ctlrno, status); xfree(ctlr); return -1; } for(timo = 6000; timo; timo--){ status = inb(cmdport+Pstatus); if(!(status & Sbusy)) break; delay(1); } DPRINT("ata%d: timo %d\n", ctlrno, 6000-timo); status = inb(cmdport+Pstatus); if(status & Sbusy){ DPRINT("ata%d: busy 2 0x%uX\n", ctlrno, status); xfree(ctlr); return -1; } . 450,451c /* * Can only get here if controller is not busy. * If there are drives Sbusy will be set within 400nS. * Wait for the command to complete (6 seconds max). */ . 441c inb(cmdport+Pstatus), inb(cmdport+Pcylmsb), inb(cmdport+Pcyllsb)); . 439c if(atactlrwait(ctlr, DHmagic, 0, MS2TK(1))){ . 433,434d 430,431c inb(cmdport+Pcylmsb), inb(cmdport+Pcyllsb)); USED(status); if(/*status == 0 &&*/ inb(cmdport+Pcylmsb) == 0xEB && inb(cmdport+Pcyllsb) == 0x14){ . 428c status = inb(cmdport+Pstatus); . 423a /* * Disable interrupts. */ outb(ctlport+Pctl, nIEN); . 418c inb(cmdport+Pstatus), inb(cmdport+Pcylmsb), inb(cmdport+Pcyllsb)); . 415c outb(ctlport+Pctl, 0); . 412,413c if(resetok && ctlport){ outb(ctlport+Pctl, Srst|nIEN); . 403,406d 392c ctlr->cmdport = cmdport; ctlr->ctlport = ctlport; . 386c DPRINT("ata%d: DHmagic not ok == 0x%uX, 0x%uX\n", ctlrno, status, inb(cmdport+Pstatus)); . 381,384c DPRINT("ata%d: port 0x%uX\n", ctlrno, cmdport); outb(cmdport+Pdh, DHmagic); for(timo = 30000; timo; timo--){ microdelay(1); status = inb(cmdport+Pdh); if(status == DHmagic) break; } status = inb(cmdport+Pdh); . 377,378d 373a cmdport = devp->cmdport; ctlport = devp->ctlport; . 371c int atapi, cmdport, ctlport, mask, once, timo; . 368c atactlrprobe(int ctlrno, Atadev* devp, int irq, int resetok) . 321c port = ctlr->cmdport; . 301,311c p = nil; while(p = pcimatch(p, 0, 0)){ if(p->vid == 0x1095 && p->did == 0x0640){ /* * CMD640B dual PCI controllers. Amongst other * bugs only one of the controllers can be active at a time. * Unfortunately there's no way to tell which pair of * controllers this is, so if one is found then all controller * pairs are synchronised. */ have640b++; /* * Make sure read-ahead is disabled on all * drives and that the 2nd controller is enabled: * reg 0x51: bit 7 - drive 1 read ahead disable * bit 6 - drive 0 read ahead disable * bit 3 - 2nd controller enable * reg 0x57: bit 3 - drive 1 read ahead disable * bit 2 - drive 0 read ahead disable */ r = pcicfgr8(p, 0x51); r |= 0xC8; pcicfgw8(p, 0x51, r); r = pcicfgr8(p, 0x57); r |= 0x0C; pcicfgw8(p, 0x57, r); } else if(p->vid == 0x1042 && (p->did == 0x1000 || p->did == 0x1001)){ /* * PC-Tech RZ1000 controllers. * Turn off prefetch. * This is overkill, but cheap. */ r = pcicfgr32(p, 0x40); r &= ~0x2000; pcicfgw32(p, 0x40, r); } else if(p->vid == 0x100B && p->did == 0x0002){ /* * National Semiconductor PC87415. * Disable interrupts on both channels until * after they are probed for drives. * This must be called before interrupts are * enabled in case the IRQ is being shared. */ pcicfgw32(p, 0x40, 0x00000300); /* * Add any native-mode channels to the list to * be probed. */ ccrp = pcicfgr8(p, PciCCRp); if((ccrp & 0x01) && natadev < nelem(atadev)){ atadev[natadev].cmdport = p->mem[0].bar & ~0x01; atadev[natadev].ctlport = p->mem[1].bar & ~0x01; atadev[natadev].irq = p->intl; atadev[natadev].p = p; atadev[natadev].ienable = pc87415ienable; natadev++; } if((ccrp & 0x04) && natadev < nelem(atadev)){ atadev[natadev].cmdport = p->mem[2].bar & ~0x01; atadev[natadev].ctlport = p->mem[3].bar & ~0x01; atadev[natadev].irq = p->intl; atadev[natadev].p = p; atadev[natadev].ienable = pc87415ienable; natadev++; } } . 299c int ccrp, r; . 296c atareset(void) . 267,292c p = devp->p; if(p == nil) return; x = pcicfgr32(p, 0x40); if(devp->cmdport == (p->mem[0].bar & ~0x01)) x &= ~0x00000100; else x &= ~0x00000200; pcicfgw32(p, 0x40, x); . 265c int x; . 262c pc87415ienable(Atadev* devp) . 209,211c static int natadev = 4; . 206,207c typedef struct Atadev Atadev; typedef struct Atadev { int cmdport; int ctlport; int irq; Pcidev* p; void (*ienable)(Atadev*); } Atadev; static void pc87415ienable(Atadev*); static Atadev atadev[NCtlr] = { { 0x1F0, 0x3F4, 14, }, /* primary */ { 0x170, 0x374, 15, }, /* secondary */ { 0x1E8, 0x3EC, 0, }, /* tertiary */ { 0x168, 0x36C, 0, }, /* quaternary */ . 178c int cmdport; /* base port */ int ctlport; . 89c NCtlr= 8, /* not really */ . 53c Pctl= 2, /* device control, alternate status */ . 30,33d 4a * The PCI hacks are truly awful. . ## diffname pc/devata.c 1999/0324 ## diff -e /n/emeliedump/1998/1126/sys/src/brazil/pc/devata.c /n/emeliedump/1999/0324/sys/src/brazil/pc/devata.c 936a if(off < 0) error(Ebadarg); . 867a if(off < 0) error(Ebadarg); . ## diffname pc/devata.c 1999/0714 ## diff -e /n/emeliedump/1999/0324/sys/src/brazil/pc/devata.c /n/emeliedump/1999/0714/sys/src/brazil/pc/devata.c 590a xfree(ctlr); return -1; } sprint(name, "ata%dcmd", ctlrno); if(ioalloc(devp->cmdport, 0x8, 0, name) < 0){ print("#H%d: cmd port %d in use", ctlrno, devp->cmdport); xfree(ctlr); return -1; } sprint(name, "ata%dctl", ctlrno); if(ioalloc(devp->ctlport+Pctl, 1, 0, name) < 0){ iofree(devp->cmdport); print("#H%d: ctl port %d in use", ctlrno, devp->ctlport); . 427a char name[13]; . ## diffname pc/devata.c 1999/0819 ## diff -e /n/emeliedump/1999/0714/sys/src/brazil/pc/devata.c /n/emeliedump/1999/0819/sys/src/brazil/pc/devata.c 622c snprint(name, sizeof name, "ata%d", ctlrno); intrenable(irq, ataintr, ctlr, ctlr->tbdf, name); . ## diffname pc/devata.c 1999/1230 ## diff -e /n/emeliedump/1999/0819/sys/src/brazil/pc/devata.c /n/emeliedump/1999/1230/sys/src/9/pc/devata.c 250a if(s == DEVDOTDOT){ devdir(c, (Qid){CHDIR, 0}, "#H", 0, eve, 0555, dirp); return 1; } . ## diffname pc/devata.c 2000/0308 ## diff -e /n/emeliedump/1999/1230/sys/src/9/pc/devata.c /n/emeliedump/2000/0308/sys/src/9/pc/devata.c 1692c if(getfields(line[i], field, 3, 1, " ") != 3) . 1684c n = getfields((char*)buf, line, Npart+1, 1, "\n"); . 1672c n = getfields((char*)buf, line, Npart+1, 1, "\n"); . 1666c n = getfields((char*)buf, line, Npart+1, 1, "\n"); . 1590c if(getfields(line[i], field, 1, 1, " ") != 1) . 1585c n = getfields((char*)buf, line, Nrepl+1, 1, "\n"); . ## diffname pc/devata.c 2000/0517 # deleted ## diff -e /n/emeliedump/2000/0308/sys/src/9/pc/devata.c /n/emeliedump/2000/0517/sys/src/9/pc/devata.c 1,2275d