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