2 * intel/amd ahci sata controller
3 * copyright © 2007-10 coraid, inc.
7 #include "../port/lib.h"
12 #include "../port/error.h"
13 #include "../port/sd.h"
16 #include "../port/led.h"
18 #pragma varargck type "T" int
19 #define dprint(...) if(debug) iprint(__VA_ARGS__); else USED(debug)
20 #define idprint(...) if(prid) print(__VA_ARGS__); else USED(prid)
21 #define aprint(...) if(datapi) print(__VA_ARGS__); else USED(datapi)
22 #define ledprint(...) if(dled) print(__VA_ARGS__); else USED(dled)
23 #define Pciwaddrh(a) 0
24 #define Tname(c) tname[(c)->type]
25 #define Ticks MACHP(0)->ticks
26 #define MS2TK(t) (((ulong)(t)*HZ)/1000)
31 NDrive = NCtlr*NCtlrdrv,
38 Eesb = 1<<0, /* must have (Eesb & Emtype) == 0 */
41 /* pci space configuration */
56 static char *tname[] = {
76 static char *diskstates[Dlast] = {
87 extern SDifc sdiahciifc;
88 typedef struct Ctlr Ctlr;
98 static char *modes[DMlast] = {
105 typedef struct Htab Htab;
119 Aportc portc; /* redundant ptr to port and portm. */
141 * ahci allows non-sequential ports.
142 * to avoid this hassle, we let
143 * driveno ctlr*NCtlrdrv + unit
144 * portno nth available port
164 Drive rawdrive[NCtlrdrv];
165 Drive* drive[NCtlrdrv];
169 static Ctlr iactlr[NCtlr];
170 static SDev sdevs[NCtlr];
173 static Drive *iadrive[NDrive];
181 static char stab[] = {
183 [8] 't', 'c', 'p', 'e',
184 [16] 'N', 'I', 'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X'
188 serrstr(ulong r, char *s, char *e)
193 for(i = 0; i < nelem(stab) && s < e; i++)
194 if(r & (1<<i) && stab[i]){
202 static char ntab[] = "0123456789abcdef";
205 preg(uchar *reg, int n)
207 char buf[25*3+1], *e;
211 for(i = 0; i < n; i++){
212 *e++ = ntab[reg[i] >> 4];
213 *e++ = ntab[reg[i] & 0xf];
222 dreg(char *s, Aport *p)
224 dprint("%stask=%lux; cmd=%lux; ci=%lux; is=%lux\n",
225 s, p->task, p->cmd, p->ci, p->isr);
233 tsleep(&up->sleep, return0, 0, ms);
248 return (s->p->ci & s->i) == 0;
252 aesleep(Aportm *m, Asleep *a, int ms)
256 tsleep(m, ahciclear, a, ms);
261 ahciwait(Aportc *c, int ms)
270 aesleep(c->m, &as, ms);
271 if((p->task & 1) == 0 && p->ci == 0)
273 dreg("ahciwait fail/timeout ", c->p);
278 mkalist(Aportm *m, uint flags, uchar *data, int len)
286 l->flags = flags | 0x5;
288 l->ctab = PCIWADDR(t);
289 l->ctabhi = Pciwaddrh(t);
293 p->dba = PCIWADDR(data);
294 p->dbahi = Pciwaddrh(data);
295 p->count = 1<<31 | len - 2 | 1;
304 if((pc->m->feat & Dnop) == 0)
306 c = pc->m->ctab->cfis;
308 mkalist(pc->m, Lwrite, 0, 0);
309 return ahciwait(pc, 3*1000);
313 setfeatures(Aportc *pc, uchar f, uint w)
317 c = pc->m->ctab->cfis;
318 featfis(pc->m, c, f);
319 mkalist(pc->m, Lwrite, 0, 0);
320 return ahciwait(pc, w);
324 * ata 7, required for sata, requires that all devices "support"
325 * udma mode 5, however sata:pata bridges allow older devices
326 * which may not. the innodisk satadom, for example allows
327 * only udma mode 2. on the assumption that actual udma is
328 * taking place on these bridges, we set the highest udma mode
329 * available, or pio if there is no udma mode available.
332 settxmode(Aportc *pc, uchar f)
336 c = pc->m->ctab->cfis;
337 if(txmodefis(pc->m, c, f) == -1)
339 mkalist(pc->m, Lwrite, 0, 0);
340 return ahciwait(pc, 3*1000);
353 ahciportreset(Aportc *c, uint mode)
361 for(i = 0; i < 500; i += 25){
362 if((*cmd & Acr) == 0)
366 p->sctl = 3*Aipm | 0*Aspd | Adet;
368 p->sctl = 3*Aipm | mode*Aspd;
373 ahciflushcache(Aportc *pc)
377 c = pc->m->ctab->cfis;
378 flushcachefis(pc->m, c);
379 mkalist(pc->m, Lwrite, 0, 0);
381 if(ahciwait(pc, 60000) == -1 || pc->p->task & (1|32)){
382 dprint("ahciflushcache fail %lux\n", pc->p->task);
383 // preg(pc->m->fis.r, 20);
390 ahciidentify0(Aportc *pc, void *id)
397 memset(id, 0, 0x200);
398 identifyfis(pc->m, c);
399 mkalist(pc->m, 0, id, 0x200);
400 return ahciwait(pc, 3*1000);
404 ahciidentify(Aportc *pc, ushort *id, uint *ss, char *d)
412 if(i > 5 || ahciidentify0(pc, id) != 0)
415 if(n & Pspinup && setfeatures(pc, 7, 20*1000) == -1)
416 print("%s: puis spinup fail\n", d);
419 print("%s: puis waiting\n", d);
423 if(s == -1 || (m->feat&Dlba) == 0){
424 if((m->feat&Dlba) == 0)
425 dprint("%s: no lba support\n", d);
438 for(i = 0; i < 500; i += 50){
445 if((a->task & (ASdrq|ASbsy)) == 0){
451 for(i = 0; i < 500; i += 50){
459 dprint("ahci: clo clear %lux\n", a->task);
467 ahcicomreset(Aportc *pc)
471 dreg("comreset ", pc->p);
472 if(ahciquiet(pc->p) == -1){
473 dprint("ahci: ahciquiet failed\n");
476 dreg("comreset ", pc->p);
478 c = pc->m->ctab->cfis;
480 mkalist(pc->m, Lclear | Lreset, 0, 0);
481 if(ahciwait(pc, 500) == -1){
482 dprint("ahci: comreset1 failed\n");
486 dreg("comreset ", pc->p);
489 mkalist(pc->m, Lwrite, 0, 0);
490 if(ahciwait(pc, 150) == -1){
491 dprint("ahci: comreset2 failed\n");
494 dreg("comreset ", pc->p);
499 ahciidle(Aport *port)
508 for(i = 0; i < 500; i += 25){
518 for(i = 0; i < 500; i += 25){
527 * §6.2.2.1 first part; comreset handled by reset disk.
528 * - remainder is handled by configdisk.
529 * - ahcirecover is a quick recovery from a failed command.
532 ahciswreset(Aportc *pc)
540 if(pc->p->task & (ASdrq|ASbsy))
546 ahcirecover(Aportc *pc)
550 if(settxmode(pc, pc->m->udma) == -1)
556 malign(int size, int align)
560 v = xspanalloc(size, align, 0);
568 f->base = malign(0x100, 0x100);
570 f->p = f->base + 0x20;
571 f->r = f->base + 0x40;
572 f->u = f->base + 0x60;
573 f->devicebits = (ulong*)(f->base + 0x58);
577 ahciwakeup(Aportc *c, uint mode)
582 if((s & Isleepy) == 0)
584 if((s & Smask) != Spresent){
585 print("ahci: slumbering drive missing %.3ux\n", s);
588 ahciportreset(c, mode);
589 // iprint("ahci: wake %.3ux -> %.3lux\n", s, c->p->sstatus);
593 ahciconfigdrive(Ahba *h, Aportc *c, int mode)
603 m->list = malign(sizeof *m->list, 1024);
604 m->ctab = malign(sizeof *m->ctab, 128);
607 p->list = PCIWADDR(m->list);
608 p->listhi = Pciwaddrh(m->list);
609 p->fis = PCIWADDR(m->fis.base);
610 p->fishi = Pciwaddrh(m->fis.base);
614 if((p->sstatus & Sbist) == 0 && (p->cmd & Apwr) != Apwr)
615 if((p->sstatus & Sphylink) == 0 && h->cap & Hss){
616 /* staggered spin-up? */
617 dprint("ahci: spin up ... [%.3lux]\n", p->sstatus);
619 for(int i = 0; i < 1400; i += 50){
620 if(p->sstatus & (Sphylink | Sbist))
628 if((p->sstatus & SSmask) == (Isleepy | Spresent))
630 /* disable power managment sequence from book. */
631 p->sctl = 3*Aipm | mode*Aspd | 0*Adet;
660 for(i = 0; i < 32; i++)
672 h = c->hba = (Ahba*)c->mmio;
678 // print("#S/sd%c: ahci %s port %#p: sss %d ncs %d coal %d "
679 // "mport %d led %d clo %d ems %d\n",
680 // c->sdev->idno, Tname(c), h,
681 // (u>>27) & 1, (u>>8) & 0x1f, (u>>7) & 1, u & 0x1f, (u>>25) & 1,
682 // (u>>24) & 1, (u>>6) & 1);
683 return countbits(h->pi);
687 ahcihbareset(Ahba *h)
692 for(wait = 0; wait < 1000; wait += 100){
706 if(d->unit && d->unit->name)
720 s = ahciidentify(&d->portc, id, &d->secsize, dnam(d));
725 osectors = d->sectors;
726 memmove(oserial, d->serial, sizeof d->serial);
730 idmove(d->serial, id+10, 20);
731 idmove(d->firmware, id+23, 8);
732 idmove(d->model, id+27, 40);
733 d->wwn = idwwn(d->portc.m, id);
736 memset(u->inquiry, 0, sizeof u->inquiry);
739 u->inquiry[4] = sizeof u->inquiry - 4;
740 memmove(u->inquiry+8, d->model, 40);
742 if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){
761 return c->pci->vid == 0x8086;
765 ignoreahdrs(Drive *d)
767 return d->portm.feat & Datapi && d->ctlr->type == Tsb600;
771 updatedrive(Drive *d)
773 ulong f, cause, serr, s0, pr, ewake;
782 if(d->ctlr->type == Tjmicron)
790 }else if(cause & Adps)
794 dprint("%s: fatal\n", dnam(d));
798 if(ignoreahdrs(d) && serr & ErrE)
800 dprint("%s: Adhrs cause %lux serr %lux task %lux\n",
801 dnam(d), cause, serr, p->task);
807 if(p->task & 1 && last != cause)
808 dprint("%s: err ca %lux serr %lux task %lux sstat %.3lux\n",
809 dnam(d), cause, serr, p->task, p->sstatus);
811 dprint("%s: upd %lux ta %lux\n", dnam(d), cause, p->task);
813 if(cause & (Aprcs|Aifs)){
815 switch(p->sstatus & Smask){
820 if((p->sstatus & Imask) == Islumber)
826 /* power mgnt crap for suprise removal */
827 p->ie |= Aprcs|Apcs; /* is this required? */
834 dprint("%s: %s → %s [Apcrs] %.3lux\n", dnam(d), diskstates[s0],
835 diskstates[d->state], p->sstatus);
836 if(s0 == Dready && d->state != Dready)
837 idprint("%s: pulled\n", dnam(d));
838 if(d->state != Dready)
840 if(d->state != Dready || p->ci)
854 pstatus(Drive *d, ulong s)
857 * bogus code because the first interrupt is currently dropped.
858 * likely my fault. serror is maybe cleared at the wrong time.
862 print("%s: pstatus: bad status %.3lux\n", dnam(d), s);
879 configdrive(Drive *d)
881 if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1)
884 pstatus(d, d->port->sstatus & Smask);
892 uint state, det, stat;
897 stat = p->sstatus & Smask;
898 state = (p->cmd>>28) & 0xf;
899 dprint("%s: resetdisk: icc %ux det %.3ux sdet %.3ux\n", dnam(d), state, det, stat);
903 if(d->state != Dready || d->state != Dnew)
904 d->portm.flag |= Ferror;
905 clearci(p); /* satisfy sleep condition. */
910 if(stat != Sphylink){
912 d->state = Dportreset;
918 if(p->cmd&Ast && ahciswreset(&d->portc) == -1){
920 d->state = Dportreset; /* get a bigger stick. */
928 dprint("%s: resetdisk: %s → %s\n", dnam(d), diskstates[state], diskstates[d->state]);
943 setfissig(m, c->p->sig);
944 if(identify(d) == -1){
945 dprint("%s: identify failure\n", dnam(d));
948 if(settxmode(c, m->udma) == -1){
949 dprint("%s: can't set udma mode\n", dnam(d));
952 if(m->feat & Dpower && setfeatures(c, 0x85, 3*1000) == -1){
954 if(ahcirecover(c) == -1)
967 idprint("%s: %sLBA %,lld sectors\n", dnam(d), s, d->sectors);
968 idprint(" %s %s %s %s\n", d->model, d->firmware, d->serial,
969 d->drivechange? "[newdrive]": "");
973 idprint("%s: can't be initialized\n", dnam(d));
983 Mphywait = 2*1024/Nms - 1,
984 Midwait = 16*1024/Nms - 1,
985 Mcomrwait = 64*1024/Nms - 1,
991 if((d->portm.feat & Datapi) == 0 && d->active &&
992 d->totick != 0 && (long)(Ticks - d->totick) > 0){
993 dprint("%s: drive hung; resetting [%lux] ci %lux\n",
994 dnam(d), d->port->task, d->port->ci);
999 static ushort olds[NCtlr*NCtlrdrv];
1002 doportreset(Drive *d)
1008 if(ahciportreset(&d->portc, d->mode) == -1)
1009 dprint("ahci: ahciportreset fails\n");
1013 dprint("ahci: portreset → %s [task %.4lux ss %.3lux]\n",
1014 diskstates[d->state], d->port->task, d->port->sstatus);
1018 /* drive must be locked */
1020 statechange(Drive *d)
1026 if(d->unit->sectors != 0){
1038 return (c->hba->cap & 0xf*Hiss)/Hiss;
1042 checkdrive(Drive *d, int i)
1047 s = d->port->sstatus;
1049 d->lastseen = Ticks;
1051 dprint("%s: status: %.3ux -> %.3ux: %s\n",
1052 dnam(d), olds[i], s, diskstates[d->state]);
1063 switch(s & (Iactive|Smask)){
1065 ahciwakeup(&d->portc, d->mode);
1069 dprint("%s: unknown status %.3ux\n", dnam(d), s);
1071 case Iactive: /* active, no device */
1072 if(++d->wait&Mphywait)
1076 d->mode = maxmode(d->ctlr);
1079 if(d->mode == DMautoneg){
1080 d->state = Dportreset;
1083 dprint("%s: reset; new mode %s\n", dnam(d),
1089 case Iactive | Sphylink:
1092 if((++d->wait&Midwait) == 0){
1093 dprint("%s: slow reset %.3ux task=%lux; %d\n",
1094 dnam(d), s, d->port->task, d->wait);
1097 s = (uchar)d->port->task;
1098 sig = d->port->sig >> 16;
1099 if(s == 0x7f || s&ASbsy ||
1100 (sig != 0xeb14 && (s & ASdrdy) == 0))
1109 if(d->wait++ & Mcomrwait)
1114 dprint("%s: reset [%s]: mode %d; status %.3ux\n",
1115 dnam(d), diskstates[d->state], d->mode, s);
1122 if(d->wait++ & 0xff && (s & Iactive) == 0)
1124 dprint("%s: portreset [%s]: mode %d; status %.3ux\n",
1125 dnam(d), diskstates[d->state], d->mode, s);
1126 d->portm.flag |= Ferror;
1129 if((s & Smask) == 0){
1130 d->state = Dmissing;
1148 tsleep(&up->sleep, return0, 0, Nms);
1149 for(i = 0; i < niadrive; i++)
1150 checkdrive(iadrive[i], i);
1155 iainterrupt(Ureg*, void *a)
1164 cause = c->hba->isr;
1165 for(i = 0; cause; i++){
1167 if((cause & m) == 0)
1170 d = c->rawdrive + i;
1172 if(d->port->isr && c->hba->pi & m)
1181 ahciencreset(Ctlr *c)
1185 if(c->enctype == Eesb)
1189 while(h->emctl & Emrst)
1195 * from the standard: (http://en.wikipedia.org/wiki/IBPI)
1196 * rebuild is preferred as locate+fail; alternate 1hz fail
1197 * we're going to assume no locate led.
1201 Ledsleep = 125, /* 8hz */
1204 L0 = Ledon*Aled | Ledon*Locled,
1205 L1 = Ledon*Aled | Ledoff*Locled,
1206 R0 = Ledon*Aled | Ledon*Locled | Ledon*Errled,
1207 R1 = Ledon*Aled | Ledoff*Errled,
1208 S0 = Ledon*Aled | Ledon*Locled /*| Ledon*Errled*/, /* botch */
1209 S1 = Ledon*Aled | Ledoff*Errled,
1210 P0 = Ledon*Aled | Ledon*Errled,
1211 P1 = Ledon*Aled | Ledoff*Errled,
1212 F0 = Ledon*Aled | Ledon*Errled,
1213 C0 = Ledon*Aled | Ledon*Locled,
1214 C1 = Ledon*Aled | Ledoff*Locled,
1218 //static ushort led3[Ibpilast*8] = {
1219 //[Ibpinone*8] 0, 0, 0, 0, 0, 0, 0, 0,
1220 //[Ibpinormal*8] N0, N0, N0, N0, N0, N0, N0, N0,
1221 //[Ibpirebuild*8] R0, R0, R0, R0, R1, R1, R1, R1,
1222 //[Ibpilocate*8] L0, L1, L0, L1, L0, L1, L0, L1,
1223 //[Ibpispare*8] S0, S1, S0, S1, S1, S1, S1, S1,
1224 //[Ibpipfa*8] P0, P1, P0, P1, P1, P1, P1, P1, /* first 1 sec */
1225 //[Ibpifail*8] F0, F0, F0, F0, F0, F0, F0, F0,
1226 //[Ibpicritarray*8] C0, C0, C0, C0, C1, C1, C1, C1,
1227 //[Ibpifailarray*8] C0, C1, C0, C1, C0, C1, C0, C1,
1230 static ushort led2[Ibpilast*8] = {
1231 [Ibpinone*8] 0, 0, 0, 0, 0, 0, 0, 0,
1232 [Ibpinormal*8] N0, N0, N0, N0, N0, N0, N0, N0,
1233 [Ibpirebuild*8] R0, R0, R0, R0, R1, R1, R1, R1,
1234 [Ibpilocate*8] L0, L0, L0, L0, L0, L0, L0, L0,
1235 [Ibpispare*8] S0, S0, S0, S0, S1, S1, S1, S1,
1236 [Ibpipfa*8] P0, P1, P0, P1, P1, P1, P1, P1, /* first 1 sec */
1237 [Ibpifail*8] F0, F0, F0, F0, F0, F0, F0, F0,
1238 [Ibpicritarray*8] C0, C0, C0, C0, C1, C1, C1, C1,
1239 [Ibpifailarray*8] C0, C1, C0, C1, C0, C1, C0, C1,
1243 ledstate(Ledport *p, uint seq)
1247 if(p->led == Ibpipfa && seq%32 >= 8)
1250 i = led2[8*p->led + seq%8];
1251 if(i != p->ledbits){
1253 ledprint("ledstate %,.011ub %ud\n", p->ledbits, seq);
1260 blink(Drive *d, ulong t)
1266 if(ledstate(d, t) == 0)
1270 /* ensure last message has been transmitted */
1271 while(h->emctl & Tmsg)
1275 panic("%s: bad led type %d\n", dnam(d), c->enctype);
1277 memset(&msg, 0, sizeof msg);
1280 msg.msize = sizeof msg - 4;
1281 msg.led[0] = d->ledbits;
1282 msg.led[1] = d->ledbits>>8;
1284 msg.hba = d->driveno;
1285 memmove(c->enctx, &msg, sizeof msg);
1293 Esbdrv0 = 4, /* start pos in bits */
1294 Esbiota = 3, /* shift in bits */
1303 uint i, e; /* except after c */
1306 for(i = 0; i < 3; i++)
1307 e |= ((s>>3*i & 7) != 0)<<i;
1312 blinkesb(Ctlr *c, ulong t)
1319 for(i = 0; i < c->ndrive; i++){
1321 s |= ledstate(d, t); /* no port mapping */
1325 memset(u, 0, sizeof u);
1326 for(i = 0; i < c->ndrive; i++){
1328 s = Esbdrv0 + Esbiota*i;
1329 v = esbbits(d->ledbits) * (1ull << s%32);
1331 u[s/32 + 1] |= v>>32;
1333 for(i = 0; i < c->encsz; i++)
1339 ahciledr(SDunit *u, Chan *ch, void *a, long n, vlong off)
1345 d = c->drive[u->subno];
1346 return ledr(d, ch, a, n, off);
1350 ahciledw(SDunit *u, Chan *ch, void *a, long n, vlong off)
1356 d = c->drive[u->subno];
1357 return ledw(d, ch, a, n, off);
1369 memset(map, 0, sizeof map);
1370 for(i = 0; i < niactlr; i++)
1371 if(iactlr[i].enctype != 0){
1372 ahciencreset(iactlr + i);
1377 pexit("no work", 1);
1378 for(i = 0; i < niadrive; i++){
1379 iadrive[i]->nled = 3; /* hardcoded */
1380 if(iadrive[i]->ctlr->enctype == Eesb)
1381 iadrive[i]->nled = 3;
1382 iadrive[i]->ledbits = -1;
1386 for(j = 0; j < niadrive; ){
1387 c = iadrive[j]->ctlr;
1390 else if(c->enctype == Eesb){
1399 esleep(Ledsleep - TK2MS(t1 - t0));
1410 d = c->drive[u->subno];
1416 sdaddfile(u, "led", 0644, eve, ahciledr, ahciledw);
1420 checkdrive(d, d->driveno); /* c->d0 + d->driveno */
1435 kproc("iasata", satakproc, 0);
1437 panic("iaenable: zero s->ctlr->ndrive");
1439 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1440 intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1441 /* supposed to squelch leftover interrupts here. */
1444 if(++once == niactlr)
1445 kproc("ialed", ledkproc, 0);
1459 ahcidisable(c->hba);
1460 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1461 intrdisable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1468 iaonline(SDunit *unit)
1474 c = unit->dev->ctlr;
1475 d = c->drive[unit->subno];
1478 if(d->portm.feat & Datapi && d->drivechange){
1479 r = scsionline(unit);
1489 /* devsd resets this after online is called; why? */
1490 unit->sectors = d->sectors;
1491 unit->secsize = d->secsize;
1492 }else if(d->state == Dready)
1499 ahcibuild(Aportm *m, int rw, void *data, uint n, vlong lba)
1507 rwfis(m, c, rw, n, lba);
1511 mkalist(m, flags, data, 512*n);
1516 ahcibuildpkt(Aportm *m, SDreq *r, void *data, int n)
1526 atapirwfis(m, c, r->cmd, r->clen, n);
1527 flags = 1<<16 | Lpref | Latapi;
1528 if(r->write != 0 && data)
1530 mkalist(m, flags, data, n);
1535 ahcibuildfis(Aportm *m, SDreq *r, void *data, uint n)
1543 if((r->ataproto & Pprotom) != Ppkt){
1544 memmove(c, r->cmd, r->clen);
1546 if(r->write || n == 0)
1548 mkalist(m, flags, data, n);
1550 atapirwfis(m, c, r->cmd, r->clen, n);
1551 flags = 1<<16 | Lpref | Latapi;
1552 if(r->write && data)
1554 mkalist(m, flags, data, n);
1564 for(i = 0; i < 15000; i += 250){
1565 if(d->state == Dreset || d->state == Dportreset ||
1568 δ = Ticks - d->lastseen;
1569 if(d->state == Dnull || δ > 10*1000)
1572 s = d->port->sstatus;
1574 if((s & Imask) == 0 && δ > 1500)
1576 if(d->state == Dready && (s & Smask) == Sphylink)
1580 print("%s: not responding; offline\n", dnam(d));
1582 d->state = Doffline;
1593 while ((i = waitready(d)) == 1) {
1602 flushcache(Drive *d)
1607 if(lockready(d) == 0)
1608 i = ahciflushcache(&d->portc);
1614 io(Drive *d, uint proto, int to, int interrupt)
1616 uint task, flag, rv;
1620 switch(waitready(d)){
1637 d->totick = Ticks + MS2TK(to) | 1; /* fix fencepost */
1644 if(ahcicomreset(&d->portc) == -1){
1651 sleep(&d->portm, ahciclear, &as);
1656 flag = d->portm.flag;
1657 task = d->port->task;
1662 rv = task >> 8 + 4 & 0xf;
1665 }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && d->state == Dready){
1667 ahcirecover(&d->portc);
1668 task = d->port->task;
1669 flag &= ~Fdone; /* either an error or do-over */
1672 print("%s: retry\n", dnam(d));
1675 if(flag & (Fahdrs | Ferror)){
1676 if((task & Eidnf) == 0)
1677 print("%s: i/o error %ux\n", dnam(d), task);
1684 iariopkt(SDreq *r, Drive *d)
1686 int n, count, try, max;
1690 aprint("%s: %.2ux %.2ux %c %d %p\n", dnam(d), cmd[0], cmd[2],
1691 "rw"[r->write], r->dlen, r->data);
1696 for(try = 0; try < 10; try++){
1701 ahcibuildpkt(&d->portm, r, r->data, n);
1702 r->status = io(d, Ppkt, 5000, 0);
1710 // print("%.2ux :: %.2ux :: %.4ux\n", r->cmd[0], r->status, d->port->task);
1711 r->rlen = d->portm.list->len;
1714 print("%s: bad disk\n", dnam(d));
1715 return r->status = SDcheck;
1719 ahcibio(SDunit *u, int lun, int write, void *a, long count, uvlong lba)
1721 int n, rw, try, status, max;
1727 d = c->drive[u->subno];
1728 if(d->portm.feat & Datapi)
1729 return scsibio(u, lun, write, a, count, lba);
1732 if(d->portm.feat & Dllba){
1733 max = 8192; /* ahci maximum */
1734 if(c->type == Tsb600)
1735 max = 255; /* errata */
1737 rw = write? SDwrite: SDread;
1739 for(try = 0; try < 10;){
1744 ahcibuild(&d->portm, rw, data, n, lba);
1745 status = io(d, Pdma, 5000, 0);
1757 data += n * u->secsize;
1759 return data - (uchar*)a;
1761 print("%s: bad disk\n", dnam(d));
1768 int i, n, count, rw;
1776 c = unit->dev->ctlr;
1777 d = c->drive[unit->subno];
1778 if(d->portm.feat & Datapi)
1779 return iariopkt(r, d);
1782 if(cmd[0] == 0x35 || cmd[0] == 0x91){
1783 if(flushcache(d) == 0)
1784 return sdsetsense(r, SDok, 0, 0, 0);
1785 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1788 if((i = sdfakescsi(r)) != SDnostatus){
1793 if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
1795 n = ahcibio(unit, r->lun, r->write, r->data, count, lba);
1802 static uchar bogusrfis[16] = {
1816 memmove(c, bogusrfis, sizeof bogusrfis);
1821 sdr(SDreq *r, Drive *d, int st)
1826 if((r->ataproto & Pprotom) == Ppkt){
1829 st = t >> 8 + 4 & 0xf;
1832 memmove(r->cmd, c, 16);
1840 fisreqchk(Sfis *f, SDreq *r)
1842 if((r->ataproto & Pprotom) == Ppkt)
1845 * handle oob requests;
1846 * restrict & sanitize commands
1850 if(r->cmd[0] == 0xf0){
1851 sigtofis(f, r->cmd);
1871 d = c->drive[u->subno];
1873 if((r->status = fisreqchk(&d->portm, r)) != SDnostatus)
1877 for(try = 0; try < 10; try++){
1879 ahcibuildfis(&d->portm, r, r->data, r->dlen);
1880 r->status = io(d, r->ataproto & Pprotom, -1, 1);
1884 return sdsetsense(r, SDcheck, 11, 0, 6);
1891 if((r->ataproto & Pprotom) == Ppkt)
1892 r->rlen = d->portm.list->len;
1893 return sdr(r, d, r->status);
1895 print("%s: bad disk\n", dnam(d));
1901 * configure drives 0-5 as ahci sata (c.f. errata)
1904 iaahcimode(Pcidev *p)
1908 u = pcicfgr16(p, 0x92);
1909 dprint("ahci: %T: iaahcimode %.2ux %.4ux\n", p->tbdf, pcicfgr8(p, 0x91), u);
1910 pcicfgw16(p, 0x92, u | 0xf); /* ports 0-15 */
1915 Ghc = 0x04/4, /* global host control */
1916 Pi = 0x0c/4, /* ports implemented */
1917 Cmddec = 1<<15, /* enable command block decode */
1920 Ahcien = 1<<31, /* ahci enable */
1924 iasetupahci(Ctlr *c)
1926 pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~Cmddec);
1927 pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~Cmddec);
1929 c->lmmio[Ghc] |= Ahcien;
1930 c->lmmio[Pi] = (1 << 6) - 1; /* 5 ports (supposedly ro pi reg) */
1932 /* enable ahci mode; from ich9 datasheet */
1933 pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
1937 sbsetupahci(Pcidev *p)
1939 print("sbsetupahci: tweaking %.4ux ccru %.2ux ccrp %.2ux\n",
1940 p->did, p->ccru, p->ccrp);
1941 pcicfgw8(p, 0x40, pcicfgr8(p, 0x40) | 1);
1942 pcicfgw8(p, PciCCRu, 6);
1943 pcicfgw8(p, PciCCRp, 1);
1952 c->enctx = (ulong*)(c->mmio + 0xa0);
1959 ahciencinit(Ctlr *c)
1961 ulong type, sz, o, *bar;
1967 if((h->cap & Hems) == 0)
1969 type = h->emctl & Emtype;
1981 sz = h->emloc & 0xffff;
1983 if(sz == 0 || o == 0)
1986 dprint("size = %.4lux; loc = %.4lux*4\n", sz, o);
1989 if((h->emctl & Xonly) == 0){
1993 c->encrx = bar + o*2;
2009 if((p->did & 0xfffc) == 0x2680)
2011 if((p->did & 0xfffb) == 0x27c1)
2012 return Tich; /* 82801g[bh]m */
2013 if((p->did & 0xffff) == 0x2822)
2014 return Tich; /* 82801 SATA RAID */
2015 if((p->did & 0xffff) == 0x2821)
2016 return Tich; /* 82801h[roh] */
2017 if((p->did & 0xfffe) == 0x2824)
2018 return Tich; /* 82801h[b] */
2019 if((p->did & 0xfeff) == 0x2829)
2020 return Tich; /* ich8 */
2021 if((p->did & 0xfffe) == 0x2922)
2022 return Tich; /* ich9 */
2023 if((p->did & 0xffff) == 0x3a02)
2024 return Tich; /* 82801jd/do */
2025 if((p->did & 0xfefe) == 0x3a22)
2026 return Tich; /* ich10, pch */
2027 if((p->did & 0xfff7) == 0x3b28)
2028 return Tich; /* pchm */
2029 if((p->did & 0xfffe) == 0x3b22)
2030 return Tich; /* pch */
2033 if(p->ccru == 1 || p->ccrp != 1)
2034 if(p->did == 0x4380 || p->did == 0x4390)
2040 * unconfirmed report that the programming
2041 * interface is set incorrectly.
2043 if(p->did == 0x3349)
2056 if(p->ccrb == Pcibcstore && p->ccru == 6 && p->ccrp == 1)
2064 int i, n, nunit, type;
2075 memset(olds, 0xff, sizeof olds);
2078 while((p = pcimatch(p, 0, 0)) != nil){
2079 if((type = didtype(p)) == -1)
2081 if(p->mem[Abar].bar == 0)
2083 if(niactlr == NCtlr){
2084 print("iapnp: %s: too many controllers\n", tname[type]);
2087 c = iactlr + niactlr;
2088 s = sdevs + niactlr;
2089 memset(c, 0, sizeof *c);
2090 memset(s, 0, sizeof *s);
2091 io = p->mem[Abar].bar & ~0xf;
2092 c->mmio = vmap(io, p->mem[Abar].size);
2094 print("%s: address %#p in use did %.4ux\n",
2095 Tname(c), io, p->did);
2098 c->lmmio = (ulong*)c->mmio;
2102 s->ifc = &sdiahciifc;
2107 if(intel(c) && p->did != 0x2681)
2109 // ahcihbareset((Ahba*)c->mmio);
2110 nunit = ahciconf(c);
2111 if(intel(c) && iaahcimode(p) == -1 || nunit < 1){
2112 vunmap(c->mmio, p->mem[Abar].size);
2115 c->ndrive = s->nunit = nunit;
2117 /* map the drives -- they don't all need to be enabled. */
2118 memset(c->rawdrive, 0, sizeof c->rawdrive);
2120 for(i = 0; i < NCtlrdrv; i++){
2121 d = c->rawdrive + i;
2127 if((c->hba->pi & 1<<i) == 0)
2129 snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
2130 d->port = (Aport*)(c->mmio + 0x80*i + 0x100);
2131 d->portc.p = d->port;
2132 d->portc.m = &d->portm;
2134 c->drive[d->driveno] = d;
2135 iadrive[niadrive + d->driveno] = d;
2137 for(i = 0; i < n; i++)
2138 if(ahciidle(c->drive[i]->port) == -1){
2139 print("%s: port %d wedged; abort\n",
2143 for(i = 0; i < n; i++){
2144 c->drive[i]->mode = DMautoneg;
2145 configdrive(c->drive[i]);
2152 i = (c->hba->cap >> 21) & 1;
2153 print("#S/%s: %s: sata-%s with %d ports\n", s->name,
2154 Tname(c), "I\0II" + i*2, nunit);
2159 static Htab ctab[] = {
2181 capfmt(char *p, char *e, Htab *t, int n, ulong cap)
2186 for(i = 0; i < n; i++)
2188 p = seprint(p, e, "%s ", t[i].name);
2193 iarctl(SDunit *u, char *p, int l)
2195 char buf[32], *e, *op;
2200 if((c = u->dev->ctlr) == nil)
2202 d = c->drive[u->subno];
2207 if(d->state == Dready){
2208 p = seprint(p, e, "model\t%s\n", d->model);
2209 p = seprint(p, e, "serial\t%s\n", d->serial);
2210 p = seprint(p, e, "firm\t%s\n", d->firmware);
2212 p = seprint(p, e, "wwn\t%ullx\n", d->wwn);
2213 p = seprint(p, e, "flag\t");
2214 p = pflag(p, e, &d->portm);
2215 p = seprint(p, e, "udma\t%d\n", d->portm.udma);
2217 p = seprint(p, e, "no disk present [%s]\n", diskstates[d->state]);
2218 serrstr(o->serror, buf, buf + sizeof buf - 1);
2219 p = seprint(p, e, "reg\ttask %lux cmd %lux serr %lux %s ci %lux is %lux "
2220 "sig %lux sstatus %.3lux\n", o->task, o->cmd, o->serror, buf,
2221 o->ci, o->isr, o->sig, o->sstatus);
2222 p = seprint(p, e, "cmd\t");
2223 p = capfmt(p, e, ctab, nelem(ctab), o->cmd);
2224 p = seprint(p, e, "\n");
2225 p = seprint(p, e, "mode\t%s %s\n", modes[d->mode], modes[maxmode(c)]);
2226 p = seprint(p, e, "geometry %llud %lud\n", d->sectors, u->secsize);
2231 forcemode(Drive *d, char *mode)
2235 for(i = 0; i < nelem(modes); i++)
2236 if(strcmp(mode, modes[i]) == 0)
2238 if(i == nelem(modes))
2246 forcestate(Drive *d, char *state)
2250 for(i = 0; i < nelem(diskstates); i++)
2251 if(strcmp(state, diskstates[i]) == 0)
2253 if(i == nelem(diskstates))
2262 runsettxmode(Drive *d, char *s)
2272 if(lockready(d) == 0){
2274 if(settxmode(c, m->udma) == 0)
2283 iawctl(SDunit *u, Cmdbuf *cmd)
2290 d = c->drive[u->subno];
2293 if(strcmp(f[0], "mode") == 0)
2294 forcemode(d, f[1]? f[1]: "satai");
2295 else if(strcmp(f[0], "state") == 0)
2296 forcestate(d, f[1]? f[1]: "null");
2297 else if(strcmp(f[0], "txmode") == 0){
2298 if(runsettxmode(d, f[1]? f[1]: "0"))
2299 cmderror(cmd, "bad txmode / stuck port");
2301 cmderror(cmd, Ebadctl);
2306 portr(char *p, char *e, uint x)
2312 for(i = 0; i < 32; i++){
2313 if((x & (1<<i)) == 0){
2314 if(a != -1 && i - 1 != a)
2315 p = seprint(p, e, "-%d", i - 1);
2321 p = seprint(p, e, ", ");
2322 p = seprint(p, e, "%d", a = i);
2325 if(a != -1 && i - 1 != a)
2326 p = seprint(p, e, "-%d", i - 1);
2330 static Htab htab[] = {
2350 static Htab htab2[] = {
2356 static Htab emtab[] = {
2368 iartopctl(SDev *s, char *p, char *e)
2378 p = seprint(p, e, "sd%c ahci %s port %#p: ", s->idno, Tname(c), h);
2379 p = capfmt(p, e, htab, nelem(htab), cap);
2380 p = capfmt(p, e, htab2, nelem(htab2), h->cap2);
2381 p = capfmt(p, e, emtab, nelem(emtab), h->emctl);
2382 portr(pr, pr + sizeof pr, h->pi);
2383 return seprint(p, e,
2384 "iss %ld ncs %ld np %ld ghc %lux isr %lux pi %lux %s ver %lux\n",
2385 (cap>>20) & 0xf, (cap>>8) & 0x1f, 1 + (cap & 0x1f),
2386 h->ghc, h->isr, h->pi, pr, h->ver);
2390 iawtopctl(SDev *, Cmdbuf *cmd)
2398 if(strcmp(f[0], "debug") == 0)
2400 else if(strcmp(f[0], "idprint") == 0)
2402 else if(strcmp(f[0], "aprint") == 0)
2404 else if(strcmp(f[0], "ledprint") == 0)
2407 cmderror(cmd, Ebadctl);
2411 cmderror(cmd, Ebadarg);
2417 *v = strcmp(f[1], "on") == 0;
2425 SDifc sdiahciifc = {