## 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<<dp->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<<driveno);
if((dp = atadrive[driveno]) == 0)
continue;
.
1183c
if((mask = spindownmask) == 0)
.
1178c
int driveno, mask;
.
1172c
IUNLOCK(&cp->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<<driveno);
DPRINT("ata%d: opt spindownmask %ux\n",
ctlrno, spindownmask);
}
else if(strcmp(isa.opt[i], "noatapi") == 0)
atactlr[ctlrno]->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<<driveno);
DPRINT("ata%d: opt spindownmask %ux\n", ctlrno, spindownmask);
.
530c
resetok = 1;
.
524,527c
driveno = ctlrno*2+slave;
.
517,519d
503,505c
driveno = resetok = spindown = 0;
.
490c
int ctlrno, driveno, i, resetok, slave, spindown;
.
390c
if(resetok){
.
362,363c
status = inb(port+Pdh) & 0xFF;
if(status != DHmagic){
DPRINT("ata%d: DHmagic not ok == %ux\n", ctlrno, status);
.
346c
atactlrprobe(int ctlrno, int irq, int resetok)
.
159d
14c
#define DPRINT if(1)print
.
## diffname pc/devata.c 1997/0818
## diff -e /n/emeliedump/1997/0815/sys/src/brazil/pc/devata.c /n/emeliedump/1997/0818/sys/src/brazil/pc/devata.c
14c
#define DPRINT if(0)print
.
## diffname pc/devata.c 1997/1230
## diff -e /n/emeliedump/1997/0818/sys/src/brazil/pc/devata.c /n/emeliedump/1997/1230/sys/src/brazil/pc/devata.c
1834a
DPRINT("%s: atapipart secs %ud, bytes %ud, cap %ud\n",
dp->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
|