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) print(__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. */
142 * ahci allows non-sequential ports.
143 * to avoid this hassle, we let
144 * driveno ctlr*NCtlrdrv + unit
145 * portno nth available port
165 Drive rawdrive[NCtlrdrv];
166 Drive* drive[NCtlrdrv];
172 static Ctlr iactlr[NCtlr];
173 static SDev sdevs[NCtlr];
176 static Drive *iadrive[NDrive];
184 static char stab[] = {
186 [8] 't', 'c', 'p', 'e',
187 [16] 'N', 'I', 'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X'
191 serrstr(ulong r, char *s, char *e)
196 for(i = 0; i < nelem(stab) && s < e; i++)
197 if(r & (1<<i) && stab[i]){
205 static char ntab[] = "0123456789abcdef";
208 preg(uchar *reg, int n)
210 char buf[25*3+1], *e;
214 for(i = 0; i < n; i++){
215 *e++ = ntab[reg[i] >> 4];
216 *e++ = ntab[reg[i] & 0xf];
225 dreg(char *s, Aport *p)
227 dprint("%stask=%lux; cmd=%lux; ci=%lux; is=%lux\n",
228 s, p->task, p->cmd, p->ci, p->isr);
236 tsleep(&up->sleep, return0, 0, ms);
251 return (s->p->ci & s->i) == 0;
255 aesleep(Aportm *m, Asleep *a, int ms)
259 tsleep(m, ahciclear, a, ms);
264 ahciwait(Aportc *c, int ms)
273 aesleep(c->m, &as, ms);
274 if((p->task & 1) == 0 && p->ci == 0)
276 dreg("ahciwait fail/timeout ", c->p);
281 mkalist(Aportm *m, uint flags, uchar *data, int len)
290 p->dba = PCIWADDR(data);
291 p->dbahi = Pciwaddrh(data);
292 p->count = 1<<31 | len - 2 | 1;
296 l->flags = flags | 0x5;
298 l->ctab = PCIWADDR(t);
299 l->ctabhi = Pciwaddrh(t);
308 if((pc->m->feat & Dnop) == 0)
310 c = pc->m->ctab->cfis;
312 mkalist(pc->m, Lwrite, 0, 0);
313 return ahciwait(pc, 3*1000);
317 setfeatures(Aportc *pc, uchar f, uint w)
321 c = pc->m->ctab->cfis;
322 featfis(pc->m, c, f);
323 mkalist(pc->m, Lwrite, 0, 0);
324 return ahciwait(pc, w);
328 * ata 7, required for sata, requires that all devices "support"
329 * udma mode 5, however sata:pata bridges allow older devices
330 * which may not. the innodisk satadom, for example allows
331 * only udma mode 2. on the assumption that actual udma is
332 * taking place on these bridges, we set the highest udma mode
333 * available, or pio if there is no udma mode available.
336 settxmode(Aportc *pc, uchar f)
340 c = pc->m->ctab->cfis;
341 if(txmodefis(pc->m, c, f) == -1)
343 mkalist(pc->m, Lwrite, 0, 0);
344 return ahciwait(pc, 3*1000);
350 if(up == nil || !islo())
357 ahciportreset(Aportc *c, uint mode)
365 for(i = 0; i < 500; i += 25){
366 if((*cmd & Acr) == 0)
370 if((*cmd & Apwr) != Apwr)
372 p->sctl = 3*Aipm | 0*Aspd | Adet;
374 p->sctl = 3*Aipm | mode*Aspd;
378 ahciflushcache(Aportc *pc)
382 c = pc->m->ctab->cfis;
383 flushcachefis(pc->m, c);
384 mkalist(pc->m, Lwrite, 0, 0);
386 if(ahciwait(pc, 60000) == -1 || pc->p->task & (1|32)){
387 dprint("ahciflushcache fail [task %lux]\n", pc->p->task);
388 // preg(pc->m->fis.r, 20);
395 ahciidentify0(Aportc *pc, void *id)
402 memset(id, 0, 0x200);
403 identifyfis(pc->m, c);
404 mkalist(pc->m, 0, id, 0x200);
405 return ahciwait(pc, 3*1000);
409 ahciidentify(Aportc *pc, ushort *id, uint *ss, char *d)
417 if(i > 5 || ahciidentify0(pc, id) != 0)
420 if(n & Pspinup && setfeatures(pc, 7, 20*1000) == -1)
421 print("%s: puis spinup fail\n", d);
424 print("%s: puis waiting\n", d);
428 if(s == -1 || (m->feat&Dlba) == 0){
429 if((m->feat&Dlba) == 0)
430 dprint("%s: no lba support\n", d);
443 for(i = 0; i < 500; i += 50){
450 if((a->task & (ASdrq|ASbsy)) == 0){
456 for(i = 0; i < 500; i += 50){
464 dprint("ahci: clo clear [task %lux]\n", a->task);
472 ahcicomreset(Aportc *pc)
476 dreg("comreset ", pc->p);
477 if(ahciquiet(pc->p) == -1){
478 dprint("ahci: ahciquiet failed\n");
481 dreg("comreset ", pc->p);
483 c = pc->m->ctab->cfis;
485 mkalist(pc->m, Lclear | Lreset, 0, 0);
486 if(ahciwait(pc, 500) == -1){
487 dprint("ahci: comreset1 failed\n");
491 dreg("comreset ", pc->p);
494 mkalist(pc->m, Lwrite, 0, 0);
495 if(ahciwait(pc, 150) == -1){
496 dprint("ahci: comreset2 failed\n");
499 dreg("comreset ", pc->p);
504 ahciidle(Aport *port)
513 for(i = 0; i < 500; i += 25){
523 for(i = 0; i < 500; i += 25){
532 * §6.2.2.1 first part; comreset handled by reset disk.
533 * - remainder is handled by configdisk.
534 * - ahcirecover is a quick recovery from a failed command.
537 ahciswreset(Aportc *pc)
545 if(pc->p->task & (ASdrq|ASbsy))
551 ahcirecover(Aportc *pc)
555 if(settxmode(pc, pc->m->udma) == -1)
561 malign(int size, int align)
565 v = xspanalloc(size, align, 0);
573 f->base = malign(0x100, 0x100);
575 f->p = f->base + 0x20;
576 f->r = f->base + 0x40;
577 f->u = f->base + 0x60;
578 f->devicebits = (ulong*)(f->base + 0x58);
582 ahciwakeup(Aportc *c, uint mode)
589 if((s & Isleepy) == 0)
591 if((s & Smask) != Spresent){
592 dprint("ahci: slumbering drive missing [ss %.3ux]\n", s);
595 ahciportreset(c, mode);
596 dprint("ahci: wake %.3ux -> %.3lux\n", s, c->p->sstatus);
600 ahciconfigdrive(Ahba *h, Aportc *c, int mode)
611 m->list = malign(sizeof *m->list, 1024);
612 m->ctab = malign(sizeof *m->ctab, 128);
615 if(ahciidle(p) == -1){
616 dprint("ahci: port not idle\n");
620 p->list = PCIWADDR(m->list);
621 p->listhi = Pciwaddrh(m->list);
622 p->fis = PCIWADDR(m->fis.base);
623 p->fishi = Pciwaddrh(m->fis.base);
627 if((p->cmd & Apwr) != Apwr)
630 if((h->cap & Hss) != 0){
631 dprint("ahci: spin up ... [%.3lux]\n", p->sstatus);
632 for(i = 0; i < 1400; i += 50){
633 if((p->sstatus & Sbist) != 0)
635 if((p->sstatus & Smask) == Sphylink)
641 if((p->sstatus & SSmask) == (Isleepy | Spresent))
647 /* we will get called again once phylink has been established */
648 if((p->sstatus & Smask) != Sphylink)
651 /* disable power managment sequence from book. */
652 p->sctl = 3*Aipm | mode*Aspd | 0*Adet;
655 p->cmd |= Afre | Ast;
680 for(i = 0; i < 32; i++)
692 h = c->hba = (Ahba*)c->mmio;
698 return countbits(h->pi);
706 if((h->cap2 & Boh) == 0)
709 for(wait = 0; wait < 2000; wait += 100){
710 if((h->bios & Bos) == 0)
714 iprint("ahci: bios handoff timed out\n");
719 ahcihbareset(Ahba *h)
724 for(wait = 0; wait < 1000; wait += 100){
725 if((h->ghc & Hhr) == 0)
738 if(d->unit && d->unit->name)
752 s = ahciidentify(&d->portc, id, &d->secsize, dnam(d));
755 osectors = d->sectors;
756 memmove(oserial, d->serial, sizeof d->serial);
760 idmove(d->serial, id+10, 20);
761 idmove(d->firmware, id+23, 8);
762 idmove(d->model, id+27, 40);
763 d->wwn = idwwn(d->portc.m, id);
766 memset(u->inquiry, 0, sizeof u->inquiry);
769 u->inquiry[4] = sizeof u->inquiry - 4;
770 memmove(u->inquiry+8, d->model, 40);
772 if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){
790 ignoreahdrs(Drive *d)
792 return d->portm.feat & Datapi && d->ctlr->type == Tsb600;
796 updatedrive(Drive *d)
798 ulong f, cause, serr, s0, pr, ewake;
807 if(d->ctlr->type == Tjmicron)
815 }else if(cause & Adps){
817 }else if(cause & Atfes){
824 dprint("%s: fatal\n", dnam(d));
828 if(ignoreahdrs(d) && serr & ErrE)
830 dprint("%s: Adhrs cause %lux serr %lux task %lux\n",
831 dnam(d), cause, serr, p->task);
837 if(p->task & 1 && last != cause)
838 dprint("%s: err ca %lux serr %lux task %lux sstat %.3lux\n",
839 dnam(d), cause, serr, p->task, p->sstatus);
841 dprint("%s: upd %lux ta %lux\n", dnam(d), cause, p->task);
843 if(cause & (Aprcs|Aifs)){
845 switch(p->sstatus & Smask){
850 if((p->sstatus & Imask) == Islumber)
856 /* power mgnt crap for suprise removal */
857 p->ie |= Aprcs|Apcs; /* is this required? */
864 dprint("%s: updatedrive: %s → %s [ss %.3lux]\n",
865 dnam(d), diskstates[s0], diskstates[d->state], p->sstatus);
866 if(s0 == Dready && d->state != Dready)
867 dprint("%s: pulled\n", dnam(d));
868 if(d->state != Dready)
870 if(d->state != Dready || p->ci)
884 dstatus(Drive *d, int s)
886 dprint("%s: dstatus: %s → %s from pc=%p\n", dnam(d),
887 diskstates[d->state], diskstates[s], getcallerpc(&d));
895 configdrive(Drive *d)
897 if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1){
898 dstatus(d, Dportreset);
903 switch(d->port->sstatus & Smask){
909 if(d->state == Dnull)
910 d->state = Dportreset;
913 if(d->state == Dready)
924 dprint("%s: configdrive: %s\n", dnam(d), diskstates[d->state]);
930 uint state, det, stat;
935 stat = p->sstatus & Smask;
936 state = (p->cmd>>28) & 0xf;
937 dprint("%s: resetdisk [icc %ux; det %.3ux; sdet %.3ux]\n", dnam(d), state, det, stat);
940 if(d->state != Dready && d->state != Dnew)
941 d->portm.flag |= Ferror;
943 d->state = Dportreset;
946 clearci(p); /* satisfy sleep condition. */
954 if(p->cmd&Ast && ahciswreset(&d->portc) == -1)
955 dstatus(d, Dportreset); /* get a bigger stick. */
972 setfissig(m, c->p->sig);
973 if(identify(d) == -1){
974 dprint("%s: identify failure\n", dnam(d));
977 if(settxmode(c, m->udma) == -1){
978 dprint("%s: can't set udma mode\n", dnam(d));
981 if(m->feat & Dpower && setfeatures(c, 0x85, 3*1000) == -1){
982 dprint("%s: can't disable apm\n", dnam(d));
984 if(ahcirecover(c) == -1)
993 idprint("%s: %sLBA %,lld sectors\n", dnam(d), s, d->sectors);
994 idprint(" %s %s %s %s\n", d->model, d->firmware, d->serial,
995 d->drivechange? "[newdrive]": "");
999 idprint("%s: can't be initialized\n", dnam(d));
1007 Mcomrwait = 1*1024/Nms - 1,
1008 Mphywait = 2*1024/Nms - 1,
1009 Midwait = 16*1024/Nms - 1,
1015 if(d->active && d->totick != 0 && (long)(Ticks - d->totick) > 0){
1016 dprint("%s: drive hung [task %lux; ci %lux; serr %lux]%s\n",
1017 dnam(d), d->port->task, d->port->ci, d->port->serror,
1018 d->nodma == 0 ? "; disabling dma" : "");
1024 static ushort olds[NCtlr*NCtlrdrv];
1027 doportreset(Drive *d)
1030 ahciportreset(&d->portc, d->mode);
1033 dprint("ahci: portreset: %s [task %lux; ss %.3lux]\n",
1034 diskstates[d->state], d->port->task, d->port->sstatus);
1037 /* drive must be locked */
1039 statechange(Drive *d)
1045 if(d->unit->sectors != 0){
1057 return (c->hba->cap & 0xf*Hiss)/Hiss;
1060 static void iainterrupt(Ureg*, void *);
1063 checkdrive(Drive *d, int i)
1067 if(d->ctlr->enabled == 0)
1070 iainterrupt(0, d->ctlr); /* check for missed irq's */
1073 s = d->port->sstatus;
1075 d->lastseen = Ticks;
1077 dprint("%s: status: %.3ux -> %.3ux: %s\n",
1078 dnam(d), olds[i], s, diskstates[d->state]);
1089 switch(s & (Iactive|Smask)){
1091 ahciwakeup(&d->portc, d->mode);
1095 dprint("%s: unknown status %.3ux\n", dnam(d), s);
1097 case Iactive: /* active, no device */
1098 if(++d->wait&Mphywait)
1102 d->mode = maxmode(d->ctlr);
1105 if(d->mode == DMautoneg){
1107 d->state = Dportreset;
1110 dprint("%s: reset; new mode %s\n", dnam(d),
1116 case Iactive | Sphylink:
1119 if((++d->wait&Midwait) == 0){
1120 dprint("%s: slow reset [task %lux; ss %.3ux; wait %d]\n",
1121 dnam(d), d->port->task, s, d->wait);
1124 s = (uchar)d->port->task;
1125 sig = d->port->sig >> 16;
1126 if(s == 0x7f || s&ASbsy ||
1127 (sig != 0xeb14 && (s & ASdrdy) == 0))
1136 if(d->wait++ & Mcomrwait)
1140 dprint("%s: reset [%s]: mode %d; status %.3ux\n",
1141 dnam(d), diskstates[d->state], d->mode, s);
1148 if(d->wait++ & Mcomrwait)
1150 if(d->wait > Mcomrwait && (s & Iactive) == 0){
1151 d->state = Dnull; /* stuck in portreset */
1154 dprint("%s: portreset [%s]: mode %d; status %.3ux\n",
1155 dnam(d), diskstates[d->state], d->mode, s);
1156 d->portm.flag |= Ferror;
1159 if((s & Smask) == Smissing){
1160 d->state = Dmissing;
1180 tsleep(&up->sleep, return0, 0, Nms);
1181 for(i = 0; i < niadrive; i++)
1182 checkdrive(iadrive[i], i);
1187 iainterrupt(Ureg *u, void *a)
1196 cause = c->hba->isr;
1197 for(i = 0; cause; i++){
1199 if((cause & m) == 0)
1202 d = c->rawdrive + i;
1204 if(d->port != nil && d->port->isr && c->hba->pi & m)
1215 ahciencreset(Ctlr *c)
1220 if(c->enctype == Eesb)
1224 for(i = 0; i < 1000; i++){
1225 if((h->emctl & Emrst) == 0)
1229 print("%s: ahciencreset: hung ctlr\n", Tname(c));
1234 * from the standard: (http://en.wikipedia.org/wiki/IBPI)
1235 * rebuild is preferred as locate+fail; alternate 1hz fail
1236 * we're going to assume no locate led.
1240 Ledsleep = 125, /* 8hz */
1243 L0 = Ledon*Aled | Ledon*Locled,
1244 L1 = Ledon*Aled | Ledoff*Locled,
1245 R0 = Ledon*Aled | Ledon*Locled | Ledon*Errled,
1246 R1 = Ledon*Aled | Ledoff*Errled,
1247 S0 = Ledon*Aled | Ledon*Locled /*| Ledon*Errled*/, /* botch */
1248 S1 = Ledon*Aled | Ledoff*Errled,
1249 P0 = Ledon*Aled | Ledon*Errled,
1250 P1 = Ledon*Aled | Ledoff*Errled,
1251 F0 = Ledon*Aled | Ledon*Errled,
1252 C0 = Ledon*Aled | Ledon*Locled,
1253 C1 = Ledon*Aled | Ledoff*Locled,
1257 //static ushort led3[Ibpilast*8] = {
1258 //[Ibpinone*8] 0, 0, 0, 0, 0, 0, 0, 0,
1259 //[Ibpinormal*8] N0, N0, N0, N0, N0, N0, N0, N0,
1260 //[Ibpirebuild*8] R0, R0, R0, R0, R1, R1, R1, R1,
1261 //[Ibpilocate*8] L0, L1, L0, L1, L0, L1, L0, L1,
1262 //[Ibpispare*8] S0, S1, S0, S1, S1, S1, S1, S1,
1263 //[Ibpipfa*8] P0, P1, P0, P1, P1, P1, P1, P1, /* first 1 sec */
1264 //[Ibpifail*8] F0, F0, F0, F0, F0, F0, F0, F0,
1265 //[Ibpicritarray*8] C0, C0, C0, C0, C1, C1, C1, C1,
1266 //[Ibpifailarray*8] C0, C1, C0, C1, C0, C1, C0, C1,
1269 static ushort led2[Ibpilast*8] = {
1270 [Ibpinone*8] 0, 0, 0, 0, 0, 0, 0, 0,
1271 [Ibpinormal*8] N0, N0, N0, N0, N0, N0, N0, N0,
1272 [Ibpirebuild*8] R0, R0, R0, R0, R1, R1, R1, R1,
1273 [Ibpilocate*8] L0, L0, L0, L0, L0, L0, L0, L0,
1274 [Ibpispare*8] S0, S0, S0, S0, S1, S1, S1, S1,
1275 [Ibpipfa*8] P0, P1, P0, P1, P1, P1, P1, P1, /* first 1 sec */
1276 [Ibpifail*8] F0, F0, F0, F0, F0, F0, F0, F0,
1277 [Ibpicritarray*8] C0, C0, C0, C0, C1, C1, C1, C1,
1278 [Ibpifailarray*8] C0, C1, C0, C1, C0, C1, C0, C1,
1282 ledstate(Ledport *p, uint seq)
1286 if(p->led == Ibpipfa && seq%32 >= 8)
1289 i = led2[8*p->led + seq%8];
1290 if(i != p->ledbits){
1292 ledprint("ledstate %,.011ub %ud\n", p->ledbits, seq);
1299 blink(Drive *d, ulong t)
1305 if(ledstate(d, t) == 0)
1310 /* ensure last message has been transmitted */
1316 panic("%s: bad led type %d", dnam(d), c->enctype);
1318 memset(&msg, 0, sizeof msg);
1321 msg.msize = sizeof msg - 4;
1322 msg.led[0] = d->ledbits;
1323 msg.led[1] = d->ledbits>>8;
1325 msg.hba = d->driveno;
1326 memmove(c->enctx, &msg, sizeof msg);
1334 Esbdrv0 = 4, /* start pos in bits */
1335 Esbiota = 3, /* shift in bits */
1344 uint i, e; /* except after c */
1347 for(i = 0; i < 3; i++)
1348 e |= ((s>>3*i & 7) != 0)<<i;
1353 blinkesb(Ctlr *c, ulong t)
1360 for(i = 0; i < c->ndrive; i++){
1362 s |= ledstate(d, t); /* no port mapping */
1366 memset(u, 0, sizeof u);
1367 for(i = 0; i < c->ndrive; i++){
1369 s = Esbdrv0 + Esbiota*i;
1370 v = esbbits(d->ledbits) * (1ull << s%32);
1372 u[s/32 + 1] |= v>>32;
1374 for(i = 0; i < c->encsz; i++)
1380 ahciledr(SDunit *u, Chan *ch, void *a, long n, vlong off)
1386 d = c->drive[u->subno];
1387 return ledr(d, ch, a, n, off);
1391 ahciledw(SDunit *u, Chan *ch, void *a, long n, vlong off)
1397 d = c->drive[u->subno];
1398 return ledw(d, ch, a, n, off);
1410 memset(map, 0, sizeof map);
1411 for(i = 0; i < niactlr; i++)
1412 if(iactlr[i].enctype != 0){
1413 if(ahciencreset(iactlr + i) == -1)
1419 pexit("no work", 1);
1420 for(i = 0; i < niadrive; i++){
1422 d->nled = 3; /* hardcoded */
1423 if(d->ctlr->enctype == Eesb)
1429 for(j = 0; j < niadrive; ){
1432 if(map[c - iactlr] == 0)
1435 if(c->enctype == Eesb){
1444 esleep(Ledsleep - TK2MS(t1 - t0));
1453 for(i = 0;; i += 250){
1454 if(d->state == Dreset || d->state == Dportreset || d->state == Dnew)
1457 s = d->port->sstatus;
1458 if(d->state == Dready && (s & Smask) == Sphylink){
1462 δ = Ticks - d->lastseen;
1463 if(d->state == Dnull || δ > 10*1000)
1465 if((s & Imask) == 0 && δ > 1500)
1468 d->state = Doffline;
1470 print("%s: not responding; offline\n", dnam(d));
1487 d = c->drive[u->subno];
1493 sdaddfile(u, "led", 0644, eve, ahciledr, ahciledw);
1497 checkdrive(d, d->driveno); /* c->d0 + d->driveno */
1509 d = c->drive[u->subno];
1511 while(d->state != Dmissing && waitready(d) == 1)
1514 dprint("%s: iaonline: %s\n", dnam(d), diskstates[d->state]);
1517 if(d->portm.feat & Datapi){
1523 return scsionline(u);
1529 }else if(d->state == Dready)
1532 u->sectors = d->sectors;
1533 u->secsize = d->secsize;
1554 panic("iaenable: zero s->ctlr->ndrive");
1556 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1557 intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1558 /* supposed to squelch leftover interrupts here. */
1564 kproc("iasata", satakproc, 0);
1565 if(++once == niactlr)
1566 kproc("ialed", ledkproc, 0);
1579 ahcidisable(c->hba);
1580 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1581 intrdisable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1588 ahcibuild(Drive *d, int rw, void *data, int nsect, vlong lba)
1596 rwfis(m, c, rw, nsect, lba);
1600 return mkalist(m, flags, data, nsect * d->secsize);
1604 ahcibuildpkt(Drive *d, SDreq *r, void *data, int n)
1615 atapirwfis(m, c, r->cmd, r->clen, 0x2000);
1616 if((n & 15) != 0 || d->nodma)
1617 c[Ffeat] &= ~1; /* use pio */
1618 else if(c[Ffeat] & 1 && d->info[62] & (1<<15)) /* dma direction */
1619 c[Ffeat] = (c[Ffeat] & ~(1<<2)) | ((r->write == 0) << 2);
1620 flags = Lpref | Latapi;
1621 if(r->write != 0 && data)
1623 return mkalist(m, flags, data, n);
1627 ahcibuildfis(Drive *d, SDreq *r, void *data, uint n)
1633 if((r->ataproto & Pprotom) == Ppkt)
1634 return ahcibuildpkt(d, r, data, n);
1638 memmove(c, r->cmd, r->clen);
1640 if(r->write || n == 0)
1642 return mkalist(m, flags, data, n);
1651 while ((i = waitready(d)) == 1) {
1660 flushcache(Drive *d)
1665 if(lockready(d) == 0)
1666 i = ahciflushcache(&d->portc);
1672 io(Drive *d, uint proto, int to, int interrupt)
1674 uint task, flag, stat, rv;
1678 switch(waitready(d)){
1695 d->totick = Ticks + MS2TK(to) | 1; /* fix fencepost */
1702 if(ahcicomreset(&d->portc) == -1)
1707 sleep(&d->portm, ahciclear, &as);
1713 flag = d->portm.flag;
1714 task = d->port->task;
1718 if(proto & Ppkt && stat == Dready){
1719 rv = task >> 8 + 4 & 0xf;
1722 }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && stat == Dready){
1724 ahcirecover(&d->portc);
1725 task = d->port->task;
1726 flag &= ~Fdone; /* either an error or do-over */
1729 print("%s: retry\n", dnam(d));
1732 if(flag & (Fahdrs | Ferror)){
1733 if((task & Eidnf) == 0)
1734 print("%s: i/o error %ux\n", dnam(d), task);
1741 iariopkt(SDreq *r, Drive *d)
1748 aprint("%s: %.2ux %.2ux %c %d %p\n", dnam(d), cmd[0], cmd[2],
1749 "rw"[r->write], r->dlen, r->data);
1754 * prevent iaonline() to hang forever by timing out
1755 * inquiry and capacity commands after 5 seconds.
1759 case 0x9e: if(cmd[1] != 0x10) break;
1766 for(try = 0; try < 10; try++){
1768 l = ahcibuildpkt(d, r, r->data, r->dlen);
1769 r->status = io(d, Ppkt, to, 0);
1782 print("%s: bad disk\n", dnam(d));
1783 return r->status = SDcheck;
1787 ahcibio(SDunit *u, int lun, int write, void *a, long count, uvlong lba)
1789 int n, rw, try, status, max;
1795 d = c->drive[u->subno];
1796 if(d->portm.feat & Datapi)
1797 return scsibio(u, lun, write, a, count, lba);
1800 if(d->portm.feat & Dllba){
1801 max = 8192; /* ahci maximum */
1802 if(c->type == Tsb600)
1803 max = 255; /* errata */
1805 rw = write? SDwrite: SDread;
1807 dprint("%s: bio: %llud %c %lud %p\n",
1808 dnam(d), lba, "rw"[rw], count, data);
1810 for(try = 0; try < 10;){
1815 ahcibuild(d, rw, data, n, lba);
1816 status = io(d, Pdma, 5000, 0);
1828 data += n * u->secsize;
1830 return data - (uchar*)a;
1832 print("%s: bad disk\n", dnam(d));
1839 int i, n, count, rw;
1848 d = c->drive[u->subno];
1849 if(d->portm.feat & Datapi)
1850 return iariopkt(r, d);
1853 if(cmd[0] == 0x35 || cmd[0] == 0x91){
1854 if(flushcache(d) == 0)
1855 return sdsetsense(r, SDok, 0, 0, 0);
1856 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1859 if((i = sdfakescsi(r)) != SDnostatus){
1864 if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
1866 n = ahcibio(u, r->lun, r->write, r->data, count, lba);
1873 static uchar bogusrfis[16] = {
1886 memmove(c, bogusrfis, sizeof bogusrfis);
1891 sdr(SDreq *r, Drive *d, int st)
1896 if((r->ataproto & Pprotom) == Ppkt){
1899 st = t >> 8 + 4 & 0xf;
1902 memmove(r->cmd, c, 16);
1910 fisreqchk(Sfis *f, SDreq *r)
1912 if((r->ataproto & Pprotom) == Ppkt)
1915 * handle oob requests;
1916 * restrict & sanitize commands
1920 if(r->cmd[0] == 0xf0){
1921 sigtofis(f, r->cmd);
1942 d = c->drive[u->subno];
1944 if((r->status = fisreqchk(&d->portm, r)) != SDnostatus)
1948 for(try = 0; try < 10; try++){
1950 l = ahcibuildfis(d, r, r->data, r->dlen);
1951 r->status = io(d, r->ataproto & Pprotom, -1, 1);
1955 return sdsetsense(r, SDcheck, 11, 0, 6);
1963 r->rlen = (r->ataproto & Pprotom) == Ppkt ? l->len : r->dlen;
1964 try = sdr(r, d, r->status);
1968 print("%s: bad disk\n", dnam(d));
1969 return r->status = SDeio;
1973 Ghc = 0x04/4, /* global host control */
1974 Pi = 0x0c/4, /* ports implemented */
1975 Cmddec = 1<<15, /* enable command block decode */
1978 Ahcien = 1<<31, /* ahci enable */
1982 iasetupahci(Ctlr *c)
1987 pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~Cmddec);
1988 pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~Cmddec);
1990 c->lmmio[Ghc] |= Ahcien;
1991 c->lmmio[Pi] = (1 << 6) - 1; /* 6 ports (supposedly ro pi reg) */
1993 /* enable ahci mode; from ich9 datasheet */
1994 pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
1996 /* configure drives 0-5 as ahci sata (c.f. errata) */
1997 pcicfgw16(c->pci, 0x92, pcicfgr16(c->pci, 0x92) | 0xf);
2001 sbsetupahci(Pcidev *p)
2003 print("sbsetupahci: tweaking %.4ux ccru %.2ux ccrp %.2ux\n",
2004 p->did, p->ccru, p->ccrp);
2005 pcicfgw8(p, 0x40, pcicfgr8(p, 0x40) | 1);
2006 pcicfgw8(p, PciCCRu, 6);
2007 pcicfgw8(p, PciCCRp, 1);
2016 c->enctx = (ulong*)(c->mmio + 0xa0);
2023 ahciencinit(Ctlr *c)
2025 ulong type, sz, o, *bar;
2031 if((h->cap & Hems) == 0)
2033 type = h->emctl & Emtype;
2045 sz = h->emloc & 0xffff;
2047 if(sz == 0 || o == 0)
2050 dprint("size = %.4lux; loc = %.4lux*4\n", sz, o);
2053 if((h->emctl & Xonly) == 0){
2057 c->encrx = bar + o*2;
2073 if((p->did & 0xffff) == 0x1e02)
2074 return Tich; /* c210 */
2075 if((p->did & 0xffff) == 0x8c02)
2076 return Tich; /* c220 */
2077 if((p->did & 0xffff) == 0x24d1)
2078 return Tich; /* 82801eb/er */
2079 if((p->did & 0xffff) == 0x2653)
2080 return Tich; /* 82801fbm */
2081 if((p->did & 0xfffc) == 0x2680)
2083 if((p->did & 0xfffb) == 0x27c1)
2084 return Tich; /* 82801g[bh]m */
2085 if((p->did & 0xffff) == 0x2822)
2086 return Tich; /* 82801 SATA RAID */
2087 if((p->did & 0xffff) == 0x2821)
2088 return Tich; /* 82801h[roh] */
2089 if((p->did & 0xfffe) == 0x2824)
2090 return Tich; /* 82801h[b] */
2091 if((p->did & 0xfeff) == 0x2829)
2092 return Tich; /* ich8 */
2093 if((p->did & 0xfffe) == 0x2922)
2094 return Tich; /* ich9 */
2095 if((p->did & 0xffff) == 0x3a02)
2096 return Tich; /* 82801jd/do */
2097 if((p->did & 0xfefe) == 0x3a22)
2098 return Tich; /* ich10, pch */
2099 if((p->did & 0xfff7) == 0x3b28)
2100 return Tich; /* pchm */
2101 if((p->did & 0xfffe) == 0x3b22)
2102 return Tich; /* pch */
2105 if(p->ccru == 1 || p->ccrp != 1)
2106 if(p->did == 0x4380 || p->did == 0x4390)
2112 * unconfirmed report that the programming
2113 * interface is set incorrectly.
2115 if(p->did == 0x3349)
2119 /* Hudson SATA Controller [AHCI mode] */
2120 if((p->did & 0xfffe) == 0x7800){
2135 if(p->ccrb == Pcibcstore && p->ccru == 6 && p->ccrp == 1)
2143 int i, n, nunit, type;
2155 if(getconf("*noahci") != nil)
2158 if(getconf("*ahcidebug") != nil){
2163 memset(olds, 0xff, sizeof olds);
2165 while((p = pcimatch(p, 0, 0)) != nil){
2166 if((type = didtype(p)) == -1)
2168 io = p->mem[Abar].bar;
2169 if(io == 0 || (io & 1) != 0 || p->mem[Abar].size < 0x180)
2172 if(niactlr == NCtlr){
2173 print("iapnp: %s: too many controllers\n", tname[type]);
2176 c = iactlr + niactlr;
2177 s = sdevs + niactlr;
2178 memset(c, 0, sizeof *c);
2179 memset(s, 0, sizeof *s);
2180 c->mmio = vmap(io, p->mem[Abar].size);
2182 print("%s: address %#p in use did %.4ux\n",
2183 Tname(c), io, p->did);
2186 c->lmmio = (ulong*)c->mmio;
2190 s->ifc = &sdiahciifc;
2196 ahcihandoff((Ahba*)c->mmio);
2197 if(p->vid == 0x8086)
2199 nunit = ahciconf(c);
2201 vunmap(c->mmio, p->mem[Abar].size);
2205 c->ndrive = s->nunit = nunit;
2207 /* map the drives -- they don't all need to be enabled. */
2208 memset(c->rawdrive, 0, sizeof c->rawdrive);
2210 for(i = 0; i < NCtlrdrv; i++){
2211 d = c->rawdrive + i;
2217 if((c->hba->pi & 1<<i) == 0)
2219 io = 0x100 + 0x80*i;
2220 if((io + 0x80) > p->mem[Abar].size)
2222 d->port = (Aport*)(c->mmio + io);
2223 d->portc.p = d->port;
2224 d->portc.m = &d->portm;
2226 snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
2227 c->drive[d->driveno] = d;
2228 iadrive[niadrive + d->driveno] = d;
2230 for(i = 0; i < n; i++){
2231 c->drive[i]->mode = DMautoneg;
2232 configdrive(c->drive[i]);
2239 i = (c->hba->cap >> 21) & 1;
2240 print("#S/%s: %s: sata-%s with %d ports\n", s->name,
2241 Tname(c), "I\0II" + i*2, nunit);
2246 static Htab ctab[] = {
2268 capfmt(char *p, char *e, Htab *t, int n, ulong cap)
2273 for(i = 0; i < n; i++)
2275 p = seprint(p, e, "%s ", t[i].name);
2280 iarctl(SDunit *u, char *p, int l)
2282 char buf[32], *e, *op;
2287 if((c = u->dev->ctlr) == nil)
2289 d = c->drive[u->subno];
2294 if(d->state == Dready){
2295 p = seprint(p, e, "model\t%s\n", d->model);
2296 p = seprint(p, e, "serial\t%s\n", d->serial);
2297 p = seprint(p, e, "firm\t%s\n", d->firmware);
2299 p = seprint(p, e, "wwn\t%ullx\n", d->wwn);
2300 p = seprint(p, e, "flag\t");
2301 p = pflag(p, e, &d->portm);
2302 p = seprint(p, e, "udma\t%d\n", d->portm.udma);
2304 p = seprint(p, e, "no disk present [%s]\n", diskstates[d->state]);
2305 serrstr(o->serror, buf, buf + sizeof buf - 1);
2306 p = seprint(p, e, "reg\ttask %lux cmd %lux serr %lux %s ci %lux is %lux "
2307 "sig %lux sstatus %.3lux\n", o->task, o->cmd, o->serror, buf,
2308 o->ci, o->isr, o->sig, o->sstatus);
2309 p = seprint(p, e, "cmd\t");
2310 p = capfmt(p, e, ctab, nelem(ctab), o->cmd);
2311 p = seprint(p, e, "\n");
2312 p = seprint(p, e, "mode\t%s %s\n", modes[d->mode], modes[maxmode(c)]);
2313 p = seprint(p, e, "geometry %llud %d\n", d->sectors, d->secsize);
2314 p = seprint(p, e, "alignment %d %d\n",
2315 d->secsize<<d->portm.physshift, d->portm.physalign);
2316 p = seprint(p, e, "missirq\t%ud\n", c->missirq);
2321 forcemode(Drive *d, char *mode)
2325 for(i = 0; i < nelem(modes); i++)
2326 if(strcmp(mode, modes[i]) == 0)
2328 if(i == nelem(modes))
2336 forcestate(Drive *d, char *state)
2340 for(i = 0; i < nelem(diskstates); i++)
2341 if(strcmp(state, diskstates[i]) == 0)
2343 if(i == nelem(diskstates))
2349 runsettxmode(Drive *d, char *s)
2359 if(lockready(d) == 0){
2361 if(settxmode(c, m->udma) == 0)
2370 iawctl(SDunit *u, Cmdbuf *cmd)
2377 d = c->drive[u->subno];
2380 if(strcmp(f[0], "mode") == 0)
2381 forcemode(d, f[1]? f[1]: "satai");
2382 else if(strcmp(f[0], "state") == 0)
2383 forcestate(d, f[1]? f[1]: "null");
2384 else if(strcmp(f[0], "txmode") == 0){
2385 if(runsettxmode(d, f[1]? f[1]: "0"))
2386 cmderror(cmd, "bad txmode / stuck port");
2388 cmderror(cmd, Ebadctl);
2393 portr(char *p, char *e, uint x)
2399 for(i = 0; i < 32; i++){
2400 if((x & (1<<i)) == 0){
2401 if(a != -1 && i - 1 != a)
2402 p = seprint(p, e, "-%d", i - 1);
2408 p = seprint(p, e, ", ");
2409 p = seprint(p, e, "%d", a = i);
2412 if(a != -1 && i - 1 != a)
2413 p = seprint(p, e, "-%d", i - 1);
2417 static Htab htab[] = {
2437 static Htab htab2[] = {
2443 static Htab emtab[] = {
2455 iartopctl(SDev *s, char *p, char *e)
2465 p = seprint(p, e, "sd%c ahci %s port %#p: ", s->idno, Tname(c), h);
2466 p = capfmt(p, e, htab, nelem(htab), cap);
2467 p = capfmt(p, e, htab2, nelem(htab2), h->cap2);
2468 p = capfmt(p, e, emtab, nelem(emtab), h->emctl);
2469 portr(pr, pr + sizeof pr, h->pi);
2470 return seprint(p, e,
2471 "iss %ld ncs %ld np %ld ghc %lux isr %lux pi %lux %s ver %lux\n",
2472 (cap>>20) & 0xf, (cap>>8) & 0x1f, 1 + (cap & 0x1f),
2473 h->ghc, h->isr, h->pi, pr, h->ver);
2477 iawtopctl(SDev *, Cmdbuf *cmd)
2485 if(strcmp(f[0], "debug") == 0)
2487 else if(strcmp(f[0], "idprint") == 0)
2489 else if(strcmp(f[0], "aprint") == 0)
2491 else if(strcmp(f[0], "ledprint") == 0)
2494 cmderror(cmd, Ebadctl);
2498 cmderror(cmd, Ebadarg);
2504 *v = strcmp(f[1], "on") == 0;
2512 SDifc sdiahciifc = {