diff options
| author | Konstantin Kirik (snegovick) <snegovick@uprojects.org> | 2025-12-28 12:27:31 +0300 |
|---|---|---|
| committer | Konstantin Kirik (snegovick) <snegovick@uprojects.org> | 2025-12-28 12:27:31 +0300 |
| commit | 78ee7d5717807e6ac779293d0d3c78341de6130a (patch) | |
| tree | a43e3b0f61318ac45e6d907c7cc5bad2c6d7f497 /os/mpc/devata.c | |
| parent | bdaf46cf45bbb59261da245d548a179d95a42768 (diff) | |
Move existing boards into subdits split per arch
Diffstat (limited to 'os/mpc/devata.c')
| -rw-r--r-- | os/mpc/devata.c | 1194 |
1 files changed, 0 insertions, 1194 deletions
diff --git a/os/mpc/devata.c b/os/mpc/devata.c deleted file mode 100644 index 69665e38..00000000 --- a/os/mpc/devata.c +++ /dev/null @@ -1,1194 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" - -#include "pcmcia.h" - -#define DPRINT if(0)print - -typedef struct Drive Drive; -typedef struct Ident Ident; -typedef struct Controller Controller; -typedef struct Partition Partition; -typedef struct Repl Repl; - -enum -{ - /* ports */ - Pbase= 0x1F0, - Pdata= 0, /* data port (16 bits) */ - Perror= 1, /* error port (read) */ - Pprecomp= 1, /* buffer mode port (write) */ - Pcount= 2, /* sector count port */ - Psector= 3, /* sector number port */ - Pcyllsb= 4, /* least significant byte cylinder # */ - Pcylmsb= 5, /* most significant byte cylinder # */ - Pdh= 6, /* drive/head port */ - Pstatus= 7, /* status port (read) */ - Sbusy= (1<<7), - Sready= (1<<6), - Sdrq= (1<<3), - Serr= (1<<0), - Pcmd= 7, /* cmd port (write) */ - - /* commands */ - Crecal= 0x10, - Cread= 0x20, - Cwrite= 0x30, - Cident= 0xEC, - Cident2= 0xFF, /* pseudo command for post Cident interrupt */ - Csetbuf= 0xEF, - Cinitparam= 0x91, - - /* conner specific commands */ - Cstandby= 0xE2, - Cidle= 0xE1, - Cpowerdown= 0xE3, - - /* disk states */ - Sspinning, - Sstandby, - Sidle, - Spowerdown, - - /* something we have to or into the drive/head reg */ - DHmagic= 0xA0, - - /* file types */ - Qdir= 0, - - Maxxfer= BY2PG, /* maximum transfer size/cmd */ - Npart= 8+2, /* 8 sub partitions, disk, and partition */ - Nrepl= 64, /* maximum replacement blocks */ -}; -#define PART(x) ((x)&0xF) -#define DRIVE(x) (((x)>>4)&0x7) -#define MKQID(d,p) (((d)<<4) | (p)) - -struct Partition -{ - ulong start; - ulong end; - char name[NAMELEN+1]; -}; - -struct Repl -{ - Partition *p; - int nrepl; - ulong blk[Nrepl]; -}; - -#define PARTMAGIC "plan9 partitions" -#define REPLMAGIC "block replacements" - -/* - * an ata drive - */ -struct Drive -{ - QLock; - - Controller *cp; - int drive; - int confused; /* needs to be recalibrated (or worse) */ - int online; - int npart; /* number of real partitions */ - Partition p[Npart]; - Repl repl; - ulong usetime; - int state; - char vol[NAMELEN]; - - ulong cap; /* total bytes */ - int bytes; /* bytes/sector */ - int sectors; /* sectors/track */ - int heads; /* heads/cyl */ - long cyl; /* cylinders/drive */ - - char lba; /* true if drive has logical block addressing */ - char multi; /* non-zero if drive does multiple block xfers */ -}; - -/* - * a controller for 2 drives - */ -struct Controller -{ - QLock; /* exclusive access to the controller */ - ISAConf; /* interface to pcmspecial */ - - Lock reglock; /* exclusive access to the registers */ - - int confused; /* needs to be recalibrated (or worse) */ - ulong pbase; /* base port (copied from ISAConf) */ - - /* - * current operation - */ - int cmd; /* current command */ - int lastcmd; /* debugging info */ - Rendez r; /* wait here for command termination */ - char *buf; /* xfer buffer */ - int nsecs; /* length of transfer (sectors) */ - int sofar; /* sectors transferred so far */ - int status; - int error; - Drive *dp; /* drive being accessed */ -}; - -Controller *atac; -Drive *ata; -static char* ataerr; -static int nhard; -static int spindowntime; - -static void ataintr(Ureg*, void*); -static long ataxfer(Drive*, Partition*, int, long, long, char*); -static void ataident(Drive*); -static void atasetbuf(Drive*, int); -static void ataparams(Drive*); -static void atapart(Drive*); -static int ataprobe(Drive*, int, int, int); - -static int -atagen(Chan *c, Dirtab*, int, int s, Dir *dirp) -{ - Qid qid; - int drive; - Drive *dp; - Partition *pp; - ulong l; - - qid.vers = 0; - drive = s/Npart; - s = s % Npart; - if(drive >= nhard) - return -1; - dp = &ata[drive]; - - if(dp->online == 0 || s >= dp->npart) - return 0; - - pp = &dp->p[s]; - sprint(up->genbuf, "%s%s", dp->vol, pp->name); - qid.path = MKQID(drive, s); - l = (pp->end - pp->start) * dp->bytes; - devdir(c, qid, up->genbuf, l, eve, 0660, dirp); - return 1; -} - -static void -atainit(void) -{ - Drive *dp; - Controller *cp; - uchar equip; - int pcmslot; - - if (atac) - return; /* already done */ - - equip = 0x10; /* hard coded */ - - print("ata init\n"); - cp = malloc(sizeof(*cp)); - if (!cp) - error(Enomem); - - cp->port = Pbase; - cp->irq = 14; - - if((pcmslot = pcmspecial("SunDisk", cp)) < 0) { - print("No ATA card\n"); - free(cp); - ataerr = Enoifc; - return; - } - ata = malloc(2 * sizeof(*ata)); - if(ata == nil) { - pcmspecialclose(pcmslot); - free(cp); - error(Enomem); - } - - atac = cp; - cp->buf = 0; - cp->lastcmd = cp->cmd; - cp->cmd = 0; - cp->pbase = cp->port; - pcmintrenable(pcmslot, ataintr, cp); - - dp = ata; - if(equip & 0xf0){ - dp->drive = 0; - dp->online = 0; - dp->cp = cp; - dp++; - } - if((equip & 0x0f)){ - dp->drive = 1; - dp->online = 0; - dp->cp = cp; - dp++; - } - nhard = dp - ata; - - spindowntime = 1; -} - - -/* - * Get the characteristics of each drive. Mark unresponsive ones - * off line. - */ -static Chan* -ataattach(char *spec) -{ - Drive *dp; - - atainit(); - if (!ata) - error(ataerr ? ataerr : Enoifc); - for(dp = ata; dp < &ata[nhard]; dp++){ - if(waserror()){ - dp->online = 0; - qunlock(dp); - continue; - } - qlock(dp); - if(!dp->online){ - /* - * Make sure ataclock() doesn't - * interfere. - */ - dp->usetime = m->ticks; - ataparams(dp); - dp->online = 1; - atasetbuf(dp, 1); - } - - /* - * read Plan 9 partition table - */ - atapart(dp); - qunlock(dp); - poperror(); - } - return devattach('H', spec); -} - -static int -atawalk(Chan *c, char *name) -{ - return devwalk(c, name, 0, 0, atagen); -} - -static void -atastat(Chan *c, char *dp) -{ - devstat(c, dp, 0, 0, atagen); -} - -static Chan* -ataopen(Chan *c, int omode) -{ - return devopen(c, omode, 0, 0, atagen); -} - -static void -ataclose(Chan *c) -{ - Drive *d; - Partition *p; - - if(c->mode != OWRITE && c->mode != ORDWR) - return; - - d = &ata[DRIVE(c->qid.path)]; - p = &d->p[PART(c->qid.path)]; - if(strcmp(p->name, "partition") != 0) - return; - - if(waserror()){ - qunlock(d); - nexterror(); - } - qlock(d); - atapart(d); - qunlock(d); - poperror(); -} - -static long -ataread(Chan *c, void *a, long n, vlong offset) -{ - Drive *dp; - long rv, i; - int skip; - uchar *aa = a; - Partition *pp; - char *buf; - - if(c->qid.path == CHDIR) - return devdirread(c, a, n, 0, 0, atagen); - - buf = smalloc(Maxxfer); - if(waserror()){ - free(buf); - nexterror(); - } - - dp = &ata[DRIVE(c->qid.path)]; - pp = &dp->p[PART(c->qid.path)]; - - skip = offset % dp->bytes; - for(rv = 0; rv < n; rv += i){ - i = ataxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf); - if(i == 0) - break; - i -= skip; - if(i > n - rv) - i = n - rv; - memmove(aa+rv, buf + skip, i); - skip = 0; - } - - free(buf); - poperror(); - - return rv; -} - -static long -atawrite(Chan *c, void *a, long n, vlong offset) -{ - Drive *dp; - long rv, i, partial; - uchar *aa = a; - Partition *pp; - char *buf; - - if(c->qid.path == CHDIR) - error(Eisdir); - - dp = &ata[DRIVE(c->qid.path)]; - pp = &dp->p[PART(c->qid.path)]; - buf = smalloc(Maxxfer); - if(waserror()){ - free(buf); - nexterror(); - } - - /* - * if not starting on a sector boundary, - * read in the first sector before writing - * it out. - */ - partial = offset % dp->bytes; - if(partial){ - ataxfer(dp, pp, Cread, offset-partial, dp->bytes, buf); - if(partial+n > dp->bytes) - rv = dp->bytes - partial; - else - rv = n; - memmove(buf+partial, aa, rv); - ataxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf); - } else - rv = 0; - - /* - * write out the full sectors - */ - partial = (n - rv) % dp->bytes; - n -= partial; - for(; rv < n; rv += i){ - i = n - rv; - if(i > Maxxfer) - i = Maxxfer; - memmove(buf, aa+rv, i); - i = ataxfer(dp, pp, Cwrite, offset+rv, i, buf); - if(i == 0) - break; - } - - /* - * if not ending on a sector boundary, - * read in the last sector before writing - * it out. - */ - if(partial){ - ataxfer(dp, pp, Cread, offset+rv, dp->bytes, buf); - memmove(buf, aa+rv, partial); - ataxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf); - rv += partial; - } - - free(buf); - poperror(); - - return rv; -} - -/* - * did an interrupt happen? - */ -static int -cmddone(void *a) -{ - Controller *cp = a; - - return cp->cmd == 0; -} - -/* - * Wait for the controller to be ready to accept a command. - * This is protected from intereference by ataclock() by - * setting dp->usetime before it is called. - */ -static void -cmdreadywait(Drive *dp) -{ - long start; - int period; - Controller *cp = dp->cp; - - /* give it 2 seconds to spin down and up */ - if(dp->state == Sspinning) - period = 10; - else - period = 2000; - - start = m->ticks; - while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready) - if(TK2MS(m->ticks - start) > period){ - DPRINT("cmdreadywait failed\n"); - error(Eio); - } -} - -static void -atarepl(Drive *dp, long bblk) -{ - int i; - - if(dp->repl.p == 0) - return; - for(i = 0; i < dp->repl.nrepl; i++){ - if(dp->repl.blk[i] == bblk) - DPRINT("found bblk %ld at offset %ld\n", bblk, i); - } -} - -static void -atasleep(Controller *cp, int ms) -{ - tsleep(&cp->r, cmddone, cp, ms); - if(cp->cmd && cp->cmd != Cident2){ - DPRINT("ata: cmd 0x%uX timeout, status=%lux\n", - cp->cmd, inb(cp->pbase+Pstatus)); - error("ata drive timeout"); - } -} - -/* - * transfer a number of sectors. ataintr will perform all the iterative - * parts. - */ -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); - } - - DPRINT("<%s %d>", (cmd == Cwrite) ? "W" : "R", lblk); - 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->reglock); - 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, DHmagic | (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; - microdelay(1); - 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->reglock); - - 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(); - } - } - atasleep(cp, 3000); - 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->reglock); - cp->cmd = Csetbuf; - outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55); /* read look ahead */ - outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); - outb(cp->pbase+Pcmd, Csetbuf); - iunlock(&cp->reglock); - - atasleep(cp, 5000); - -/* 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()){ - cp->buf = 0; - qunlock(cp); - free(buf); - nexterror(); - } - - cmdreadywait(dp); - - ilock(&cp->reglock); - cp->nsecs = 1; - cp->sofar = 0; - cp->cmd = Cident; - cp->dp = dp; - cp->buf = buf; - outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); - outb(cp->pbase+Pcmd, Cident); - iunlock(&cp->reglock); - - atasleep(cp, 5000); - 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("\nata%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("\nata%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->reglock); - 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, DHmagic | head | (dp->lba<<6) | (dp->drive<<4)); - outb(cp->pbase+Pcyllsb, cyl); - outb(cp->pbase+Pcylmsb, cyl>>8); - outb(cp->pbase+Pcmd, Cread); - iunlock(&cp->reglock); - - atasleep(cp, 5000); - - 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)-1, (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. - */ - 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, 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, " ") != 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; - pp++; - 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, dp->p+1, Cread, 0, dp->bytes, buf); - buf[dp->bytes-1] = 0; - n = getfields(buf, line, Npart+1, 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(buf, line, Npart+1, 1, "\n"); - } - - /* - * parse partition table. - */ - if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ - for(i = 1; i < n; i++){ - switch(getfields(line[i], field, 3, 1, " ")) { - 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->end > dp->p[0].end) - break; - dp->npart++; - pp++; - } - } - } - free(buf); - poperror(); - - if(dp->repl.p) - atareplinit(dp); -} - -enum -{ - Maxloop= 10000, -}; - -/* - * we get an interrupt for every sector transferred - */ -static void -ataintr(Ureg*, void *arg) -{ - Controller *cp; - Drive *dp; - long loop; - char *addr; - - cp = arg; - dp = cp->dp; - - ilock(&cp->reglock); - - loop = 0; - while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ - if(++loop > Maxloop) { - 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 > Maxloop) { - 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 > Maxloop) { - 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->reglock); -} - -void -hardclock(void) -{ - int drive; - Drive *dp; - Controller *cp; - int diff; - - if(spindowntime <= 0) - return; - - for(drive = 0; drive < nhard; drive++){ - dp = &ata[drive]; - cp = dp->cp; - - diff = TK2SEC(m->ticks - dp->usetime); - if((dp->state == Sspinning) && (diff >= spindowntime)){ - ilock(&cp->reglock); - cp->cmd = Cstandby; - outb(cp->pbase+Pcount, 0); - outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | 0); - outb(cp->pbase+Pcmd, cp->cmd); - iunlock(&cp->reglock); - dp->state = Sstandby; - } - } -} - -Dev atadevtab = { - 'H', - "ata", - - devreset, - atainit, - ataattach, - devdetach, - devclone, - atawalk, - atastat, - ataopen, - devcreate, - ataclose, - ataread, - devbread, - atawrite, - devbwrite, - devremove, - devwstat, -}; |
