esleep(ms);
}
-static int
+static void
ahciportreset(Aportc *c, uint mode)
{
ulong *cmd, i;
p->sctl = 3*Aipm | 0*Aspd | Adet;
delay(1);
p->sctl = 3*Aipm | mode*Aspd;
- return 0;
}
static int
}
}
-static int
-intel(Ctlr *c)
-{
- return c->pci->vid == 0x8086;
-}
-
static int
ignoreahdrs(Drive *d)
{
enum {
Nms = 256,
+ Mcomrwait = 1*1024/Nms - 1,
Mphywait = 2*1024/Nms - 1,
Midwait = 16*1024/Nms - 1,
- Mcomrwait = 64*1024/Nms - 1,
};
static void
else
d->mode--;
if(d->mode == DMautoneg){
+ d->wait = 0;
d->state = Dportreset;
goto portreset;
}
case Doffline:
if(d->wait++ & Mcomrwait)
break;
- /* fallthrough */
case Derror:
case Dreset:
dprint("%s: reset [%s]: mode %d; status %.3ux\n",
break;
case Dportreset:
portreset:
- if(d->wait++ & 0xff && (s & Iactive) == 0)
+ if(d->wait++ & Mcomrwait)
+ break;
+ if(d->wait > Mcomrwait && (s & Iactive) == 0){
+ d->state = Dnull; /* stuck in portreset */
break;
+ }
dprint("%s: portreset [%s]: mode %d; status %.3ux\n",
dnam(d), diskstates[d->state], d->mode, s);
d->portm.flag |= Ferror;
ahciencreset(Ctlr *c)
{
Ahba *h;
+ int i;
if(c->enctype == Eesb)
return 0;
h = c->hba;
h->emctl |= Emrst;
- while(h->emctl & Emrst)
- delay(1);
- return 0;
+ for(i = 0; i < 1000; i++){
+ if((h->emctl & Emrst) == 0)
+ return 0;
+ esleep(1);
+ }
+ print("%s: ahciencreset: hung ctlr\n", Tname(c));
+ return -1;
}
/*
return 0;
c = d->ctlr;
h = c->hba;
+
/* ensure last message has been transmitted */
- while(h->emctl & Tmsg)
- microdelay(1);
+ if(h->emctl & Tmsg)
+ return -1;
+
switch(c->enctype){
default:
panic("%s: bad led type %d", dnam(d), c->enctype);
memset(map, 0, sizeof map);
for(i = 0; i < niactlr; i++)
if(iactlr[i].enctype != 0){
- ahciencreset(iactlr + i);
+ if(ahciencreset(iactlr + i) == -1)
+ continue;
map[i] = 1;
j++;
}
if(j == 0)
pexit("no work", 1);
for(i = 0; i < niadrive; i++){
- iadrive[i]->nled = 3; /* hardcoded */
- if(iadrive[i]->ctlr->enctype == Eesb)
- iadrive[i]->nled = 3;
- iadrive[i]->ledbits = -1;
+ d = iadrive[i];
+ d->nled = 3; /* hardcoded */
+ if(d->ctlr->enctype == Eesb)
+ d->nled = 3;
+ d->ledbits = -1;
}
for(i = 0; ; i++){
t0 = Ticks;
for(j = 0; j < niadrive; ){
- c = iadrive[j]->ctlr;
- if(map[j] == 0)
- j += c->enctype;
- else if(c->enctype == Eesb){
+ d = iadrive[j];
+ c = d->ctlr;
+ if(map[c - iactlr] == 0)
+ j++;
+ else
+ if(c->enctype == Eesb){
blinkesb(c, i);
j += c->ndrive;
}else{
- d = iadrive[j++];
blink(d, i);
+ j++;
}
}
t1 = Ticks;
c = s->ctlr;
ilock(c);
- if(!c->enabled){
- if(once == 0)
- kproc("iasata", satakproc, 0);
- if(c->ndrive == 0)
- panic("iaenable: zero s->ctlr->ndrive");
- pcisetbme(c->pci);
- snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
- intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
- /* supposed to squelch leftover interrupts here. */
- ahcienable(c->hba);
- c->enabled = 1;
- if(++once == niactlr)
- kproc("ialed", ledkproc, 0);
+ if(c->enabled){
+ iunlock(c);
+ return 1;
}
+ if(c->ndrive == 0)
+ panic("iaenable: zero s->ctlr->ndrive");
+ pcisetbme(c->pci);
+ snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
+ intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
+ /* supposed to squelch leftover interrupts here. */
+ ahcienable(c->hba);
+ c->enabled = 1;
iunlock(c);
+
+ if(once == 0)
+ kproc("iasata", satakproc, 0);
+ if(++once == niactlr)
+ kproc("ialed", ledkproc, 0);
+
return 1;
}
return r->status = SDeio;
}
-/*
- * configure drives 0-5 as ahci sata (c.f. errata)
- */
-static int
-iaahcimode(Pcidev *p)
-{
- uint u;
-
- u = pcicfgr16(p, 0x92);
- dprint("ahci: %T: iaahcimode %.2ux %.4ux\n", p->tbdf, pcicfgr8(p, 0x91), u);
- pcicfgw16(p, 0x92, u | 0xf); /* ports 0-15 */
- return 0;
-}
-
enum{
Ghc = 0x04/4, /* global host control */
Pi = 0x0c/4, /* ports implemented */
static void
iasetupahci(Ctlr *c)
{
+ if(c->type != Tich)
+ return;
+
pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~Cmddec);
pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~Cmddec);
c->lmmio[Ghc] |= Ahcien;
- c->lmmio[Pi] = (1 << 6) - 1; /* 5 ports (supposedly ro pi reg) */
+ c->lmmio[Pi] = (1 << 6) - 1; /* 6 ports (supposedly ro pi reg) */
/* enable ahci mode; from ich9 datasheet */
pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
+
+ /* configure drives 0-5 as ahci sata (c.f. errata) */
+ pcicfgw16(c->pci, 0x92, pcicfgr16(c->pci, 0x92) | 0xf);
}
static void
break;
case 0x1022:
/* Hudson SATA Controller [AHCI mode] */
- if(p->did == 0x7801)
+ if((p->did & 0xfffe) == 0x7800){
+ sbsetupahci(p);
return Tahci;
+ }
break;
case 0x10de:
case 0x1039:
while((p = pcimatch(p, 0, 0)) != nil){
if((type = didtype(p)) == -1)
continue;
- if(p->mem[Abar].bar == 0)
+ io = p->mem[Abar].bar;
+ if(io == 0 || (io & 1) != 0 || p->mem[Abar].size < 0x180)
continue;
+ io &= ~0xf;
if(niactlr == NCtlr){
print("iapnp: %s: too many controllers\n", tname[type]);
break;
s = sdevs + niactlr;
memset(c, 0, sizeof *c);
memset(s, 0, sizeof *s);
- io = p->mem[Abar].bar & ~0xf;
c->mmio = vmap(io, p->mem[Abar].size);
if(c->mmio == 0){
print("%s: address %#p in use did %.4ux\n",
s->ctlr = c;
c->sdev = s;
+ pcienable(p);
ahcihandoff((Ahba*)c->mmio);
- if(intel(c) && p->did != 0x2681)
+ if(p->vid == 0x8086)
iasetupahci(c);
-// ahcihbareset((Ahba*)c->mmio);
nunit = ahciconf(c);
- if(intel(c) && iaahcimode(p) == -1 || nunit < 1){
+ if(nunit < 1){
vunmap(c->mmio, p->mem[Abar].size);
+ pcidisable(p);
continue;
}
c->ndrive = s->nunit = nunit;
d->ctlr = c;
if((c->hba->pi & 1<<i) == 0)
continue;
- snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
- d->port = (Aport*)(c->mmio + 0x80*i + 0x100);
+ io = 0x100 + 0x80*i;
+ if((io + 0x80) > p->mem[Abar].size)
+ continue;
+ d->port = (Aport*)(c->mmio + io);
d->portc.p = d->port;
d->portc.m = &d->portm;
d->driveno = n++;
+ snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
c->drive[d->driveno] = d;
iadrive[niadrive + d->driveno] = d;
}