From ecc2125b28ee5cd9a4872f02ad89a8fd853a6d0b Mon Sep 17 00:00:00 2001 From: Giacomo Tesio Date: Sat, 12 Aug 2017 15:18:02 +0200 Subject: [PATCH] Revert "kernel: import sdahci from 9front" This reverts commit d9975caeb001e83ef89c9bce8865c70bf97d6404. --- sys/src/kern/amd64/sdahci.c | 1266 +++++++++++++---------------------- 1 file changed, 467 insertions(+), 799 deletions(-) diff --git a/sys/src/kern/amd64/sdahci.c b/sys/src/kern/amd64/sdahci.c index f951b87..42b08d4 100644 --- a/sys/src/kern/amd64/sdahci.c +++ b/sys/src/kern/amd64/sdahci.c @@ -17,18 +17,15 @@ #include "../port/led.h" #pragma varargck type "T" int -#define dprint(...) if(debug) print(__VA_ARGS__); else USED(debug) -#define idprint(...) if(prid) print(__VA_ARGS__); else USED(prid) -#define aprint(...) if(datapi) print(__VA_ARGS__); else USED(datapi) -#define ledprint(...) if(dled) print(__VA_ARGS__); else USED(dled) -#define Pciwaddrh(a) 0 -#define Tname(c) tname[(c)->type] +#define dprint(...) if(debug) iprint(__VA_ARGS__); else USED(debug) +#define idprint(...) if(prid) jehanne_print(__VA_ARGS__); else USED(prid) +#define aprint(...) if(datapi) jehanne_print(__VA_ARGS__); else USED(datapi) +#define ledprint(...) if(dled) jehanne_print(__VA_ARGS__); else USED(dled) #define Ticks sys->ticks -#define MS2TK(t) (((uint32_t)(t)*HZ)/1000) enum { NCtlr = 4, - NCtlrdrv = 32, + NCtlrdrv = 32, NDrive = NCtlr*NCtlrdrv, Fahdrs = 4, @@ -36,42 +33,54 @@ enum { Read = 0, Write, - Eesb = 1<<0, /* must have (Eesb & Emtype) == 0 */ -}; + Eesb = 1<<0, /* must have (Eesb & Emtype) == 0 */ -/* pci space configuration */ -enum { - Pmap = 0x90, - Ppcs = 0x91, - Prev = 0xa8, + /* pci space configuration */ + Pmap = 0x90, + Ppcs = 0x91, + + Nms = 256, + Mphywait = 2*1024/Nms - 1, + Midwait = 16*1024/Nms - 1, + Mcomrwait = 64*1024/Nms - 1, }; enum { Tesb, - Tich, Tsb600, Tjmicron, Tahci, + Tlast, }; -static char *tname[] = { - "63xxesb", - "ich", - "sb600", - "jmicron", - "ahci", +typedef struct Ctlrtype Ctlrtype; +typedef struct Ctlr Ctlr; +typedef struct Drive Drive; + +struct Ctlrtype { + uint32_t type; + uint32_t maxdmaxfr; + uint32_t flags; + char *name; +}; + +Ctlrtype cttab[Tlast] = { +[Tesb] Tesb, 8192, 0, "63xxesb", +[Tsb600] Tsb600, 256, 0, "sb600", +[Tjmicron] Tjmicron, 8192, 0, "jmicron", +[Tahci] Tahci, 8192, 0, "ahci", }; enum { - Dnull, - Dmissing, - Dnew, - Dready, - Derror, - Dreset, - Doffline, - Dportreset, - Dlast, + Dnull = 0, + Dmissing = 1<<0, + Dnew = 1<<1, + Dready = 1<<2, + Derror = 1<<3, + Dreset = 1<<4, + Doffline = 1<<5, + Dportreset = 1<<6, + Dlast = 8, }; static char *diskstates[Dlast] = { @@ -85,8 +94,7 @@ static char *diskstates[Dlast] = { "portreset", }; -extern SDifc sdiahciifc; -typedef struct Ctlr Ctlr; +extern SDifc sdahciifc; enum { DMautoneg, @@ -109,7 +117,7 @@ struct Htab { char *name; }; -typedef struct { +struct Drive { Lock; Ctlr *ctlr; @@ -120,24 +128,11 @@ typedef struct { Aportc portc; /* redundant ptr to port and portm. */ Ledport; - uint8_t drivechange; - uint8_t nodma; - uint8_t state; - - uint64_t sectors; - uint32_t secsize; uint32_t totick; uint32_t lastseen; uint32_t wait; uint8_t mode; - uint8_t active; - - char serial[20+1]; - char firmware[8+1]; - char model[40+1]; - uint64_t wwn; - - uint16_t info[0x200]; + uint8_t state; /* * ahci allows non-sequential ports. @@ -147,12 +142,12 @@ typedef struct { */ uint32_t driveno; uint32_t portno; -} Drive; +}; struct Ctlr { Lock; - int type; + Ctlrtype *type; int enabled; SDev *sdev; Pcidev *pci; @@ -166,13 +161,13 @@ struct Ctlr { Drive rawdrive[NCtlrdrv]; Drive* drive[NCtlrdrv]; int ndrive; - - uint32_t missirq; + uint32_t pi; }; static Ctlr iactlr[NCtlr]; static SDev sdevs[NCtlr]; static int niactlr; +static uint16_t olds[NCtlr*NCtlrdrv]; static Drive *iadrive[NDrive]; static int niadrive; @@ -203,29 +198,10 @@ serrstr(uint32_t r, char *s, char *e) *s = 0; } -static char ntab[] = "0123456789abcdef"; - -static void -preg(uint8_t *reg, int n) -{ - char buf[25*3+1], *e; - int i; - - e = buf; - for(i = 0; i < n; i++){ - *e++ = ntab[reg[i] >> 4]; - *e++ = ntab[reg[i] & 0xf]; - *e++ = ' '; - } - *e++ = '\n'; - *e = 0; - dprint(buf); -} - static void dreg(char *s, Aport *p) { - dprint("%stask=%lux; cmd=%lux; ci=%lux; is=%lux\n", + dprint("%stask=%ux; cmd=%ux; ci=%ux; is=%ux\n", s, p->task, p->cmd, p->ci, p->isr); } @@ -278,7 +254,7 @@ ahciwait(Aportc *c, int ms) return -1; } -static Alist* +static void mkalist(Aportm *m, uint32_t flags, uint8_t *data, int len) { Actab *t; @@ -286,23 +262,22 @@ mkalist(Aportm *m, uint32_t flags, uint8_t *data, int len) Aprdt *p; t = m->ctab; - 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->ctab = Pciwaddrl(t); l->ctabhi = Pciwaddrh(t); - return l; + if(data){ + l->flags |= 1<<16; + p = &t->prdt; + p->dba = Pciwaddrl(data); + p->dbahi = Pciwaddrh(data); + p->count = 1<<31 | len - 2 | 1; + } } static int -nop(Aportc *pc) +settxmode(Aportc *pc, uint8_t f) { uint8_t *c; @@ -316,7 +291,7 @@ nop(Aportc *pc) static void asleep(int ms) { - if(up == nil || !islo()) + if(up == nil) delay(ms); else esleep(ms); @@ -325,7 +300,8 @@ asleep(int ms) static int ahciportreset(Aportc *c, uint32_t mode) { - uint32_t *cmd, i; + int i; + uint32_t *cmd; Aport *p; p = c->p; @@ -336,77 +312,17 @@ ahciportreset(Aportc *c, uint32_t mode) break; asleep(25); } - if((*cmd & Apwr) != Apwr) - *cmd |= Apwr; p->sctl = 3*Aipm | 0*Aspd | Adet; delay(1); p->sctl = 3*Aipm | mode*Aspd; return 0; } -static int -ahciflushcache(Aportc *pc) -{ - uint8_t *c; - - c = pc->m->ctab->cfis; - flushcachefis(pc->m, c); - mkalist(pc->m, Lwrite, 0, 0); - - if(ahciwait(pc, 60000) == -1 || pc->p->task & (1|32)){ - dprint("ahciflushcache fail [task %lux]\n", pc->p->task); -// preg(pc->m->fis.r, 20); - return -1; - } - return 0; -} - -static int -ahciidentify0(Aportc *pc, void *id) -{ - uint8_t *c; - Actab *t; - - t = pc->m->ctab; - c = t->cfis; - memset(id, 0, 0x200); - identifyfis(pc->m, c); - mkalist(pc->m, 0, id, 0x200); - return ahciwait(pc, 3*1000); -} - -static vlong -ahciidentify(Aportc *pc, uint16_t *id, uint32_t *ss, char *d) -{ - int i, n; - vlong s; - Aportm *m; - - m = pc->m; - for(i = 0;; i++){ - if(i > 5 || ahciidentify0(pc, id) != 0) - return -1; - n = idpuis(id); - if(n & Pspinup && setfeatures(pc, 7, 20*1000) == -1) - print("%s: puis spinup fail\n", d); - if(n & Pidready) - break; - print("%s: puis waiting\n", d); - } - s = idfeat(m, id); - *ss = idss(m, id); - if(s == -1 || (m->feat&Dlba) == 0){ - if((m->feat&Dlba) == 0) - dprint("%s: no lba support\n", d); - return -1; - } - return s; -} - static int ahciquiet(Aport *a) { - uint32_t *p, i; + int i; + uint32_t *p; p = &a->cmd; *p &= ~Ast; @@ -431,7 +347,7 @@ stop: return -1; stop1: /* extra check */ - dprint("ahci: clo clear [task %lux]\n", a->task); + dprint("ahci: clo clear %ux\n", a->task); if(a->task & ASbsy) return -1; *p |= Afre | Ast; @@ -473,7 +389,8 @@ ahcicomreset(Aportc *pc) static int ahciidle(Aport *port) { - uint32_t *p, i, r; + int i, r; + uint32_t *p; p = &port->cmd; if((*p & Arun) == 0) @@ -527,20 +444,10 @@ ahcirecover(Aportc *pc) return 0; } -static void* -malign(int size, int align) -{ - void *v; - - v = xspanalloc(size, align, 0); - memset(v, 0, size); - return v; -} - static void setupfis(Afis *f) { - f->base = malign(0x100, 0x100); + f->base = jehanne_mallocalign(0x100, 0x100, 0, 0); f->d = f->base + 0; f->p = f->base + 0x20; f->r = f->base + 0x40; @@ -552,18 +459,16 @@ static void ahciwakeup(Aportc *c, uint32_t mode) { uint16_t s; - Aport *p; - p = c->p; - s = p->sstatus; + s = c->p->sstatus; if((s & Isleepy) == 0) return; if((s & Smask) != Spresent){ - dprint("ahci: slumbering drive missing [ss %.3ux]\n", s); + jehanne_print("ahci: slumbering drive missing %.3ux\n", s); return; } ahciportreset(c, mode); - dprint("ahci: wake %.3ux -> %.3lux\n", s, c->p->sstatus); +// iprint("ahci: wake %.3ux -> %.3lux\n", s, c->p->sstatus); } static int @@ -571,74 +476,66 @@ ahciconfigdrive(Ahba *h, Aportc *c, int mode) { Aportm *m; Aport *p; - int i; p = c->p; m = c->m; if(m->list == 0){ setupfis(&m->fis); - m->list = malign(sizeof *m->list, 1024); - m->ctab = malign(sizeof *m->ctab, 128); + m->list = jehanne_mallocalign(sizeof *m->list, 1024, 0, 0); + m->ctab = jehanne_mallocalign(sizeof *m->ctab, 128, 0, 0); } - if(ahciidle(p) == -1){ - dprint("ahci: port not idle\n"); - return -1; - } - - p->list = PCIWADDR(m->list); + p->list = Pciwaddrl(m->list); p->listhi = Pciwaddrh(m->list); - p->fis = PCIWADDR(m->fis.base); + p->fis = Pciwaddrl(m->fis.base); p->fishi = Pciwaddrh(m->fis.base); p->cmd |= Afre; - if((p->cmd & Apwr) != Apwr) + if((p->sstatus & Sbist) == 0 && (p->cmd & Apwr) != Apwr) + if((p->sstatus & Sphylink) == 0 && h->cap & Hss){ + dprint("ahci: spin up ... [%.3ux]\n", p->sstatus); p->cmd |= Apwr; - - if((h->cap & Hss) != 0){ - dprint("ahci: spin up ... [%.3lux]\n", p->sstatus); - for(i = 0; i < 1400; i += 50){ - if((p->sstatus & Sbist) != 0) - break; - if((p->sstatus & Smask) == Sphylink) + for(int i = 0; i < 1400; i += 50){ + if(p->sstatus & (Sphylink | Sbist)) break; asleep(50); } } + p->serror = SerrAll; + if((p->sstatus & SSmask) == (Isleepy | Spresent)) ahciwakeup(c, mode); - - p->serror = SerrAll; - p->ie = IEM; - - /* we will get called again once phylink has been established */ - if((p->sstatus & Smask) != Sphylink) - return 0; - /* disable power managment sequence from book. */ p->sctl = 3*Aipm | mode*Aspd | 0*Adet; p->cmd &= ~Aalpe; - p->cmd |= Afre | Ast; + p->cmd |= Ast; + p->ie = IEM; return 0; } -static int +static void +setstate(Drive *d, int state) +{ + ilock(d); + d->state = state; + iunlock(d); +} + +static void ahcienable(Ahba *h) { h->ghc |= Hie; - return 0; } -static int +static void ahcidisable(Ahba *h) { h->ghc &= ~Hie; - return 0; } static int @@ -661,30 +558,11 @@ ahciconf(Ctlr *c) h = c->hba = (Ahba*)c->mmio; u = h->cap; - if((u & Ham) == 0) h->ghc |= Hae; - return countbits(h->pi); } -static int -ahcihandoff(Ahba *h) -{ - int wait; - - if((h->cap2 & Boh) == 0) - return 0; - h->bios |= Oos; - for(wait = 0; wait < 2000; wait += 100){ - if((h->bios & Bos) == 0) - return 0; - delay(100); - } - iprint("ahci: bios handoff timed out\n"); - return -1; -} - static int ahcihbareset(Ahba *h) { @@ -692,13 +570,60 @@ ahcihbareset(Ahba *h) h->ghc |= Hhr; for(wait = 0; wait < 1000; wait += 100){ - if((h->ghc & Hhr) == 0) + if(h->ghc == 0) return 0; delay(100); } return -1; } +/* under development */ +static int +ahcibioshandoff(Ahba *h) +{ + int i, wait; + + if((h->cap2 & Boh) == 0) + return 0; + if((h->bios & Bos) == 0) + return 0; + + jehanne_print("ahcibioshandoff: claim\n"); + h->bios |= Oos; + + wait = 25; + for(i = 0; i < wait; i++){ + delay(1); + if((h->bios & Bos) == 0) + break; + if(i < 25 && h->bios & Bb){ + jehanne_print("ahcibioshandoff: busy\n"); + wait = 2000; + } + } + if(i == wait){ + jehanne_print("ahcibioshandoff: timeout %.1ux\n", h->bios); + h->bios = Oos; + } + return 0; +} + +static char* +dstate(uint32_t s) +{ + int i; + + for(i = 0; s; i++) + s >>= 1; + return diskstates[i]; +} + +static char* +tnam(Ctlr *c) +{ + return c->type->name; +} + static char* dnam(Drive *d) { @@ -710,43 +635,6 @@ dnam(Drive *d) return s; } -static int -identify(Drive *d) -{ - uint8_t oserial[21]; - uint16_t *id; - vlong osectors, s; - SDunit *u; - - id = d->info; - s = ahciidentify(&d->portc, id, &d->secsize, dnam(d)); - if(s == -1) - return -1; - osectors = d->sectors; - memmove(oserial, d->serial, sizeof d->serial); - - d->sectors = s; - - idmove(d->serial, id+10, 20); - idmove(d->firmware, id+23, 8); - idmove(d->model, id+27, 40); - d->wwn = idwwn(d->portc.m, id); - - u = d->unit; - memset(u->inquiry, 0, sizeof u->inquiry); - u->inquiry[2] = 2; - u->inquiry[3] = 2; - u->inquiry[4] = sizeof u->inquiry - 4; - memmove(u->inquiry+8, d->model, 40); - - if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){ - d->drivechange = 1; - d->nodma = 0; - u->sectors = 0; - } - return 0; -} - static void clearci(Aport *p) { @@ -765,7 +653,7 @@ intel(Ctlr *c) static int ignoreahdrs(Drive *d) { - return d->portm.feat & Datapi && d->ctlr->type == Tsb600; + return d->portm.feat & Datapi && d->ctlr->type->type == Tsb600; } static void @@ -780,7 +668,7 @@ updatedrive(Drive *d) f = 0; p = d->port; cause = p->isr; - if(d->ctlr->type == Tjmicron) + if(d->ctlr->type->type == Tjmicron) cause &= ~Aifs; serr = p->serror; p->isr = cause; @@ -788,13 +676,8 @@ updatedrive(Drive *d) if(p->ci == 0){ f |= Fdone; pr = 0; - }else if(cause & Adps){ + }else if(cause & Adps) pr = 0; - }else if(cause & Atfes){ - f |= Ferror; - ewake = 1; - pr = 0; - } if(cause & Ifatal){ ewake = 1; dprint("%s: fatal\n", dnam(d)); @@ -803,7 +686,7 @@ updatedrive(Drive *d) if(p->task & 33){ if(ignoreahdrs(d) && serr & ErrE) f |= Fahdrs; - dprint("%s: Adhrs cause %lux serr %lux task %lux\n", + dprint("%s: Adhrs cause %ux serr %ux task %ux\n", dnam(d), cause, serr, p->task); f |= Ferror; ewake = 1; @@ -811,10 +694,10 @@ updatedrive(Drive *d) pr = 0; } if(p->task & 1 && last != cause) - dprint("%s: err ca %lux serr %lux task %lux sstat %.3lux\n", + dprint("%s: err ca %ux serr %ux task %ux sstat %.3ux\n", dnam(d), cause, serr, p->task, p->sstatus); if(pr) - dprint("%s: upd %lux ta %lux\n", dnam(d), cause, p->task); + dprint("%s: upd %ux ta %ux\n", dnam(d), cause, p->task); if(cause & (Aprcs|Aifs)){ s0 = d->state; @@ -837,10 +720,10 @@ updatedrive(Drive *d) d->state = Doffline; break; } - dprint("%s: updatedrive: %s → %s [ss %.3lux]\n", - dnam(d), diskstates[s0], diskstates[d->state], p->sstatus); + dprint("%s: %s → %s [Apcrs] %.3ux\n", dnam(d), dstate(s0), + dstate(d->state), p->sstatus); if(s0 == Dready && d->state != Dready) - dprint("%s: pulled\n", dnam(d)); + idprint("%s: pulled\n", dnam(d)); if(d->state != Dready) f |= Ferror; if(d->state != Dready || p->ci) @@ -857,37 +740,23 @@ updatedrive(Drive *d) } static void -dstatus(Drive *d, int s) +pstatus(Drive *d, uint32_t s) { - dprint("%s: dstatus: %s → %s from pc=%p\n", dnam(d), - diskstates[d->state], diskstates[s], getcallerpc(&d)); - - ilock(d); - d->state = s; - iunlock(d); -} - -static void -configdrive(Drive *d) -{ - if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1){ - dstatus(d, Dportreset); - return; - } - - ilock(d); - switch(d->port->sstatus & Smask){ + /* + * bogus code because the first interrupt is currently dropped. + * likely my fault. serror is maybe cleared at the wrong time. + */ + if(s) + d->lastseen = Ticks; + switch(s){ default: + jehanne_print("%s: pstatus: bad status %.3ux\n", dnam(d), s); case Smissing: d->state = Dmissing; break; case Spresent: - if(d->state == Dnull) - d->state = Dportreset; break; case Sphylink: - if(d->state == Dready) - break; d->wait = 0; d->state = Dnew; break; @@ -895,9 +764,17 @@ configdrive(Drive *d) d->state = Doffline; break; } - iunlock(d); +} - dprint("%s: configdrive: %s\n", dnam(d), diskstates[d->state]); +static int +configdrive(Drive *d) +{ + if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1) + return -1; + ilock(d); + pstatus(d, d->port->sstatus & Smask); + iunlock(d); + return 0; } static void @@ -910,34 +787,36 @@ resetdisk(Drive *d) det = p->sctl & 7; stat = p->sstatus & Smask; state = (p->cmd>>28) & 0xf; - dprint("%s: resetdisk [icc %ux; det %.3ux; sdet %.3ux]\n", dnam(d), state, det, stat); + dprint("%s: resetdisk: icc %ux det %.3ux sdet %.3ux\n", dnam(d), state, det, stat); ilock(d); - if(d->state != Dready && d->state != Dnew) + state = d->state; + if(d->state != Dready || d->state != Dnew) d->portm.flag |= Ferror; - if(stat != Sphylink) - d->state = Dportreset; - else - d->state = Dreset; clearci(p); /* satisfy sleep condition. */ wakeup(&d->portm); + d->state = Derror; iunlock(d); - if(stat != Sphylink) + if(stat != Sphylink){ + setstate(d, Dportreset); return; + } qlock(&d->portm); if(p->cmd&Ast && ahciswreset(&d->portc) == -1) - dstatus(d, Dportreset); /* get a bigger stick. */ - else + setstate(d, Dportreset); /* get a bigger stick. */ + else{ + setstate(d, Dmissing); configdrive(d); + } + dprint("%s: resetdisk: %s → %s\n", dnam(d), dstate(state), dstate(d->state)); qunlock(&d->portm); } static int newdrive(Drive *d) { - char *s; Aportc *c; Aportm *m; @@ -946,81 +825,56 @@ newdrive(Drive *d) qlock(c->m); setfissig(m, c->p->sig); - if(identify(d) == -1){ - dprint("%s: identify failure\n", dnam(d)); - goto lose; - } - if(settxmode(c, m->udma) == -1){ - dprint("%s: can't set udma mode\n", dnam(d)); - goto lose; - } - if(m->feat & Dpower && setfeatures(c, 0x85, 3*1000) == -1){ - dprint("%s: can't disable apm\n", dnam(d)); - m->feat &= ~Dpower; - if(ahcirecover(c) == -1) - goto lose; - } - dstatus(d, Dready); qunlock(c->m); - s = ""; - if(m->feat & Dllba) - s = "L"; - idprint("%s: %sLBA %,lld sectors\n", dnam(d), s, d->sectors); - idprint(" %s %s %s %s\n", d->model, d->firmware, d->serial, - d->drivechange? "[newdrive]": ""); + if(ataonline(d->unit, m) != 0) + goto lose; + m->atamaxxfr = 128; + if(d->portm.feat & Dllba) + m->atamaxxfr = d->ctlr->type->maxdmaxfr; + + setstate(d, Dready); + pronline(d->unit, m); return 0; lose: + qlock(c->m); idprint("%s: can't be initialized\n", dnam(d)); - dstatus(d, Dnull); + setstate(d, Dnull); qunlock(c->m); return -1; } -enum { - Nms = 256, - Mphywait = 2*1024/Nms - 1, - Midwait = 16*1024/Nms - 1, - Mcomrwait = 64*1024/Nms - 1, -}; - -static void -hangck(Drive *d) -{ - if(d->active && d->totick != 0 && (long)(Ticks - d->totick) > 0){ - 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; - } -} - -static uint16_t olds[NCtlr*NCtlrdrv]; - -static void +static int doportreset(Drive *d) { - qlock(&d->portm); - ahciportreset(&d->portc, d->mode); - qunlock(&d->portm); + int i; - dprint("ahci: portreset: %s [task %lux; ss %.3lux]\n", - diskstates[d->state], d->port->task, d->port->sstatus); + i = -1; + qlock(&d->portm); + if(ahciportreset(&d->portc, d->mode) == -1) + dprint("ahci: ahciportreset fails\n"); + else + i = 0; + qunlock(&d->portm); + dprint("ahci: portreset → %s [task %.4ux ss %.3ux]\n", + dstate(d->state), d->port->task, d->port->sstatus); + return i; } -/* drive must be locked */ static void statechange(Drive *d) { + Aportm *m; + + m = &d->portm; switch(d->state){ case Dnull: case Doffline: if(d->unit) if(d->unit->sectors != 0){ - d->sectors = 0; - d->drivechange = 1; + m->sectors = 0; + m->drivechange = 1; } case Dready: d->wait = 0; @@ -1033,29 +887,21 @@ maxmode(Ctlr *c) return (c->hba->cap & 0xf*Hiss)/Hiss; } -static void iainterrupt(Ureg*, void *); - static void checkdrive(Drive *d, int i) { uint16_t s, sig; - if(d->ctlr->enabled == 0) - return; - if(d->driveno == 0) - iainterrupt(0, d->ctlr); /* check for missed irq's */ - ilock(d); s = d->port->sstatus; if(s) d->lastseen = Ticks; if(s != olds[i]){ dprint("%s: status: %.3ux -> %.3ux: %s\n", - dnam(d), olds[i], s, diskstates[d->state]); + dnam(d), olds[i], s, dstate(d->state)); olds[i] = s; d->wait = 0; } - hangck(d); switch(d->state){ case Dnull: case Dready: @@ -1092,8 +938,8 @@ reset: if(d->unit == nil) break; if((++d->wait&Midwait) == 0){ - dprint("%s: slow reset [task %lux; ss %.3ux; wait %d]\n", - dnam(d), d->port->task, s, d->wait); + dprint("%s: slow reset %.3ux task=%ux; %d\n", + dnam(d), s, d->port->task, d->wait); goto reset; } s = (uint8_t)d->port->task; @@ -1114,7 +960,7 @@ reset: case Derror: case Dreset: dprint("%s: reset [%s]: mode %d; status %.3ux\n", - dnam(d), diskstates[d->state], d->mode, s); + dnam(d), dstate(d->state), d->mode, s); iunlock(d); resetdisk(d); ilock(d); @@ -1124,11 +970,11 @@ portreset: if(d->wait++ & 0xff && (s & Iactive) == 0) break; dprint("%s: portreset [%s]: mode %d; status %.3ux\n", - dnam(d), diskstates[d->state], d->mode, s); + dnam(d), dstate(d->state), d->mode, s); d->portm.flag |= Ferror; clearci(d->port); wakeup(&d->portm); - if((s & Smask) == Smissing){ + if((s & Smask) == 0){ d->state = Dmissing; break; } @@ -1146,8 +992,6 @@ satakproc(void*) { int i; - while(waserror()) - ; for(;;){ tsleep(&up->sleep, return0, 0, Nms); for(i = 0; i < niadrive; i++) @@ -1156,7 +1000,7 @@ satakproc(void*) } static void -iainterrupt(Ureg *u, void *a) +iainterrupt(Ureg*, void *a) { int i; uint32_t cause, m; @@ -1173,13 +1017,11 @@ iainterrupt(Ureg *u, void *a) cause &= ~m; d = c->rawdrive + i; ilock(d); - if(d->port != nil && d->port->isr && c->hba->pi & m) + if(d->port->isr && c->pi & m) updatedrive(d); c->hba->isr = m; iunlock(d); } - if(u == 0 && i > 0) - c->missirq++; iunlock(c); } @@ -1202,7 +1044,6 @@ ahciencreset(Ctlr *c) * rebuild is preferred as locate+fail; alternate 1hz fail * we're going to assume no locate led. */ - enum { Ledsleep = 125, /* 8hz */ @@ -1246,17 +1087,19 @@ static uint16_t led2[Ibpilast*8] = { }; static int -ledstate(Ledport *p, uint32_t seq) +ledstate(Drive *d, uint32_t seq) { uint16_t i; + Ledport *p; + p = d; if(p->led == Ibpipfa && seq%32 >= 8) i = P1; else i = led2[8*p->led + seq%8]; if(i != p->ledbits){ p->ledbits = i; - ledprint("ledstate %,.011ub %ud\n", p->ledbits, seq); + ledprint("%s: led %,.011ub %ud\n", dnam(d), p->ledbits, seq%8); return 1; } return 0; @@ -1280,15 +1123,15 @@ blink(Drive *d, uint32_t t) default: panic("%s: bad led type %d", dnam(d), c->enctype); case Elmt: - memset(&msg, 0, sizeof msg); + jehanne_memset(&msg, 0, sizeof msg); msg.type = Mled; msg.dsize = 0; - msg.msize = sizeof msg - 4; + msg.msize = Ledmsz - 4; msg.led[0] = d->ledbits; msg.led[1] = d->ledbits>>8; msg.pm = 0; msg.hba = d->driveno; - memmove(c->enctx, &msg, sizeof msg); + jehanne_memmove(c->enctx, &msg, Ledmsz); break; } h->emctl |= Tmsg; @@ -1306,7 +1149,7 @@ enum { uint32_t esbbits(uint32_t s) { - uint32_t i, e; /* except after c */ + uint32_t i, e; /* except after c */ e = 0; for(i = 0; i < 3; i++) @@ -1328,7 +1171,7 @@ blinkesb(Ctlr *c, uint32_t t) } if(s == 0) return 0; - memset(u, 0, sizeof u); + jehanne_memset(u, 0, sizeof u); for(i = 0; i < c->ndrive; i++){ d = c->drive[i]; s = Esbdrv0 + Esbiota*i; @@ -1342,7 +1185,7 @@ blinkesb(Ctlr *c, uint32_t t) } static long -ahciledr(SDunit *u, Chan *ch, void *a, long n, vlong off) +ahciledr(SDunit *u, Chan *ch, void *a, long n, int64_t off) { Ctlr *c; Drive *d; @@ -1353,7 +1196,7 @@ ahciledr(SDunit *u, Chan *ch, void *a, long n, vlong off) } static long -ahciledw(SDunit *u, Chan *ch, void *a, long n, vlong off) +ahciledw(SDunit *u, Chan *ch, void *a, long n, int64_t off) { Ctlr *c; Drive *d; @@ -1372,7 +1215,7 @@ ledkproc(void*) Drive *d; j = 0; - memset(map, 0, sizeof map); + jehanne_memset(map, 0, sizeof map); for(i = 0; i < niactlr; i++) if(iactlr[i].enctype != 0){ ahciencreset(iactlr + i); @@ -1391,8 +1234,8 @@ ledkproc(void*) t0 = Ticks; for(j = 0; j < niadrive; ){ c = iadrive[j]->ctlr; - if(map[j] == 0) - j += c->enctype; + if(map[c - iactlr] == 0) + j += c->ndrive; else if(c->enctype == Eesb){ blinkesb(c, i); j += c->ndrive; @@ -1406,38 +1249,6 @@ ledkproc(void*) } } -static int -waitready(Drive *d) -{ - uint32_t s, i, δ; - - 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) - 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; - } - iunlock(d); - esleep(250); - } - iunlock(d); - return -1; -} - static int iaverify(SDunit *u) { @@ -1459,45 +1270,6 @@ iaverify(SDunit *u) return 1; } -static int -iaonline(SDunit *u) -{ - int r; - Ctlr *c; - Drive *d; - - c = u->dev->ctlr; - d = c->drive[u->subno]; - - while(d->state != Dmissing && waitready(d) == 1) - 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; - if(d->drivechange){ - d->drivechange = 0; - r = 2; - }else if(d->state == Dready) - r = 1; - if(r){ - u->sectors = d->sectors; - u->secsize = d->secsize; - } - iunlock(d); - - return r; -} - static int iaenable(SDev *s) { @@ -1513,7 +1285,7 @@ iaenable(SDev *s) if(c->ndrive == 0) panic("iaenable: zero s->ctlr->ndrive"); pcisetbme(c->pci); - snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name); + jehanne_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); @@ -1532,107 +1304,140 @@ iadisable(SDev *s) Ctlr *c; c = s->ctlr; - ilock(c); - ahcidisable(c->hba); - snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name); - intrdisable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name); c->enabled = 0; - iunlock(c); + ahcidisable(c->hba); + intrdisable(c->vector); return 1; } -static Alist* -ahcibuild(Drive *d, int rw, void *data, int nsect, vlong lba) +static int +iaonline(SDunit *u) { - uint8_t *c; - uint32_t flags; + int r; + Ctlr *c; + Drive *d; Aportm *m; + c = u->dev->ctlr; + d = c->drive[u->subno]; m = &d->portm; - c = m->ctab->cfis; - rwfis(m, c, rw, nsect, lba); - flags = Lpref; - if(rw == SDwrite) - flags |= Lwrite; - return mkalist(m, flags, data, nsect * d->secsize); + r = 0; + + if(m->feat & Datapi && m->drivechange){ + r = scsionlinex(u, m) == SDok; + if(r > 0) + m->drivechange = 0; + return r; + } + + ilock(d); + if(m->drivechange){ + r = 2; + m->drivechange = 0; + /* devsd resets this after online is called; why? */ + u->sectors = m->sectors; + u->secsize = m->secsize; + }else if(d->state == Dready) + r = 1; + iunlock(d); + return r; } static Alist* -ahcibuildpkt(Drive *d, SDreq *r, void *data, int n) +ahcibuildpkt(Aportm *m, SDreq *r, void *data, int n) { uint32_t flags; - Aportm *m; uint8_t *c; Actab *t; + Alist *l; - m = &d->portm; + l = m->list; t = m->ctab; c = t->cfis; - - 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; + atapirwfis(m, c, r->cmd, r->clen, n); + flags = 1<<16 | Lpref | Latapi; if(r->write != 0 && data) flags |= Lwrite; - return mkalist(m, flags, data, n); + mkalist(m, flags, data, n); + return l; } static Alist* -ahcibuildfis(Drive *d, SDreq *r, void *data, uint32_t n) +ahcibuildfis(Aportm *m, SDreq *r, void *data, uint32_t n) { - uint32_t flags; uint8_t *c; - Aportm *m; + uint32_t flags, dir; + Alist *l; - if((r->ataproto & Pprotom) == Ppkt) - return ahcibuildpkt(d, r, data, n); - - m = &d->portm; + l = m->list; c = m->ctab->cfis; - memmove(c, r->cmd, r->clen); - flags = Lpref; - if(r->write || n == 0) - flags |= Lwrite; - return mkalist(m, flags, data, n); -} - -static int -lockready(Drive *d) -{ - int i; - - qlock(&d->portm); - while ((i = waitready(d)) == 1) { - qunlock(&d->portm); - esleep(1); - qlock(&d->portm); + if((r->ataproto & Pprotom) != Ppkt){ + jehanne_memmove(c, r->cmd, r->clen); + flags = Lpref; + if(r->ataproto&Pout && n > 0) + flags |= Lwrite; + dir = r->ataproto&Pdatam; + if(dir == Pnd && 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 i; + return l; } static int -flushcache(Drive *d) +isready(Drive *d) { - int i; + uint32_t s; + uint32_t δ; - i = -1; - if(lockready(d) == 0) - i = ahciflushcache(&d->portc); - qunlock(&d->portm); - return i; + if(d->state & (Dreset | Dportreset /*| Dnew*/)) + return 1; + δ = TK2MS(Ticks - d->lastseen); + if(d->state == Dnull || δ > 10*1000){ + dprint("%s: last seen too long ago: %ld\n", dnam(d), δ); + return -1; + } + ilock(d); + s = d->port->sstatus; + iunlock(d); + if((s & Imask) == 0 && δ > 1500){ + dprint("%s: phy off %ldms\n", dnam(d), δ); + return -1; + } + if(d->state & (Dready | Dnew) && (s & Smask) == Sphylink) + return 0; + return 1; } static int -io(Drive *d, uint32_t proto, int to, int interrupt) +waitready(Drive *d, int tk) { - uint32_t task, flag, stat, rv; + int r; + + for(;;){ + r = isready(d); + if(r <= 0) + return r; + if(tk - Ticks - 10 < 1ul<<31) + return -1; + esleep(10); + } +} + +static int +io(Drive *d, uint32_t proto, int totk, int interrupt) +{ + uint32_t task, flag, rv; Aport *p; Asleep as; - switch(waitready(d)){ + switch(waitready(d, totk)){ case -1: return SDeio; case 1: @@ -1648,47 +1453,42 @@ io(Drive *d, uint32_t proto, int to, int interrupt) as.p = p; as.i = 1; d->totick = 0; - if(to > 0) - d->totick = Ticks + MS2TK(to) | 1; /* fix fencepost */ - d->active++; + if(totk > 0) + d->totick = totk | 1; /* fix fencepost */ while(waserror()) if(interrupt){ - d->active--; d->port->ci = 0; if(ahcicomreset(&d->portc) == -1) - dstatus(d, Dreset); + setstate(d, Dreset); return SDtimeout; } - sleep(&d->portm, ahciclear, &as); poperror(); - d->active--; ilock(d); - stat = d->state; flag = d->portm.flag; - task = d->port->task; + task = p->task; iunlock(d); rv = SDok; - if(proto & Ppkt && stat == Dready){ + if(proto & Ppkt){ rv = task >> 8 + 4 & 0xf; flag &= ~Fahdrs; flag |= Fdone; - }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && stat == Dready){ - d->port->ci = 0; + }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && d->state == Dready){ + p->ci = 0; ahcirecover(&d->portc); - task = d->port->task; + task = p->task; flag &= ~Fdone; /* either an error or do-over */ } if(flag == 0){ - print("%s: retry\n", dnam(d)); + jehanne_print("%s: retry\n", dnam(d)); return SDretry; } if(flag & (Fahdrs | Ferror)){ if((task & Eidnf) == 0) - print("%s: i/o error %ux\n", dnam(d), task); + jehanne_print("%s: i/o error %ux\n", dnam(d), task); return SDcheck; } return rv; @@ -1697,105 +1497,55 @@ io(Drive *d, uint32_t proto, int to, int interrupt) static int iariopkt(SDreq *r, Drive *d) { - int try, to; + int n, count, t, max, δ; uint8_t *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; + δ = r->timeout - Ticks; - /* - * prevent iaonline() to hang forever by timing out - * inquiry and capacity commands after 5 seconds. - */ - to = 30*1000; - switch(cmd[0]){ - case 0x9e: if(cmd[1] != 0x10) break; - case 0x25: - case 0x12: - to = 5*1000; - break; - } - - for(try = 0; try < 10; try++){ + for(t = r->timeout; setreqto(r, t) != -1;){ + n = count; + if(n > max) + n = max; qlock(&d->portm); - l = ahcibuildpkt(d, r, r->data, r->dlen); - r->status = io(d, Ppkt, to, 0); + ahcibuildpkt(&d->portm, r, r->data, n); + r->status = io(d, Ppkt, r->timeout, 0); + qunlock(&d->portm); switch(r->status){ case SDeio: - qunlock(&d->portm); - return SDeio; + return r->status = SDcheck; case SDretry: - qunlock(&d->portm); continue; } - r->rlen = l->len; - qunlock(&d->portm); +// aprint("%s: OK %.2ux :: %d :: %.4lux\n", dnam(d), r->cmd[0], r->status, d->port->task); + r->rlen = d->portm.list->len; return SDok; } - print("%s: bad disk\n", dnam(d)); + jehanne_print("%s: atapi timeout %dms\n", dnam(d), TK2MS(δ)); return r->status = SDcheck; } static long -ahcibio(SDunit *u, int lun, int write, void *a, long count, uint64_t lba) +ahcibio(SDunit *u, int lun, int write, void *a, long count0, uint64_t lba) { - int n, rw, try, status, max; - uint8_t *data; Ctlr *c; Drive *d; c = u->dev->ctlr; d = c->drive[u->subno]; if(d->portm.feat & Datapi) - return scsibio(u, lun, write, a, count, lba); - - max = 128; - if(d->portm.feat & Dllba){ - max = 8192; /* ahci maximum */ - if(c->type == Tsb600) - max = 255; /* errata */ - } - rw = write? SDwrite: SDread; - data = a; - 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, rw, data, n, lba); - status = io(d, Pdma, 5000, 0); - qunlock(&d->portm); - switch(status){ - case SDeio: - return -1; - case SDretry: - try++; - continue; - } - try = 0; - count -= n; - lba += n; - data += n * u->secsize; - if(count == 0) - return data - (uint8_t*)a; - } - print("%s: bad disk\n", dnam(d)); - return -1; + return scsibiox(u, &d->portm, lun, write, a, count0, lba); + return atabio(u, &d->portm, lun, write, a, count0, lba); } static int iario(SDreq *r) { - int i, n, count, rw; - uint8_t *cmd; - uint64_t lba; Ctlr *c; Drive *d; SDunit *u; @@ -1803,34 +1553,19 @@ iario(SDreq *r) u = r->unit; c = u->dev->ctlr; d = c->drive[u->subno]; + if((d->state & (Dnew | Dready)) == 0) + return sdsetsense(r, SDcheck, 3, 0x04, 0x24); + if(r->timeout == 0) + r->timeout = totk(Ms2tk(600*1000)); if(d->portm.feat & Datapi) return iariopkt(r, d); - cmd = r->cmd; - - if(cmd[0] == 0x35 || cmd[0] == 0x91){ - if(flushcache(d) == 0) - return sdsetsense(r, SDok, 0, 0, 0); - return sdsetsense(r, SDcheck, 3, 0xc, 2); - } - - if((i = sdfakescsi(r)) != SDnostatus){ - r->status = i; - return i; - } - - if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus) - return i; - n = ahcibio(u, r->lun, r->write, r->data, count, lba); - if(n == -1) - return SDeio; - r->rlen = n; - return SDok; + return atariosata(u, &d->portm, r); } static uint8_t bogusrfis[16] = { [Ftype] 0x34, [Fioport] 0x40, -[Fstatus] 0x50, +[Fstatus] 0x50, [Fdev] 0xa0, }; @@ -1840,7 +1575,7 @@ sdr0(Drive *d) uint8_t *c; c = d->portm.fis.r; - memmove(c, bogusrfis, sizeof bogusrfis); + jehanne_memmove(c, bogusrfis, sizeof bogusrfis); coherence(); } @@ -1856,7 +1591,7 @@ sdr(SDreq *r, Drive *d, int st) st = t >> 8 + 4 & 0xf; } c = d->portm.fis.r; - memmove(r->cmd, c, 16); + jehanne_memmove(r->cmd, c, 16); r->status = st; if(st == SDcheck) st = SDok; @@ -1888,47 +1623,34 @@ fisreqchk(Sfis *f, SDreq *r) static int iaataio(SDreq *r) { - int try; Ctlr *c; Drive *d; SDunit *u; - Alist *l; u = r->unit; c = u->dev->ctlr; d = c->drive[u->subno]; + if(r->timeout == 0) + r->timeout = totk(Ms2tk(600*1000)); if((r->status = fisreqchk(&d->portm, r)) != SDnostatus) return r->status; r->rlen = 0; sdr0(d); - for(try = 0; try < 10; try++){ - qlock(&d->portm); - l = ahcibuildfis(d, r, r->data, r->dlen); - r->status = io(d, r->ataproto & Pprotom, -1, 1); - 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->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; + + qlock(&d->portm); + ahcibuildfis(&d->portm, r, r->data, r->dlen); + r->status = io(d, r->ataproto & Pprotom, -1, 1); + qunlock(&d->portm); + if(r->status != SDok) + return r->status; + r->rlen = r->dlen; + if((r->ataproto & Pprotom) == Ppkt) + r->rlen = d->portm.list->len; + return sdr(r, d, r->status); } -/* - * configure drives 0-5 as ahci sata (c.f. errata) - */ +/* configure drives 0-5 as ahci sata (c.f. errata) */ static int iaahcimode(Pcidev *p) { @@ -1936,7 +1658,7 @@ iaahcimode(Pcidev *p) 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 */ + pcicfgw16(p, 0x92, u | 0xf); /* ports 0-15 (sic) */ return 0; } @@ -1965,7 +1687,7 @@ iasetupahci(Ctlr *c) static void sbsetupahci(Pcidev *p) { - print("sbsetupahci: tweaking %.4ux ccru %.2ux ccrp %.2ux\n", + jehanne_print("sbsetupahci: tweaking %.4ux ccru %.2ux ccrp %.2ux\n", p->did, p->ccru, p->ccrp); pcicfgw8(p, 0x40, pcicfgr8(p, 0x40) | 1); pcicfgw8(p, PciCCRu, 6); @@ -1987,7 +1709,8 @@ esbenc(Ctlr *c) static int ahciencinit(Ctlr *c) { - uint32_t type, sz, o, *bar; + uint32_t type, sz, o; + uint32_t *bar; Ahba *h; h = c->hba; @@ -2012,7 +1735,8 @@ ahciencinit(Ctlr *c) if(sz == 0 || o == 0) return -1; bar = c->lmmio; - dprint("size = %.4lux; loc = %.4lux*4\n", sz, o); + ledprint("size = %#.4ux; loc = %#.4ux*4\n", sz, o); + c->encsz = sz; c->enctx = bar + o; if((h->emctl & Xonly) == 0){ @@ -2025,46 +1749,32 @@ ahciencinit(Ctlr *c) return 0; } +static uint16_t itab[] = { + 0xfffc, 0x2680, Tesb, + 0xfffb, 0x27c1, Tahci, /* 82801g[bh]m */ + 0xffff, 0x2821, Tahci, /* 82801h[roh] */ + 0xfffe, 0x2824, Tahci, /* 82801h[b] */ + 0xfeff, 0x2829, Tahci, /* ich8 */ + 0xfffe, 0x2922, Tahci, /* ich9 */ + 0xffff, 0x3a02, Tahci, /* 82801jd/do */ + 0xfefe, 0x3a22, Tahci, /* ich10, pch */ + 0xfff7, 0x3b28, Tahci, /* pchm */ + 0xfffe, 0x3b22, Tahci, /* pch */ +}; + static int didtype(Pcidev *p) { - int type; + int type, i; type = Tahci; switch(p->vid){ default: return -1; case 0x8086: - if((p->did & 0xffff) == 0x1e02) - return Tich; /* c210 */ - if((p->did & 0xffff) == 0x8c02) - return Tich; /* c220 */ - if((p->did & 0xffff) == 0x24d1) - return Tich; /* 82801eb/er */ - if((p->did & 0xffff) == 0x2653) - return Tich; /* 82801fbm */ - if((p->did & 0xfffc) == 0x2680) - return Tesb; - if((p->did & 0xfffb) == 0x27c1) - return Tich; /* 82801g[bh]m */ - if((p->did & 0xffff) == 0x2822) - return Tich; /* 82801 SATA RAID */ - if((p->did & 0xffff) == 0x2821) - return Tich; /* 82801h[roh] */ - if((p->did & 0xfffe) == 0x2824) - return Tich; /* 82801h[b] */ - if((p->did & 0xfeff) == 0x2829) - return Tich; /* ich8 */ - if((p->did & 0xfffe) == 0x2922) - return Tich; /* ich9 */ - if((p->did & 0xffff) == 0x3a02) - return Tich; /* 82801jd/do */ - if((p->did & 0xfefe) == 0x3a22) - return Tich; /* ich10, pch */ - if((p->did & 0xfff7) == 0x3b28) - return Tich; /* pchm */ - if((p->did & 0xfffe) == 0x3b22) - return Tich; /* pch */ + for(i = 0; i < nelem(itab); i += 3) + if((p->did & itab[i]) == itab[i+1]) + return itab[i+2]; break; case 0x1002: if(p->ccru == 1 || p->ccrp != 1) @@ -2080,11 +1790,6 @@ didtype(Pcidev *p) if(p->did == 0x3349) return Tahci; break; - case 0x1022: - /* Hudson SATA Controller [AHCI mode] */ - if(p->did == 0x7801) - return Tahci; - break; case 0x10de: case 0x1039: case 0x1b4b: @@ -2095,7 +1800,7 @@ didtype(Pcidev *p) type = Tjmicron; break; } - if(p->ccrb == Pcibcstore && p->ccru == 6 && p->ccrp == 1) + if(p->ccrb == 1 && p->ccru == 6 && p->ccrp == 1) return type; return -1; } @@ -2104,7 +1809,7 @@ static SDev* iapnp(void) { int i, n, nunit, type; - uintptr io; + uintmem io; Ctlr *c; Drive *d; Pcidev *p; @@ -2114,52 +1819,48 @@ iapnp(void) if(done) return nil; done = 1; - - if(getconf("*noahci") != nil) - return nil; - - if(getconf("*ahcidebug") != nil){ - debug = 1; - datapi = 1; - } - - memset(olds, 0xff, sizeof olds); + jehanne_memset(olds, 0xff, sizeof olds); p = nil; +loop: while((p = pcimatch(p, 0, 0)) != nil){ if((type = didtype(p)) == -1) continue; - io = p->mem[Abar].bar; - if(io == 0 || (io & 1) != 0 || p->mem[Abar].size < 0x180) + if(p->mem[Abar].bar == 0) continue; - io &= ~0xf; if(niactlr == NCtlr){ - print("iapnp: %s: too many controllers\n", tname[type]); + jehanne_print("iapnp: %s: too many controllers\n", cttab[type].name); break; } c = iactlr + niactlr; s = sdevs + niactlr; - memset(c, 0, sizeof *c); - memset(s, 0, sizeof *s); + jehanne_memset(c, 0, sizeof *c); + jehanne_memset(s, 0, sizeof *s); + c->type = cttab + type; + io = p->mem[Abar].bar & ~(uintmem)0xf; c->mmio = vmap(io, p->mem[Abar].size); - if(c->mmio == 0){ - print("%s: address %#p in use did %.4ux\n", - Tname(c), io, p->did); + if(c->mmio == nil){ + jehanne_print("%s: %T: address %#P in use\n", + tnam(c), p->tbdf, io); continue; } c->lmmio = (uint32_t*)c->mmio; c->pci = p; - c->type = type; - s->ifc = &sdiahciifc; + s->ifc = &sdahciifc; s->idno = 'E'; s->ctlr = c; c->sdev = s; - ahcihandoff((Ahba*)c->mmio); if(intel(c) && p->did != 0x2681) iasetupahci(c); + ahcibioshandoff((Ahba*)c->mmio); // ahcihbareset((Ahba*)c->mmio); nunit = ahciconf(c); + c->pi = c->hba->pi; + if(0 && p->vid == 0x1002 && p->did == 0x4391){ + c->pi = 0x3f; /* noah's opteron */ + nunit = 6; + } if(intel(c) && iaahcimode(p) == -1 || nunit < 1){ vunmap(c->mmio, p->mem[Abar].size); continue; @@ -2167,28 +1868,33 @@ iapnp(void) c->ndrive = s->nunit = nunit; /* map the drives -- they don't all need to be enabled. */ - memset(c->rawdrive, 0, sizeof c->rawdrive); + jehanne_memset(c->rawdrive, 0, sizeof c->rawdrive); n = 0; for(i = 0; i < NCtlrdrv; i++){ d = c->rawdrive + i; d->portno = i; d->driveno = -1; - d->sectors = 0; - d->serial[0] = ' '; + d->portm.tler = 5000; + d->portm.sectors = 0; + d->portm.serial[0] = ' '; + d->led = Ibpinormal; d->ctlr = c; - if((c->hba->pi & 1<pi & 1< p->mem[Abar].size) - continue; - d->port = (Aport*)(c->mmio + io); + jehanne_snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i); + d->port = (Aport*)(c->mmio + 0x80*i + 0x100); 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; } + for(i = 0; i < n; i++) + if(ahciidle(c->drive[i]->port) == -1){ + jehanne_print("%s: port %d wedged; abort\n", + tnam(c), i); + goto loop; + } for(i = 0; i < n; i++){ c->drive[i]->mode = DMautoneg; configdrive(c->drive[i]); @@ -2199,8 +1905,8 @@ iapnp(void) niactlr++; sdadddevs(s); i = (c->hba->cap >> 21) & 1; - print("#S/%s: %s: sata-%s with %d ports\n", s->name, - Tname(c), "I\0II" + i*2, nunit); + jehanne_print("#S/%s: %s: sata-%s with %d ports\n", s->name, + tnam(c), "I\0II" + i*2, nunit); } return nil; } @@ -2234,7 +1940,7 @@ capfmt(char *p, char *e, Htab *t, int n, uint32_t cap) *p = 0; for(i = 0; i < n; i++) if(cap & t[i].bit) - p = seprint(p, e, "%s ", t[i].name); + p = jehanne_seprint(p, e, "%s ", t[i].name); return p; } @@ -2253,29 +1959,19 @@ iarctl(SDunit *u, char *p, int l) e = p+l; op = p; - if(d->state == Dready){ - p = seprint(p, e, "model\t%s\n", d->model); - p = seprint(p, e, "serial\t%s\n", d->serial); - p = seprint(p, e, "firm\t%s\n", d->firmware); - if(d->wwn != 0) - p = seprint(p, e, "wwn\t%ullx\n", d->wwn); - p = seprint(p, e, "flag\t"); - p = pflag(p, e, &d->portm); - p = seprint(p, e, "udma\t%d\n", d->portm.udma); - }else - p = seprint(p, e, "no disk present [%s]\n", diskstates[d->state]); + if(d->state == Dready) + p = sfisxrdctl(&d->portm, p, e); + else + p = jehanne_seprint(p, e, "no disk present [%s]\n", dstate(d->state)); serrstr(o->serror, buf, buf + sizeof buf - 1); - p = seprint(p, e, "reg\ttask %lux cmd %lux serr %lux %s ci %lux is %lux " - "sig %lux sstatus %.3lux\n", o->task, o->cmd, o->serror, buf, + p = jehanne_seprint(p, e, "reg\ttask %ux cmd %ux serr %ux %s ci %ux is %ux " + "sig %ux sstatus %.3ux\n", o->task, o->cmd, o->serror, buf, o->ci, o->isr, o->sig, o->sstatus); - p = seprint(p, e, "cmd\t"); + p = jehanne_seprint(p, e, "cmd\t"); p = capfmt(p, e, ctab, nelem(ctab), o->cmd); - p = seprint(p, e, "\n"); - p = seprint(p, e, "mode\t%s %s\n", modes[d->mode], modes[maxmode(c)]); - p = seprint(p, e, "geometry %llud %d\n", d->sectors, d->secsize); - p = seprint(p, e, "alignment %d %d\n", - d->secsize<portm.physshift, d->portm.physalign); - p = seprint(p, e, "missirq\t%ud\n", c->missirq); + p = jehanne_seprint(p, e, "\n"); + p = jehanne_seprint(p, e, "mode\t%s %s\n", modes[d->mode], modes[maxmode(c)]); + p = jehanne_seprint(p, e, "geometry %llud %lud\n", u->sectors, u->secsize); return p - op; } @@ -2285,7 +1981,7 @@ forcemode(Drive *d, char *mode) int i; for(i = 0; i < nelem(modes); i++) - if(strcmp(mode, modes[i]) == 0) + if(jehanne_strcmp(mode, modes[i]) == 0) break; if(i == nelem(modes)) i = 0; @@ -2299,35 +1995,14 @@ forcestate(Drive *d, char *state) { int i; - for(i = 0; i < nelem(diskstates); i++) - if(strcmp(state, diskstates[i]) == 0) + for(i = 1; i < nelem(diskstates); i++) + if(jehanne_strcmp(state, diskstates[i]) == 0) break; if(i == nelem(diskstates)) error(Ebadctl); - dstatus(d, i); + setstate(d, 1 << i-1); } -static int -runsettxmode(Drive *d, char *s) -{ - int i; - Aportc *c; - Aportm *m; - - c = &d->portc; - m = &d->portm; - - i = 1; - if(lockready(d) == 0){ - m->udma = atoi(s); - if(settxmode(c, m->udma) == 0) - i = 0; - } - qunlock(m); - return i; -} - - static int iawctl(SDunit *u, Cmdbuf *cmd) { @@ -2339,14 +2014,11 @@ iawctl(SDunit *u, Cmdbuf *cmd) d = c->drive[u->subno]; f = cmd->f; - if(strcmp(f[0], "mode") == 0) + if(jehanne_strcmp(f[0], "mode") == 0) forcemode(d, f[1]? f[1]: "satai"); - else if(strcmp(f[0], "state") == 0) + else if(jehanne_strcmp(f[0], "state") == 0) forcestate(d, f[1]? f[1]: "null"); - else if(strcmp(f[0], "txmode") == 0){ - if(runsettxmode(d, f[1]? f[1]: "0")) - cmderror(cmd, "bad txmode / stuck port"); - }else + else cmderror(cmd, Ebadctl); return 0; } @@ -2361,18 +2033,18 @@ portr(char *p, char *e, uint32_t x) for(i = 0; i < 32; i++){ if((x & (1< 0) - p = seprint(p, e, ", "); - p = seprint(p, e, "%d", a = i); + p = jehanne_seprint(p, e, ", "); + p = jehanne_seprint(p, e, "%d", a = i); } } if(a != -1 && i - 1 != a) - p = seprint(p, e, "-%d", i - 1); + p = jehanne_seprint(p, e, "-%d", i - 1); return p; } @@ -2424,13 +2096,13 @@ iartopctl(SDev *s, char *p, char *e) c = s->ctlr; h = c->hba; cap = h->cap; - p = seprint(p, e, "sd%c ahci %s port %#p: ", s->idno, Tname(c), h); + p = jehanne_seprint(p, e, "sd%c ahci %s port %#p: ", s->idno, tnam(c), h); p = capfmt(p, e, htab, nelem(htab), cap); p = capfmt(p, e, htab2, nelem(htab2), h->cap2); p = capfmt(p, e, emtab, nelem(emtab), h->emctl); portr(pr, pr + sizeof pr, h->pi); - return seprint(p, e, - "iss %ld ncs %ld np %ld ghc %lux isr %lux pi %lux %s ver %lux\n", + return jehanne_seprint(p, e, + "iss %d ncs %d np %d ghc %ux isr %ux pi %ux %s ver %ux\n", (cap>>20) & 0xf, (cap>>8) & 0x1f, 1 + (cap & 0x1f), h->ghc, h->isr, h->pi, pr, h->ver); } @@ -2444,13 +2116,13 @@ iawtopctl(SDev *, Cmdbuf *cmd) f = cmd->f; v = 0; - if(strcmp(f[0], "debug") == 0) + if(jehanne_strcmp(f[0], "debug") == 0) v = &debug; - else if(strcmp(f[0], "idprint") == 0) + else if(jehanne_strcmp(f[0], "idprint") == 0) v = &prid; - else if(strcmp(f[0], "aprint") == 0) + else if(jehanne_strcmp(f[0], "aprint") == 0) v = &datapi; - else if(strcmp(f[0], "ledprint") == 0) + else if(jehanne_strcmp(f[0], "ledprint") == 0) v = &dled; else cmderror(cmd, Ebadctl); @@ -2460,18 +2132,14 @@ iawtopctl(SDev *, Cmdbuf *cmd) cmderror(cmd, Ebadarg); case 1: *v ^= 1; - break; + return 0; case 2: - if(f[1]) - *v = strcmp(f[1], "on") == 0; - else - *v ^= 1; - break; + *v = jehanne_strcmp(f[1], "on") == 0; + return 0; } - return 0; } -SDifc sdiahciifc = { +SDifc sdahciifc = { "ahci", iapnp,