summaryrefslogtreecommitdiff
path: root/os/mpc/devata.c
diff options
context:
space:
mode:
authorKonstantin Kirik (snegovick) <snegovick@uprojects.org>2025-12-28 12:27:31 +0300
committerKonstantin Kirik (snegovick) <snegovick@uprojects.org>2025-12-28 12:27:31 +0300
commit78ee7d5717807e6ac779293d0d3c78341de6130a (patch)
treea43e3b0f61318ac45e6d907c7cc5bad2c6d7f497 /os/mpc/devata.c
parentbdaf46cf45bbb59261da245d548a179d95a42768 (diff)
Move existing boards into subdits split per arch
Diffstat (limited to 'os/mpc/devata.c')
-rw-r--r--os/mpc/devata.c1194
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,
-};