]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/sdiahci.c
pc, pc64: more conservative pcirouting
[plan9front.git] / sys / src / 9 / pc / sdiahci.c
1 /*
2  * intel/amd ahci sata controller
3  * copyright © 2007-10 coraid, inc.
4  */
5
6 #include "u.h"
7 #include "../port/lib.h"
8 #include "mem.h"
9 #include "dat.h"
10 #include "fns.h"
11 #include "io.h"
12 #include "../port/error.h"
13 #include "../port/sd.h"
14 #include <fis.h>
15 #include "ahci.h"
16 #include "../port/led.h"
17
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)
27
28 enum {
29         NCtlr   = 4,
30         NCtlrdrv= 32,
31         NDrive  = NCtlr*NCtlrdrv,
32
33         Fahdrs  = 4,
34
35         Read    = 0,
36         Write,
37
38         Eesb    = 1<<0, /* must have (Eesb & Emtype) == 0 */
39 };
40
41 /* pci space configuration */
42 enum {
43         Pmap    = 0x90,
44         Ppcs    = 0x91,
45         Prev    = 0xa8,
46 };
47
48 enum {
49         Tesb,
50         Tich,
51         Tsb600,
52         Tjmicron,
53         Tahci,
54 };
55
56 static char *tname[] = {
57         "63xxesb",
58         "ich",
59         "sb600",
60         "jmicron",
61         "ahci",
62 };
63
64 enum {
65         Dnull,
66         Dmissing,
67         Dnew,
68         Dready,
69         Derror,
70         Dreset,
71         Doffline,
72         Dportreset,
73         Dlast,
74 };
75
76 static char *diskstates[Dlast] = {
77         "null",
78         "missing",
79         "new",
80         "ready",
81         "error",
82         "reset",
83         "offline",
84         "portreset",
85 };
86
87 extern SDifc sdiahciifc;
88 typedef struct Ctlr Ctlr;
89
90 enum {
91         DMautoneg,
92         DMsatai,
93         DMsataii,
94         DMsataiii,
95         DMlast,
96 };
97
98 static char *modes[DMlast] = {
99         "auto",
100         "satai",
101         "sataii",
102         "sataiii",
103 };
104
105 typedef struct Htab Htab;
106 struct Htab {
107         ulong   bit;
108         char    *name;
109 };
110
111 typedef struct {
112         Lock;
113
114         Ctlr    *ctlr;
115         SDunit  *unit;
116         char    name[10];
117         Aport   *port;
118         Aportm  portm;
119         Aportc  portc;  /* redundant ptr to port and portm. */
120         Ledport;
121
122         uchar   drivechange;
123         uchar   nodma;
124         uchar   state;
125
126         uvlong  sectors;
127         uint    secsize;
128         ulong   totick;
129         ulong   lastseen;
130         uint    wait;
131         uchar   mode;
132         uchar   active;
133
134         char    serial[20+1];
135         char    firmware[8+1];
136         char    model[40+1];
137         uvlong  wwn;
138
139         ushort  info[0x200];
140
141         /*
142          * ahci allows non-sequential ports.
143          * to avoid this hassle, we let
144          * driveno      ctlr*NCtlrdrv + unit
145          * portno       nth available port
146          */
147         uint    driveno;
148         uint    portno;
149 } Drive;
150
151 struct Ctlr {
152         Lock;
153
154         int     type;
155         int     enabled;
156         SDev    *sdev;
157         Pcidev  *pci;
158
159         uchar   *mmio;
160         ulong   *lmmio;
161         Ahba    *hba;
162         Aenc;
163         uint    enctype;
164
165         Drive   rawdrive[NCtlrdrv];
166         Drive*  drive[NCtlrdrv];
167         int     ndrive;
168
169         uint    missirq;
170 };
171
172 static  Ctlr    iactlr[NCtlr];
173 static  SDev    sdevs[NCtlr];
174 static  int     niactlr;
175
176 static  Drive   *iadrive[NDrive];
177 static  int     niadrive;
178
179 static  int     debug;
180 static  int     prid = 1;
181 static  int     datapi;
182 static  int     dled;
183
184 static char stab[] = {
185 [0]     'i', 'm',
186 [8]     't', 'c', 'p', 'e',
187 [16]    'N', 'I', 'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X'
188 };
189
190 static void
191 serrstr(ulong r, char *s, char *e)
192 {
193         int i;
194
195         e -= 3;
196         for(i = 0; i < nelem(stab) && s < e; i++)
197                 if(r & (1<<i) && stab[i]){
198                         *s++ = stab[i];
199                         if(SerrBad & (1<<i))
200                                 *s++ = '*';
201                 }
202         *s = 0;
203 }
204
205 static char ntab[] = "0123456789abcdef";
206
207 static void
208 preg(uchar *reg, int n)
209 {
210         char buf[25*3+1], *e;
211         int i;
212
213         e = buf;
214         for(i = 0; i < n; i++){
215                 *e++ = ntab[reg[i] >> 4];
216                 *e++ = ntab[reg[i] & 0xf];
217                 *e++ = ' ';
218         }
219         *e++ = '\n';
220         *e = 0;
221         dprint(buf);
222 }
223
224 static void
225 dreg(char *s, Aport *p)
226 {
227         dprint("%stask=%lux; cmd=%lux; ci=%lux; is=%lux\n",
228                 s, p->task, p->cmd, p->ci, p->isr);
229 }
230
231 static void
232 esleep(int ms)
233 {
234         if(waserror())
235                 return;
236         tsleep(&up->sleep, return0, 0, ms);
237         poperror();
238 }
239
240 typedef struct {
241         Aport   *p;
242         int     i;
243 } Asleep;
244
245 static int
246 ahciclear(void *v)
247 {
248         Asleep *s;
249
250         s = v;
251         return (s->p->ci & s->i) == 0;
252 }
253
254 static void
255 aesleep(Aportm *m, Asleep *a, int ms)
256 {
257         if(waserror())
258                 return;
259         tsleep(m, ahciclear, a, ms);
260         poperror();
261 }
262
263 static int
264 ahciwait(Aportc *c, int ms)
265 {
266         Aport *p;
267         Asleep as;
268
269         p = c->p;
270         p->ci = 1;
271         as.p = p;
272         as.i = 1;
273         aesleep(c->m, &as, ms);
274         if((p->task & 1) == 0 && p->ci == 0)
275                 return 0;
276         dreg("ahciwait fail/timeout ", c->p);
277         return -1;
278 }
279
280 static Alist*
281 mkalist(Aportm *m, uint flags, uchar *data, int len)
282 {
283         Actab *t;
284         Alist *l;
285         Aprdt *p;
286
287         t = m->ctab;
288         if(data && len > 0){
289                 p = &t->prdt;
290                 p->dba = PCIWADDR(data);
291                 p->dbahi = Pciwaddrh(data);
292                 p->count = 1<<31 | len - 2 | 1;
293                 flags |= 1<<16;
294         }
295         l = m->list;
296         l->flags = flags | 0x5;
297         l->len = 0;
298         l->ctab = PCIWADDR(t);
299         l->ctabhi = Pciwaddrh(t);
300         return l;
301 }
302
303 static int
304 nop(Aportc *pc)
305 {
306         uchar *c;
307
308         if((pc->m->feat & Dnop) == 0)
309                 return -1;
310         c = pc->m->ctab->cfis;
311         nopfis(pc->m, c, 0);
312         mkalist(pc->m, Lwrite, 0, 0);
313         return ahciwait(pc, 3*1000);
314 }
315
316 static int
317 setfeatures(Aportc *pc, uchar f, uint w)
318 {
319         uchar *c;
320
321         c = pc->m->ctab->cfis;
322         featfis(pc->m, c, f);
323         mkalist(pc->m, Lwrite, 0, 0);
324         return ahciwait(pc, w);
325 }
326
327 /*
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.
334  */
335 static int
336 settxmode(Aportc *pc, uchar f)
337 {
338         uchar *c;
339
340         c = pc->m->ctab->cfis;
341         if(txmodefis(pc->m, c, f) == -1)
342                 return 0;
343         mkalist(pc->m, Lwrite, 0, 0);
344         return ahciwait(pc, 3*1000);
345 }
346
347 static void
348 asleep(int ms)
349 {
350         if(up == nil || !islo())
351                 delay(ms);
352         else
353                 esleep(ms);
354 }
355
356 static int
357 ahciportreset(Aportc *c, uint mode)
358 {
359         ulong *cmd, i;
360         Aport *p;
361
362         p = c->p;
363         cmd = &p->cmd;
364         *cmd &= ~(Afre|Ast);
365         for(i = 0; i < 500; i += 25){
366                 if((*cmd & Acr) == 0)
367                         break;
368                 asleep(25);
369         }
370         if((*cmd & Apwr) != Apwr)
371                 *cmd |= Apwr;
372         p->sctl = 3*Aipm | 0*Aspd | Adet;
373         delay(1);
374         p->sctl = 3*Aipm | mode*Aspd;
375         return 0;
376 }
377
378 static int
379 ahciflushcache(Aportc *pc)
380 {
381         uchar *c;
382
383         c = pc->m->ctab->cfis;
384         flushcachefis(pc->m, c);
385         mkalist(pc->m, Lwrite, 0, 0);
386
387         if(ahciwait(pc, 60000) == -1 || pc->p->task & (1|32)){
388                 dprint("ahciflushcache fail [task %lux]\n", pc->p->task);
389 //              preg(pc->m->fis.r, 20);
390                 return -1;
391         }
392         return 0;
393 }
394
395 static int
396 ahciidentify0(Aportc *pc, void *id)
397 {
398         uchar *c;
399         Actab *t;
400
401         t = pc->m->ctab;
402         c = t->cfis;
403         memset(id, 0, 0x200);
404         identifyfis(pc->m, c);
405         mkalist(pc->m, 0, id, 0x200);
406         return ahciwait(pc, 3*1000);
407 }
408
409 static vlong
410 ahciidentify(Aportc *pc, ushort *id, uint *ss, char *d)
411 {
412         int i, n;
413         vlong s;
414         Aportm *m;
415
416         m = pc->m;
417         for(i = 0;; i++){
418                 if(i > 5 || ahciidentify0(pc, id) != 0)
419                         return -1;
420                 n = idpuis(id);
421                 if(n & Pspinup && setfeatures(pc, 7, 20*1000) == -1)
422                         print("%s: puis spinup fail\n", d);
423                 if(n & Pidready)
424                         break;
425                 print("%s: puis waiting\n", d);
426         }
427         s = idfeat(m, id);
428         *ss = idss(m, id);
429         if(s == -1 || (m->feat&Dlba) == 0){
430                 if((m->feat&Dlba) == 0)
431                         dprint("%s: no lba support\n", d);
432                 return -1;
433         }
434         return s;
435 }
436
437 static int
438 ahciquiet(Aport *a)
439 {
440         ulong *p, i;
441
442         p = &a->cmd;
443         *p &= ~Ast;
444         for(i = 0; i < 500; i += 50){
445                 if((*p & Acr) == 0)
446                         goto stop;
447                 asleep(50);
448         }
449         return -1;
450 stop:
451         if((a->task & (ASdrq|ASbsy)) == 0){
452                 *p |= Ast;
453                 return 0;
454         }
455
456         *p |= Aclo;
457         for(i = 0; i < 500; i += 50){
458                 if((*p & Aclo) == 0)
459                         goto stop1;
460                 asleep(50);
461         }
462         return -1;
463 stop1:
464         /* extra check */
465         dprint("ahci: clo clear [task %lux]\n", a->task);
466         if(a->task & ASbsy)
467                 return -1;
468         *p |= Afre | Ast;
469         return 0;
470 }
471
472 static int
473 ahcicomreset(Aportc *pc)
474 {
475         uchar *c;
476
477         dreg("comreset ", pc->p);
478         if(ahciquiet(pc->p) == -1){
479                 dprint("ahci: ahciquiet failed\n");
480                 return -1;
481         }
482         dreg("comreset ", pc->p);
483
484         c = pc->m->ctab->cfis;
485         nopfis(pc->m, c, 1);
486         mkalist(pc->m, Lclear | Lreset, 0, 0);
487         if(ahciwait(pc, 500) == -1){
488                 dprint("ahci: comreset1 failed\n");
489                 return -1;
490         }
491         microdelay(250);
492         dreg("comreset ", pc->p);
493
494         nopfis(pc->m, c, 0);
495         mkalist(pc->m, Lwrite, 0, 0);
496         if(ahciwait(pc, 150) == -1){
497                 dprint("ahci: comreset2 failed\n");
498                 return -1;
499         }
500         dreg("comreset ", pc->p);
501         return 0;
502 }
503
504 static int
505 ahciidle(Aport *port)
506 {
507         ulong *p, i, r;
508
509         p = &port->cmd;
510         if((*p & Arun) == 0)
511                 return 0;
512         *p &= ~Ast;
513         r = 0;
514         for(i = 0; i < 500; i += 25){
515                 if((*p & Acr) == 0)
516                         goto stop;
517                 asleep(25);
518         }
519         r = -1;
520 stop:
521         if((*p & Afre) == 0)
522                 return r;
523         *p &= ~Afre;
524         for(i = 0; i < 500; i += 25){
525                 if((*p & Afre) == 0)
526                         return 0;
527                 asleep(25);
528         }
529         return -1;
530 }
531
532 /*
533  * §6.2.2.1  first part; comreset handled by reset disk.
534  *      - remainder is handled by configdisk.
535  *      - ahcirecover is a quick recovery from a failed command.
536  */
537 static int
538 ahciswreset(Aportc *pc)
539 {
540         int i;
541
542         i = ahciidle(pc->p);
543         pc->p->cmd |= Afre;
544         if(i == -1)
545                 return -1;
546         if(pc->p->task & (ASdrq|ASbsy))
547                 return -1;
548         return 0;
549 }
550
551 static int
552 ahcirecover(Aportc *pc)
553 {
554         ahciswreset(pc);
555         pc->p->cmd |= Ast;
556         if(settxmode(pc, pc->m->udma) == -1)
557                 return -1;
558         return 0;
559 }
560
561 static void*
562 malign(int size, int align)
563 {
564         void *v;
565
566         v = xspanalloc(size, align, 0);
567         memset(v, 0, size);
568         return v;
569 }
570
571 static void
572 setupfis(Afis *f)
573 {
574         f->base = malign(0x100, 0x100);
575         f->d = f->base + 0;
576         f->p = f->base + 0x20;
577         f->r = f->base + 0x40;
578         f->u = f->base + 0x60;
579         f->devicebits = (ulong*)(f->base + 0x58);
580 }
581
582 static void
583 ahciwakeup(Aportc *c, uint mode)
584 {
585         ushort s;
586         Aport *p;
587
588         p = c->p;
589         s = p->sstatus;
590         if((s & Isleepy) == 0)
591                 return;
592         if((s & Smask) != Spresent){
593                 dprint("ahci: slumbering drive missing [ss %.3ux]\n", s);
594                 return;
595         }
596         ahciportreset(c, mode);
597         dprint("ahci: wake %.3ux -> %.3lux\n", s, c->p->sstatus);
598 }
599
600 static int
601 ahciconfigdrive(Ahba *h, Aportc *c, int mode)
602 {
603         Aportm *m;
604         Aport *p;
605         int i;
606
607         p = c->p;
608         m = c->m;
609
610         if(m->list == 0){
611                 setupfis(&m->fis);
612                 m->list = malign(sizeof *m->list, 1024);
613                 m->ctab = malign(sizeof *m->ctab, 128);
614         }
615
616         if(ahciidle(p) == -1){
617                 dprint("ahci: port not idle\n");
618                 return -1;
619         }
620
621         p->list = PCIWADDR(m->list);
622         p->listhi = Pciwaddrh(m->list);
623         p->fis = PCIWADDR(m->fis.base);
624         p->fishi = Pciwaddrh(m->fis.base);
625
626         p->cmd |= Afre;
627
628         if((p->cmd & Apwr) != Apwr)
629                 p->cmd |= Apwr;
630
631         if((h->cap & Hss) != 0){
632                 dprint("ahci: spin up ... [%.3lux]\n", p->sstatus);
633                 for(i = 0; i < 1400; i += 50){
634                         if((p->sstatus & Sbist) != 0)
635                                 break;
636                         if((p->sstatus & Smask) == Sphylink)
637                                 break;
638                         asleep(50);
639                 }
640         }
641
642         if((p->sstatus & SSmask) == (Isleepy | Spresent))
643                 ahciwakeup(c, mode);
644
645         p->serror = SerrAll;
646         p->ie = IEM;
647
648         /* we will get called again once phylink has been established */
649         if((p->sstatus & Smask) != Sphylink)
650                 return 0;
651
652         /* disable power managment sequence from book. */
653         p->sctl = 3*Aipm | mode*Aspd | 0*Adet;
654         p->cmd &= ~Aalpe;
655
656         p->cmd |= Afre | Ast;
657
658         return 0;
659 }
660
661 static int
662 ahcienable(Ahba *h)
663 {
664         h->ghc |= Hie;
665         return 0;
666 }
667
668 static int
669 ahcidisable(Ahba *h)
670 {
671         h->ghc &= ~Hie;
672         return 0;
673 }
674
675 static int
676 countbits(ulong u)
677 {
678         int i, n;
679
680         n = 0;
681         for(i = 0; i < 32; i++)
682                 if(u & (1<<i))
683                         n++;
684         return n;
685 }
686
687 static int
688 ahciconf(Ctlr *c)
689 {
690         uint u;
691         Ahba *h;
692
693         h = c->hba = (Ahba*)c->mmio;
694         u = h->cap;
695
696         if((u & Ham) == 0)
697                 h->ghc |= Hae;
698
699         return countbits(h->pi);
700 }
701
702 static int
703 ahcihandoff(Ahba *h)
704 {
705         int wait;
706
707         if((h->cap2 & Boh) == 0)
708                 return 0;
709         h->bios |= Oos;
710         for(wait = 0; wait < 2000; wait += 100){
711                 if((h->bios & Bos) == 0)
712                         return 0;
713                 delay(100);
714         }
715         iprint("ahci: bios handoff timed out\n");
716         return -1;
717 }
718
719 static int
720 ahcihbareset(Ahba *h)
721 {
722         int wait;
723
724         h->ghc |= Hhr;
725         for(wait = 0; wait < 1000; wait += 100){
726                 if((h->ghc & Hhr) == 0)
727                         return 0;
728                 delay(100);
729         }
730         return -1;
731 }
732
733 static char*
734 dnam(Drive *d)
735 {
736         char *s;
737
738         s = d->name;
739         if(d->unit && d->unit->name)
740                 s = d->unit->name;
741         return s;
742 }
743
744 static int
745 identify(Drive *d)
746 {
747         uchar oserial[21];
748         ushort *id;
749         vlong osectors, s;
750         SDunit *u;
751
752         id = d->info;
753         s = ahciidentify(&d->portc, id, &d->secsize, dnam(d));
754         if(s == -1)
755                 return -1;
756         osectors = d->sectors;
757         memmove(oserial, d->serial, sizeof d->serial);
758
759         d->sectors = s;
760
761         idmove(d->serial, id+10, 20);
762         idmove(d->firmware, id+23, 8);
763         idmove(d->model, id+27, 40);
764         d->wwn = idwwn(d->portc.m, id);
765
766         u = d->unit;
767         memset(u->inquiry, 0, sizeof u->inquiry);
768         u->inquiry[2] = 2;
769         u->inquiry[3] = 2;
770         u->inquiry[4] = sizeof u->inquiry - 4;
771         memmove(u->inquiry+8, d->model, 40);
772
773         if(osectors != s || memcmp(oserial, d->serial, sizeof oserial)){
774                 d->drivechange = 1;
775                 d->nodma = 0;
776                 u->sectors = 0;
777         }
778         return 0;
779 }
780
781 static void
782 clearci(Aport *p)
783 {
784         if(p->cmd & Ast){
785                 p->cmd &= ~Ast;
786                 p->cmd |=  Ast;
787         }
788 }
789
790 static int
791 intel(Ctlr *c)
792 {
793         return c->pci->vid == 0x8086;
794 }
795
796 static int
797 ignoreahdrs(Drive *d)
798 {
799         return d->portm.feat & Datapi && d->ctlr->type == Tsb600;
800 }
801
802 static void
803 updatedrive(Drive *d)
804 {
805         ulong f, cause, serr, s0, pr, ewake;
806         Aport *p;
807         static ulong last;
808
809         pr = 1;
810         ewake = 0;
811         f = 0;
812         p = d->port;
813         cause = p->isr;
814         if(d->ctlr->type == Tjmicron)
815                 cause &= ~Aifs;
816         serr = p->serror;
817         p->isr = cause;
818
819         if(p->ci == 0){
820                 f |= Fdone;
821                 pr = 0;
822         }else if(cause & Adps){
823                 pr = 0;
824         }else if(cause & Atfes){
825                 f |= Ferror;
826                 ewake = 1;
827                 pr = 0;
828         }
829         if(cause & Ifatal){
830                 ewake = 1;
831                 dprint("%s: fatal\n", dnam(d));
832         }
833         if(cause & Adhrs){
834                 if(p->task & 33){
835                         if(ignoreahdrs(d) && serr & ErrE)
836                                 f |= Fahdrs;
837                         dprint("%s: Adhrs cause %lux serr %lux task %lux\n",
838                                 dnam(d), cause, serr, p->task);
839                         f |= Ferror;
840                         ewake = 1;
841                 }
842                 pr = 0;
843         }
844         if(p->task & 1 && last != cause)
845                 dprint("%s: err ca %lux serr %lux task %lux sstat %.3lux\n",
846                         dnam(d), cause, serr, p->task, p->sstatus);
847         if(pr)
848                 dprint("%s: upd %lux ta %lux\n", dnam(d), cause, p->task);
849
850         if(cause & (Aprcs|Aifs)){
851                 s0 = d->state;
852                 switch(p->sstatus & Smask){
853                 case Smissing:
854                         d->state = Dmissing;
855                         break;
856                 case Spresent:
857                         if((p->sstatus & Imask) == Islumber)
858                                 d->state = Dnew;
859                         else
860                                 d->state = Derror;
861                         break;
862                 case Sphylink:
863                         /* power mgnt crap for suprise removal */
864                         p->ie |= Aprcs|Apcs;    /* is this required? */
865                         d->state = Dreset;
866                         break;
867                 case Sbist:
868                         d->state = Doffline;
869                         break;
870                 }
871                 dprint("%s: updatedrive: %s → %s [ss %.3lux]\n",
872                         dnam(d), diskstates[s0], diskstates[d->state], p->sstatus);
873                 if(s0 == Dready && d->state != Dready)
874                         dprint("%s: pulled\n", dnam(d));
875                 if(d->state != Dready)
876                         f |= Ferror;
877                 if(d->state != Dready || p->ci)
878                         ewake = 1;
879         }
880         p->serror = serr;
881         if(ewake)
882                 clearci(p);
883         if(f){
884                 d->portm.flag = f;
885                 wakeup(&d->portm);
886         }
887         last = cause;
888 }
889
890 static void
891 dstatus(Drive *d, int s)
892 {
893         dprint("%s: dstatus: %s → %s from pc=%p\n", dnam(d), 
894                 diskstates[d->state], diskstates[s], getcallerpc(&d));
895
896         ilock(d);
897         d->state = s;
898         iunlock(d);
899 }
900
901 static void
902 configdrive(Drive *d)
903 {
904         if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1){
905                 dstatus(d, Dportreset);
906                 return;
907         }
908
909         ilock(d);
910         switch(d->port->sstatus & Smask){
911         default:
912         case Smissing:
913                 d->state = Dmissing;
914                 break;
915         case Spresent:
916                 if(d->state == Dnull)
917                         d->state = Dportreset;
918                 break;
919         case Sphylink:
920                 if(d->state == Dready)
921                         break;
922                 d->wait = 0;
923                 d->state = Dnew;
924                 break;
925         case Sbist:
926                 d->state = Doffline;
927                 break;
928         }
929         iunlock(d);
930
931         dprint("%s: configdrive: %s\n", dnam(d), diskstates[d->state]);
932 }
933
934 static void
935 resetdisk(Drive *d)
936 {
937         uint state, det, stat;
938         Aport *p;
939
940         p = d->port;
941         det = p->sctl & 7;
942         stat = p->sstatus & Smask;
943         state = (p->cmd>>28) & 0xf;
944         dprint("%s: resetdisk [icc %ux; det %.3ux; sdet %.3ux]\n", dnam(d), state, det, stat);
945
946         ilock(d);
947         if(d->state != Dready && d->state != Dnew)
948                 d->portm.flag |= Ferror;
949         if(stat != Sphylink)
950                 d->state = Dportreset;
951         else
952                 d->state = Dreset;
953         clearci(p);                     /* satisfy sleep condition. */
954         wakeup(&d->portm);
955         iunlock(d);
956
957         if(stat != Sphylink)
958                 return;
959
960         qlock(&d->portm);
961         if(p->cmd&Ast && ahciswreset(&d->portc) == -1)
962                 dstatus(d, Dportreset); /* get a bigger stick. */
963         else
964                 configdrive(d);
965         qunlock(&d->portm);
966 }
967
968 static int
969 newdrive(Drive *d)
970 {
971         char *s;
972         Aportc *c;
973         Aportm *m;
974
975         c = &d->portc;
976         m = &d->portm;
977
978         qlock(c->m);
979         setfissig(m, c->p->sig);
980         if(identify(d) == -1){
981                 dprint("%s: identify failure\n", dnam(d));
982                 goto lose;
983         }
984         if(settxmode(c, m->udma) == -1){
985                 dprint("%s: can't set udma mode\n", dnam(d));
986                 goto lose;
987         }
988         if(m->feat & Dpower && setfeatures(c, 0x85, 3*1000) == -1){
989                 dprint("%s: can't disable apm\n", dnam(d));
990                 m->feat &= ~Dpower;
991                 if(ahcirecover(c) == -1)
992                         goto lose;
993         }
994         dstatus(d, Dready);
995         qunlock(c->m);
996
997         s = "";
998         if(m->feat & Dllba)
999                 s = "L";
1000         idprint("%s: %sLBA %,lld sectors\n", dnam(d), s, d->sectors);
1001         idprint("  %s %s %s %s\n", d->model, d->firmware, d->serial,
1002                 d->drivechange? "[newdrive]": "");
1003         return 0;
1004
1005 lose:
1006         idprint("%s: can't be initialized\n", dnam(d));
1007         dstatus(d, Dnull);
1008         qunlock(c->m);
1009         return -1;
1010 }
1011
1012 enum {
1013         Nms             = 256,
1014         Mphywait        =  2*1024/Nms - 1,
1015         Midwait         = 16*1024/Nms - 1,
1016         Mcomrwait       = 64*1024/Nms - 1,
1017 };
1018
1019 static void
1020 hangck(Drive *d)
1021 {
1022         if(d->active && d->totick != 0 && (long)(Ticks - d->totick) > 0){
1023                 dprint("%s: drive hung [task %lux; ci %lux; serr %lux]%s\n",
1024                         dnam(d), d->port->task, d->port->ci, d->port->serror,
1025                         d->nodma == 0 ? "; disabling dma" : "");
1026                 d->nodma = 1;
1027                 d->state = Dreset;
1028         }
1029 }
1030
1031 static ushort olds[NCtlr*NCtlrdrv];
1032
1033 static void
1034 doportreset(Drive *d)
1035 {
1036         qlock(&d->portm);
1037         ahciportreset(&d->portc, d->mode);
1038         qunlock(&d->portm);
1039
1040         dprint("ahci: portreset: %s [task %lux; ss %.3lux]\n",
1041                 diskstates[d->state], d->port->task, d->port->sstatus);
1042 }
1043
1044 /* drive must be locked */
1045 static void
1046 statechange(Drive *d)
1047 {
1048         switch(d->state){
1049         case Dnull:
1050         case Doffline:
1051                 if(d->unit)
1052                 if(d->unit->sectors != 0){
1053                         d->sectors = 0;
1054                         d->drivechange = 1;
1055                 }
1056         case Dready:
1057                 d->wait = 0;
1058         }
1059 }
1060
1061 static uint
1062 maxmode(Ctlr *c)
1063 {
1064         return (c->hba->cap & 0xf*Hiss)/Hiss;
1065 }
1066
1067 static void iainterrupt(Ureg*, void *);
1068
1069 static void
1070 checkdrive(Drive *d, int i)
1071 {
1072         ushort s, sig;
1073
1074         if(d->ctlr->enabled == 0)
1075                 return;
1076         if(d->driveno == 0)
1077                 iainterrupt(0, d->ctlr);        /* check for missed irq's */
1078
1079         ilock(d);
1080         s = d->port->sstatus;
1081         if(s)
1082                 d->lastseen = Ticks;
1083         if(s != olds[i]){
1084                 dprint("%s: status: %.3ux -> %.3ux: %s\n",
1085                         dnam(d), olds[i], s, diskstates[d->state]);
1086                 olds[i] = s;
1087                 d->wait = 0;
1088         }
1089         hangck(d);
1090         switch(d->state){
1091         case Dnull:
1092         case Dready:
1093                 break;
1094         case Dmissing:
1095         case Dnew:
1096                 switch(s & (Iactive|Smask)){
1097                 case Spresent:
1098                         ahciwakeup(&d->portc, d->mode);
1099                 case Smissing:
1100                         break;
1101                 default:
1102                         dprint("%s: unknown status %.3ux\n", dnam(d), s);
1103                         /* fall through */
1104                 case Iactive:           /* active, no device */
1105                         if(++d->wait&Mphywait)
1106                                 break;
1107 reset:
1108                         if(d->mode == 0)
1109                                 d->mode = maxmode(d->ctlr);
1110                         else
1111                                 d->mode--;
1112                         if(d->mode == DMautoneg){
1113                                 d->state = Dportreset;
1114                                 goto portreset;
1115                         }
1116                         dprint("%s: reset; new mode %s\n", dnam(d),
1117                                 modes[d->mode]);
1118                         iunlock(d);
1119                         resetdisk(d);
1120                         ilock(d);
1121                         break;
1122                 case Iactive | Sphylink:
1123                         if(d->unit == nil)
1124                                 break;
1125                         if((++d->wait&Midwait) == 0){
1126                                 dprint("%s: slow reset [task %lux; ss %.3ux; wait %d]\n",
1127                                         dnam(d), d->port->task, s, d->wait);
1128                                 goto reset;
1129                         }
1130                         s = (uchar)d->port->task;
1131                         sig = d->port->sig >> 16;
1132                         if(s == 0x7f || s&ASbsy ||
1133                             (sig != 0xeb14 && (s & ASdrdy) == 0))
1134                                 break;
1135                         iunlock(d);
1136                         newdrive(d);
1137                         ilock(d);
1138                         break;
1139                 }
1140                 break;
1141         case Doffline:
1142                 if(d->wait++ & Mcomrwait)
1143                         break;
1144                 /* fallthrough */
1145         case Derror:
1146         case Dreset:
1147                 dprint("%s: reset [%s]: mode %d; status %.3ux\n",
1148                         dnam(d), diskstates[d->state], d->mode, s);
1149                 iunlock(d);
1150                 resetdisk(d);
1151                 ilock(d);
1152                 break;
1153         case Dportreset:
1154 portreset:
1155                 if(d->wait++ & 0xff && (s & Iactive) == 0)
1156                         break;
1157                 dprint("%s: portreset [%s]: mode %d; status %.3ux\n",
1158                         dnam(d), diskstates[d->state], d->mode, s);
1159                 d->portm.flag |= Ferror;
1160                 clearci(d->port);
1161                 wakeup(&d->portm);
1162                 if((s & Smask) == Smissing){
1163                         d->state = Dmissing;
1164                         break;
1165                 }
1166                 iunlock(d);
1167                 doportreset(d);
1168                 ilock(d);
1169                 break;
1170         }
1171         statechange(d);
1172         iunlock(d);
1173 }
1174
1175 static void
1176 satakproc(void*)
1177 {
1178         int i;
1179
1180         while(waserror())
1181                 ;
1182         for(;;){
1183                 tsleep(&up->sleep, return0, 0, Nms);
1184                 for(i = 0; i < niadrive; i++)
1185                         checkdrive(iadrive[i], i);
1186         }
1187 }
1188
1189 static void
1190 iainterrupt(Ureg *u, void *a)
1191 {
1192         int i;
1193         ulong cause, m;
1194         Ctlr *c;
1195         Drive *d;
1196
1197         c = a;
1198         ilock(c);
1199         cause = c->hba->isr;
1200         for(i = 0; cause; i++){
1201                 m = 1 << i;
1202                 if((cause & m) == 0)
1203                         continue;
1204                 cause &= ~m;
1205                 d = c->rawdrive + i;
1206                 ilock(d);
1207                 if(d->port != nil && d->port->isr && c->hba->pi & m)
1208                         updatedrive(d);
1209                 c->hba->isr = m;
1210                 iunlock(d);
1211         }
1212         if(u == 0 && i > 0)
1213                 c->missirq++;
1214         iunlock(c);
1215 }
1216
1217 static int
1218 ahciencreset(Ctlr *c)
1219 {
1220         Ahba *h;
1221
1222         if(c->enctype == Eesb)
1223                 return 0;
1224         h = c->hba;
1225         h->emctl |= Emrst;
1226         while(h->emctl & Emrst)
1227                 delay(1);
1228         return 0;
1229 }
1230
1231 /*
1232  * from the standard: (http://en.wikipedia.org/wiki/IBPI)
1233  * rebuild is preferred as locate+fail; alternate 1hz fail
1234  * we're going to assume no locate led.
1235  */
1236
1237 enum {
1238         Ledsleep        = 125,          /* 8hz */
1239
1240         N0      = Ledon*Aled,
1241         L0      = Ledon*Aled | Ledon*Locled,
1242         L1      = Ledon*Aled | Ledoff*Locled,
1243         R0      = Ledon*Aled | Ledon*Locled |   Ledon*Errled,
1244         R1      = Ledon*Aled |                  Ledoff*Errled,
1245         S0      = Ledon*Aled |  Ledon*Locled /*|        Ledon*Errled*/, /* botch */
1246         S1      = Ledon*Aled |                  Ledoff*Errled,
1247         P0      = Ledon*Aled |                  Ledon*Errled,
1248         P1      = Ledon*Aled |                  Ledoff*Errled,
1249         F0      = Ledon*Aled |                  Ledon*Errled,
1250         C0      = Ledon*Aled | Ledon*Locled,
1251         C1      = Ledon*Aled | Ledoff*Locled,
1252
1253 };
1254
1255 //static ushort led3[Ibpilast*8] = {
1256 //[Ibpinone*8]  0,      0,      0,      0,      0,      0,      0,      0,
1257 //[Ibpinormal*8]        N0,     N0,     N0,     N0,     N0,     N0,     N0,     N0,
1258 //[Ibpirebuild*8]       R0,     R0,     R0,     R0,     R1,     R1,     R1,     R1,
1259 //[Ibpilocate*8]        L0,     L1,     L0,     L1,     L0,     L1,     L0,     L1,
1260 //[Ibpispare*8] S0,     S1,     S0,     S1,     S1,     S1,     S1,     S1,
1261 //[Ibpipfa*8]   P0,     P1,     P0,     P1,     P1,     P1,     P1,     P1,     /* first 1 sec */
1262 //[Ibpifail*8]  F0,     F0,     F0,     F0,     F0,     F0,     F0,     F0,
1263 //[Ibpicritarray*8]     C0,     C0,     C0,     C0,     C1,     C1,     C1,     C1,
1264 //[Ibpifailarray*8]     C0,     C1,     C0,     C1,     C0,     C1,     C0,     C1,
1265 //};
1266
1267 static ushort led2[Ibpilast*8] = {
1268 [Ibpinone*8]    0,      0,      0,      0,      0,      0,      0,      0,
1269 [Ibpinormal*8]  N0,     N0,     N0,     N0,     N0,     N0,     N0,     N0,
1270 [Ibpirebuild*8] R0,     R0,     R0,     R0,     R1,     R1,     R1,     R1,
1271 [Ibpilocate*8]  L0,     L0,     L0,     L0,     L0,     L0,     L0,     L0,
1272 [Ibpispare*8]   S0,     S0,     S0,     S0,     S1,     S1,     S1,     S1,
1273 [Ibpipfa*8]     P0,     P1,     P0,     P1,     P1,     P1,     P1,     P1,     /* first 1 sec */
1274 [Ibpifail*8]    F0,     F0,     F0,     F0,     F0,     F0,     F0,     F0,
1275 [Ibpicritarray*8]       C0,     C0,     C0,     C0,     C1,     C1,     C1,     C1,
1276 [Ibpifailarray*8]       C0,     C1,     C0,     C1,     C0,     C1,     C0,     C1,
1277 };
1278
1279 static int
1280 ledstate(Ledport *p, uint seq)
1281 {
1282         ushort i;
1283
1284         if(p->led == Ibpipfa && seq%32 >= 8)
1285                 i = P1;
1286         else
1287                 i = led2[8*p->led + seq%8];
1288         if(i != p->ledbits){
1289                 p->ledbits = i;
1290                 ledprint("ledstate %,.011ub %ud\n", p->ledbits, seq);
1291                 return 1;
1292         }
1293         return 0;
1294 }
1295
1296 static int
1297 blink(Drive *d, ulong t)
1298 {
1299         Ahba *h;
1300         Ctlr *c;
1301         Aledmsg msg;
1302
1303         if(ledstate(d, t) == 0)
1304                 return 0;
1305         c = d->ctlr;
1306         h = c->hba;
1307         /* ensure last message has been transmitted */
1308         while(h->emctl & Tmsg)
1309                 microdelay(1);
1310         switch(c->enctype){
1311         default:
1312                 panic("%s: bad led type %d", dnam(d), c->enctype);
1313         case Elmt:
1314                 memset(&msg, 0, sizeof msg);
1315                 msg.type = Mled;
1316                 msg.dsize = 0;
1317                 msg.msize = sizeof msg - 4;
1318                 msg.led[0] = d->ledbits;
1319                 msg.led[1] = d->ledbits>>8;
1320                 msg.pm = 0;
1321                 msg.hba = d->driveno;
1322                 memmove(c->enctx, &msg, sizeof msg);
1323                 break;
1324         }
1325         h->emctl |= Tmsg;
1326         return 1;
1327 }
1328
1329 enum {
1330         Esbdrv0 = 4,            /* start pos in bits */
1331         Esbiota = 3,            /* shift in bits */
1332         Esbact  = 1,
1333         Esbloc  = 2,
1334         Esberr  = 4,
1335 };
1336
1337 uint
1338 esbbits(uint s)
1339 {
1340         uint i, e;                              /* except after c */
1341
1342         e = 0;
1343         for(i = 0; i < 3; i++)
1344                 e |= ((s>>3*i & 7) != 0)<<i;
1345         return e;
1346 }
1347
1348 static int
1349 blinkesb(Ctlr *c, ulong t)
1350 {
1351         uint i, s, u[32/4];
1352         uvlong v;
1353         Drive *d;
1354
1355         s = 0;
1356         for(i = 0; i < c->ndrive; i++){
1357                 d = c->drive[i];
1358                 s |= ledstate(d, t);            /* no port mapping */
1359         }
1360         if(s == 0)
1361                 return 0;
1362         memset(u, 0, sizeof u);
1363         for(i = 0; i < c->ndrive; i++){
1364                 d = c->drive[i];
1365                 s = Esbdrv0 + Esbiota*i;
1366                 v = esbbits(d->ledbits) * (1ull << s%32);
1367                 u[s/32 + 0] |= v;
1368                 u[s/32 + 1] |= v>>32;
1369         }
1370         for(i = 0; i < c->encsz; i++)
1371                 c->enctx[i] = u[i];
1372         return 1;
1373 }
1374
1375 static long
1376 ahciledr(SDunit *u, Chan *ch, void *a, long n, vlong off)
1377 {
1378         Ctlr *c;
1379         Drive *d;
1380
1381         c = u->dev->ctlr;
1382         d = c->drive[u->subno];
1383         return ledr(d, ch, a, n, off);
1384 }
1385
1386 static long
1387 ahciledw(SDunit *u, Chan *ch, void *a, long n, vlong off)
1388 {
1389         Ctlr *c;
1390         Drive *d;
1391
1392         c = u->dev->ctlr;
1393         d = c->drive[u->subno];
1394         return ledw(d, ch, a, n, off);
1395 }
1396
1397 static void
1398 ledkproc(void*)
1399 {
1400         uchar map[NCtlr];
1401         uint i, j, t0, t1;
1402         Ctlr *c;
1403         Drive *d;
1404
1405         j = 0;
1406         memset(map, 0, sizeof map);
1407         for(i = 0; i < niactlr; i++)
1408                 if(iactlr[i].enctype != 0){
1409                         ahciencreset(iactlr + i);
1410                         map[i] = 1;
1411                         j++;
1412                 }
1413         if(j == 0)
1414                 pexit("no work", 1);
1415         for(i = 0; i < niadrive; i++){
1416                 iadrive[i]->nled = 3;           /* hardcoded */
1417                 if(iadrive[i]->ctlr->enctype == Eesb)
1418                         iadrive[i]->nled = 3;
1419                 iadrive[i]->ledbits = -1;
1420         }
1421         for(i = 0; ; i++){
1422                 t0 = Ticks;
1423                 for(j = 0; j < niadrive; ){
1424                         c = iadrive[j]->ctlr;
1425                         if(map[j] == 0)
1426                                 j += c->enctype;
1427                         else if(c->enctype == Eesb){
1428                                 blinkesb(c, i);
1429                                 j += c->ndrive;
1430                         }else{
1431                                 d = iadrive[j++];
1432                                 blink(d, i);
1433                         }
1434                 }
1435                 t1 = Ticks;
1436                 esleep(Ledsleep - TK2MS(t1 - t0));
1437         }
1438 }
1439
1440 static int
1441 waitready(Drive *d)
1442 {
1443         ulong s, i, δ;
1444
1445         for(i = 0;; i += 250){
1446                 if(d->state == Dreset || d->state == Dportreset || d->state == Dnew)
1447                         return 1;
1448                 ilock(d);
1449                 s = d->port->sstatus;
1450                 if(d->state == Dready && (s & Smask) == Sphylink){
1451                         iunlock(d);
1452                         return 0;
1453                 }
1454                 δ = Ticks - d->lastseen;
1455                 if(d->state == Dnull || δ > 10*1000)
1456                         break;
1457                 if((s & Imask) == 0 && δ > 1500)
1458                         break;
1459                 if(i >= 15*1000){
1460                         d->state = Doffline;
1461                         iunlock(d);
1462                         print("%s: not responding; offline\n", dnam(d));
1463                         return -1;
1464                 }
1465                 iunlock(d);
1466                 esleep(250);
1467         }
1468         iunlock(d);
1469         return -1;
1470 }
1471
1472 static int
1473 iaverify(SDunit *u)
1474 {
1475         Ctlr *c;
1476         Drive *d;
1477
1478         c = u->dev->ctlr;
1479         d = c->drive[u->subno];
1480         ilock(c);
1481         ilock(d);
1482         if(d->unit == nil){
1483                 d->unit = u;
1484                 if(c->enctype != 0)
1485                         sdaddfile(u, "led", 0644, eve, ahciledr, ahciledw);
1486         }
1487         iunlock(d);
1488         iunlock(c);
1489         checkdrive(d, d->driveno);              /* c->d0 + d->driveno */
1490         return 1;
1491 }
1492
1493 static int
1494 iaonline(SDunit *u)
1495 {
1496         int r;
1497         Ctlr *c;
1498         Drive *d;
1499
1500         c = u->dev->ctlr;
1501         d = c->drive[u->subno];
1502
1503         while(d->state != Dmissing && waitready(d) == 1)
1504                 esleep(1);
1505
1506         dprint("%s: iaonline: %s\n", dnam(d), diskstates[d->state]);
1507
1508         ilock(d);
1509         if(d->portm.feat & Datapi){
1510                 r = d->drivechange;
1511                 d->drivechange = 0;
1512                 iunlock(d);
1513                 if(r != 0)
1514                         scsiverify(u);
1515                 return scsionline(u);
1516         }
1517         r = 0;
1518         if(d->drivechange){
1519                 d->drivechange = 0;
1520                 r = 2;
1521         }else if(d->state == Dready)
1522                 r = 1;
1523         if(r){
1524                 u->sectors = d->sectors;
1525                 u->secsize = d->secsize;
1526         }
1527         iunlock(d);
1528
1529         return r;
1530 }
1531
1532 static int
1533 iaenable(SDev *s)
1534 {
1535         char name[32];
1536         Ctlr *c;
1537         static int once;
1538
1539         c = s->ctlr;
1540         ilock(c);
1541         if(!c->enabled){
1542                 if(once == 0)
1543                         kproc("iasata", satakproc, 0);
1544                 if(c->ndrive == 0)
1545                         panic("iaenable: zero s->ctlr->ndrive");
1546                 pcisetbme(c->pci);
1547                 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1548                 intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1549                 /* supposed to squelch leftover interrupts here. */
1550                 ahcienable(c->hba);
1551                 c->enabled = 1;
1552                 if(++once == niactlr)
1553                         kproc("ialed", ledkproc, 0);
1554         }
1555         iunlock(c);
1556         return 1;
1557 }
1558
1559 static int
1560 iadisable(SDev *s)
1561 {
1562         char name[32];
1563         Ctlr *c;
1564
1565         c = s->ctlr;
1566         ilock(c);
1567         ahcidisable(c->hba);
1568         snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1569         intrdisable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1570         c->enabled = 0;
1571         iunlock(c);
1572         return 1;
1573 }
1574
1575 static Alist*
1576 ahcibuild(Drive *d, int rw, void *data, int nsect, vlong lba)
1577 {
1578         uchar *c;
1579         uint flags;
1580         Aportm *m;
1581
1582         m = &d->portm;
1583         c = m->ctab->cfis;
1584         rwfis(m, c, rw, nsect, lba);
1585         flags = Lpref;
1586         if(rw == SDwrite)
1587                 flags |= Lwrite;
1588         return mkalist(m, flags, data, nsect * d->secsize);
1589 }
1590
1591 static Alist*
1592 ahcibuildpkt(Drive *d, SDreq *r, void *data, int n)
1593 {
1594         uint flags;
1595         Aportm *m;
1596         uchar *c;
1597         Actab *t;
1598
1599         m = &d->portm;
1600         t = m->ctab;
1601         c = t->cfis;
1602
1603         atapirwfis(m, c, r->cmd, r->clen, 0x2000);
1604         if((n & 15) != 0 || d->nodma)
1605                 c[Ffeat] &= ~1; /* use pio */
1606         else if(c[Ffeat] & 1 && d->info[62] & (1<<15))  /* dma direction */
1607                 c[Ffeat] = (c[Ffeat] & ~(1<<2)) | ((r->write == 0) << 2);
1608         flags = Lpref | Latapi;
1609         if(r->write != 0 && data)
1610                 flags |= Lwrite;
1611         return mkalist(m, flags, data, n);
1612 }
1613
1614 static Alist*
1615 ahcibuildfis(Drive *d, SDreq *r, void *data, uint n)
1616 {
1617         uint flags;
1618         uchar *c;
1619         Aportm *m;
1620
1621         if((r->ataproto & Pprotom) == Ppkt)
1622                 return ahcibuildpkt(d, r, data, n);
1623
1624         m = &d->portm;
1625         c = m->ctab->cfis;
1626         memmove(c, r->cmd, r->clen);
1627         flags = Lpref;
1628         if(r->write || n == 0)
1629                 flags |= Lwrite;
1630         return mkalist(m, flags, data, n);
1631 }
1632
1633 static int
1634 lockready(Drive *d)
1635 {
1636         int i;
1637
1638         qlock(&d->portm);
1639         while ((i = waitready(d)) == 1) {
1640                 qunlock(&d->portm);
1641                 esleep(1);
1642                 qlock(&d->portm);
1643         }
1644         return i;
1645 }
1646
1647 static int
1648 flushcache(Drive *d)
1649 {
1650         int i;
1651
1652         i = -1;
1653         if(lockready(d) == 0)
1654                 i = ahciflushcache(&d->portc);
1655         qunlock(&d->portm);
1656         return i;
1657 }
1658
1659 static int
1660 io(Drive *d, uint proto, int to, int interrupt)
1661 {
1662         uint task, flag, stat, rv;
1663         Aport *p;
1664         Asleep as;
1665
1666         switch(waitready(d)){
1667         case -1:
1668                 return SDeio;
1669         case 1:
1670                 return SDretry;
1671         }
1672
1673         ilock(d);
1674         d->portm.flag = 0;
1675         iunlock(d);
1676         p = d->port;
1677         p->ci = 1;
1678
1679         as.p = p;
1680         as.i = 1;
1681         d->totick = 0;
1682         if(to > 0)
1683                 d->totick = Ticks + MS2TK(to) | 1;      /* fix fencepost */
1684         d->active++;
1685
1686         while(waserror())
1687                 if(interrupt){
1688                         d->active--;
1689                         d->port->ci = 0;
1690                         if(ahcicomreset(&d->portc) == -1)
1691                                 dstatus(d, Dreset);
1692                         return SDtimeout;
1693                 }
1694         
1695         sleep(&d->portm, ahciclear, &as);
1696         poperror();
1697
1698         d->active--;
1699         ilock(d);
1700         stat = d->state;
1701         flag = d->portm.flag;
1702         task = d->port->task;
1703         iunlock(d);
1704
1705         rv = SDok;
1706         if(proto & Ppkt && stat == Dready){
1707                 rv = task >> 8 + 4 & 0xf;
1708                 flag &= ~Fahdrs;
1709                 flag |= Fdone;
1710         }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && stat == Dready){
1711                 d->port->ci = 0;
1712                 ahcirecover(&d->portc);
1713                 task = d->port->task;
1714                 flag &= ~Fdone;         /* either an error or do-over */
1715         }
1716         if(flag == 0){
1717                 print("%s: retry\n", dnam(d));
1718                 return SDretry;
1719         }
1720         if(flag & (Fahdrs | Ferror)){
1721                 if((task & Eidnf) == 0)
1722                         print("%s: i/o error %ux\n", dnam(d), task);
1723                 return SDcheck;
1724         }
1725         return rv;
1726 }
1727
1728 static int
1729 iariopkt(SDreq *r, Drive *d)
1730 {
1731         int try, to;
1732         uchar *cmd;
1733         Alist *l;
1734
1735         cmd = r->cmd;
1736         aprint("%s: %.2ux %.2ux %c %d %p\n", dnam(d), cmd[0], cmd[2],
1737                 "rw"[r->write], r->dlen, r->data);
1738
1739         r->rlen = 0;
1740
1741         /*
1742          * prevent iaonline() to hang forever by timing out
1743          * inquiry and capacity commands after 5 seconds.
1744          */
1745         to = 30*1000;
1746         switch(cmd[0]){
1747         case 0x9e: if(cmd[1] != 0x10) break;
1748         case 0x25:
1749         case 0x12:
1750                 to = 5*1000;
1751                 break;
1752         }
1753
1754         for(try = 0; try < 10; try++){
1755                 qlock(&d->portm);
1756                 l = ahcibuildpkt(d, r, r->data, r->dlen);
1757                 r->status = io(d, Ppkt, to, 0);
1758                 switch(r->status){
1759                 case SDeio:
1760                         qunlock(&d->portm);
1761                         return SDeio;
1762                 case SDretry:
1763                         qunlock(&d->portm);
1764                         continue;
1765                 }
1766                 r->rlen = l->len;
1767                 qunlock(&d->portm);
1768                 return SDok;
1769         }
1770         print("%s: bad disk\n", dnam(d));
1771         return r->status = SDcheck;
1772 }
1773
1774 static long
1775 ahcibio(SDunit *u, int lun, int write, void *a, long count, uvlong lba)
1776 {
1777         int n, rw, try, status, max;
1778         uchar *data;
1779         Ctlr *c;
1780         Drive *d;
1781
1782         c = u->dev->ctlr;
1783         d = c->drive[u->subno];
1784         if(d->portm.feat & Datapi)
1785                 return scsibio(u, lun, write, a, count, lba);
1786
1787         max = 128;
1788         if(d->portm.feat & Dllba){
1789                 max = 8192;             /* ahci maximum */
1790                 if(c->type == Tsb600)
1791                         max = 255;      /* errata */
1792         }
1793         rw = write? SDwrite: SDread;
1794         data = a;
1795         dprint("%s: bio: %llud %c %lud %p\n",
1796                 dnam(d), lba, "rw"[rw], count, data);
1797
1798         for(try = 0; try < 10;){
1799                 n = count;
1800                 if(n > max)
1801                         n = max;
1802                 qlock(&d->portm);
1803                 ahcibuild(d, rw, data, n, lba);
1804                 status = io(d, Pdma, 5000, 0);
1805                 qunlock(&d->portm);
1806                 switch(status){
1807                 case SDeio:
1808                         return -1;
1809                 case SDretry:
1810                         try++;
1811                         continue;
1812                 }
1813                 try = 0;
1814                 count -= n;
1815                 lba += n;
1816                 data += n * u->secsize;
1817                 if(count == 0)
1818                         return data - (uchar*)a;
1819         }
1820         print("%s: bad disk\n", dnam(d));
1821         return -1;
1822 }
1823
1824 static int
1825 iario(SDreq *r)
1826 {
1827         int i, n, count, rw;
1828         uchar *cmd;
1829         uvlong lba;
1830         Ctlr *c;
1831         Drive *d;
1832         SDunit *u;
1833
1834         u = r->unit;
1835         c = u->dev->ctlr;
1836         d = c->drive[u->subno];
1837         if(d->portm.feat & Datapi)
1838                 return iariopkt(r, d);
1839         cmd = r->cmd;
1840
1841         if(cmd[0] == 0x35 || cmd[0] == 0x91){
1842                 if(flushcache(d) == 0)
1843                         return sdsetsense(r, SDok, 0, 0, 0);
1844                 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1845         }
1846
1847         if((i = sdfakescsi(r)) != SDnostatus){
1848                 r->status = i;
1849                 return i;
1850         }
1851
1852         if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
1853                 return i;
1854         n = ahcibio(u, r->lun, r->write, r->data, count, lba);
1855         if(n == -1)
1856                 return SDeio;
1857         r->rlen = n;
1858         return SDok;
1859 }
1860
1861 static uchar bogusrfis[16] = {
1862 [Ftype]         0x34,
1863 [Fioport]       0x40,
1864 [Fstatus]       0x50,
1865 [Fdev]          0xa0,
1866 };
1867
1868 static void
1869 sdr0(Drive *d)
1870 {
1871         uchar *c;
1872
1873         c = d->portm.fis.r;
1874         memmove(c, bogusrfis, sizeof bogusrfis);
1875         coherence();
1876 }
1877
1878 static int
1879 sdr(SDreq *r, Drive *d, int st)
1880 {
1881         uchar *c;
1882         uint t;
1883
1884         if((r->ataproto & Pprotom) == Ppkt){
1885                 t = d->port->task;
1886                 if(t & ASerr)
1887                         st = t >> 8 + 4 & 0xf;
1888         }
1889         c = d->portm.fis.r;
1890         memmove(r->cmd, c, 16);
1891         r->status = st;
1892         if(st == SDcheck)
1893                 st = SDok;
1894         return st;
1895 }
1896
1897 static int
1898 fisreqchk(Sfis *f, SDreq *r)
1899 {
1900         if((r->ataproto & Pprotom) == Ppkt)
1901                 return SDnostatus;
1902         /*
1903          * handle oob requests;
1904          *    restrict & sanitize commands
1905          */
1906         if(r->clen != 16)
1907                 error(Eio);
1908         if(r->cmd[0] == 0xf0){
1909                 sigtofis(f, r->cmd);
1910                 r->status = SDok;
1911                 return SDok;
1912         }
1913         r->cmd[0] = 0x27;
1914         r->cmd[1] = 0x80;
1915         r->cmd[7] |= 0xa0;
1916         return SDnostatus;
1917 }
1918
1919 static int
1920 iaataio(SDreq *r)
1921 {
1922         int try;
1923         Ctlr *c;
1924         Drive *d;
1925         SDunit *u;
1926         Alist *l;
1927
1928         u = r->unit;
1929         c = u->dev->ctlr;
1930         d = c->drive[u->subno];
1931
1932         if((r->status = fisreqchk(&d->portm, r)) != SDnostatus)
1933                 return r->status;
1934         r->rlen = 0;
1935         sdr0(d);
1936         for(try = 0; try < 10; try++){
1937                 qlock(&d->portm);
1938                 l = ahcibuildfis(d, r, r->data, r->dlen);
1939                 r->status = io(d, r->ataproto & Pprotom, -1, 1);
1940                 switch(r->status){
1941                 case SDtimeout:
1942                         qunlock(&d->portm);
1943                         return sdsetsense(r, SDcheck, 11, 0, 6);
1944                 case SDeio:
1945                         qunlock(&d->portm);
1946                         return SDeio;
1947                 case SDretry:
1948                         qunlock(&d->portm);
1949                         continue;
1950                 }
1951                 r->rlen = (r->ataproto & Pprotom) == Ppkt ? l->len : r->dlen;
1952                 try = sdr(r, d, r->status);
1953                 qunlock(&d->portm);
1954                 return try;
1955         }
1956         print("%s: bad disk\n", dnam(d));
1957         return r->status = SDeio;
1958 }
1959
1960 /*
1961  * configure drives 0-5 as ahci sata  (c.f. errata)
1962  */
1963 static int
1964 iaahcimode(Pcidev *p)
1965 {
1966         uint u;
1967
1968         u = pcicfgr16(p, 0x92);
1969         dprint("ahci: %T: iaahcimode %.2ux %.4ux\n", p->tbdf, pcicfgr8(p, 0x91), u);
1970         pcicfgw16(p, 0x92, u | 0xf);    /* ports 0-15 */
1971         return 0;
1972 }
1973
1974 enum{
1975         Ghc     = 0x04/4,       /* global host control */
1976         Pi      = 0x0c/4,       /* ports implemented */
1977         Cmddec  = 1<<15,        /* enable command block decode */
1978
1979         /* Ghc bits */
1980         Ahcien  = 1<<31,        /* ahci enable */
1981 };
1982
1983 static void
1984 iasetupahci(Ctlr *c)
1985 {
1986         pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~Cmddec);
1987         pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~Cmddec);
1988
1989         c->lmmio[Ghc] |= Ahcien;
1990         c->lmmio[Pi] = (1 << 6) - 1;    /* 5 ports (supposedly ro pi reg) */
1991
1992         /* enable ahci mode; from ich9 datasheet */
1993         pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
1994 }
1995
1996 static void
1997 sbsetupahci(Pcidev *p)
1998 {
1999         print("sbsetupahci: tweaking %.4ux ccru %.2ux ccrp %.2ux\n",
2000                 p->did, p->ccru, p->ccrp);
2001         pcicfgw8(p, 0x40, pcicfgr8(p, 0x40) | 1);
2002         pcicfgw8(p, PciCCRu, 6);
2003         pcicfgw8(p, PciCCRp, 1);
2004         p->ccru = 6;
2005         p->ccrp = 1;
2006 }
2007
2008 static int
2009 esbenc(Ctlr *c)
2010 {
2011         c->encsz = 1;
2012         c->enctx = (ulong*)(c->mmio + 0xa0);
2013         c->enctype = Eesb;
2014         c->enctx[0] = 0;
2015         return 0;
2016 }
2017
2018 static int
2019 ahciencinit(Ctlr *c)
2020 {
2021         ulong type, sz, o, *bar;
2022         Ahba *h;
2023
2024         h = c->hba;
2025         if(c->type == Tesb)
2026                 return esbenc(c);
2027         if((h->cap & Hems) == 0)
2028                 return -1;
2029         type = h->emctl & Emtype;
2030         switch(type){
2031         case Esgpio:
2032         case Eses2:
2033         case Esafte:
2034                 return -1;
2035         case Elmt:
2036                 break;
2037         default:
2038                 return -1;
2039         }
2040
2041         sz = h->emloc & 0xffff;
2042         o = h->emloc>>16;
2043         if(sz == 0 || o == 0)
2044                 return -1;
2045         bar = c->lmmio;
2046         dprint("size = %.4lux; loc = %.4lux*4\n", sz, o);
2047         c->encsz = sz;
2048         c->enctx = bar + o;
2049         if((h->emctl & Xonly) == 0){
2050                 if(h->emctl & Smb)
2051                         c->encrx = bar + o;
2052                 else
2053                         c->encrx = bar + o*2;
2054         }
2055         c->enctype = type;
2056         return 0;
2057 }
2058
2059 static int
2060 didtype(Pcidev *p)
2061 {
2062         int type;
2063
2064         type = Tahci;
2065         switch(p->vid){
2066         default:
2067                 return -1;
2068         case 0x8086:
2069                 if((p->did & 0xffff) == 0x1e02)
2070                         return Tich;            /* c210 */
2071                 if((p->did & 0xffff) == 0x8c02)
2072                         return Tich;            /* c220 */
2073                 if((p->did & 0xffff) == 0x24d1)
2074                         return Tich;            /* 82801eb/er */
2075                 if((p->did & 0xffff) == 0x2653)
2076                         return Tich;            /* 82801fbm */
2077                 if((p->did & 0xfffc) == 0x2680)
2078                         return Tesb;
2079                 if((p->did & 0xfffb) == 0x27c1)
2080                         return Tich;            /* 82801g[bh]m */
2081                 if((p->did & 0xffff) == 0x2822)
2082                         return Tich;            /* 82801 SATA RAID */
2083                 if((p->did & 0xffff) == 0x2821)
2084                         return Tich;            /* 82801h[roh] */
2085                 if((p->did & 0xfffe) == 0x2824)
2086                         return Tich;            /* 82801h[b] */
2087                 if((p->did & 0xfeff) == 0x2829)
2088                         return Tich;            /* ich8 */
2089                 if((p->did & 0xfffe) == 0x2922)
2090                         return Tich;            /* ich9 */
2091                 if((p->did & 0xffff) == 0x3a02)
2092                         return Tich;            /* 82801jd/do */
2093                 if((p->did & 0xfefe) == 0x3a22)
2094                         return Tich;            /* ich10, pch */
2095                 if((p->did & 0xfff7) == 0x3b28)
2096                         return Tich;            /* pchm */
2097                 if((p->did & 0xfffe) == 0x3b22)
2098                         return Tich;            /* pch */
2099                 break;
2100         case 0x1002:
2101                 if(p->ccru == 1 || p->ccrp != 1)
2102                 if(p->did == 0x4380 || p->did == 0x4390)
2103                         sbsetupahci(p);
2104                 type = Tsb600;
2105                 break;
2106         case 0x1106:
2107                 /*
2108                  * unconfirmed report that the programming
2109                  * interface is set incorrectly.
2110                  */
2111                 if(p->did == 0x3349)
2112                         return Tahci;
2113                 break;
2114         case 0x1022:
2115                 /* Hudson SATA Controller [AHCI mode] */
2116                 if(p->did == 0x7801)
2117                         return Tahci;
2118                 break;
2119         case 0x10de:
2120         case 0x1039:
2121         case 0x1b4b:
2122         case 0x11ab:
2123                 break;
2124         case 0x197b:
2125         case 0x10b9:
2126                 type = Tjmicron;
2127                 break;
2128         }
2129         if(p->ccrb == Pcibcstore && p->ccru == 6 && p->ccrp == 1)
2130                 return type;
2131         return -1;
2132 }
2133
2134 static SDev*
2135 iapnp(void)
2136 {
2137         int i, n, nunit, type;
2138         uintptr io;
2139         Ctlr *c;
2140         Drive *d;
2141         Pcidev *p;
2142         SDev *s;
2143         static int done;
2144
2145         if(done)
2146                 return nil;
2147         done = 1;
2148
2149         if(getconf("*noahci") != nil)
2150                 return nil;
2151
2152         if(getconf("*ahcidebug") != nil){
2153                 debug = 1;
2154                 datapi = 1;
2155         }
2156
2157         memset(olds, 0xff, sizeof olds);
2158         p = nil;
2159         while((p = pcimatch(p, 0, 0)) != nil){
2160                 if((type = didtype(p)) == -1)
2161                         continue;
2162                 if(p->mem[Abar].bar == 0)
2163                         continue;
2164                 if(niactlr == NCtlr){
2165                         print("iapnp: %s: too many controllers\n", tname[type]);
2166                         break;
2167                 }
2168                 c = iactlr + niactlr;
2169                 s = sdevs + niactlr;
2170                 memset(c, 0, sizeof *c);
2171                 memset(s, 0, sizeof *s);
2172                 io = p->mem[Abar].bar & ~0xf;
2173                 c->mmio = vmap(io, p->mem[Abar].size);
2174                 if(c->mmio == 0){
2175                         print("%s: address %#p in use did %.4ux\n",
2176                                 Tname(c), io, p->did);
2177                         continue;
2178                 }
2179                 c->lmmio = (ulong*)c->mmio;
2180                 c->pci = p;
2181                 c->type = type;
2182
2183                 s->ifc = &sdiahciifc;
2184                 s->idno = 'E';
2185                 s->ctlr = c;
2186                 c->sdev = s;
2187
2188                 ahcihandoff((Ahba*)c->mmio);
2189                 if(intel(c) && p->did != 0x2681)
2190                         iasetupahci(c);
2191 //              ahcihbareset((Ahba*)c->mmio);
2192                 nunit = ahciconf(c);
2193                 if(intel(c) && iaahcimode(p) == -1 || nunit < 1){
2194                         vunmap(c->mmio, p->mem[Abar].size);
2195                         continue;
2196                 }
2197                 c->ndrive = s->nunit = nunit;
2198
2199                 /* map the drives -- they don't all need to be enabled. */
2200                 memset(c->rawdrive, 0, sizeof c->rawdrive);
2201                 n = 0;
2202                 for(i = 0; i < NCtlrdrv; i++){
2203                         d = c->rawdrive + i;
2204                         d->portno = i;
2205                         d->driveno = -1;
2206                         d->sectors = 0;
2207                         d->serial[0] = ' ';
2208                         d->ctlr = c;
2209                         if((c->hba->pi & 1<<i) == 0)
2210                                 continue;
2211                         snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
2212                         d->port = (Aport*)(c->mmio + 0x80*i + 0x100);
2213                         d->portc.p = d->port;
2214                         d->portc.m = &d->portm;
2215                         d->driveno = n++;
2216                         c->drive[d->driveno] = d;
2217                         iadrive[niadrive + d->driveno] = d;
2218                 }
2219                 for(i = 0; i < n; i++){
2220                         c->drive[i]->mode = DMautoneg;
2221                         configdrive(c->drive[i]);
2222                 }
2223                 ahciencinit(c);
2224
2225                 niadrive += n;
2226                 niactlr++;
2227                 sdadddevs(s);
2228                 i = (c->hba->cap >> 21) & 1;
2229                 print("#S/%s: %s: sata-%s with %d ports\n", s->name,
2230                         Tname(c), "I\0II" + i*2, nunit);
2231         }
2232         return nil;
2233 }
2234
2235 static Htab ctab[] = {
2236         Aasp,   "asp",
2237         Aalpe , "alpe ",
2238         Adlae,  "dlae",
2239         Aatapi, "atapi",
2240         Apste,  "pste",
2241         Afbsc,  "fbsc",
2242         Aesp,   "esp",
2243         Acpd,   "cpd",
2244         Ampsp,  "mpsp",
2245         Ahpcp,  "hpcp",
2246         Apma,   "pma",
2247         Acps,   "cps",
2248         Acr,    "cr",
2249         Afr,    "fr",
2250         Ampss,  "mpss",
2251         Apod,   "pod",
2252         Asud,   "sud",
2253         Ast,    "st",
2254 };
2255
2256 static char*
2257 capfmt(char *p, char *e, Htab *t, int n, ulong cap)
2258 {
2259         uint i;
2260
2261         *p = 0;
2262         for(i = 0; i < n; i++)
2263                 if(cap & t[i].bit)
2264                         p = seprint(p, e, "%s ", t[i].name);
2265         return p;
2266 }
2267
2268 static int
2269 iarctl(SDunit *u, char *p, int l)
2270 {
2271         char buf[32], *e, *op;
2272         Aport *o;
2273         Ctlr *c;
2274         Drive *d;
2275
2276         if((c = u->dev->ctlr) == nil)
2277                 return 0;
2278         d = c->drive[u->subno];
2279         o = d->port;
2280
2281         e = p+l;
2282         op = p;
2283         if(d->state == Dready){
2284                 p = seprint(p, e, "model\t%s\n", d->model);
2285                 p = seprint(p, e, "serial\t%s\n", d->serial);
2286                 p = seprint(p, e, "firm\t%s\n", d->firmware);
2287                 if(d->wwn != 0)
2288                         p = seprint(p, e, "wwn\t%ullx\n", d->wwn);
2289                 p = seprint(p, e, "flag\t");
2290                 p = pflag(p, e, &d->portm);
2291                 p = seprint(p, e, "udma\t%d\n", d->portm.udma);
2292         }else
2293                 p = seprint(p, e, "no disk present [%s]\n", diskstates[d->state]);
2294         serrstr(o->serror, buf, buf + sizeof buf - 1);
2295         p = seprint(p, e, "reg\ttask %lux cmd %lux serr %lux %s ci %lux is %lux "
2296                 "sig %lux sstatus %.3lux\n", o->task, o->cmd, o->serror, buf,
2297                 o->ci, o->isr, o->sig, o->sstatus);
2298         p = seprint(p, e, "cmd\t");
2299         p = capfmt(p, e, ctab, nelem(ctab), o->cmd);
2300         p = seprint(p, e, "\n");
2301         p = seprint(p, e, "mode\t%s %s\n", modes[d->mode], modes[maxmode(c)]);
2302         p = seprint(p, e, "geometry %llud %d\n", d->sectors, d->secsize);
2303         p = seprint(p, e, "alignment %d %d\n", 
2304                 d->secsize<<d->portm.physshift, d->portm.physalign);
2305         p = seprint(p, e, "missirq\t%ud\n", c->missirq);
2306         return p - op;
2307 }
2308
2309 static void
2310 forcemode(Drive *d, char *mode)
2311 {
2312         int i;
2313
2314         for(i = 0; i < nelem(modes); i++)
2315                 if(strcmp(mode, modes[i]) == 0)
2316                         break;
2317         if(i == nelem(modes))
2318                 i = 0;
2319         ilock(d);
2320         d->mode = i;
2321         iunlock(d);
2322 }
2323
2324 static void
2325 forcestate(Drive *d, char *state)
2326 {
2327         int i;
2328
2329         for(i = 0; i < nelem(diskstates); i++)
2330                 if(strcmp(state, diskstates[i]) == 0)
2331                         break;
2332         if(i == nelem(diskstates))
2333                 error(Ebadctl);
2334         dstatus(d, i);
2335 }
2336
2337 static int
2338 runsettxmode(Drive *d, char *s)
2339 {
2340         int i;
2341         Aportc *c;
2342         Aportm *m;
2343
2344         c = &d->portc;
2345         m = &d->portm;
2346
2347         i = 1;
2348         if(lockready(d) == 0){
2349                 m->udma = atoi(s);
2350                 if(settxmode(c, m->udma) == 0)
2351                         i = 0;
2352         }
2353         qunlock(m);
2354         return i;
2355 }
2356
2357
2358 static int
2359 iawctl(SDunit *u, Cmdbuf *cmd)
2360 {
2361         char **f;
2362         Ctlr *c;
2363         Drive *d;
2364
2365         c = u->dev->ctlr;
2366         d = c->drive[u->subno];
2367         f = cmd->f;
2368
2369         if(strcmp(f[0], "mode") == 0)
2370                 forcemode(d, f[1]? f[1]: "satai");
2371         else if(strcmp(f[0], "state") == 0)
2372                 forcestate(d, f[1]? f[1]: "null");
2373         else if(strcmp(f[0], "txmode") == 0){
2374                 if(runsettxmode(d, f[1]? f[1]: "0"))
2375                         cmderror(cmd, "bad txmode / stuck port");
2376         }else
2377                 cmderror(cmd, Ebadctl);
2378         return 0;
2379 }
2380
2381 static char *
2382 portr(char *p, char *e, uint x)
2383 {
2384         int i, a;
2385
2386         p[0] = 0;
2387         a = -1;
2388         for(i = 0; i < 32; i++){
2389                 if((x & (1<<i)) == 0){
2390                         if(a != -1 && i - 1 != a)
2391                                 p = seprint(p, e, "-%d", i - 1);
2392                         a = -1;
2393                         continue;
2394                 }
2395                 if(a == -1){
2396                         if(i > 0)
2397                                 p = seprint(p, e, ", ");
2398                         p = seprint(p, e, "%d", a = i);
2399                 }
2400         }
2401         if(a != -1 && i - 1 != a)
2402                 p = seprint(p, e, "-%d", i - 1);
2403         return p;
2404 }
2405
2406 static Htab htab[] = {
2407         H64a,   "64a",
2408         Hncq,   "ncq",
2409         Hsntf,  "ntf",
2410         Hmps,   "mps",
2411         Hss,    "ss",
2412         Halp,   "alp",
2413         Hal,    "led",
2414         Hclo,   "clo",
2415         Ham,    "am",
2416         Hpm,    "pm",
2417         Hfbs,   "fbs",
2418         Hpmb,   "pmb",
2419         Hssc,   "slum",
2420         Hpsc,   "pslum",
2421         Hcccs,  "coal",
2422         Hems,   "ems",
2423         Hxs,    "xs",
2424 };
2425
2426 static Htab htab2[] = {
2427         Apts,   "apts",
2428         Nvmp,   "nvmp",
2429         Boh,    "boh",
2430 };
2431
2432 static Htab emtab[] = {
2433         Pm,     "pm",
2434         Alhd,   "alhd",
2435         Xonly,  "xonly",
2436         Smb,    "smb",
2437         Esgpio, "esgpio",
2438         Eses2,  "eses2",
2439         Esafte, "esafte",
2440         Elmt,   "elmt",
2441 };
2442
2443 static char*
2444 iartopctl(SDev *s, char *p, char *e)
2445 {
2446         char pr[25];
2447         ulong cap;
2448         Ahba *h;
2449         Ctlr *c;
2450
2451         c = s->ctlr;
2452         h = c->hba;
2453         cap = h->cap;
2454         p = seprint(p, e, "sd%c ahci %s port %#p: ", s->idno, Tname(c), h);
2455         p = capfmt(p, e, htab, nelem(htab), cap);
2456         p = capfmt(p, e, htab2, nelem(htab2), h->cap2);
2457         p = capfmt(p, e, emtab, nelem(emtab), h->emctl);
2458         portr(pr, pr + sizeof pr, h->pi);
2459         return seprint(p, e,
2460                 "iss %ld ncs %ld np %ld ghc %lux isr %lux pi %lux %s ver %lux\n",
2461                 (cap>>20) & 0xf, (cap>>8) & 0x1f, 1 + (cap & 0x1f),
2462                 h->ghc, h->isr, h->pi, pr, h->ver);
2463 }
2464
2465 static int
2466 iawtopctl(SDev *, Cmdbuf *cmd)
2467 {
2468         int *v;
2469         char **f;
2470
2471         f = cmd->f;
2472         v = 0;
2473
2474         if(strcmp(f[0], "debug") == 0)
2475                 v = &debug;
2476         else if(strcmp(f[0], "idprint") == 0)
2477                 v = &prid;
2478         else if(strcmp(f[0], "aprint") == 0)
2479                 v = &datapi;
2480         else if(strcmp(f[0], "ledprint") == 0)
2481                 v = &dled;
2482         else
2483                 cmderror(cmd, Ebadctl);
2484
2485         switch(cmd->nf){
2486         default:
2487                 cmderror(cmd, Ebadarg);
2488         case 1:
2489                 *v ^= 1;
2490                 break;
2491         case 2:
2492                 if(f[1])
2493                         *v = strcmp(f[1], "on") == 0;
2494                 else
2495                         *v ^= 1;
2496                 break;
2497         }
2498         return 0;
2499 }
2500
2501 SDifc sdiahciifc = {
2502         "ahci",
2503
2504         iapnp,
2505         nil,            /* legacy */
2506         iaenable,
2507         iadisable,
2508
2509         iaverify,
2510         iaonline,
2511         iario,
2512         iarctl,
2513         iawctl,
2514
2515         ahcibio,
2516         nil,            /* probe */
2517         nil,            /* clear */
2518         iartopctl,
2519         iawtopctl,
2520         iaataio,
2521 };