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