]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/sdiahci.c
sdiahci: add pci did for 82801fbm (ich6) SATA controller
[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 == 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         case Smissing:
912                 d->state = Dmissing;
913                 break;
914         case Spresent:
915                 break;
916         case Sphylink:
917                 if(d->state == Dready)
918                         break;
919                 d->wait = 0;
920                 d->state = Dnew;
921                 break;
922         case Sbist:
923                 d->state = Doffline;
924                 break;
925         }
926         iunlock(d);
927
928         dprint("%s: configdrive: %s\n", dnam(d), diskstates[d->state]);
929 }
930
931 static void
932 resetdisk(Drive *d)
933 {
934         uint state, det, stat;
935         Aport *p;
936
937         p = d->port;
938         det = p->sctl & 7;
939         stat = p->sstatus & Smask;
940         state = (p->cmd>>28) & 0xf;
941         dprint("%s: resetdisk [icc %ux; det %.3ux; sdet %.3ux]\n", dnam(d), state, det, stat);
942
943         ilock(d);
944         if(d->state != Dready && d->state != Dnew)
945                 d->portm.flag |= Ferror;
946         if(stat != Sphylink)
947                 d->state = Dportreset;
948         else
949                 d->state = Dreset;
950         clearci(p);                     /* satisfy sleep condition. */
951         wakeup(&d->portm);
952         iunlock(d);
953
954         if(stat != Sphylink)
955                 return;
956
957         qlock(&d->portm);
958         if(p->cmd&Ast && ahciswreset(&d->portc) == -1)
959                 dstatus(d, Dportreset); /* get a bigger stick. */
960         else
961                 configdrive(d);
962         qunlock(&d->portm);
963 }
964
965 static int
966 newdrive(Drive *d)
967 {
968         char *s;
969         Aportc *c;
970         Aportm *m;
971
972         c = &d->portc;
973         m = &d->portm;
974
975         qlock(c->m);
976         setfissig(m, c->p->sig);
977         if(identify(d) == -1){
978                 dprint("%s: identify failure\n", dnam(d));
979                 goto lose;
980         }
981         if(settxmode(c, m->udma) == -1){
982                 dprint("%s: can't set udma mode\n", dnam(d));
983                 goto lose;
984         }
985         if(m->feat & Dpower && setfeatures(c, 0x85, 3*1000) == -1){
986                 dprint("%s: can't disable apm\n", dnam(d));
987                 m->feat &= ~Dpower;
988                 if(ahcirecover(c) == -1)
989                         goto lose;
990         }
991         dstatus(d, Dready);
992         qunlock(c->m);
993
994         s = "";
995         if(m->feat & Dllba)
996                 s = "L";
997         idprint("%s: %sLBA %,lld sectors\n", dnam(d), s, d->sectors);
998         idprint("  %s %s %s %s\n", d->model, d->firmware, d->serial,
999                 d->drivechange? "[newdrive]": "");
1000         return 0;
1001
1002 lose:
1003         idprint("%s: can't be initialized\n", dnam(d));
1004         dstatus(d, Dnull);
1005         qunlock(c->m);
1006         return -1;
1007 }
1008
1009 enum {
1010         Nms             = 256,
1011         Mphywait        =  2*1024/Nms - 1,
1012         Midwait         = 16*1024/Nms - 1,
1013         Mcomrwait       = 64*1024/Nms - 1,
1014 };
1015
1016 static void
1017 hangck(Drive *d)
1018 {
1019         if(d->active && d->totick != 0 && (long)(Ticks - d->totick) > 0){
1020                 dprint("%s: drive hung [task %lux; ci %lux; serr %lux]%s\n",
1021                         dnam(d), d->port->task, d->port->ci, d->port->serror,
1022                         d->nodma == 0 ? "; disabling dma" : "");
1023                 d->nodma = 1;
1024                 d->state = Dreset;
1025         }
1026 }
1027
1028 static ushort olds[NCtlr*NCtlrdrv];
1029
1030 static void
1031 doportreset(Drive *d)
1032 {
1033         qlock(&d->portm);
1034         ahciportreset(&d->portc, d->mode);
1035         qunlock(&d->portm);
1036
1037         dprint("ahci: portreset: %s [task %lux; ss %.3lux]\n",
1038                 diskstates[d->state], d->port->task, d->port->sstatus);
1039 }
1040
1041 /* drive must be locked */
1042 static void
1043 statechange(Drive *d)
1044 {
1045         switch(d->state){
1046         case Dnull:
1047         case Doffline:
1048                 if(d->unit)
1049                 if(d->unit->sectors != 0){
1050                         d->sectors = 0;
1051                         d->drivechange = 1;
1052                 }
1053         case Dready:
1054                 d->wait = 0;
1055         }
1056 }
1057
1058 static uint
1059 maxmode(Ctlr *c)
1060 {
1061         return (c->hba->cap & 0xf*Hiss)/Hiss;
1062 }
1063
1064 static void iainterrupt(Ureg*, void *);
1065
1066 static void
1067 checkdrive(Drive *d, int i)
1068 {
1069         ushort s, sig;
1070
1071         if(d->ctlr->enabled == 0)
1072                 return;
1073         if(d->driveno == 0)
1074                 iainterrupt(0, d->ctlr);        /* check for missed irq's */
1075
1076         ilock(d);
1077         s = d->port->sstatus;
1078         if(s)
1079                 d->lastseen = Ticks;
1080         if(s != olds[i]){
1081                 dprint("%s: status: %.3ux -> %.3ux: %s\n",
1082                         dnam(d), olds[i], s, diskstates[d->state]);
1083                 olds[i] = s;
1084                 d->wait = 0;
1085         }
1086         hangck(d);
1087         switch(d->state){
1088         case Dnull:
1089         case Dready:
1090                 break;
1091         case Dmissing:
1092         case Dnew:
1093                 switch(s & (Iactive|Smask)){
1094                 case Spresent:
1095                         ahciwakeup(&d->portc, d->mode);
1096                 case Smissing:
1097                         break;
1098                 default:
1099                         dprint("%s: unknown status %.3ux\n", dnam(d), s);
1100                         /* fall through */
1101                 case Iactive:           /* active, no device */
1102                         if(++d->wait&Mphywait)
1103                                 break;
1104 reset:
1105                         if(d->mode == 0)
1106                                 d->mode = maxmode(d->ctlr);
1107                         else
1108                                 d->mode--;
1109                         if(d->mode == DMautoneg){
1110                                 d->state = Dportreset;
1111                                 goto portreset;
1112                         }
1113                         dprint("%s: reset; new mode %s\n", dnam(d),
1114                                 modes[d->mode]);
1115                         iunlock(d);
1116                         resetdisk(d);
1117                         ilock(d);
1118                         break;
1119                 case Iactive | Sphylink:
1120                         if(d->unit == nil)
1121                                 break;
1122                         if((++d->wait&Midwait) == 0){
1123                                 dprint("%s: slow reset [task %lux; ss %.3ux; wait %d]\n",
1124                                         dnam(d), d->port->task, s, d->wait);
1125                                 goto reset;
1126                         }
1127                         s = (uchar)d->port->task;
1128                         sig = d->port->sig >> 16;
1129                         if(s == 0x7f || s&ASbsy ||
1130                             (sig != 0xeb14 && (s & ASdrdy) == 0))
1131                                 break;
1132                         iunlock(d);
1133                         newdrive(d);
1134                         ilock(d);
1135                         break;
1136                 }
1137                 break;
1138         case Doffline:
1139                 if(d->wait++ & Mcomrwait)
1140                         break;
1141                 /* fallthrough */
1142         case Derror:
1143         case Dreset:
1144                 dprint("%s: reset [%s]: mode %d; status %.3ux\n",
1145                         dnam(d), diskstates[d->state], d->mode, s);
1146                 iunlock(d);
1147                 resetdisk(d);
1148                 ilock(d);
1149                 break;
1150         case Dportreset:
1151 portreset:
1152                 if(d->wait++ & 0xff && (s & Iactive) == 0)
1153                         break;
1154                 dprint("%s: portreset [%s]: mode %d; status %.3ux\n",
1155                         dnam(d), diskstates[d->state], d->mode, s);
1156                 d->portm.flag |= Ferror;
1157                 clearci(d->port);
1158                 wakeup(&d->portm);
1159                 if((s & Smask) == Smissing){
1160                         d->state = Dmissing;
1161                         break;
1162                 }
1163                 iunlock(d);
1164                 doportreset(d);
1165                 ilock(d);
1166                 break;
1167         }
1168         statechange(d);
1169         iunlock(d);
1170 }
1171
1172 static void
1173 satakproc(void*)
1174 {
1175         int i;
1176
1177         for(;;){
1178                 tsleep(&up->sleep, return0, 0, Nms);
1179                 for(i = 0; i < niadrive; i++)
1180                         checkdrive(iadrive[i], i);
1181         }
1182 }
1183
1184 static void
1185 iainterrupt(Ureg *u, void *a)
1186 {
1187         int i;
1188         ulong cause, m;
1189         Ctlr *c;
1190         Drive *d;
1191
1192         c = a;
1193         ilock(c);
1194         cause = c->hba->isr;
1195         for(i = 0; cause; i++){
1196                 m = 1 << i;
1197                 if((cause & m) == 0)
1198                         continue;
1199                 cause &= ~m;
1200                 d = c->rawdrive + i;
1201                 ilock(d);
1202                 if(d->port->isr && c->hba->pi & m)
1203                         updatedrive(d);
1204                 c->hba->isr = m;
1205                 iunlock(d);
1206         }
1207         if(u == 0 && i > 0)
1208                 c->missirq++;
1209         iunlock(c);
1210 }
1211
1212 static int
1213 ahciencreset(Ctlr *c)
1214 {
1215         Ahba *h;
1216
1217         if(c->enctype == Eesb)
1218                 return 0;
1219         h = c->hba;
1220         h->emctl |= Emrst;
1221         while(h->emctl & Emrst)
1222                 delay(1);
1223         return 0;
1224 }
1225
1226 /*
1227  * from the standard: (http://en.wikipedia.org/wiki/IBPI)
1228  * rebuild is preferred as locate+fail; alternate 1hz fail
1229  * we're going to assume no locate led.
1230  */
1231
1232 enum {
1233         Ledsleep        = 125,          /* 8hz */
1234
1235         N0      = Ledon*Aled,
1236         L0      = Ledon*Aled | Ledon*Locled,
1237         L1      = Ledon*Aled | Ledoff*Locled,
1238         R0      = Ledon*Aled | Ledon*Locled |   Ledon*Errled,
1239         R1      = Ledon*Aled |                  Ledoff*Errled,
1240         S0      = Ledon*Aled |  Ledon*Locled /*|        Ledon*Errled*/, /* botch */
1241         S1      = Ledon*Aled |                  Ledoff*Errled,
1242         P0      = Ledon*Aled |                  Ledon*Errled,
1243         P1      = Ledon*Aled |                  Ledoff*Errled,
1244         F0      = Ledon*Aled |                  Ledon*Errled,
1245         C0      = Ledon*Aled | Ledon*Locled,
1246         C1      = Ledon*Aled | Ledoff*Locled,
1247
1248 };
1249
1250 //static ushort led3[Ibpilast*8] = {
1251 //[Ibpinone*8]  0,      0,      0,      0,      0,      0,      0,      0,
1252 //[Ibpinormal*8]        N0,     N0,     N0,     N0,     N0,     N0,     N0,     N0,
1253 //[Ibpirebuild*8]       R0,     R0,     R0,     R0,     R1,     R1,     R1,     R1,
1254 //[Ibpilocate*8]        L0,     L1,     L0,     L1,     L0,     L1,     L0,     L1,
1255 //[Ibpispare*8] S0,     S1,     S0,     S1,     S1,     S1,     S1,     S1,
1256 //[Ibpipfa*8]   P0,     P1,     P0,     P1,     P1,     P1,     P1,     P1,     /* first 1 sec */
1257 //[Ibpifail*8]  F0,     F0,     F0,     F0,     F0,     F0,     F0,     F0,
1258 //[Ibpicritarray*8]     C0,     C0,     C0,     C0,     C1,     C1,     C1,     C1,
1259 //[Ibpifailarray*8]     C0,     C1,     C0,     C1,     C0,     C1,     C0,     C1,
1260 //};
1261
1262 static ushort led2[Ibpilast*8] = {
1263 [Ibpinone*8]    0,      0,      0,      0,      0,      0,      0,      0,
1264 [Ibpinormal*8]  N0,     N0,     N0,     N0,     N0,     N0,     N0,     N0,
1265 [Ibpirebuild*8] R0,     R0,     R0,     R0,     R1,     R1,     R1,     R1,
1266 [Ibpilocate*8]  L0,     L0,     L0,     L0,     L0,     L0,     L0,     L0,
1267 [Ibpispare*8]   S0,     S0,     S0,     S0,     S1,     S1,     S1,     S1,
1268 [Ibpipfa*8]     P0,     P1,     P0,     P1,     P1,     P1,     P1,     P1,     /* first 1 sec */
1269 [Ibpifail*8]    F0,     F0,     F0,     F0,     F0,     F0,     F0,     F0,
1270 [Ibpicritarray*8]       C0,     C0,     C0,     C0,     C1,     C1,     C1,     C1,
1271 [Ibpifailarray*8]       C0,     C1,     C0,     C1,     C0,     C1,     C0,     C1,
1272 };
1273
1274 static int
1275 ledstate(Ledport *p, uint seq)
1276 {
1277         ushort i;
1278
1279         if(p->led == Ibpipfa && seq%32 >= 8)
1280                 i = P1;
1281         else
1282                 i = led2[8*p->led + seq%8];
1283         if(i != p->ledbits){
1284                 p->ledbits = i;
1285                 ledprint("ledstate %,.011ub %ud\n", p->ledbits, seq);
1286                 return 1;
1287         }
1288         return 0;
1289 }
1290
1291 static int
1292 blink(Drive *d, ulong t)
1293 {
1294         Ahba *h;
1295         Ctlr *c;
1296         Aledmsg msg;
1297
1298         if(ledstate(d, t) == 0)
1299                 return 0;
1300         c = d->ctlr;
1301         h = c->hba;
1302         /* ensure last message has been transmitted */
1303         while(h->emctl & Tmsg)
1304                 microdelay(1);
1305         switch(c->enctype){
1306         default:
1307                 panic("%s: bad led type %d", dnam(d), c->enctype);
1308         case Elmt:
1309                 memset(&msg, 0, sizeof msg);
1310                 msg.type = Mled;
1311                 msg.dsize = 0;
1312                 msg.msize = sizeof msg - 4;
1313                 msg.led[0] = d->ledbits;
1314                 msg.led[1] = d->ledbits>>8;
1315                 msg.pm = 0;
1316                 msg.hba = d->driveno;
1317                 memmove(c->enctx, &msg, sizeof msg);
1318                 break;
1319         }
1320         h->emctl |= Tmsg;
1321         return 1;
1322 }
1323
1324 enum {
1325         Esbdrv0 = 4,            /* start pos in bits */
1326         Esbiota = 3,            /* shift in bits */
1327         Esbact  = 1,
1328         Esbloc  = 2,
1329         Esberr  = 4,
1330 };
1331
1332 uint
1333 esbbits(uint s)
1334 {
1335         uint i, e;                              /* except after c */
1336
1337         e = 0;
1338         for(i = 0; i < 3; i++)
1339                 e |= ((s>>3*i & 7) != 0)<<i;
1340         return e;
1341 }
1342
1343 static int
1344 blinkesb(Ctlr *c, ulong t)
1345 {
1346         uint i, s, u[32/4];
1347         uvlong v;
1348         Drive *d;
1349
1350         s = 0;
1351         for(i = 0; i < c->ndrive; i++){
1352                 d = c->drive[i];
1353                 s |= ledstate(d, t);            /* no port mapping */
1354         }
1355         if(s == 0)
1356                 return 0;
1357         memset(u, 0, sizeof u);
1358         for(i = 0; i < c->ndrive; i++){
1359                 d = c->drive[i];
1360                 s = Esbdrv0 + Esbiota*i;
1361                 v = esbbits(d->ledbits) * (1ull << s%32);
1362                 u[s/32 + 0] |= v;
1363                 u[s/32 + 1] |= v>>32;
1364         }
1365         for(i = 0; i < c->encsz; i++)
1366                 c->enctx[i] = u[i];
1367         return 1;
1368 }
1369
1370 static long
1371 ahciledr(SDunit *u, Chan *ch, void *a, long n, vlong off)
1372 {
1373         Ctlr *c;
1374         Drive *d;
1375
1376         c = u->dev->ctlr;
1377         d = c->drive[u->subno];
1378         return ledr(d, ch, a, n, off);
1379 }
1380
1381 static long
1382 ahciledw(SDunit *u, Chan *ch, void *a, long n, vlong off)
1383 {
1384         Ctlr *c;
1385         Drive *d;
1386
1387         c = u->dev->ctlr;
1388         d = c->drive[u->subno];
1389         return ledw(d, ch, a, n, off);
1390 }
1391
1392 static void
1393 ledkproc(void*)
1394 {
1395         uchar map[NCtlr];
1396         uint i, j, t0, t1;
1397         Ctlr *c;
1398         Drive *d;
1399
1400         j = 0;
1401         memset(map, 0, sizeof map);
1402         for(i = 0; i < niactlr; i++)
1403                 if(iactlr[i].enctype != 0){
1404                         ahciencreset(iactlr + i);
1405                         map[i] = 1;
1406                         j++;
1407                 }
1408         if(j == 0)
1409                 pexit("no work", 1);
1410         for(i = 0; i < niadrive; i++){
1411                 iadrive[i]->nled = 3;           /* hardcoded */
1412                 if(iadrive[i]->ctlr->enctype == Eesb)
1413                         iadrive[i]->nled = 3;
1414                 iadrive[i]->ledbits = -1;
1415         }
1416         for(i = 0; ; i++){
1417                 t0 = Ticks;
1418                 for(j = 0; j < niadrive; ){
1419                         c = iadrive[j]->ctlr;
1420                         if(map[j] == 0)
1421                                 j += c->enctype;
1422                         else if(c->enctype == Eesb){
1423                                 blinkesb(c, i);
1424                                 j += c->ndrive;
1425                         }else{
1426                                 d = iadrive[j++];
1427                                 blink(d, i);
1428                         }
1429                 }
1430                 t1 = Ticks;
1431                 esleep(Ledsleep - TK2MS(t1 - t0));
1432         }
1433 }
1434
1435 static int
1436 waitready(Drive *d)
1437 {
1438         ulong s, i, δ;
1439
1440         for(i = 0;; i += 250){
1441                 if(d->state == Dreset || d->state == Dportreset || d->state == Dnew)
1442                         return 1;
1443                 ilock(d);
1444                 s = d->port->sstatus;
1445                 if(d->state == Dready && (s & Smask) == Sphylink){
1446                         iunlock(d);
1447                         return 0;
1448                 }
1449                 δ = Ticks - d->lastseen;
1450                 if(d->state == Dnull || δ > 10*1000)
1451                         break;
1452                 if((s & Imask) == 0 && δ > 1500)
1453                         break;
1454                 if(i >= 15*1000){
1455                         d->state = Doffline;
1456                         iunlock(d);
1457                         print("%s: not responding; offline\n", dnam(d));
1458                         return -1;
1459                 }
1460                 iunlock(d);
1461                 esleep(250);
1462         }
1463         iunlock(d);
1464         return -1;
1465 }
1466
1467 static int
1468 iaverify(SDunit *u)
1469 {
1470         Ctlr *c;
1471         Drive *d;
1472
1473         c = u->dev->ctlr;
1474         d = c->drive[u->subno];
1475         ilock(c);
1476         ilock(d);
1477         if(d->unit == nil){
1478                 d->unit = u;
1479                 if(c->enctype != 0)
1480                         sdaddfile(u, "led", 0644, eve, ahciledr, ahciledw);
1481         }
1482         iunlock(d);
1483         iunlock(c);
1484         checkdrive(d, d->driveno);              /* c->d0 + d->driveno */
1485         return 1;
1486 }
1487
1488 static int
1489 iaonline(SDunit *u)
1490 {
1491         int r;
1492         Ctlr *c;
1493         Drive *d;
1494
1495         c = u->dev->ctlr;
1496         d = c->drive[u->subno];
1497
1498         while(waitready(d) == 1)
1499                 esleep(1);
1500
1501         dprint("%s: iaonline: %s\n", dnam(d), diskstates[d->state]);
1502
1503         ilock(d);
1504         if(d->portm.feat & Datapi){
1505                 r = d->drivechange;
1506                 d->drivechange = 0;
1507                 iunlock(d);
1508                 if(r != 0)
1509                         scsiverify(u);
1510                 return scsionline(u);
1511         }
1512         r = 0;
1513         if(d->drivechange){
1514                 d->drivechange = 0;
1515                 r = 2;
1516         }else if(d->state == Dready)
1517                 r = 1;
1518         if(r){
1519                 u->sectors = d->sectors;
1520                 u->secsize = d->secsize;
1521         }
1522         iunlock(d);
1523
1524         return r;
1525 }
1526
1527 static int
1528 iaenable(SDev *s)
1529 {
1530         char name[32];
1531         Ctlr *c;
1532         static int once;
1533
1534         c = s->ctlr;
1535         ilock(c);
1536         if(!c->enabled){
1537                 if(once == 0)
1538                         kproc("iasata", satakproc, 0);
1539                 if(c->ndrive == 0)
1540                         panic("iaenable: zero s->ctlr->ndrive");
1541                 pcisetbme(c->pci);
1542                 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1543                 intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1544                 /* supposed to squelch leftover interrupts here. */
1545                 ahcienable(c->hba);
1546                 c->enabled = 1;
1547                 if(++once == niactlr)
1548                         kproc("ialed", ledkproc, 0);
1549         }
1550         iunlock(c);
1551         return 1;
1552 }
1553
1554 static int
1555 iadisable(SDev *s)
1556 {
1557         char name[32];
1558         Ctlr *c;
1559
1560         c = s->ctlr;
1561         ilock(c);
1562         ahcidisable(c->hba);
1563         snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1564         intrdisable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1565         c->enabled = 0;
1566         iunlock(c);
1567         return 1;
1568 }
1569
1570 static Alist*
1571 ahcibuild(Drive *d, int rw, void *data, uint n, vlong lba)
1572 {
1573         uchar *c;
1574         uint flags;
1575         Aportm *m;
1576
1577         m = &d->portm;
1578         c = m->ctab->cfis;
1579         rwfis(m, c, rw, n, lba);
1580         flags = Lpref;
1581         if(rw == SDwrite)
1582                 flags |= Lwrite;
1583         return mkalist(m, flags, data, 512*n);
1584 }
1585
1586 static Alist*
1587 ahcibuildpkt(Drive *d, SDreq *r, void *data, int n)
1588 {
1589         uint flags;
1590         Aportm *m;
1591         uchar *c;
1592         Actab *t;
1593
1594         m = &d->portm;
1595         t = m->ctab;
1596         c = t->cfis;
1597
1598         atapirwfis(m, c, r->cmd, r->clen, 0x2000);
1599         if((n & 15) != 0 || d->nodma)
1600                 c[Ffeat] &= ~1; /* use pio */
1601         else if(c[Ffeat] & 1 && d->info[62] & (1<<15))  /* dma direction */
1602                 c[Ffeat] = (c[Ffeat] & ~(1<<2)) | ((r->write == 0) << 2);
1603         flags = Lpref | Latapi;
1604         if(r->write != 0 && data)
1605                 flags |= Lwrite;
1606         return mkalist(m, flags, data, n);
1607 }
1608
1609 static Alist*
1610 ahcibuildfis(Drive *d, SDreq *r, void *data, uint n)
1611 {
1612         uint flags;
1613         uchar *c;
1614         Aportm *m;
1615
1616         if((r->ataproto & Pprotom) == Ppkt)
1617                 return ahcibuildpkt(d, r, data, n);
1618
1619         m = &d->portm;
1620         c = m->ctab->cfis;
1621         memmove(c, r->cmd, r->clen);
1622         flags = Lpref;
1623         if(r->write || n == 0)
1624                 flags |= Lwrite;
1625         return mkalist(m, flags, data, n);
1626 }
1627
1628 static int
1629 lockready(Drive *d)
1630 {
1631         int i;
1632
1633         qlock(&d->portm);
1634         while ((i = waitready(d)) == 1) {
1635                 qunlock(&d->portm);
1636                 esleep(1);
1637                 qlock(&d->portm);
1638         }
1639         return i;
1640 }
1641
1642 static int
1643 flushcache(Drive *d)
1644 {
1645         int i;
1646
1647         i = -1;
1648         if(lockready(d) == 0)
1649                 i = ahciflushcache(&d->portc);
1650         qunlock(&d->portm);
1651         return i;
1652 }
1653
1654 static int
1655 io(Drive *d, uint proto, int to, int interrupt)
1656 {
1657         uint task, flag, stat, rv;
1658         Aport *p;
1659         Asleep as;
1660
1661         switch(waitready(d)){
1662         case -1:
1663                 return SDeio;
1664         case 1:
1665                 return SDretry;
1666         }
1667
1668         ilock(d);
1669         d->portm.flag = 0;
1670         iunlock(d);
1671         p = d->port;
1672         p->ci = 1;
1673
1674         as.p = p;
1675         as.i = 1;
1676         d->totick = 0;
1677         if(to > 0)
1678                 d->totick = Ticks + MS2TK(to) | 1;      /* fix fencepost */
1679         d->active++;
1680
1681         while(waserror())
1682                 if(interrupt){
1683                         d->active--;
1684                         d->port->ci = 0;
1685                         if(ahcicomreset(&d->portc) == -1)
1686                                 dstatus(d, Dreset);
1687                         return SDtimeout;
1688                 }
1689         
1690         sleep(&d->portm, ahciclear, &as);
1691         poperror();
1692
1693         d->active--;
1694         ilock(d);
1695         stat = d->state;
1696         flag = d->portm.flag;
1697         task = d->port->task;
1698         iunlock(d);
1699
1700         rv = SDok;
1701         if(proto & Ppkt && stat == Dready){
1702                 rv = task >> 8 + 4 & 0xf;
1703                 flag &= ~Fahdrs;
1704                 flag |= Fdone;
1705         }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && stat == Dready){
1706                 d->port->ci = 0;
1707                 ahcirecover(&d->portc);
1708                 task = d->port->task;
1709                 flag &= ~Fdone;         /* either an error or do-over */
1710         }
1711         if(flag == 0){
1712                 print("%s: retry\n", dnam(d));
1713                 return SDretry;
1714         }
1715         if(flag & (Fahdrs | Ferror)){
1716                 if((task & Eidnf) == 0)
1717                         print("%s: i/o error %ux\n", dnam(d), task);
1718                 return SDcheck;
1719         }
1720         return rv;
1721 }
1722
1723 static int
1724 iariopkt(SDreq *r, Drive *d)
1725 {
1726         int try, to;
1727         uchar *cmd;
1728         Alist *l;
1729
1730         cmd = r->cmd;
1731         aprint("%s: %.2ux %.2ux %c %d %p\n", dnam(d), cmd[0], cmd[2],
1732                 "rw"[r->write], r->dlen, r->data);
1733
1734         r->rlen = 0;
1735
1736         /*
1737          * prevent iaonline() to hang forever by timing out
1738          * inquiry and capacity commands after 5 seconds.
1739          */
1740         to = 30*1000;
1741         switch(cmd[0]){
1742         case 0x9e: if(cmd[1] != 0x10) break;
1743         case 0x25:
1744         case 0x12:
1745                 to = 5*1000;
1746                 break;
1747         }
1748
1749         for(try = 0; try < 10; try++){
1750                 qlock(&d->portm);
1751                 l = ahcibuildpkt(d, r, r->data, r->dlen);
1752                 r->status = io(d, Ppkt, to, 0);
1753                 switch(r->status){
1754                 case SDeio:
1755                         qunlock(&d->portm);
1756                         return SDeio;
1757                 case SDretry:
1758                         qunlock(&d->portm);
1759                         continue;
1760                 }
1761                 r->rlen = l->len;
1762                 qunlock(&d->portm);
1763                 return SDok;
1764         }
1765         print("%s: bad disk\n", dnam(d));
1766         return r->status = SDcheck;
1767 }
1768
1769 static long
1770 ahcibio(SDunit *u, int lun, int write, void *a, long count, uvlong lba)
1771 {
1772         int n, rw, try, status, max;
1773         uchar *data;
1774         Ctlr *c;
1775         Drive *d;
1776
1777         c = u->dev->ctlr;
1778         d = c->drive[u->subno];
1779         if(d->portm.feat & Datapi)
1780                 return scsibio(u, lun, write, a, count, lba);
1781
1782         max = 128;
1783         if(d->portm.feat & Dllba){
1784                 max = 8192;             /* ahci maximum */
1785                 if(c->type == Tsb600)
1786                         max = 255;      /* errata */
1787         }
1788         rw = write? SDwrite: SDread;
1789         data = a;
1790         dprint("%s: bio: %llud %c %lud %p\n",
1791                 dnam(d), lba, "rw"[rw], count, data);
1792
1793         for(try = 0; try < 10;){
1794                 n = count;
1795                 if(n > max)
1796                         n = max;
1797                 qlock(&d->portm);
1798                 ahcibuild(d, rw, data, n, lba);
1799                 status = io(d, Pdma, 5000, 0);
1800                 qunlock(&d->portm);
1801                 switch(status){
1802                 case SDeio:
1803                         return -1;
1804                 case SDretry:
1805                         try++;
1806                         continue;
1807                 }
1808                 try = 0;
1809                 count -= n;
1810                 lba   += n;
1811                 data += n * u->secsize;
1812                 if(count == 0)
1813                         return data - (uchar*)a;
1814         }
1815         print("%s: bad disk\n", dnam(d));
1816         return -1;
1817 }
1818
1819 static int
1820 iario(SDreq *r)
1821 {
1822         int i, n, count, rw;
1823         uchar *cmd;
1824         uvlong lba;
1825         Ctlr *c;
1826         Drive *d;
1827         SDunit *u;
1828
1829         u = r->unit;
1830         c = u->dev->ctlr;
1831         d = c->drive[u->subno];
1832         if(d->portm.feat & Datapi)
1833                 return iariopkt(r, d);
1834         cmd = r->cmd;
1835
1836         if(cmd[0] == 0x35 || cmd[0] == 0x91){
1837                 if(flushcache(d) == 0)
1838                         return sdsetsense(r, SDok, 0, 0, 0);
1839                 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1840         }
1841
1842         if((i = sdfakescsi(r)) != SDnostatus){
1843                 r->status = i;
1844                 return i;
1845         }
1846
1847         if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
1848                 return i;
1849         n = ahcibio(u, r->lun, r->write, r->data, count, lba);
1850         if(n == -1)
1851                 return SDeio;
1852         r->rlen = n;
1853         return SDok;
1854 }
1855
1856 static uchar bogusrfis[16] = {
1857 [Ftype]         0x34,
1858 [Fioport]       0x40,
1859 [Fstatus]       0x50,
1860 [Fdev]          0xa0,
1861 };
1862
1863 static void
1864 sdr0(Drive *d)
1865 {
1866         uchar *c;
1867
1868         c = d->portm.fis.r;
1869         memmove(c, bogusrfis, sizeof bogusrfis);
1870         coherence();
1871 }
1872
1873 static int
1874 sdr(SDreq *r, Drive *d, int st)
1875 {
1876         uchar *c;
1877         uint t;
1878
1879         if((r->ataproto & Pprotom) == Ppkt){
1880                 t = d->port->task;
1881                 if(t & ASerr)
1882                         st = t >> 8 + 4 & 0xf;
1883         }
1884         c = d->portm.fis.r;
1885         memmove(r->cmd, c, 16);
1886         r->status = st;
1887         if(st == SDcheck)
1888                 st = SDok;
1889         return st;
1890 }
1891
1892 static int
1893 fisreqchk(Sfis *f, SDreq *r)
1894 {
1895         if((r->ataproto & Pprotom) == Ppkt)
1896                 return SDnostatus;
1897         /*
1898          * handle oob requests;
1899          *    restrict & sanitize commands
1900          */
1901         if(r->clen != 16)
1902                 error(Eio);
1903         if(r->cmd[0] == 0xf0){
1904                 sigtofis(f, r->cmd);
1905                 r->status = SDok;
1906                 return SDok;
1907         }
1908         r->cmd[0] = 0x27;
1909         r->cmd[1] = 0x80;
1910         r->cmd[7] |= 0xa0;
1911         return SDnostatus;
1912 }
1913
1914 static int
1915 iaataio(SDreq *r)
1916 {
1917         int try;
1918         Ctlr *c;
1919         Drive *d;
1920         SDunit *u;
1921         Alist *l;
1922
1923         u = r->unit;
1924         c = u->dev->ctlr;
1925         d = c->drive[u->subno];
1926
1927         if((r->status = fisreqchk(&d->portm, r)) != SDnostatus)
1928                 return r->status;
1929         r->rlen = 0;
1930         sdr0(d);
1931         for(try = 0; try < 10; try++){
1932                 qlock(&d->portm);
1933                 l = ahcibuildfis(d, r, r->data, r->dlen);
1934                 r->status = io(d, r->ataproto & Pprotom, -1, 1);
1935                 switch(r->status){
1936                 case SDtimeout:
1937                         qunlock(&d->portm);
1938                         return sdsetsense(r, SDcheck, 11, 0, 6);
1939                 case SDeio:
1940                         qunlock(&d->portm);
1941                         return SDeio;
1942                 case SDretry:
1943                         qunlock(&d->portm);
1944                         continue;
1945                 }
1946                 r->rlen = (r->ataproto & Pprotom) == Ppkt ? l->len : r->dlen;
1947                 try = sdr(r, d, r->status);
1948                 qunlock(&d->portm);
1949                 return try;
1950         }
1951         print("%s: bad disk\n", dnam(d));
1952         return r->status = SDeio;
1953 }
1954
1955 /*
1956  * configure drives 0-5 as ahci sata  (c.f. errata)
1957  */
1958 static int
1959 iaahcimode(Pcidev *p)
1960 {
1961         uint u;
1962
1963         u = pcicfgr16(p, 0x92);
1964         dprint("ahci: %T: iaahcimode %.2ux %.4ux\n", p->tbdf, pcicfgr8(p, 0x91), u);
1965         pcicfgw16(p, 0x92, u | 0xf);    /* ports 0-15 */
1966         return 0;
1967 }
1968
1969 enum{
1970         Ghc     = 0x04/4,       /* global host control */
1971         Pi      = 0x0c/4,       /* ports implemented */
1972         Cmddec  = 1<<15,        /* enable command block decode */
1973
1974         /* Ghc bits */
1975         Ahcien  = 1<<31,        /* ahci enable */
1976 };
1977
1978 static void
1979 iasetupahci(Ctlr *c)
1980 {
1981         pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~Cmddec);
1982         pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~Cmddec);
1983
1984         c->lmmio[Ghc] |= Ahcien;
1985         c->lmmio[Pi] = (1 << 6) - 1;    /* 5 ports (supposedly ro pi reg) */
1986
1987         /* enable ahci mode; from ich9 datasheet */
1988         pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
1989 }
1990
1991 static void
1992 sbsetupahci(Pcidev *p)
1993 {
1994         print("sbsetupahci: tweaking %.4ux ccru %.2ux ccrp %.2ux\n",
1995                 p->did, p->ccru, p->ccrp);
1996         pcicfgw8(p, 0x40, pcicfgr8(p, 0x40) | 1);
1997         pcicfgw8(p, PciCCRu, 6);
1998         pcicfgw8(p, PciCCRp, 1);
1999         p->ccru = 6;
2000         p->ccrp = 1;
2001 }
2002
2003 static int
2004 esbenc(Ctlr *c)
2005 {
2006         c->encsz = 1;
2007         c->enctx = (ulong*)(c->mmio + 0xa0);
2008         c->enctype = Eesb;
2009         c->enctx[0] = 0;
2010         return 0;
2011 }
2012
2013 static int
2014 ahciencinit(Ctlr *c)
2015 {
2016         ulong type, sz, o, *bar;
2017         Ahba *h;
2018
2019         h = c->hba;
2020         if(c->type == Tesb)
2021                 return esbenc(c);
2022         if((h->cap & Hems) == 0)
2023                 return -1;
2024         type = h->emctl & Emtype;
2025         switch(type){
2026         case Esgpio:
2027         case Eses2:
2028         case Esafte:
2029                 return -1;
2030         case Elmt:
2031                 break;
2032         default:
2033                 return -1;
2034         }
2035
2036         sz = h->emloc & 0xffff;
2037         o = h->emloc>>16;
2038         if(sz == 0 || o == 0)
2039                 return -1;
2040         bar = c->lmmio;
2041         dprint("size = %.4lux; loc = %.4lux*4\n", sz, o);
2042         c->encsz = sz;
2043         c->enctx = bar + o;
2044         if((h->emctl & Xonly) == 0){
2045                 if(h->emctl & Smb)
2046                         c->encrx = bar + o;
2047                 else
2048                         c->encrx = bar + o*2;
2049         }
2050         c->enctype = type;
2051         return 0;
2052 }
2053
2054 static int
2055 didtype(Pcidev *p)
2056 {
2057         int type;
2058
2059         type = Tahci;
2060         switch(p->vid){
2061         default:
2062                 return -1;
2063         case 0x8086:
2064                 if((p->did & 0xffff) == 0x2653)
2065                         return Tich;            /* 82801fbm */
2066                 if((p->did & 0xfffc) == 0x2680)
2067                         return Tesb;
2068                 if((p->did & 0xfffb) == 0x27c1)
2069                         return Tich;            /* 82801g[bh]m */
2070                 if((p->did & 0xffff) == 0x2822)
2071                         return Tich;            /* 82801 SATA RAID */
2072                 if((p->did & 0xffff) == 0x2821)
2073                         return Tich;            /* 82801h[roh] */
2074                 if((p->did & 0xfffe) == 0x2824)
2075                         return Tich;            /* 82801h[b] */
2076                 if((p->did & 0xfeff) == 0x2829)
2077                         return Tich;            /* ich8 */
2078                 if((p->did & 0xfffe) == 0x2922)
2079                         return Tich;            /* ich9 */
2080                 if((p->did & 0xffff)  == 0x3a02)
2081                         return Tich;            /* 82801jd/do */
2082                 if((p->did & 0xfefe)  == 0x3a22)
2083                         return Tich;            /* ich10, pch */
2084                 if((p->did & 0xfff7)  == 0x3b28)
2085                         return Tich;            /* pchm */
2086                 if((p->did & 0xfffe) == 0x3b22)
2087                         return Tich;            /* pch */
2088                 break;
2089         case 0x1002:
2090                 if(p->ccru == 1 || p->ccrp != 1)
2091                 if(p->did == 0x4380 || p->did == 0x4390)
2092                         sbsetupahci(p);
2093                 type = Tsb600;
2094                 break;
2095         case 0x1106:
2096                 /*
2097                  * unconfirmed report that the programming
2098                  * interface is set incorrectly.
2099                  */
2100                 if(p->did == 0x3349)
2101                         return Tahci;
2102                 break;
2103         case 0x1022:
2104                 /* Hudson SATA Controller [AHCI mode] */
2105                 if(p->did == 0x7801)
2106                         return Tahci;
2107                 break;
2108         case 0x10de:
2109         case 0x1039:
2110         case 0x1b4b:
2111         case 0x11ab:
2112                 break;
2113         case 0x197b:
2114         case 0x10b9:
2115                 type = Tjmicron;
2116                 break;
2117         }
2118         if(p->ccrb == Pcibcstore && p->ccru == 6 && p->ccrp == 1)
2119                 return type;
2120         return -1;
2121 }
2122
2123 static SDev*
2124 iapnp(void)
2125 {
2126         int i, n, nunit, type;
2127         ulong io;
2128         Ctlr *c;
2129         Drive *d;
2130         Pcidev *p;
2131         SDev *s;
2132         static int done;
2133
2134         if(done)
2135                 return nil;
2136         done = 1;
2137
2138         if(getconf("*ahcidebug") != nil){
2139                 debug = 1;
2140                 datapi = 1;
2141         }
2142
2143         memset(olds, 0xff, sizeof olds);
2144         p = nil;
2145         while((p = pcimatch(p, 0, 0)) != nil){
2146                 if((type = didtype(p)) == -1)
2147                         continue;
2148                 if(p->mem[Abar].bar == 0)
2149                         continue;
2150                 if(niactlr == NCtlr){
2151                         print("iapnp: %s: too many controllers\n", tname[type]);
2152                         break;
2153                 }
2154                 c = iactlr + niactlr;
2155                 s = sdevs + niactlr;
2156                 memset(c, 0, sizeof *c);
2157                 memset(s, 0, sizeof *s);
2158                 io = p->mem[Abar].bar & ~0xf;
2159                 c->mmio = vmap(io, p->mem[Abar].size);
2160                 if(c->mmio == 0){
2161                         print("%s: address %#p in use did %.4ux\n",
2162                                 Tname(c), io, p->did);
2163                         continue;
2164                 }
2165                 c->lmmio = (ulong*)c->mmio;
2166                 c->pci = p;
2167                 c->type = type;
2168
2169                 s->ifc = &sdiahciifc;
2170                 s->idno = 'E';
2171                 s->ctlr = c;
2172                 c->sdev = s;
2173
2174                 ahcihandoff((Ahba*)c->mmio);
2175                 if(intel(c) && p->did != 0x2681)
2176                         iasetupahci(c);
2177 //              ahcihbareset((Ahba*)c->mmio);
2178                 nunit = ahciconf(c);
2179                 if(intel(c) && iaahcimode(p) == -1 || nunit < 1){
2180                         vunmap(c->mmio, p->mem[Abar].size);
2181                         continue;
2182                 }
2183                 c->ndrive = s->nunit = nunit;
2184
2185                 /* map the drives -- they don't all need to be enabled. */
2186                 memset(c->rawdrive, 0, sizeof c->rawdrive);
2187                 n = 0;
2188                 for(i = 0; i < NCtlrdrv; i++){
2189                         d = c->rawdrive + i;
2190                         d->portno = i;
2191                         d->driveno = -1;
2192                         d->sectors = 0;
2193                         d->serial[0] = ' ';
2194                         d->ctlr = c;
2195                         if((c->hba->pi & 1<<i) == 0)
2196                                 continue;
2197                         snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
2198                         d->port = (Aport*)(c->mmio + 0x80*i + 0x100);
2199                         d->portc.p = d->port;
2200                         d->portc.m = &d->portm;
2201                         d->driveno = n++;
2202                         c->drive[d->driveno] = d;
2203                         iadrive[niadrive + d->driveno] = d;
2204                 }
2205                 for(i = 0; i < n; i++){
2206                         c->drive[i]->mode = DMautoneg;
2207                         configdrive(c->drive[i]);
2208                 }
2209                 ahciencinit(c);
2210
2211                 niadrive += n;
2212                 niactlr++;
2213                 sdadddevs(s);
2214                 i = (c->hba->cap >> 21) & 1;
2215                 print("#S/%s: %s: sata-%s with %d ports\n", s->name,
2216                         Tname(c), "I\0II" + i*2, nunit);
2217         }
2218         return nil;
2219 }
2220
2221 static Htab ctab[] = {
2222         Aasp,   "asp",
2223         Aalpe , "alpe ",
2224         Adlae,  "dlae",
2225         Aatapi, "atapi",
2226         Apste,  "pste",
2227         Afbsc,  "fbsc",
2228         Aesp,   "esp",
2229         Acpd,   "cpd",
2230         Ampsp,  "mpsp",
2231         Ahpcp,  "hpcp",
2232         Apma,   "pma",
2233         Acps,   "cps",
2234         Acr,    "cr",
2235         Afr,    "fr",
2236         Ampss,  "mpss",
2237         Apod,   "pod",
2238         Asud,   "sud",
2239         Ast,    "st",
2240 };
2241
2242 static char*
2243 capfmt(char *p, char *e, Htab *t, int n, ulong cap)
2244 {
2245         uint i;
2246
2247         *p = 0;
2248         for(i = 0; i < n; i++)
2249                 if(cap & t[i].bit)
2250                         p = seprint(p, e, "%s ", t[i].name);
2251         return p;
2252 }
2253
2254 static int
2255 iarctl(SDunit *u, char *p, int l)
2256 {
2257         char buf[32], *e, *op;
2258         Aport *o;
2259         Ctlr *c;
2260         Drive *d;
2261
2262         if((c = u->dev->ctlr) == nil)
2263                 return 0;
2264         d = c->drive[u->subno];
2265         o = d->port;
2266
2267         e = p+l;
2268         op = p;
2269         if(d->state == Dready){
2270                 p = seprint(p, e, "model\t%s\n", d->model);
2271                 p = seprint(p, e, "serial\t%s\n", d->serial);
2272                 p = seprint(p, e, "firm\t%s\n", d->firmware);
2273                 if(d->wwn != 0)
2274                         p = seprint(p, e, "wwn\t%ullx\n", d->wwn);
2275                 p = seprint(p, e, "flag\t");
2276                 p = pflag(p, e, &d->portm);
2277                 p = seprint(p, e, "udma\t%d\n", d->portm.udma);
2278         }else
2279                 p = seprint(p, e, "no disk present [%s]\n", diskstates[d->state]);
2280         serrstr(o->serror, buf, buf + sizeof buf - 1);
2281         p = seprint(p, e, "reg\ttask %lux cmd %lux serr %lux %s ci %lux is %lux "
2282                 "sig %lux sstatus %.3lux\n", o->task, o->cmd, o->serror, buf,
2283                 o->ci, o->isr, o->sig, o->sstatus);
2284         p = seprint(p, e, "cmd\t");
2285         p = capfmt(p, e, ctab, nelem(ctab), o->cmd);
2286         p = seprint(p, e, "\n");
2287         p = seprint(p, e, "mode\t%s %s\n", modes[d->mode], modes[maxmode(c)]);
2288         p = seprint(p, e, "geometry %llud %lud\n", d->sectors, u->secsize);
2289         p = seprint(p, e, "alignment %d %d\n", 
2290                 d->secsize<<d->portm.physshift, d->portm.physalign);
2291         p = seprint(p, e, "missirq\t%ud\n", c->missirq);
2292         return p - op;
2293 }
2294
2295 static void
2296 forcemode(Drive *d, char *mode)
2297 {
2298         int i;
2299
2300         for(i = 0; i < nelem(modes); i++)
2301                 if(strcmp(mode, modes[i]) == 0)
2302                         break;
2303         if(i == nelem(modes))
2304                 i = 0;
2305         ilock(d);
2306         d->mode = i;
2307         iunlock(d);
2308 }
2309
2310 static void
2311 forcestate(Drive *d, char *state)
2312 {
2313         int i;
2314
2315         for(i = 0; i < nelem(diskstates); i++)
2316                 if(strcmp(state, diskstates[i]) == 0)
2317                         break;
2318         if(i == nelem(diskstates))
2319                 error(Ebadctl);
2320         dstatus(d, i);
2321 }
2322
2323 static int
2324 runsettxmode(Drive *d, char *s)
2325 {
2326         int i;
2327         Aportc *c;
2328         Aportm *m;
2329
2330         c = &d->portc;
2331         m = &d->portm;
2332
2333         i = 1;
2334         if(lockready(d) == 0){
2335                 m->udma = atoi(s);
2336                 if(settxmode(c, m->udma) == 0)
2337                         i = 0;
2338         }
2339         qunlock(m);
2340         return i;
2341 }
2342
2343
2344 static int
2345 iawctl(SDunit *u, Cmdbuf *cmd)
2346 {
2347         char **f;
2348         Ctlr *c;
2349         Drive *d;
2350
2351         c = u->dev->ctlr;
2352         d = c->drive[u->subno];
2353         f = cmd->f;
2354
2355         if(strcmp(f[0], "mode") == 0)
2356                 forcemode(d, f[1]? f[1]: "satai");
2357         else if(strcmp(f[0], "state") == 0)
2358                 forcestate(d, f[1]? f[1]: "null");
2359         else if(strcmp(f[0], "txmode") == 0){
2360                 if(runsettxmode(d, f[1]? f[1]: "0"))
2361                         cmderror(cmd, "bad txmode / stuck port");
2362         }else
2363                 cmderror(cmd, Ebadctl);
2364         return 0;
2365 }
2366
2367 static char *
2368 portr(char *p, char *e, uint x)
2369 {
2370         int i, a;
2371
2372         p[0] = 0;
2373         a = -1;
2374         for(i = 0; i < 32; i++){
2375                 if((x & (1<<i)) == 0){
2376                         if(a != -1 && i - 1 != a)
2377                                 p = seprint(p, e, "-%d", i - 1);
2378                         a = -1;
2379                         continue;
2380                 }
2381                 if(a == -1){
2382                         if(i > 0)
2383                                 p = seprint(p, e, ", ");
2384                         p = seprint(p, e, "%d", a = i);
2385                 }
2386         }
2387         if(a != -1 && i - 1 != a)
2388                 p = seprint(p, e, "-%d", i - 1);
2389         return p;
2390 }
2391
2392 static Htab htab[] = {
2393         H64a,   "64a",
2394         Hncq,   "ncq",
2395         Hsntf,  "ntf",
2396         Hmps,   "mps",
2397         Hss,    "ss",
2398         Halp,   "alp",
2399         Hal,    "led",
2400         Hclo,   "clo",
2401         Ham,    "am",
2402         Hpm,    "pm",
2403         Hfbs,   "fbs",
2404         Hpmb,   "pmb",
2405         Hssc,   "slum",
2406         Hpsc,   "pslum",
2407         Hcccs,  "coal",
2408         Hems,   "ems",
2409         Hxs,    "xs",
2410 };
2411
2412 static Htab htab2[] = {
2413         Apts,   "apts",
2414         Nvmp,   "nvmp",
2415         Boh,    "boh",
2416 };
2417
2418 static Htab emtab[] = {
2419         Pm,     "pm",
2420         Alhd,   "alhd",
2421         Xonly,  "xonly",
2422         Smb,    "smb",
2423         Esgpio, "esgpio",
2424         Eses2,  "eses2",
2425         Esafte, "esafte",
2426         Elmt,   "elmt",
2427 };
2428
2429 static char*
2430 iartopctl(SDev *s, char *p, char *e)
2431 {
2432         char pr[25];
2433         ulong cap;
2434         Ahba *h;
2435         Ctlr *c;
2436
2437         c = s->ctlr;
2438         h = c->hba;
2439         cap = h->cap;
2440         p = seprint(p, e, "sd%c ahci %s port %#p: ", s->idno, Tname(c), h);
2441         p = capfmt(p, e, htab, nelem(htab), cap);
2442         p = capfmt(p, e, htab2, nelem(htab2), h->cap2);
2443         p = capfmt(p, e, emtab, nelem(emtab), h->emctl);
2444         portr(pr, pr + sizeof pr, h->pi);
2445         return seprint(p, e,
2446                 "iss %ld ncs %ld np %ld ghc %lux isr %lux pi %lux %s ver %lux\n",
2447                 (cap>>20) & 0xf, (cap>>8) & 0x1f, 1 + (cap & 0x1f),
2448                 h->ghc, h->isr, h->pi, pr, h->ver);
2449 }
2450
2451 static int
2452 iawtopctl(SDev *, Cmdbuf *cmd)
2453 {
2454         int *v;
2455         char **f;
2456
2457         f = cmd->f;
2458         v = 0;
2459
2460         if(strcmp(f[0], "debug") == 0)
2461                 v = &debug;
2462         else if(strcmp(f[0], "idprint") == 0)
2463                 v = &prid;
2464         else if(strcmp(f[0], "aprint") == 0)
2465                 v = &datapi;
2466         else if(strcmp(f[0], "ledprint") == 0)
2467                 v = &dled;
2468         else
2469                 cmderror(cmd, Ebadctl);
2470
2471         switch(cmd->nf){
2472         default:
2473                 cmderror(cmd, Ebadarg);
2474         case 1:
2475                 *v ^= 1;
2476                 break;
2477         case 2:
2478                 if(f[1])
2479                         *v = strcmp(f[1], "on") == 0;
2480                 else
2481                         *v ^= 1;
2482                 break;
2483         }
2484         return 0;
2485 }
2486
2487 SDifc sdiahciifc = {
2488         "ahci",
2489
2490         iapnp,
2491         nil,            /* legacy */
2492         iaenable,
2493         iadisable,
2494
2495         iaverify,
2496         iaonline,
2497         iario,
2498         iarctl,
2499         iawctl,
2500
2501         ahcibio,
2502         nil,            /* probe */
2503         nil,            /* clear */
2504         iartopctl,
2505         iawtopctl,
2506         iaataio,
2507 };