ref: b7b2fea16f0da4d2da4cc8350dd914250d9b9c91
parent: f9b9cab6a17e446b243da154050a9d4b6b4dad15
author: cinap_lenrek <[email protected]>
date: Thu Dec 27 22:54:06 EST 2012
sdahci: get dvd drive to work with x301
--- a/sys/src/9/pc/sdiahci.c
+++ b/sys/src/9/pc/sdiahci.c
@@ -120,6 +120,7 @@
Ledport;
uchar drivechange;
+ uchar nodma;
uchar state;
uvlong sectors;
@@ -276,7 +277,7 @@
return -1;
}
-static void
+static Alist*
mkalist(Aportm *m, uint flags, uchar *data, int len)
{
Actab *t;
@@ -284,18 +285,19 @@
Aprdt *p;
t = m->ctab;
- l = m->list;
- l->flags = flags | 0x5;
- l->len = 0;
- l->ctab = PCIWADDR(t);
- l->ctabhi = Pciwaddrh(t);
- if(data){
- l->flags |= 1<<16;
+ if(data && len > 0){
p = &t->prdt;
p->dba = PCIWADDR(data);
p->dbahi = Pciwaddrh(data);
p->count = 1<<31 | len - 2 | 1;
+ flags |= 1<<16;
}
+ l = m->list;
+ l->flags = flags | 0x5;
+ l->len = 0;
+ l->ctab = PCIWADDR(t);
+ l->ctabhi = Pciwaddrh(t);
+ return l;
}
static int
@@ -631,7 +633,7 @@
for(i = 0; i < 1400; i += 50){
if((p->sstatus & Sbist) != 0)
break;
- if((p->sstatus & Sphylink) == Sphylink)
+ if((p->sstatus & Smask) == Sphylink)
break;
asleep(50);
}
@@ -644,7 +646,7 @@
p->ie = IEM;
/* we will get called again once phylink has been established */
- if((p->sstatus & Sphylink) != Sphylink)
+ if((p->sstatus & Smask) != Sphylink)
return 0;
/* disable power managment sequence from book. */
@@ -770,6 +772,7 @@
if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){
d->drivechange = 1;
+ d->nodma = 0;
u->sectors = 0;
}
return 0;
@@ -898,10 +901,8 @@
static void
configdrive(Drive *d)
{
- if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1){
+ if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1)
dstatus(d, Dportreset);
- return;
- }
ilock(d);
switch(d->port->sstatus & Smask){
@@ -1014,8 +1015,10 @@
hangck(Drive *d)
{
if(d->active && d->totick != 0 && (long)(Ticks - d->totick) > 0){
- dprint("%s: drive hung [task %lux; ci %lux; serr %lux]\n",
- dnam(d), d->port->task, d->port->ci, d->port->serror);
+ dprint("%s: drive hung [task %lux; ci %lux; serr %lux]%s\n",
+ dnam(d), d->port->task, d->port->ci, d->port->serror,
+ d->nodma == 0 ? "; disabling dma" : "");
+ d->nodma = 1;
d->state = Dreset;
}
}
@@ -1432,21 +1435,30 @@
{
ulong s, i, δ;
- for(i = 0; i < 15000; i += 250){
+ for(i = 0;; i += 250){
if(d->state == Dreset || d->state == Dportreset || d->state == Dnew)
return 1;
+ ilock(d);
+ s = d->port->sstatus;
+ if(d->state == Dready && (s & Smask) == Sphylink){
+ iunlock(d);
+ return 0;
+ }
δ = Ticks - d->lastseen;
if(d->state == Dnull || δ > 10*1000)
- return -1;
- s = d->port->sstatus;
+ break;
if((s & Imask) == 0 && δ > 1500)
+ break;
+ if(i >= 15*1000){
+ d->state = Doffline;
+ iunlock(d);
+ print("%s: not responding; offline\n", dnam(d));
return -1;
- if(d->state == Dready && (s & Smask) == Sphylink)
- return 0;
+ }
+ iunlock(d);
esleep(250);
}
- print("%s: not responding; offline\n", dnam(d));
- dstatus(d, Doffline);
+ iunlock(d);
return -1;
}
@@ -1467,16 +1479,7 @@
}
iunlock(d);
iunlock(c);
-
checkdrive(d, d->driveno); /* c->d0 + d->driveno */
-
- while(waitready(d) == 1)
- esleep(1);
-
- dprint("%s: iaveirfy: %s\n", dnam(d), diskstates[d->state]);
- if(d->portm.feat & Datapi)
- scsiverify(u);
-
return 1;
}
@@ -1494,10 +1497,14 @@
esleep(1);
dprint("%s: iaonline: %s\n", dnam(d), diskstates[d->state]);
+
ilock(d);
if(d->portm.feat & Datapi){
+ r = d->drivechange;
d->drivechange = 0;
iunlock(d);
+ if(r != 0)
+ scsiverify(u);
return scsionline(u);
}
r = 0;
@@ -1559,64 +1566,61 @@
}
static Alist*
-ahcibuild(Aportm *m, int rw, void *data, uint n, vlong lba)
+ahcibuild(Drive *d, int rw, void *data, uint n, vlong lba)
{
uchar *c;
uint flags;
- Alist *l;
+ Aportm *m;
- l = m->list;
+ m = &d->portm;
c = m->ctab->cfis;
rwfis(m, c, rw, n, lba);
flags = Lpref;
if(rw == SDwrite)
flags |= Lwrite;
- mkalist(m, flags, data, 512*n);
- return l;
+ return mkalist(m, flags, data, 512*n);
}
static Alist*
-ahcibuildpkt(Aportm *m, SDreq *r, void *data, int n)
+ahcibuildpkt(Drive *d, SDreq *r, void *data, int n)
{
uint flags;
+ Aportm *m;
uchar *c;
Actab *t;
- Alist *l;
- l = m->list;
+ m = &d->portm;
t = m->ctab;
c = t->cfis;
- atapirwfis(m, c, r->cmd, r->clen, n);
- flags = 1<<16 | Lpref | Latapi;
+
+ atapirwfis(m, c, r->cmd, r->clen, 0x2000);
+ if((n & 15) != 0 || d->nodma)
+ c[Ffeat] &= ~1; /* use pio */
+ else if(c[Ffeat] & 1 && d->info[62] & (1<<15)) /* dma direction */
+ c[Ffeat] = (c[Ffeat] & ~(1<<2)) | ((r->write == 0) << 2);
+ flags = Lpref | Latapi;
if(r->write != 0 && data)
flags |= Lwrite;
- mkalist(m, flags, data, n);
- return l;
+ return mkalist(m, flags, data, n);
}
static Alist*
-ahcibuildfis(Aportm *m, SDreq *r, void *data, uint n)
+ahcibuildfis(Drive *d, SDreq *r, void *data, uint n)
{
- uchar *c;
uint flags;
- Alist *l;
+ uchar *c;
+ Aportm *m;
- l = m->list;
+ if((r->ataproto & Pprotom) == Ppkt)
+ return ahcibuildpkt(d, r, data, n);
+
+ m = &d->portm;
c = m->ctab->cfis;
- if((r->ataproto & Pprotom) != Ppkt){
- memmove(c, r->cmd, r->clen);
- flags = Lpref;
- if(r->write || n == 0)
- flags |= Lwrite;
- mkalist(m, flags, data, n);
- }else{
- atapirwfis(m, c, r->cmd, r->clen, n);
- flags = 1<<16 | Lpref | Latapi;
- if(r->write && data)
- flags |= Lwrite;
- mkalist(m, flags, data, n);
- }
- return l;
+ memmove(c, r->cmd, r->clen);
+ flags = Lpref;
+ if(r->write || n == 0)
+ flags |= Lwrite;
+ return mkalist(m, flags, data, n);
}
static int
@@ -1648,7 +1652,7 @@
static int
io(Drive *d, uint proto, int to, int interrupt)
{
- uint task, flag, rv;
+ uint task, flag, stat, rv;
Aport *p;
Asleep as;
@@ -1686,16 +1690,17 @@
d->active--;
ilock(d);
+ stat = d->state;
flag = d->portm.flag;
task = d->port->task;
iunlock(d);
rv = SDok;
- if(proto & Ppkt){
+ if(proto & Ppkt && stat == Dready){
rv = task >> 8 + 4 & 0xf;
flag &= ~Fahdrs;
flag |= Fdone;
- }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && d->state == Dready){
+ }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && stat == Dready){
d->port->ci = 0;
ahcirecover(&d->portc);
task = d->port->task;
@@ -1716,22 +1721,21 @@
static int
iariopkt(SDreq *r, Drive *d)
{
- int n, count, try, max, to;
+ int try, to;
uchar *cmd;
+ Alist *l;
cmd = r->cmd;
aprint("%s: %.2ux %.2ux %c %d %p\n", dnam(d), cmd[0], cmd[2],
"rw"[r->write], r->dlen, r->data);
+
r->rlen = 0;
- count = r->dlen;
- max = 65536;
/*
- * prevent iaonline() and iaverify() to hang forever by timing
- * out inquiry and capacity commands after 5 seconds. problem
- * occurs with MASUSHITA DVD-RAM UJ-844 on thinkpad x301
+ * prevent iaonline() to hang forever by timing out
+ * inquiry and capacity commands after 5 seconds.
*/
- to = 0;
+ to = 30*1000;
switch(cmd[0]){
case 0x9e: if(cmd[1] != 0x10) break;
case 0x25:
@@ -1741,20 +1745,19 @@
}
for(try = 0; try < 10; try++){
- n = count;
- if(n > max)
- n = max;
qlock(&d->portm);
- ahcibuildpkt(&d->portm, r, r->data, n);
+ l = ahcibuildpkt(d, r, r->data, r->dlen);
r->status = io(d, Ppkt, to, 0);
- qunlock(&d->portm);
switch(r->status){
case SDeio:
+ qunlock(&d->portm);
return SDeio;
case SDretry:
+ qunlock(&d->portm);
continue;
}
- r->rlen = d->portm.list->len;
+ r->rlen = l->len;
+ qunlock(&d->portm);
return SDok;
}
print("%s: bad disk\n", dnam(d));
@@ -1782,14 +1785,15 @@
}
rw = write? SDwrite: SDread;
data = a;
- dprint("%s: bio: %llud %c %lud (max %d) %p\n",
- dnam(d), lba, "rw"[rw], count, max, data);
+ dprint("%s: bio: %llud %c %lud %p\n",
+ dnam(d), lba, "rw"[rw], count, data);
+
for(try = 0; try < 10;){
n = count;
if(n > max)
n = max;
qlock(&d->portm);
- ahcibuild(&d->portm, rw, data, n, lba);
+ ahcibuild(d, rw, data, n, lba);
status = io(d, Pdma, 5000, 0);
qunlock(&d->portm);
switch(status){
@@ -1912,6 +1916,7 @@
Ctlr *c;
Drive *d;
SDunit *u;
+ Alist *l;
u = r->unit;
c = u->dev->ctlr;
@@ -1923,21 +1928,23 @@
sdr0(d);
for(try = 0; try < 10; try++){
qlock(&d->portm);
- ahcibuildfis(&d->portm, r, r->data, r->dlen);
+ l = ahcibuildfis(d, r, r->data, r->dlen);
r->status = io(d, r->ataproto & Pprotom, -1, 1);
- qunlock(&d->portm);
switch(r->status){
case SDtimeout:
+ qunlock(&d->portm);
return sdsetsense(r, SDcheck, 11, 0, 6);
case SDeio:
+ qunlock(&d->portm);
return SDeio;
case SDretry:
+ qunlock(&d->portm);
continue;
}
- r->rlen = r->dlen;
- if((r->ataproto & Pprotom) == Ppkt)
- r->rlen = d->portm.list->len;
- return sdr(r, d, r->status);
+ r->rlen = (r->ataproto & Pprotom) == Ppkt ? l->len : r->dlen;
+ try = sdr(r, d, r->status);
+ qunlock(&d->portm);
+ return try;
}
print("%s: bad disk\n", dnam(d));
return r->status = SDeio;
@@ -2131,7 +2138,6 @@
memset(olds, 0xff, sizeof olds);
p = nil;
-loop:
while((p = pcimatch(p, 0, 0)) != nil){
if((type = didtype(p)) == -1)
continue;
@@ -2192,12 +2198,6 @@
c->drive[d->driveno] = d;
iadrive[niadrive + d->driveno] = d;
}
- for(i = 0; i < n; i++)
- if(ahciidle(c->drive[i]->port) == -1){
- print("%s: port %d wedged; abort\n",
- Tname(c), i);
- goto loop;
- }
for(i = 0; i < n; i++){
c->drive[i]->mode = DMautoneg;
configdrive(c->drive[i]);