]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/sdiahci.c
sdide: Marvell PATA, sdiahci: 82801 SATA RAID
[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\n", 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         r = 0;
1477
1478         if(d->portm.feat & Datapi && d->drivechange){
1479                 r = scsionline(unit);
1480                 if(r > 0)
1481                         d->drivechange = 0;
1482                 return r;
1483         }
1484
1485         ilock(d);
1486         if(d->drivechange){
1487                 r = 2;
1488                 d->drivechange = 0;
1489                 /* devsd resets this after online is called; why? */
1490                 unit->sectors = d->sectors;
1491                 unit->secsize = d->secsize;
1492         }else if(d->state == Dready)
1493                 r = 1;
1494         iunlock(d);
1495         return r;
1496 }
1497
1498 static Alist*
1499 ahcibuild(Aportm *m, int rw, void *data, uint n, vlong lba)
1500 {
1501         uchar *c;
1502         uint flags;
1503         Alist *l;
1504
1505         l = m->list;
1506         c = m->ctab->cfis;
1507         rwfis(m, c, rw, n, lba);
1508         flags = Lpref;
1509         if(rw == SDwrite)
1510                 flags |= Lwrite;
1511         mkalist(m, flags, data, 512*n);
1512         return l;
1513 }
1514
1515 static Alist*
1516 ahcibuildpkt(Aportm *m, SDreq *r, void *data, int n)
1517 {
1518         uint flags;
1519         uchar *c;
1520         Actab *t;
1521         Alist *l;
1522
1523         l = m->list;
1524         t = m->ctab;
1525         c = t->cfis;
1526         atapirwfis(m, c, r->cmd, r->clen, n);
1527         flags = 1<<16 | Lpref | Latapi;
1528         if(r->write != 0 && data)
1529                 flags |= Lwrite;
1530         mkalist(m, flags, data, n);
1531         return l;
1532 }
1533
1534 static Alist*
1535 ahcibuildfis(Aportm *m, SDreq *r, void *data, uint n)
1536 {
1537         uchar *c;
1538         uint flags;
1539         Alist *l;
1540
1541         l = m->list;
1542         c = m->ctab->cfis;
1543         if((r->ataproto & Pprotom) != Ppkt){
1544                 memmove(c, r->cmd, r->clen);
1545                 flags = Lpref;
1546                 if(r->write || n == 0)
1547                         flags |= Lwrite;
1548                 mkalist(m, flags, data, n);
1549         }else{
1550                 atapirwfis(m, c, r->cmd, r->clen, n);
1551                 flags = 1<<16 | Lpref | Latapi;
1552                 if(r->write && data)
1553                         flags |= Lwrite;
1554                 mkalist(m, flags, data, n);
1555         }
1556         return l;
1557 }
1558
1559 static int
1560 waitready(Drive *d)
1561 {
1562         ulong s, i, δ;
1563
1564         for(i = 0; i < 15000; i += 250){
1565                 if(d->state == Dreset || d->state == Dportreset ||
1566                     d->state == Dnew)
1567                         return 1;
1568                 δ = Ticks - d->lastseen;
1569                 if(d->state == Dnull || δ > 10*1000)
1570                         return -1;
1571                 ilock(d);
1572                 s = d->port->sstatus;
1573                 iunlock(d);
1574                 if((s & Imask) == 0 && δ > 1500)
1575                         return -1;
1576                 if(d->state == Dready && (s & Smask) == Sphylink)
1577                         return 0;
1578                 esleep(250);
1579         }
1580         print("%s: not responding; offline\n", dnam(d));
1581         ilock(d);
1582         d->state = Doffline;
1583         iunlock(d);
1584         return -1;
1585 }
1586
1587 static int
1588 lockready(Drive *d)
1589 {
1590         int i;
1591
1592         qlock(&d->portm);
1593         while ((i = waitready(d)) == 1) {
1594                 qunlock(&d->portm);
1595                 esleep(1);
1596                 qlock(&d->portm);
1597         }
1598         return i;
1599 }
1600
1601 static int
1602 flushcache(Drive *d)
1603 {
1604         int i;
1605
1606         i = -1;
1607         if(lockready(d) == 0)
1608                 i = ahciflushcache(&d->portc);
1609         qunlock(&d->portm);
1610         return i;
1611 }
1612
1613 static int
1614 io(Drive *d, uint proto, int to, int interrupt)
1615 {
1616         uint task, flag, rv;
1617         Aport *p;
1618         Asleep as;
1619
1620         switch(waitready(d)){
1621         case -1:
1622                 return SDeio;
1623         case 1:
1624                 return SDretry;
1625         }
1626
1627         ilock(d);
1628         d->portm.flag = 0;
1629         iunlock(d);
1630         p = d->port;
1631         p->ci = 1;
1632
1633         as.p = p;
1634         as.i = 1;
1635         d->totick = 0;
1636         if(to > 0)
1637                 d->totick = Ticks + MS2TK(to) | 1;      /* fix fencepost */
1638         d->active++;
1639
1640         while(waserror())
1641                 if(interrupt){
1642                         d->active--;
1643                         d->port->ci = 0;
1644                         if(ahcicomreset(&d->portc) == -1){
1645                                 ilock(d);
1646                                 d->state = Dreset;
1647                                 iunlock(d);
1648                         }
1649                         return SDtimeout;
1650                 }
1651         sleep(&d->portm, ahciclear, &as);
1652         poperror();
1653
1654         d->active--;
1655         ilock(d);
1656         flag = d->portm.flag;
1657         task = d->port->task;
1658         iunlock(d);
1659
1660         rv = SDok;
1661         if(proto & Ppkt){
1662                 rv = task >> 8 + 4 & 0xf;
1663                 flag &= ~Fahdrs;
1664                 flag |= Fdone;
1665         }else if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && d->state == Dready){
1666                 d->port->ci = 0;
1667                 ahcirecover(&d->portc);
1668                 task = d->port->task;
1669                 flag &= ~Fdone;         /* either an error or do-over */
1670         }
1671         if(flag == 0){
1672                 print("%s: retry\n", dnam(d));
1673                 return SDretry;
1674         }
1675         if(flag & (Fahdrs | Ferror)){
1676                 if((task & Eidnf) == 0)
1677                         print("%s: i/o error %ux\n", dnam(d), task);
1678                 return SDcheck;
1679         }
1680         return rv;
1681 }
1682
1683 static int
1684 iariopkt(SDreq *r, Drive *d)
1685 {
1686         int n, count, try, max;
1687         uchar *cmd;
1688
1689         cmd = r->cmd;
1690         aprint("%s: %.2ux %.2ux %c %d %p\n", dnam(d), cmd[0], cmd[2],
1691                 "rw"[r->write], r->dlen, r->data);
1692         r->rlen = 0;
1693         count = r->dlen;
1694         max = 65536;
1695
1696         for(try = 0; try < 10; try++){
1697                 n = count;
1698                 if(n > max)
1699                         n = max;
1700                 qlock(&d->portm);
1701                 ahcibuildpkt(&d->portm, r, r->data, n);
1702                 r->status = io(d, Ppkt, 5000, 0);
1703                 qunlock(&d->portm);
1704                 switch(r->status){
1705                 case SDeio:
1706                         return SDeio;
1707                 case SDretry:
1708                         continue;
1709                 }
1710 //              print("%.2ux :: %.2ux :: %.4ux\n", r->cmd[0], r->status, d->port->task);
1711                 r->rlen = d->portm.list->len;
1712                 return SDok;
1713         }
1714         print("%s: bad disk\n", dnam(d));
1715         return r->status = SDcheck;
1716 }
1717
1718 static long
1719 ahcibio(SDunit *u, int lun, int write, void *a, long count, uvlong lba)
1720 {
1721         int n, rw, try, status, max;
1722         uchar *data;
1723         Ctlr *c;
1724         Drive *d;
1725
1726         c = u->dev->ctlr;
1727         d = c->drive[u->subno];
1728         if(d->portm.feat & Datapi)
1729                 return scsibio(u, lun, write, a, count, lba);
1730
1731         max = 128;
1732         if(d->portm.feat & Dllba){
1733                 max = 8192;             /* ahci maximum */
1734                 if(c->type == Tsb600)
1735                         max = 255;      /* errata */
1736         }
1737         rw = write? SDwrite: SDread;
1738         data = a;
1739         for(try = 0; try < 10;){
1740                 n = count;
1741                 if(n > max)
1742                         n = max;
1743                 qlock(&d->portm);
1744                 ahcibuild(&d->portm, rw, data, n, lba);
1745                 status = io(d, Pdma, 5000, 0);
1746                 qunlock(&d->portm);
1747                 switch(status){
1748                 case SDeio:
1749                         return -1;
1750                 case SDretry:
1751                         try++;
1752                         continue;
1753                 }
1754                 try = 0;
1755                 count -= n;
1756                 lba   += n;
1757                 data += n * u->secsize;
1758                 if(count == 0)
1759                         return data - (uchar*)a;
1760         }
1761         print("%s: bad disk\n", dnam(d));
1762         return -1;
1763 }
1764
1765 static int
1766 iario(SDreq *r)
1767 {
1768         int i, n, count, rw;
1769         uchar *cmd;
1770         uvlong lba;
1771         Ctlr *c;
1772         Drive *d;
1773         SDunit *unit;
1774
1775         unit = r->unit;
1776         c = unit->dev->ctlr;
1777         d = c->drive[unit->subno];
1778         if(d->portm.feat & Datapi)
1779                 return iariopkt(r, d);
1780         cmd = r->cmd;
1781
1782         if(cmd[0] == 0x35 || cmd[0] == 0x91){
1783                 if(flushcache(d) == 0)
1784                         return sdsetsense(r, SDok, 0, 0, 0);
1785                 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1786         }
1787
1788         if((i = sdfakescsi(r)) != SDnostatus){
1789                 r->status = i;
1790                 return i;
1791         }
1792
1793         if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus)
1794                 return i;
1795         n = ahcibio(unit, r->lun, r->write, r->data, count, lba);
1796         if(n == -1)
1797                 return SDeio;
1798         r->rlen = n;
1799         return SDok;
1800 }
1801
1802 static uchar bogusrfis[16] = {
1803 [Ftype]         0x34,
1804 [Fioport]       0x40,
1805 [Fstatus]               0x50,
1806
1807 [Fdev]          0xa0,
1808 };
1809
1810 static void
1811 sdr0(Drive *d)
1812 {
1813         uchar *c;
1814
1815         c = d->portm.fis.r;
1816         memmove(c, bogusrfis, sizeof bogusrfis);
1817         coherence();
1818 }
1819
1820 static int
1821 sdr(SDreq *r, Drive *d, int st)
1822 {
1823         uchar *c;
1824         uint t;
1825
1826         if((r->ataproto & Pprotom) == Ppkt){
1827                 t = d->port->task;
1828                 if(t & ASerr)
1829                         st = t >> 8 + 4 & 0xf;
1830         }
1831         c = d->portm.fis.r;
1832         memmove(r->cmd, c, 16);
1833         r->status = st;
1834         if(st == SDcheck)
1835                 st = SDok;
1836         return st;
1837 }
1838
1839 static int
1840 fisreqchk(Sfis *f, SDreq *r)
1841 {
1842         if((r->ataproto & Pprotom) == Ppkt)
1843                 return SDnostatus;
1844         /*
1845          * handle oob requests;
1846          *    restrict & sanitize commands
1847          */
1848         if(r->clen != 16)
1849                 error(Eio);
1850         if(r->cmd[0] == 0xf0){
1851                 sigtofis(f, r->cmd);
1852                 r->status = SDok;
1853                 return SDok;
1854         }
1855         r->cmd[0] = 0x27;
1856         r->cmd[1] = 0x80;
1857         r->cmd[7] |= 0xa0;
1858         return SDnostatus;
1859 }
1860
1861 static int
1862 iaataio(SDreq *r)
1863 {
1864         int try;
1865         Ctlr *c;
1866         Drive *d;
1867         SDunit *u;
1868
1869         u = r->unit;
1870         c = u->dev->ctlr;
1871         d = c->drive[u->subno];
1872
1873         if((r->status = fisreqchk(&d->portm, r)) != SDnostatus)
1874                 return r->status;
1875         r->rlen = 0;
1876         sdr0(d);
1877         for(try = 0; try < 10; try++){
1878                 qlock(&d->portm);
1879                 ahcibuildfis(&d->portm, r, r->data, r->dlen);
1880                 r->status = io(d, r->ataproto & Pprotom, -1, 1);
1881                 qunlock(&d->portm);
1882                 switch(r->status){
1883                 case SDtimeout:
1884                         return sdsetsense(r, SDcheck, 11, 0, 6);
1885                 case SDeio:
1886                         return SDeio;
1887                 case SDretry:
1888                         continue;
1889                 }
1890                 r->rlen = r->dlen;
1891                 if((r->ataproto & Pprotom) == Ppkt)
1892                         r->rlen = d->portm.list->len;
1893                 return sdr(r, d, r->status);
1894         }
1895         print("%s: bad disk\n", dnam(d));
1896         r->status = SDeio;
1897         return SDeio;
1898 }
1899
1900 /*
1901  * configure drives 0-5 as ahci sata  (c.f. errata)
1902  */
1903 static int
1904 iaahcimode(Pcidev *p)
1905 {
1906         uint u;
1907
1908         u = pcicfgr16(p, 0x92);
1909         dprint("ahci: %T: iaahcimode %.2ux %.4ux\n", p->tbdf, pcicfgr8(p, 0x91), u);
1910         pcicfgw16(p, 0x92, u | 0xf);    /* ports 0-15 */
1911         return 0;
1912 }
1913
1914 enum{
1915         Ghc     = 0x04/4,       /* global host control */
1916         Pi      = 0x0c/4,       /* ports implemented */
1917         Cmddec  = 1<<15,        /* enable command block decode */
1918
1919         /* Ghc bits */
1920         Ahcien  = 1<<31,        /* ahci enable */
1921 };
1922
1923 static void
1924 iasetupahci(Ctlr *c)
1925 {
1926         pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~Cmddec);
1927         pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~Cmddec);
1928
1929         c->lmmio[Ghc] |= Ahcien;
1930         c->lmmio[Pi] = (1 << 6) - 1;    /* 5 ports (supposedly ro pi reg) */
1931
1932         /* enable ahci mode; from ich9 datasheet */
1933         pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
1934 }
1935
1936 static void
1937 sbsetupahci(Pcidev *p)
1938 {
1939         print("sbsetupahci: tweaking %.4ux ccru %.2ux ccrp %.2ux\n",
1940                 p->did, p->ccru, p->ccrp);
1941         pcicfgw8(p, 0x40, pcicfgr8(p, 0x40) | 1);
1942         pcicfgw8(p, PciCCRu, 6);
1943         pcicfgw8(p, PciCCRp, 1);
1944         p->ccru = 6;
1945         p->ccrp = 1;
1946 }
1947
1948 static int
1949 esbenc(Ctlr *c)
1950 {
1951         c->encsz = 1;
1952         c->enctx = (ulong*)(c->mmio + 0xa0);
1953         c->enctype = Eesb;
1954         c->enctx[0] = 0;
1955         return 0;
1956 }
1957
1958 static int
1959 ahciencinit(Ctlr *c)
1960 {
1961         ulong type, sz, o, *bar;
1962         Ahba *h;
1963
1964         h = c->hba;
1965         if(c->type == Tesb)
1966                 return esbenc(c);
1967         if((h->cap & Hems) == 0)
1968                 return -1;
1969         type = h->emctl & Emtype;
1970         switch(type){
1971         case Esgpio:
1972         case Eses2:
1973         case Esafte:
1974                 return -1;
1975         case Elmt:
1976                 break;
1977         default:
1978                 return -1;
1979         }
1980
1981         sz = h->emloc & 0xffff;
1982         o = h->emloc>>16;
1983         if(sz == 0 || o == 0)
1984                 return -1;
1985         bar = c->lmmio;
1986         dprint("size = %.4lux; loc = %.4lux*4\n", sz, o);
1987         c->encsz = sz;
1988         c->enctx = bar + o;
1989         if((h->emctl & Xonly) == 0){
1990                 if(h->emctl & Smb)
1991                         c->encrx = bar + o;
1992                 else
1993                         c->encrx = bar + o*2;
1994         }
1995         c->enctype = type;
1996         return 0;
1997 }
1998
1999 static int
2000 didtype(Pcidev *p)
2001 {
2002         int type;
2003
2004         type = Tahci;
2005         switch(p->vid){
2006         default:
2007                 return -1;
2008         case 0x8086:
2009                 if((p->did & 0xfffc) == 0x2680)
2010                         return Tesb;
2011                 if((p->did & 0xfffb) == 0x27c1)
2012                         return Tich;            /* 82801g[bh]m */
2013                 if((p->did & 0xffff) == 0x2822)
2014                         return Tich;            /* 82801 SATA RAID */
2015                 if((p->did & 0xffff) == 0x2821)
2016                         return Tich;            /* 82801h[roh] */
2017                 if((p->did & 0xfffe) == 0x2824)
2018                         return Tich;            /* 82801h[b] */
2019                 if((p->did & 0xfeff) == 0x2829)
2020                         return Tich;            /* ich8 */
2021                 if((p->did & 0xfffe) == 0x2922)
2022                         return Tich;            /* ich9 */
2023                 if((p->did & 0xffff)  == 0x3a02)
2024                         return Tich;            /* 82801jd/do */
2025                 if((p->did & 0xfefe)  == 0x3a22)
2026                         return Tich;            /* ich10, pch */
2027                 if((p->did & 0xfff7)  == 0x3b28)
2028                         return Tich;            /* pchm */
2029                 if((p->did & 0xfffe) == 0x3b22)
2030                         return Tich;            /* pch */
2031                 break;
2032         case 0x1002:
2033                 if(p->ccru == 1 || p->ccrp != 1)
2034                 if(p->did == 0x4380 || p->did == 0x4390)
2035                         sbsetupahci(p);
2036                 type = Tsb600;
2037                 break;
2038         case 0x1106:
2039                 /*
2040                  * unconfirmed report that the programming
2041                  * interface is set incorrectly.
2042                  */
2043                 if(p->did == 0x3349)
2044                         return Tahci;
2045                 break;
2046         case 0x10de:
2047         case 0x1039:
2048         case 0x1b4b:
2049         case 0x11ab:
2050                 break;
2051         case 0x197b:
2052         case 0x10b9:
2053                 type = Tjmicron;
2054                 break;
2055         }
2056         if(p->ccrb == Pcibcstore && p->ccru == 6 && p->ccrp == 1)
2057                 return type;
2058         return -1;
2059 }
2060
2061 static SDev*
2062 iapnp(void)
2063 {
2064         int i, n, nunit, type;
2065         ulong io;
2066         Ctlr *c;
2067         Drive *d;
2068         Pcidev *p;
2069         SDev *s;
2070         static int done;
2071
2072         if(done)
2073                 return nil;
2074         done = 1;
2075         memset(olds, 0xff, sizeof olds);
2076         p = nil;
2077 loop:
2078         while((p = pcimatch(p, 0, 0)) != nil){
2079                 if((type = didtype(p)) == -1)
2080                         continue;
2081                 if(p->mem[Abar].bar == 0)
2082                         continue;
2083                 if(niactlr == NCtlr){
2084                         print("iapnp: %s: too many controllers\n", tname[type]);
2085                         break;
2086                 }
2087                 c = iactlr + niactlr;
2088                 s = sdevs + niactlr;
2089                 memset(c, 0, sizeof *c);
2090                 memset(s, 0, sizeof *s);
2091                 io = p->mem[Abar].bar & ~0xf;
2092                 c->mmio = vmap(io, p->mem[Abar].size);
2093                 if(c->mmio == 0){
2094                         print("%s: address %#p in use did %.4ux\n",
2095                                 Tname(c), io, p->did);
2096                         continue;
2097                 }
2098                 c->lmmio = (ulong*)c->mmio;
2099                 c->pci = p;
2100                 c->type = type;
2101
2102                 s->ifc = &sdiahciifc;
2103                 s->idno = 'E';
2104                 s->ctlr = c;
2105                 c->sdev = s;
2106
2107                 if(intel(c) && p->did != 0x2681)
2108                         iasetupahci(c);
2109 //              ahcihbareset((Ahba*)c->mmio);
2110                 nunit = ahciconf(c);
2111                 if(intel(c) && iaahcimode(p) == -1 || nunit < 1){
2112                         vunmap(c->mmio, p->mem[Abar].size);
2113                         continue;
2114                 }
2115                 c->ndrive = s->nunit = nunit;
2116
2117                 /* map the drives -- they don't all need to be enabled. */
2118                 memset(c->rawdrive, 0, sizeof c->rawdrive);
2119                 n = 0;
2120                 for(i = 0; i < NCtlrdrv; i++){
2121                         d = c->rawdrive + i;
2122                         d->portno = i;
2123                         d->driveno = -1;
2124                         d->sectors = 0;
2125                         d->serial[0] = ' ';
2126                         d->ctlr = c;
2127                         if((c->hba->pi & 1<<i) == 0)
2128                                 continue;
2129                         snprint(d->name, sizeof d->name, "iahci%d.%d", niactlr, i);
2130                         d->port = (Aport*)(c->mmio + 0x80*i + 0x100);
2131                         d->portc.p = d->port;
2132                         d->portc.m = &d->portm;
2133                         d->driveno = n++;
2134                         c->drive[d->driveno] = d;
2135                         iadrive[niadrive + d->driveno] = d;
2136                 }
2137                 for(i = 0; i < n; i++)
2138                         if(ahciidle(c->drive[i]->port) == -1){
2139                                 print("%s: port %d wedged; abort\n",
2140                                         Tname(c), i);
2141                                 goto loop;
2142                         }
2143                 for(i = 0; i < n; i++){
2144                         c->drive[i]->mode = DMautoneg;
2145                         configdrive(c->drive[i]);
2146                 }
2147                 ahciencinit(c);
2148
2149                 niadrive += n;
2150                 niactlr++;
2151                 sdadddevs(s);
2152                 i = (c->hba->cap >> 21) & 1;
2153                 print("#S/%s: %s: sata-%s with %d ports\n", s->name,
2154                         Tname(c), "I\0II" + i*2, nunit);
2155         }
2156         return nil;
2157 }
2158
2159 static Htab ctab[] = {
2160         Aasp,   "asp",
2161         Aalpe , "alpe ",
2162         Adlae,  "dlae",
2163         Aatapi, "atapi",
2164         Apste,  "pste",
2165         Afbsc,  "fbsc",
2166         Aesp,   "esp",
2167         Acpd,   "cpd",
2168         Ampsp,  "mpsp",
2169         Ahpcp,  "hpcp",
2170         Apma,   "pma",
2171         Acps,   "cps",
2172         Acr,    "cr",
2173         Afr,    "fr",
2174         Ampss,  "mpss",
2175         Apod,   "pod",
2176         Asud,   "sud",
2177         Ast,    "st",
2178 };
2179
2180 static char*
2181 capfmt(char *p, char *e, Htab *t, int n, ulong cap)
2182 {
2183         uint i;
2184
2185         *p = 0;
2186         for(i = 0; i < n; i++)
2187                 if(cap & t[i].bit)
2188                         p = seprint(p, e, "%s ", t[i].name);
2189         return p;
2190 }
2191
2192 static int
2193 iarctl(SDunit *u, char *p, int l)
2194 {
2195         char buf[32], *e, *op;
2196         Aport *o;
2197         Ctlr *c;
2198         Drive *d;
2199
2200         if((c = u->dev->ctlr) == nil)
2201                 return 0;
2202         d = c->drive[u->subno];
2203         o = d->port;
2204
2205         e = p+l;
2206         op = p;
2207         if(d->state == Dready){
2208                 p = seprint(p, e, "model\t%s\n", d->model);
2209                 p = seprint(p, e, "serial\t%s\n", d->serial);
2210                 p = seprint(p, e, "firm\t%s\n", d->firmware);
2211                 if(d->wwn != 0)
2212                         p = seprint(p, e, "wwn\t%ullx\n", d->wwn);
2213                 p = seprint(p, e, "flag\t");
2214                 p = pflag(p, e, &d->portm);
2215                 p = seprint(p, e, "udma\t%d\n", d->portm.udma);
2216         }else
2217                 p = seprint(p, e, "no disk present [%s]\n", diskstates[d->state]);
2218         serrstr(o->serror, buf, buf + sizeof buf - 1);
2219         p = seprint(p, e, "reg\ttask %lux cmd %lux serr %lux %s ci %lux is %lux "
2220                 "sig %lux sstatus %.3lux\n", o->task, o->cmd, o->serror, buf,
2221                 o->ci, o->isr, o->sig, o->sstatus);
2222         p = seprint(p, e, "cmd\t");
2223         p = capfmt(p, e, ctab, nelem(ctab), o->cmd);
2224         p = seprint(p, e, "\n");
2225         p = seprint(p, e, "mode\t%s %s\n", modes[d->mode], modes[maxmode(c)]);
2226         p = seprint(p, e, "geometry %llud %lud\n", d->sectors, u->secsize);
2227         return p - op;
2228 }
2229
2230 static void
2231 forcemode(Drive *d, char *mode)
2232 {
2233         int i;
2234
2235         for(i = 0; i < nelem(modes); i++)
2236                 if(strcmp(mode, modes[i]) == 0)
2237                         break;
2238         if(i == nelem(modes))
2239                 i = 0;
2240         ilock(d);
2241         d->mode = i;
2242         iunlock(d);
2243 }
2244
2245 static void
2246 forcestate(Drive *d, char *state)
2247 {
2248         int i;
2249
2250         for(i = 0; i < nelem(diskstates); i++)
2251                 if(strcmp(state, diskstates[i]) == 0)
2252                         break;
2253         if(i == nelem(diskstates))
2254                 error(Ebadctl);
2255         ilock(d);
2256         d->state = i;
2257 //      statechange(d);
2258         iunlock(d);
2259 }
2260
2261 static int
2262 runsettxmode(Drive *d, char *s)
2263 {
2264         int i;
2265         Aportc *c;
2266         Aportm *m;
2267
2268         c = &d->portc;
2269         m = &d->portm;
2270
2271         i = 1;
2272         if(lockready(d) == 0){
2273                 m->udma = atoi(s);
2274                 if(settxmode(c, m->udma) == 0)
2275                         i = 0;
2276         }
2277         qunlock(m);
2278         return i;
2279 }
2280
2281
2282 static int
2283 iawctl(SDunit *u, Cmdbuf *cmd)
2284 {
2285         char **f;
2286         Ctlr *c;
2287         Drive *d;
2288
2289         c = u->dev->ctlr;
2290         d = c->drive[u->subno];
2291         f = cmd->f;
2292
2293         if(strcmp(f[0], "mode") == 0)
2294                 forcemode(d, f[1]? f[1]: "satai");
2295         else if(strcmp(f[0], "state") == 0)
2296                 forcestate(d, f[1]? f[1]: "null");
2297         else if(strcmp(f[0], "txmode") == 0){
2298                 if(runsettxmode(d, f[1]? f[1]: "0"))
2299                         cmderror(cmd, "bad txmode / stuck port");
2300         }else
2301                 cmderror(cmd, Ebadctl);
2302         return 0;
2303 }
2304
2305 static char *
2306 portr(char *p, char *e, uint x)
2307 {
2308         int i, a;
2309
2310         p[0] = 0;
2311         a = -1;
2312         for(i = 0; i < 32; i++){
2313                 if((x & (1<<i)) == 0){
2314                         if(a != -1 && i - 1 != a)
2315                                 p = seprint(p, e, "-%d", i - 1);
2316                         a = -1;
2317                         continue;
2318                 }
2319                 if(a == -1){
2320                         if(i > 0)
2321                                 p = seprint(p, e, ", ");
2322                         p = seprint(p, e, "%d", a = i);
2323                 }
2324         }
2325         if(a != -1 && i - 1 != a)
2326                 p = seprint(p, e, "-%d", i - 1);
2327         return p;
2328 }
2329
2330 static Htab htab[] = {
2331         H64a,   "64a",
2332         Hncq,   "ncq",
2333         Hsntf,  "ntf",
2334         Hmps,   "mps",
2335         Hss,    "ss",
2336         Halp,   "alp",
2337         Hal,    "led",
2338         Hclo,   "clo",
2339         Ham,    "am",
2340         Hpm,    "pm",
2341         Hfbs,   "fbs",
2342         Hpmb,   "pmb",
2343         Hssc,   "slum",
2344         Hpsc,   "pslum",
2345         Hcccs,  "coal",
2346         Hems,   "ems",
2347         Hxs,    "xs",
2348 };
2349
2350 static Htab htab2[] = {
2351         Apts,   "apts",
2352         Nvmp,   "nvmp",
2353         Boh,    "boh",
2354 };
2355
2356 static Htab emtab[] = {
2357         Pm,     "pm",
2358         Alhd,   "alhd",
2359         Xonly,  "xonly",
2360         Smb,    "smb",
2361         Esgpio, "esgpio",
2362         Eses2,  "eses2",
2363         Esafte, "esafte",
2364         Elmt,   "elmt",
2365 };
2366
2367 static char*
2368 iartopctl(SDev *s, char *p, char *e)
2369 {
2370         char pr[25];
2371         ulong cap;
2372         Ahba *h;
2373         Ctlr *c;
2374
2375         c = s->ctlr;
2376         h = c->hba;
2377         cap = h->cap;
2378         p = seprint(p, e, "sd%c ahci %s port %#p: ", s->idno, Tname(c), h);
2379         p = capfmt(p, e, htab, nelem(htab), cap);
2380         p = capfmt(p, e, htab2, nelem(htab2), h->cap2);
2381         p = capfmt(p, e, emtab, nelem(emtab), h->emctl);
2382         portr(pr, pr + sizeof pr, h->pi);
2383         return seprint(p, e,
2384                 "iss %ld ncs %ld np %ld ghc %lux isr %lux pi %lux %s ver %lux\n",
2385                 (cap>>20) & 0xf, (cap>>8) & 0x1f, 1 + (cap & 0x1f),
2386                 h->ghc, h->isr, h->pi, pr, h->ver);
2387 }
2388
2389 static int
2390 iawtopctl(SDev *, Cmdbuf *cmd)
2391 {
2392         int *v;
2393         char **f;
2394
2395         f = cmd->f;
2396         v = 0;
2397
2398         if(strcmp(f[0], "debug") == 0)
2399                 v = &debug;
2400         else if(strcmp(f[0], "idprint") == 0)
2401                 v = &prid;
2402         else if(strcmp(f[0], "aprint") == 0)
2403                 v = &datapi;
2404         else if(strcmp(f[0], "ledprint") == 0)
2405                 v = &dled;
2406         else
2407                 cmderror(cmd, Ebadctl);
2408
2409         switch(cmd->nf){
2410         default:
2411                 cmderror(cmd, Ebadarg);
2412         case 1:
2413                 *v ^= 1;
2414                 break;
2415         case 2:
2416                 if(f[1])
2417                         *v = strcmp(f[1], "on") == 0;
2418                 else
2419                         *v ^= 1;
2420                 break;
2421         }
2422         return 0;
2423 }
2424
2425 SDifc sdiahciifc = {
2426         "ahci",
2427
2428         iapnp,
2429         nil,            /* legacy */
2430         iaenable,
2431         iadisable,
2432
2433         iaverify,
2434         iaonline,
2435         iario,
2436         iarctl,
2437         iawctl,
2438
2439         ahcibio,
2440         nil,            /* probe */
2441         nil,            /* clear */
2442         iartopctl,
2443         iawtopctl,
2444         iaataio,
2445 };