1 /*
2 * ahci serial ata driver
3 * copyright © 2007-8 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 "ahci.h"
15
16 #define dprint(...) if(debug) iprint(__VA_ARGS__); else USED(debug)
17 #define idprint(...) if(prid) iprint(__VA_ARGS__); else USED(prid)
18 #define aprint(...) if(datapi) iprint(__VA_ARGS__); else USED(datapi)
19
20 #define Tname(c) tname[(c)->type]
21 #define Intel(x) ((x)->pci->vid == Vintel)
22
23 enum {
24 NCtlr = 16,
25 NCtlrdrv= 32,
26 NDrive = NCtlr*NCtlrdrv,
27
28 Read = 0,
29 Write,
30
31 Nms = 256, /* ms. between drive checks */
32 Mphywait= 2*1024/Nms - 1,
33 Midwait = 16*1024/Nms - 1,
34 Mcomrwait= 64*1024/Nms - 1,
35
36 Obs = 0xa0, /* obsolete device bits */
37
38 /*
39 * if we get more than this many interrupts per tick for a drive,
40 * either the hardware is broken or we've got a bug in this driver.
41 */
42 Maxintrspertick = 2000, /* was 1000 */
43 };
44
45 /* pci space configuration */
46 enum {
47 Pmap = 0x90,
48 Ppcs = 0x91,
49 Prev = 0xa8,
50 };
51
52 enum {
53 Tesb,
54 Tich,
55 Tsb600,
56 Tunk,
57 };
58
59 static char *tname[] = {
60 "63xxesb",
61 "ich",
62 "sb600",
63 "unknown",
64 };
65
66 enum {
67 Dnull,
68 Dmissing,
69 Dnew,
70 Dready,
71 Derror,
72 Dreset,
73 Doffline,
74 Dportreset,
75 Dlast,
76 };
77
78 static char *diskstates[Dlast] = {
79 "null",
80 "missing",
81 "new",
82 "ready",
83 "error",
84 "reset",
85 "offline",
86 "portreset",
87 };
88
89 enum {
90 DMautoneg,
91 DMsatai,
92 DMsataii,
93 DMsata3,
94 };
95
96 static char *modename[] = { /* used in control messages */
97 "auto",
98 "satai",
99 "sataii",
100 "sata3",
101 };
102 static char *descmode[] = { /* only printed */
103 "auto",
104 "sata 1",
105 "sata 2",
106 "sata 3",
107 };
108
109 static char *flagname[] = {
110 "llba",
111 "smart",
112 "power",
113 "nop",
114 "atapi",
115 "atapi16",
116 };
117
118 typedef struct Asleep Asleep;
119 typedef struct Ctlr Ctlr;
120 typedef struct Drive Drive;
121
122 struct Drive {
123 Lock;
124
125 Ctlr *ctlr;
126 SDunit *unit;
127 char name[10];
128 Aport *port;
129 Aportm portm;
130 Aportc portc; /* redundant ptr to port and portm */
131
132 uchar mediachange;
133 uchar state;
134 uchar smartrs;
135
136 uvlong sectors;
137 ulong secsize;
138 ulong intick; /* start tick of current transfer */
139 ulong lastseen;
140 int wait;
141 uchar mode; /* DMautoneg, satai or sataii */
142 uchar active;
143
144 char serial[20+1];
145 char firmware[8+1];
146 char model[40+1];
147
148 int infosz;
149 ushort *info;
150 ushort tinyinfo[2]; /* used iff malloc fails */
151
152 int driveno; /* ctlr*NCtlrdrv + unit */
153 /* controller port # != driveno when not all ports are enabled */
154 int portno;
155
156 ulong lastintr0;
157 ulong intrs;
158 };
159
160 struct Ctlr {
161 Lock;
162
163 int type;
164 int enabled;
165 SDev *sdev;
166 Pcidev *pci;
167
168 /* virtual register addresses */
169 uchar *mmio;
170 ulong *lmmio;
171 Ahba *hba;
172
173 /* phyical register address */
174 uchar *physio;
175
176 Drive *rawdrive;
177 Drive *drive[NCtlrdrv];
178 int ndrive;
179 int mport; /* highest drive # (0-origin) on ich9 at least */
180
181 ulong lastintr0;
182 ulong intrs; /* not attributable to any drive */
183 };
184
185 struct Asleep {
186 Aport *p;
187 int i;
188 };
189
190 extern SDifc sdiahciifc;
191
192 static Ctlr iactlr[NCtlr];
193 static SDev sdevs[NCtlr];
194 static int niactlr;
195
196 static Drive *iadrive[NDrive];
197 static int niadrive;
198
199 /* these are fiddled in iawtopctl() */
200 static int debug;
201 static int prid = 1;
202 static int datapi;
203
204 static char stab[] = {
205 [0] 'i', 'm',
206 [8] 't', 'c', 'p', 'e',
207 [16] 'N', 'I', 'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X'
208 };
209
210 static void
serrstr(ulong r,char * s,char * e)211 serrstr(ulong r, char *s, char *e)
212 {
213 int i;
214
215 e -= 3;
216 for(i = 0; i < nelem(stab) && s < e; i++)
217 if(r & (1<<i) && stab[i]){
218 *s++ = stab[i];
219 if(SerrBad & (1<<i))
220 *s++ = '*';
221 }
222 *s = 0;
223 }
224
225 static char ntab[] = "0123456789abcdef";
226
227 static void
preg(uchar * reg,int n)228 preg(uchar *reg, int n)
229 {
230 int i;
231 char buf[25*3+1], *e;
232
233 e = buf;
234 for(i = 0; i < n; i++){
235 *e++ = ntab[reg[i]>>4];
236 *e++ = ntab[reg[i]&0xf];
237 *e++ = ' ';
238 }
239 *e++ = '\n';
240 *e = 0;
241 dprint(buf);
242 }
243
244 static void
dreg(char * s,Aport * p)245 dreg(char *s, Aport *p)
246 {
247 dprint("ahci: %stask=%#lux; cmd=%#lux; ci=%#lux; is=%#lux\n",
248 s, p->task, p->cmd, p->ci, p->isr);
249 }
250
251 static void
esleep(int ms)252 esleep(int ms)
253 {
254 if(waserror())
255 return;
256 tsleep(&up->sleep, return0, 0, ms);
257 poperror();
258 }
259
260 static int
ahciclear(void * v)261 ahciclear(void *v)
262 {
263 Asleep *s;
264
265 s = v;
266 return (s->p->ci & s->i) == 0;
267 }
268
269 static void
aesleep(Aportm * pm,Asleep * a,int ms)270 aesleep(Aportm *pm, Asleep *a, int ms)
271 {
272 if(waserror())
273 return;
274 tsleep(pm, ahciclear, a, ms);
275 poperror();
276 }
277
278 static int
ahciwait(Aportc * c,int ms)279 ahciwait(Aportc *c, int ms)
280 {
281 Asleep as;
282 Aport *p;
283
284 p = c->p;
285 p->ci = 1;
286 as.p = p;
287 as.i = 1;
288 aesleep(c->pm, &as, ms);
289 if((p->task&1) == 0 && p->ci == 0)
290 return 0;
291 dreg("ahciwait timeout ", c->p);
292 return -1;
293 }
294
295 /* fill in cfis boilerplate */
296 static uchar *
cfissetup(Aportc * pc)297 cfissetup(Aportc *pc)
298 {
299 uchar *cfis;
300
301 cfis = pc->pm->ctab->cfis;
302 memset(cfis, 0, 0x20);
303 cfis[0] = 0x27;
304 cfis[1] = 0x80;
305 cfis[7] = Obs;
306 return cfis;
307 }
308
309 /* initialise pc's list */
310 static void
listsetup(Aportc * pc,int flags)311 listsetup(Aportc *pc, int flags)
312 {
313 Alist *list;
314
315 list = pc->pm->list;
316 list->flags = flags | 5;
317 list->len = 0;
318 list->ctab = PCIWADDR(pc->pm->ctab);
319 list->ctabhi = 0;
320 }
321
322 static int
nop(Aportc * pc)323 nop(Aportc *pc)
324 {
325 uchar *c;
326
327 if((pc->pm->feat & Dnop) == 0)
328 return -1;
329 c = cfissetup(pc);
330 c[2] = 0;
331 listsetup(pc, Lwrite);
332 return ahciwait(pc, 3*1000);
333 }
334
335 static int
setfeatures(Aportc * pc,uchar f)336 setfeatures(Aportc *pc, uchar f)
337 {
338 uchar *c;
339
340 c = cfissetup(pc);
341 c[2] = 0xef;
342 c[3] = f;
343 listsetup(pc, Lwrite);
344 return ahciwait(pc, 3*1000);
345 }
346
347 static int
setudmamode(Aportc * pc,uchar f)348 setudmamode(Aportc *pc, uchar f)
349 {
350 uchar *c;
351
352 /* hack */
353 if((pc->p->sig >> 16) == 0xeb14)
354 return 0;
355 c = cfissetup(pc);
356 c[2] = 0xef;
357 c[3] = 3; /* set transfer mode */
358 c[12] = 0x40 | f; /* sector count */
359 listsetup(pc, Lwrite);
360 return ahciwait(pc, 3*1000);
361 }
362
363 static void
asleep(int ms)364 asleep(int ms)
365 {
366 if(up == nil)
367 delay(ms);
368 else
369 esleep(ms);
370 }
371
372 static int
ahciportreset(Aportc * c)373 ahciportreset(Aportc *c)
374 {
375 ulong *cmd, i;
376 Aport *p;
377
378 p = c->p;
379 cmd = &p->cmd;
380 *cmd &= ~(Afre|Ast);
381 for(i = 0; i < 500; i += 25){
382 if((*cmd&Acr) == 0)
383 break;
384 asleep(25);
385 }
386 p->sctl = 1|(p->sctl&~7);
387 delay(1);
388 p->sctl &= ~7;
389 return 0;
390 }
391
392 static int
smart(Aportc * pc,int n)393 smart(Aportc *pc, int n)
394 {
395 uchar *c;
396
397 if((pc->pm->feat&Dsmart) == 0)
398 return -1;
399 c = cfissetup(pc);
400 c[2] = 0xb0;
401 c[3] = 0xd8 + n; /* able smart */
402 c[5] = 0x4f;
403 c[6] = 0xc2;
404 listsetup(pc, Lwrite);
405 if(ahciwait(pc, 1000) == -1 || pc->p->task & (1|32)){
406 dprint("ahci: smart fail %#lux\n", pc->p->task);
407 // preg(pc->m->fis.r, 20);
408 return -1;
409 }
410 if(n)
411 return 0;
412 return 1;
413 }
414
415 static int
smartrs(Aportc * pc)416 smartrs(Aportc *pc)
417 {
418 uchar *c;
419
420 c = cfissetup(pc);
421 c[2] = 0xb0;
422 c[3] = 0xda; /* return smart status */
423 c[5] = 0x4f;
424 c[6] = 0xc2;
425 listsetup(pc, Lwrite);
426
427 c = pc->pm->fis.r;
428 if(ahciwait(pc, 1000) == -1 || pc->p->task & (1|32)){
429 dprint("ahci: smart fail %#lux\n", pc->p->task);
430 preg(c, 20);
431 return -1;
432 }
433 if(c[5] == 0x4f && c[6] == 0xc2)
434 return 1;
435 return 0;
436 }
437
438 static int
ahciflushcache(Aportc * pc)439 ahciflushcache(Aportc *pc)
440 {
441 uchar *c;
442
443 c = cfissetup(pc);
444 c[2] = pc->pm->feat & Dllba? 0xea: 0xe7;
445 listsetup(pc, Lwrite);
446 if(ahciwait(pc, 60000) == -1 || pc->p->task & (1|32)){
447 dprint("ahciflushcache: fail %#lux\n", pc->p->task);
448 // preg(pc->m->fis.r, 20);
449 return -1;
450 }
451 return 0;
452 }
453
454 static ushort
gbit16(void * a)455 gbit16(void *a)
456 {
457 uchar *i;
458
459 i = a;
460 return i[1]<<8 | i[0];
461 }
462
463 static ulong
gbit32(void * a)464 gbit32(void *a)
465 {
466 ulong j;
467 uchar *i;
468
469 i = a;
470 j = i[3] << 24;
471 j |= i[2] << 16;
472 j |= i[1] << 8;
473 j |= i[0];
474 return j;
475 }
476
477 static uvlong
gbit64(void * a)478 gbit64(void *a)
479 {
480 uchar *i;
481
482 i = a;
483 return (uvlong)gbit32(i+4) << 32 | gbit32(a);
484 }
485
486 static int
ahciidentify0(Aportc * pc,void * id,int atapi)487 ahciidentify0(Aportc *pc, void *id, int atapi)
488 {
489 uchar *c;
490 Aprdt *p;
491 static uchar tab[] = { 0xec, 0xa1, };
492
493 c = cfissetup(pc);
494 c[2] = tab[atapi];
495 listsetup(pc, 1<<16);
496
497 memset(id, 0, 0x100); /* magic */
498 p = &pc->pm->ctab->prdt;
499 p->dba = PCIWADDR(id);
500 p->dbahi = 0;
501 p->count = 1<<31 | (0x200-2) | 1;
502 return ahciwait(pc, 3*1000);
503 }
504
505 static vlong
ahciidentify(Aportc * pc,ushort * id)506 ahciidentify(Aportc *pc, ushort *id)
507 {
508 int i, sig;
509 vlong s;
510 Aportm *pm;
511
512 pm = pc->pm;
513 pm->feat = 0;
514 pm->smart = 0;
515 i = 0;
516 sig = pc->p->sig >> 16;
517 if(sig == 0xeb14){
518 pm->feat |= Datapi;
519 i = 1;
520 }
521 if(ahciidentify0(pc, id, i) == -1)
522 return -1;
523
524 i = gbit16(id+83) | gbit16(id+86);
525 if(i & (1<<10)){
526 pm->feat |= Dllba;
527 s = gbit64(id+100);
528 }else
529 s = gbit32(id+60);
530
531 if(pm->feat&Datapi){
532 i = gbit16(id+0);
533 if(i&1)
534 pm->feat |= Datapi16;
535 }
536
537 i = gbit16(id+83);
538 if((i>>14) == 1) {
539 if(i & (1<<3))
540 pm->feat |= Dpower;
541 i = gbit16(id+82);
542 if(i & 1)
543 pm->feat |= Dsmart;
544 if(i & (1<<14))
545 pm->feat |= Dnop;
546 }
547 return s;
548 }
549
550 static int
ahciquiet(Aport * a)551 ahciquiet(Aport *a)
552 {
553 ulong *p, i;
554
555 p = &a->cmd;
556 *p &= ~Ast;
557 for(i = 0; i < 500; i += 50){
558 if((*p & Acr) == 0)
559 goto stop;
560 asleep(50);
561 }
562 return -1;
563 stop:
564 if((a->task & (ASdrq|ASbsy)) == 0){
565 *p |= Ast;
566 return 0;
567 }
568
569 *p |= Aclo;
570 for(i = 0; i < 500; i += 50){
571 if((*p & Aclo) == 0)
572 goto stop1;
573 asleep(50);
574 }
575 return -1;
576 stop1:
577 /* extra check */
578 dprint("ahci: clo clear %#lx\n", a->task);
579 if(a->task & ASbsy)
580 return -1;
581 *p |= Ast;
582 return 0;
583 }
584
585 static int
ahcicomreset(Aportc * pc)586 ahcicomreset(Aportc *pc)
587 {
588 uchar *c;
589
590 dprint("ahcicomreset\n");
591 dreg("ahci: comreset ", pc->p);
592 if(ahciquiet(pc->p) == -1){
593 dprint("ahciquiet failed\n");
594 return -1;
595 }
596 dreg("comreset ", pc->p);
597
598 c = cfissetup(pc);
599 c[1] = 0;
600 c[15] = 1<<2; /* srst */
601 listsetup(pc, Lclear | Lreset);
602 if(ahciwait(pc, 500) == -1){
603 dprint("ahcicomreset: first command failed\n");
604 return -1;
605 }
606 microdelay(250);
607 dreg("comreset ", pc->p);
608
609 c = cfissetup(pc);
610 c[1] = 0;
611 listsetup(pc, Lwrite);
612 if(ahciwait(pc, 150) == -1){
613 dprint("ahcicomreset: second command failed\n");
614 return -1;
615 }
616 dreg("comreset ", pc->p);
617 return 0;
618 }
619
620 static int
ahciidle(Aport * port)621 ahciidle(Aport *port)
622 {
623 ulong *p, i, r;
624
625 p = &port->cmd;
626 if((*p & Arun) == 0)
627 return 0;
628 *p &= ~Ast;
629 r = 0;
630 for(i = 0; i < 500; i += 25){
631 if((*p & Acr) == 0)
632 goto stop;
633 asleep(25);
634 }
635 r = -1;
636 stop:
637 if((*p & Afre) == 0)
638 return r;
639 *p &= ~Afre;
640 for(i = 0; i < 500; i += 25){
641 if((*p & Afre) == 0)
642 return 0;
643 asleep(25);
644 }
645 return -1;
646 }
647
648 /*
649 * § 6.2.2.1 first part; comreset handled by reset disk.
650 * - remainder is handled by configdisk.
651 * - ahcirecover is a quick recovery from a failed command.
652 */
653 static int
ahciswreset(Aportc * pc)654 ahciswreset(Aportc *pc)
655 {
656 int i;
657
658 i = ahciidle(pc->p);
659 pc->p->cmd |= Afre;
660 if(i == -1)
661 return -1;
662 if(pc->p->task & (ASdrq|ASbsy))
663 return -1;
664 return 0;
665 }
666
667 static int
ahcirecover(Aportc * pc)668 ahcirecover(Aportc *pc)
669 {
670 ahciswreset(pc);
671 pc->p->cmd |= Ast;
672 if(setudmamode(pc, 5) == -1)
673 return -1;
674 return 0;
675 }
676
677 static void*
malign(int size,int align)678 malign(int size, int align)
679 {
680 void *v;
681
682 v = xspanalloc(size, align, 0);
683 memset(v, 0, size);
684 return v;
685 }
686
687 static void
setupfis(Afis * f)688 setupfis(Afis *f)
689 {
690 f->base = malign(0x100, 0x100); /* magic */
691 f->d = f->base + 0;
692 f->p = f->base + 0x20;
693 f->r = f->base + 0x40;
694 f->u = f->base + 0x60;
695 f->devicebits = (ulong*)(f->base + 0x58);
696 }
697
698 static void
ahciwakeup(Aport * p)699 ahciwakeup(Aport *p)
700 {
701 ushort s;
702
703 s = p->sstatus;
704 if((s & Intpm) != Intslumber && (s & Intpm) != Intpartpwr)
705 return;
706 if((s & Devdet) != Devpresent){ /* not (device, no phy) */
707 iprint("ahci: slumbering drive unwakable %#ux\n", s);
708 return;
709 }
710 p->sctl = 3*Aipm | 0*Aspd | Adet;
711 delay(1);
712 p->sctl &= ~7;
713 // iprint("ahci: wake %#ux -> %#ux\n", s, p->sstatus);
714 }
715
716 static int
ahciconfigdrive(Drive * d)717 ahciconfigdrive(Drive *d)
718 {
719 char *name;
720 Ahba *h;
721 Aport *p;
722 Aportm *pm;
723
724 h = d->ctlr->hba;
725 p = d->portc.p;
726 pm = d->portc.pm;
727 if(pm->list == 0){
728 setupfis(&pm->fis);
729 pm->list = malign(sizeof *pm->list, 1024);
730 pm->ctab = malign(sizeof *pm->ctab, 128);
731 }
732
733 if (d->unit)
734 name = d->unit->name;
735 else
736 name = nil;
737 if(p->sstatus & (Devphycomm|Devpresent) && h->cap & Hsss){
738 /* device connected & staggered spin-up */
739 dprint("ahci: configdrive: %s: spinning up ... [%#lux]\n",
740 name, p->sstatus);
741 p->cmd |= Apod|Asud;
742 asleep(1400);
743 }
744
745 p->serror = SerrAll;
746
747 p->list = PCIWADDR(pm->list);
748 p->listhi = 0;
749 p->fis = PCIWADDR(pm->fis.base);
750 p->fishi = 0;
751 p->cmd |= Afre|Ast;
752
753 /* drive coming up in slumbering? */
754 if((p->sstatus & Devdet) == Devpresent &&
755 ((p->sstatus & Intpm) == Intslumber ||
756 (p->sstatus & Intpm) == Intpartpwr))
757 ahciwakeup(p);
758
759 /* "disable power managment" sequence from book. */
760 p->sctl = (3*Aipm) | (d->mode*Aspd) | (0*Adet);
761 p->cmd &= ~Aalpe;
762
763 p->ie = IEM;
764
765 return 0;
766 }
767
768 static void
ahcienable(Ahba * h)769 ahcienable(Ahba *h)
770 {
771 h->ghc |= Hie;
772 }
773
774 static void
ahcidisable(Ahba * h)775 ahcidisable(Ahba *h)
776 {
777 h->ghc &= ~Hie;
778 }
779
780 static int
countbits(ulong u)781 countbits(ulong u)
782 {
783 int n;
784
785 n = 0;
786 for (; u != 0; u >>= 1)
787 if(u & 1)
788 n++;
789 return n;
790 }
791
792 static int
ahciconf(Ctlr * ctlr)793 ahciconf(Ctlr *ctlr)
794 {
795 Ahba *h;
796 ulong u;
797
798 h = ctlr->hba = (Ahba*)ctlr->mmio;
799 u = h->cap;
800
801 if((u&Hsam) == 0)
802 h->ghc |= Hae;
803
804 dprint("#S/sd%c: type %s port %#p: sss %ld ncs %ld coal %ld "
805 "%ld ports, led %ld clo %ld ems %ld\n",
806 ctlr->sdev->idno, tname[ctlr->type], h,
807 (u>>27) & 1, (u>>8) & 0x1f, (u>>7) & 1,
808 (u & 0x1f) + 1, (u>>25) & 1, (u>>24) & 1, (u>>6) & 1);
809 return countbits(h->pi);
810 }
811
812 static int
ahcihbareset(Ahba * h)813 ahcihbareset(Ahba *h)
814 {
815 int wait;
816
817 h->ghc |= 1;
818 for(wait = 0; wait < 1000; wait += 100){
819 if(h->ghc == 0)
820 return 0;
821 delay(100);
822 }
823 return -1;
824 }
825
826 static void
idmove(char * p,ushort * a,int n)827 idmove(char *p, ushort *a, int n)
828 {
829 int i;
830 char *op, *e;
831
832 op = p;
833 for(i = 0; i < n/2; i++){
834 *p++ = a[i] >> 8;
835 *p++ = a[i];
836 }
837 *p = 0;
838 while(p > op && *--p == ' ')
839 *p = 0;
840 e = p;
841 for (p = op; *p == ' '; p++)
842 ;
843 memmove(op, p, n - (e - p));
844 }
845
846 static int
identify(Drive * d)847 identify(Drive *d)
848 {
849 ushort *id;
850 vlong osectors, s;
851 uchar oserial[21];
852 SDunit *u;
853
854 if(d->info == nil) {
855 d->infosz = 512 * sizeof(ushort);
856 d->info = malloc(d->infosz);
857 }
858 if(d->info == nil) {
859 d->info = d->tinyinfo;
860 d->infosz = sizeof d->tinyinfo;
861 }
862 id = d->info;
863 s = ahciidentify(&d->portc, id);
864 if(s == -1){
865 d->state = Derror;
866 return -1;
867 }
868 osectors = d->sectors;
869 memmove(oserial, d->serial, sizeof d->serial);
870
871 u = d->unit;
872 d->sectors = s;
873 d->secsize = u->secsize;
874 if(d->secsize == 0)
875 d->secsize = 512; /* default */
876 d->smartrs = 0;
877
878 idmove(d->serial, id+10, 20);
879 idmove(d->firmware, id+23, 8);
880 idmove(d->model, id+27, 40);
881
882 memset(u->inquiry, 0, sizeof u->inquiry);
883 u->inquiry[2] = 2;
884 u->inquiry[3] = 2;
885 u->inquiry[4] = sizeof u->inquiry - 4;
886 memmove(u->inquiry+8, d->model, 40);
887
888 if(osectors != s || memcmp(oserial, d->serial, sizeof oserial) != 0){
889 d->mediachange = 1;
890 u->sectors = 0;
891 }
892 return 0;
893 }
894
895 static void
clearci(Aport * p)896 clearci(Aport *p)
897 {
898 if(p->cmd & Ast) {
899 p->cmd &= ~Ast;
900 p->cmd |= Ast;
901 }
902 }
903
904 static void
updatedrive(Drive * d)905 updatedrive(Drive *d)
906 {
907 ulong cause, serr, s0, pr, ewake;
908 char *name;
909 Aport *p;
910 static ulong last;
911
912 pr = 1;
913 ewake = 0;
914 p = d->port;
915 cause = p->isr;
916 serr = p->serror;
917 p->isr = cause;
918 name = "??";
919 if(d->unit && d->unit->name)
920 name = d->unit->name;
921
922 if(p->ci == 0){
923 d->portm.flag |= Fdone;
924 wakeup(&d->portm);
925 pr = 0;
926 }else if(cause & Adps)
927 pr = 0;
928 if(cause & Ifatal){
929 ewake = 1;
930 dprint("ahci: updatedrive: %s: fatal\n", name);
931 }
932 if(cause & Adhrs){
933 if(p->task & (1<<5|1)){
934 dprint("ahci: %s: Adhrs cause %#lux serr %#lux task %#lux\n",
935 name, cause, serr, p->task);
936 d->portm.flag |= Ferror;
937 ewake = 1;
938 }
939 pr = 0;
940 }
941 if(p->task & 1 && last != cause)
942 dprint("%s: err ca %#lux serr %#lux task %#lux sstat %#lux\n",
943 name, cause, serr, p->task, p->sstatus);
944 if(pr)
945 dprint("%s: upd %#lux ta %#lux\n", name, cause, p->task);
946
947 if(cause & (Aprcs|Aifs)){
948 s0 = d->state;
949 switch(p->sstatus & Devdet){
950 case 0: /* no device */
951 d->state = Dmissing;
952 break;
953 case Devpresent: /* device but no phy comm. */
954 if((p->sstatus & Intpm) == Intslumber ||
955 (p->sstatus & Intpm) == Intpartpwr)
956 d->state = Dnew; /* slumbering */
957 else
958 d->state = Derror;
959 break;
960 case Devpresent|Devphycomm:
961 /* power mgnt crap for surprise removal */
962 p->ie |= Aprcs|Apcs; /* is this required? */
963 d->state = Dreset;
964 break;
965 case Devphyoffline:
966 d->state = Doffline;
967 break;
968 }
969 dprint("%s: %s → %s [Apcrs] %#lux\n", name,
970 diskstates[s0], diskstates[d->state], p->sstatus);
971 /* print pulled message here. */
972 if(s0 == Dready && d->state != Dready)
973 idprint("%s: pulled\n", name); /* wtf? */
974 if(d->state != Dready)
975 d->portm.flag |= Ferror;
976 ewake = 1;
977 }
978 p->serror = serr;
979 if(ewake){
980 clearci(p);
981 wakeup(&d->portm);
982 }
983 last = cause;
984 }
985
986 static void
pstatus(Drive * d,ulong s)987 pstatus(Drive *d, ulong s)
988 {
989 /*
990 * s is masked with Devdet.
991 *
992 * bogus code because the first interrupt is currently dropped.
993 * likely my fault. serror may be cleared at the wrong time.
994 */
995 switch(s){
996 case 0: /* no device */
997 d->state = Dmissing;
998 break;
999 case Devpresent: /* device but no phy. comm. */
1000 break;
1001 case Devphycomm: /* should this be missing? need testcase. */
1002 dprint("ahci: pstatus 2\n");
1003 /* fallthrough */
1004 case Devpresent|Devphycomm:
1005 d->wait = 0;
1006 d->state = Dnew;
1007 break;
1008 case Devphyoffline:
1009 d->state = Doffline;
1010 break;
1011 case Devphyoffline|Devphycomm: /* does this make sense? */
1012 d->state = Dnew;
1013 break;
1014 }
1015 }
1016
1017 static int
configdrive(Drive * d)1018 configdrive(Drive *d)
1019 {
1020 if(ahciconfigdrive(d) == -1)
1021 return -1;
1022 ilock(d);
1023 pstatus(d, d->port->sstatus & Devdet);
1024 iunlock(d);
1025 return 0;
1026 }
1027
1028 static void
setstate(Drive * d,int state)1029 setstate(Drive *d, int state)
1030 {
1031 ilock(d);
1032 d->state = state;
1033 iunlock(d);
1034 }
1035
1036 static void
resetdisk(Drive * d)1037 resetdisk(Drive *d)
1038 {
1039 uint state, det, stat;
1040 Aport *p;
1041
1042 p = d->port;
1043 det = p->sctl & 7;
1044 stat = p->sstatus & Devdet;
1045 state = (p->cmd>>28) & 0xf;
1046 dprint("ahci: resetdisk: icc %#ux det %d sdet %d\n", state, det, stat);
1047
1048 ilock(d);
1049 state = d->state;
1050 if(d->state != Dready || d->state != Dnew)
1051 d->portm.flag |= Ferror;
1052 clearci(p); /* satisfy sleep condition. */
1053 wakeup(&d->portm);
1054 if(stat != (Devpresent|Devphycomm)){
1055 /* device absent or phy not communicating */
1056 d->state = Dportreset;
1057 iunlock(d);
1058 return;
1059 }
1060 d->state = Derror;
1061 iunlock(d);
1062
1063 qlock(&d->portm);
1064 if(p->cmd&Ast && ahciswreset(&d->portc) == -1)
1065 setstate(d, Dportreset); /* get a bigger stick. */
1066 else {
1067 setstate(d, Dmissing);
1068 configdrive(d);
1069 }
1070 dprint("ahci: %s: resetdisk: %s → %s\n", (d->unit? d->unit->name: nil),
1071 diskstates[state], diskstates[d->state]);
1072 qunlock(&d->portm);
1073 }
1074
1075 static int
newdrive(Drive * d)1076 newdrive(Drive *d)
1077 {
1078 char *name;
1079 Aportc *c;
1080 Aportm *pm;
1081
1082 c = &d->portc;
1083 pm = &d->portm;
1084
1085 name = d->unit->name;
1086 if(name == 0)
1087 name = "??";
1088
1089 if(d->port->task == 0x80)
1090 return -1;
1091 qlock(c->pm);
1092 if(setudmamode(c, 5) == -1){
1093 dprint("%s: can't set udma mode\n", name);
1094 goto lose;
1095 }
1096 if(identify(d) == -1){
1097 dprint("%s: identify failure\n", name);
1098 goto lose;
1099 }
1100 if(pm->feat & Dpower && setfeatures(c, 0x85) == -1){
1101 pm->feat &= ~Dpower;
1102 if(ahcirecover(c) == -1)
1103 goto lose;
1104 }
1105 setstate(d, Dready);
1106 qunlock(c->pm);
1107
1108 idprint("%s: %sLBA %,llud sectors: %s %s %s %s\n", d->unit->name,
1109 (pm->feat & Dllba? "L": ""), d->sectors, d->model, d->firmware,
1110 d->serial, d->mediachange? "[mediachange]": "");
1111 return 0;
1112
1113 lose:
1114 idprint("%s: can't be initialized\n", d->unit->name);
1115 setstate(d, Dnull);
1116 qunlock(c->pm);
1117 return -1;
1118 }
1119
1120 static void
westerndigitalhung(Drive * d)1121 westerndigitalhung(Drive *d)
1122 {
1123 if((d->portm.feat&Datapi) == 0 && d->active &&
1124 TK2MS(MACHP(0)->ticks - d->intick) > 5000){
1125 dprint("%s: drive hung; resetting [%#lux] ci %#lx\n",
1126 d->unit->name, d->port->task, d->port->ci);
1127 d->state = Dreset;
1128 }
1129 }
1130
1131 static ushort olds[NCtlr*NCtlrdrv];
1132
1133 static int
doportreset(Drive * d)1134 doportreset(Drive *d)
1135 {
1136 int i;
1137
1138 i = -1;
1139 qlock(&d->portm);
1140 if(ahciportreset(&d->portc) == -1)
1141 dprint("ahci: doportreset: fails\n");
1142 else
1143 i = 0;
1144 qunlock(&d->portm);
1145 dprint("ahci: doportreset: portreset → %s [task %#lux]\n",
1146 diskstates[d->state], d->port->task);
1147 return i;
1148 }
1149
1150 /* drive must be locked */
1151 static void
statechange(Drive * d)1152 statechange(Drive *d)
1153 {
1154 switch(d->state){
1155 case Dnull:
1156 case Doffline:
1157 if(d->unit->sectors != 0){
1158 d->sectors = 0;
1159 d->mediachange = 1;
1160 }
1161 /* fallthrough */
1162 case Dready:
1163 d->wait = 0;
1164 break;
1165 }
1166 }
1167
1168 static void
checkdrive(Drive * d,int i)1169 checkdrive(Drive *d, int i)
1170 {
1171 ushort s;
1172 char *name;
1173
1174 if(d == nil) {
1175 print("checkdrive: nil d\n");
1176 return;
1177 }
1178 ilock(d);
1179 if(d->unit == nil || d->port == nil) {
1180 if(0)
1181 print("checkdrive: nil d->%s\n",
1182 d->unit == nil? "unit": "port");
1183 iunlock(d);
1184 return;
1185 }
1186 name = d->unit->name;
1187 s = d->port->sstatus;
1188 if(s)
1189 d->lastseen = MACHP(0)->ticks;
1190 if(s != olds[i]){
1191 dprint("%s: status: %06#ux -> %06#ux: %s\n",
1192 name, olds[i], s, diskstates[d->state]);
1193 olds[i] = s;
1194 d->wait = 0;
1195 }
1196 westerndigitalhung(d);
1197
1198 switch(d->state){
1199 case Dnull:
1200 case Dready:
1201 break;
1202 case Dmissing:
1203 case Dnew:
1204 switch(s & (Intactive | Devdet)){
1205 case Devpresent: /* no device (pm), device but no phy. comm. */
1206 ahciwakeup(d->port);
1207 /* fall through */
1208 case 0: /* no device */
1209 break;
1210 default:
1211 dprint("%s: unknown status %06#ux\n", name, s);
1212 /* fall through */
1213 case Intactive: /* active, no device */
1214 if(++d->wait&Mphywait)
1215 break;
1216 reset:
1217 if(++d->mode > DMsataii)
1218 d->mode = 0;
1219 if(d->mode == DMsatai){ /* we tried everything */
1220 d->state = Dportreset;
1221 goto portreset;
1222 }
1223 dprint("%s: reset; new mode %s\n", name,
1224 modename[d->mode]);
1225 iunlock(d);
1226 resetdisk(d);
1227 ilock(d);
1228 break;
1229 case Intactive|Devphycomm|Devpresent:
1230 if((++d->wait&Midwait) == 0){
1231 dprint("%s: slow reset %06#ux task=%#lux; %d\n",
1232 name, s, d->port->task, d->wait);
1233 goto reset;
1234 }
1235 s = (uchar)d->port->task;
1236 if(s == 0x7f || ((d->port->sig >> 16) != 0xeb14 &&
1237 (s & ~0x17) != (1<<6)))
1238 break;
1239 iunlock(d);
1240 newdrive(d);
1241 ilock(d);
1242 break;
1243 }
1244 break;
1245 case Doffline:
1246 if(d->wait++ & Mcomrwait)
1247 break;
1248 /* fallthrough */
1249 case Derror:
1250 case Dreset:
1251 dprint("%s: reset [%s]: mode %d; status %06#ux\n",
1252 name, diskstates[d->state], d->mode, s);
1253 iunlock(d);
1254 resetdisk(d);
1255 ilock(d);
1256 break;
1257 case Dportreset:
1258 portreset:
1259 if(d->wait++ & 0xff && (s & Intactive) == 0)
1260 break;
1261 /* device is active */
1262 dprint("%s: portreset [%s]: mode %d; status %06#ux\n",
1263 name, diskstates[d->state], d->mode, s);
1264 d->portm.flag |= Ferror;
1265 clearci(d->port);
1266 wakeup(&d->portm);
1267 if((s & Devdet) == 0){ /* no device */
1268 d->state = Dmissing;
1269 break;
1270 }
1271 iunlock(d);
1272 doportreset(d);
1273 ilock(d);
1274 break;
1275 }
1276 statechange(d);
1277 iunlock(d);
1278 }
1279
1280 static void
satakproc(void *)1281 satakproc(void*)
1282 {
1283 int i;
1284
1285 for(;;){
1286 tsleep(&up->sleep, return0, 0, Nms);
1287 for(i = 0; i < niadrive; i++)
1288 if(iadrive[i] != nil)
1289 checkdrive(iadrive[i], i);
1290 }
1291 }
1292
1293 static void
isctlrjabbering(Ctlr * c,ulong cause)1294 isctlrjabbering(Ctlr *c, ulong cause)
1295 {
1296 ulong now;
1297
1298 now = TK2MS(MACHP(0)->ticks);
1299 if (now > c->lastintr0) {
1300 c->intrs = 0;
1301 c->lastintr0 = now;
1302 }
1303 if (++c->intrs > Maxintrspertick) {
1304 iprint("sdiahci: %lud intrs per tick for no serviced "
1305 "drive; cause %#lux mport %d\n",
1306 c->intrs, cause, c->mport);
1307 c->intrs = 0;
1308 }
1309 }
1310
1311 static void
isdrivejabbering(Drive * d)1312 isdrivejabbering(Drive *d)
1313 {
1314 ulong now;
1315
1316 now = TK2MS(MACHP(0)->ticks);
1317 if (now > d->lastintr0) {
1318 d->intrs = 0;
1319 d->lastintr0 = now;
1320 }
1321 if (++d->intrs > Maxintrspertick) {
1322 iprint("sdiahci: %lud interrupts per tick for %s\n",
1323 d->intrs, d->unit->name);
1324 d->intrs = 0;
1325 }
1326 }
1327
1328 static void
iainterrupt(Ureg *,void * a)1329 iainterrupt(Ureg*, void *a)
1330 {
1331 int i;
1332 ulong cause, mask;
1333 Ctlr *c;
1334 Drive *d;
1335
1336 c = a;
1337 ilock(c);
1338 cause = c->hba->isr;
1339 if (cause == 0) {
1340 isctlrjabbering(c, cause);
1341 // iprint("sdiahci: interrupt for no drive\n");
1342 iunlock(c);
1343 return;
1344 }
1345 for(i = 0; cause && i <= c->mport; i++){
1346 mask = 1 << i;
1347 if((cause & mask) == 0)
1348 continue;
1349 d = c->rawdrive + i;
1350 ilock(d);
1351 isdrivejabbering(d);
1352 if(d->port->isr && c->hba->pi & mask)
1353 updatedrive(d);
1354 c->hba->isr = mask;
1355 iunlock(d);
1356
1357 cause &= ~mask;
1358 }
1359 if (cause) {
1360 isctlrjabbering(c, cause);
1361 iprint("sdiachi: intr cause unserviced: %#lux\n", cause);
1362 }
1363 iunlock(c);
1364 }
1365
1366 /* checkdrive, called from satakproc, will prod the drive while we wait */
1367 static void
awaitspinup(Drive * d)1368 awaitspinup(Drive *d)
1369 {
1370 int ms;
1371 ushort s;
1372 char *name;
1373
1374 ilock(d);
1375 if(d->unit == nil || d->port == nil) {
1376 panic("awaitspinup: nil d->unit or d->port");
1377 iunlock(d);
1378 return;
1379 }
1380 name = (d->unit? d->unit->name: nil);
1381 s = d->port->sstatus;
1382 if(!(s & Devpresent)) { /* never going to be ready */
1383 dprint("awaitspinup: %s absent, not waiting\n", name);
1384 iunlock(d);
1385 return;
1386 }
1387
1388 for (ms = 20000; ms > 0; ms -= 50)
1389 switch(d->state){
1390 case Dnull:
1391 /* absent; done */
1392 iunlock(d);
1393 dprint("awaitspinup: %s in null state\n", name);
1394 return;
1395 case Dready:
1396 case Dnew:
1397 if(d->sectors || d->mediachange) {
1398 /* ready to use; done */
1399 iunlock(d);
1400 dprint("awaitspinup: %s ready!\n", name);
1401 return;
1402 }
1403 /* fall through */
1404 default:
1405 case Dmissing: /* normal waiting states */
1406 case Dreset:
1407 case Doffline: /* transitional states */
1408 case Derror:
1409 case Dportreset:
1410 iunlock(d);
1411 asleep(50);
1412 ilock(d);
1413 break;
1414 }
1415 print("awaitspinup: %s didn't spin up after 20 seconds\n", name);
1416 iunlock(d);
1417 }
1418
1419 static int
iaverify(SDunit * u)1420 iaverify(SDunit *u)
1421 {
1422 Ctlr *c;
1423 Drive *d;
1424
1425 c = u->dev->ctlr;
1426 d = c->drive[u->subno];
1427 ilock(c);
1428 ilock(d);
1429 d->unit = u;
1430 iunlock(d);
1431 iunlock(c);
1432 checkdrive(d, d->driveno); /* c->d0 + d->driveno */
1433
1434 /*
1435 * hang around until disks are spun up and thus available as
1436 * nvram, dos file systems, etc. you wouldn't expect it, but
1437 * the intel 330 ssd takes a while to `spin up'.
1438 */
1439 awaitspinup(d);
1440 return 1;
1441 }
1442
1443 static int
iaenable(SDev * s)1444 iaenable(SDev *s)
1445 {
1446 char name[32];
1447 Ctlr *c;
1448 static int once;
1449
1450 c = s->ctlr;
1451 ilock(c);
1452 if(!c->enabled) {
1453 if(once == 0) {
1454 once = 1;
1455 kproc("ahci", satakproc, 0);
1456 }
1457 if(c->ndrive == 0)
1458 panic("iaenable: zero s->ctlr->ndrive");
1459 pcisetbme(c->pci);
1460 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1461 intrenable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1462 /* supposed to squelch leftover interrupts here. */
1463 ahcienable(c->hba);
1464 c->enabled = 1;
1465 }
1466 iunlock(c);
1467 return 1;
1468 }
1469
1470 static int
iadisable(SDev * s)1471 iadisable(SDev *s)
1472 {
1473 char name[32];
1474 Ctlr *c;
1475
1476 c = s->ctlr;
1477 ilock(c);
1478 ahcidisable(c->hba);
1479 snprint(name, sizeof name, "%s (%s)", s->name, s->ifc->name);
1480 intrdisable(c->pci->intl, iainterrupt, c, c->pci->tbdf, name);
1481 c->enabled = 0;
1482 iunlock(c);
1483 return 1;
1484 }
1485
1486 static int
iaonline(SDunit * unit)1487 iaonline(SDunit *unit)
1488 {
1489 int r;
1490 Ctlr *c;
1491 Drive *d;
1492
1493 c = unit->dev->ctlr;
1494 d = c->drive[unit->subno];
1495 r = 0;
1496
1497 if(d->portm.feat & Datapi && d->mediachange){
1498 r = scsionline(unit);
1499 if(r > 0)
1500 d->mediachange = 0;
1501 return r;
1502 }
1503
1504 ilock(d);
1505 if(d->mediachange){
1506 r = 2;
1507 d->mediachange = 0;
1508 /* devsd resets this after online is called; why? */
1509 unit->sectors = d->sectors;
1510 unit->secsize = 512; /* default size */
1511 } else if(d->state == Dready)
1512 r = 1;
1513 iunlock(d);
1514 return r;
1515 }
1516
1517 /* returns locked list! */
1518 static Alist*
ahcibuild(Drive * d,uchar * cmd,void * data,int n,vlong lba)1519 ahcibuild(Drive *d, uchar *cmd, void *data, int n, vlong lba)
1520 {
1521 uchar *c, acmd, dir, llba;
1522 Alist *l;
1523 Actab *t;
1524 Aportm *pm;
1525 Aprdt *p;
1526 static uchar tab[2][2] = { 0xc8, 0x25, 0xca, 0x35, };
1527
1528 pm = &d->portm;
1529 dir = *cmd != 0x28;
1530 llba = pm->feat&Dllba? 1: 0;
1531 acmd = tab[dir][llba];
1532 qlock(pm);
1533 l = pm->list;
1534 t = pm->ctab;
1535 c = t->cfis;
1536
1537 c[0] = 0x27;
1538 c[1] = 0x80;
1539 c[2] = acmd;
1540 c[3] = 0;
1541
1542 c[4] = lba; /* sector lba low 7:0 */
1543 c[5] = lba >> 8; /* cylinder low lba mid 15:8 */
1544 c[6] = lba >> 16; /* cylinder hi lba hi 23:16 */
1545 c[7] = Obs | 0x40; /* 0x40 == lba */
1546 if(llba == 0)
1547 c[7] |= (lba>>24) & 7;
1548
1549 c[8] = lba >> 24; /* sector (exp) lba 31:24 */
1550 c[9] = lba >> 32; /* cylinder low (exp) lba 39:32 */
1551 c[10] = lba >> 48; /* cylinder hi (exp) lba 48:40 */
1552 c[11] = 0; /* features (exp); */
1553
1554 c[12] = n; /* sector count */
1555 c[13] = n >> 8; /* sector count (exp) */
1556 c[14] = 0; /* r */
1557 c[15] = 0; /* control */
1558
1559 *(ulong*)(c + 16) = 0;
1560
1561 l->flags = 1<<16 | Lpref | 0x5; /* Lpref ?? */
1562 if(dir == Write)
1563 l->flags |= Lwrite;
1564 l->len = 0;
1565 l->ctab = PCIWADDR(t);
1566 l->ctabhi = 0;
1567
1568 p = &t->prdt;
1569 p->dba = PCIWADDR(data);
1570 p->dbahi = 0;
1571 if(d->unit == nil)
1572 panic("ahcibuild: nil d->unit");
1573 p->count = 1<<31 | (d->unit->secsize*n - 2) | 1;
1574
1575 return l;
1576 }
1577
1578 static Alist*
ahcibuildpkt(Aportm * pm,SDreq * r,void * data,int n)1579 ahcibuildpkt(Aportm *pm, SDreq *r, void *data, int n)
1580 {
1581 int fill, len;
1582 uchar *c;
1583 Alist *l;
1584 Actab *t;
1585 Aprdt *p;
1586
1587 qlock(pm);
1588 l = pm->list;
1589 t = pm->ctab;
1590 c = t->cfis;
1591
1592 fill = pm->feat&Datapi16? 16: 12;
1593 if((len = r->clen) > fill)
1594 len = fill;
1595 memmove(t->atapi, r->cmd, len);
1596 memset(t->atapi+len, 0, fill-len);
1597
1598 c[0] = 0x27;
1599 c[1] = 0x80;
1600 c[2] = 0xa0;
1601 if(n != 0)
1602 c[3] = 1; /* dma */
1603 else
1604 c[3] = 0; /* features (exp); */
1605
1606 c[4] = 0; /* sector lba low 7:0 */
1607 c[5] = n; /* cylinder low lba mid 15:8 */
1608 c[6] = n >> 8; /* cylinder hi lba hi 23:16 */
1609 c[7] = Obs;
1610
1611 *(ulong*)(c + 8) = 0;
1612 *(ulong*)(c + 12) = 0;
1613 *(ulong*)(c + 16) = 0;
1614
1615 l->flags = 1<<16 | Lpref | Latapi | 0x5;
1616 if(r->write != 0 && data)
1617 l->flags |= Lwrite;
1618 l->len = 0;
1619 l->ctab = PCIWADDR(t);
1620 l->ctabhi = 0;
1621
1622 if(data == 0)
1623 return l;
1624
1625 p = &t->prdt;
1626 p->dba = PCIWADDR(data);
1627 p->dbahi = 0;
1628 p->count = 1<<31 | (n - 2) | 1;
1629
1630 return l;
1631 }
1632
1633 static int
waitready(Drive * d)1634 waitready(Drive *d)
1635 {
1636 ulong s, i, δ;
1637
1638 for(i = 0; i < 15000; i += 250){
1639 if(d->state == Dreset || d->state == Dportreset ||
1640 d->state == Dnew)
1641 return 1;
1642 δ = MACHP(0)->ticks - d->lastseen;
1643 if(d->state == Dnull || δ > 10*1000)
1644 return -1;
1645 ilock(d);
1646 s = d->port->sstatus;
1647 iunlock(d);
1648 if((s & Intpm) == 0 && δ > 1500)
1649 return -1; /* no detect */
1650 if(d->state == Dready &&
1651 (s & Devdet) == (Devphycomm|Devpresent))
1652 return 0; /* ready, present & phy. comm. */
1653 esleep(250);
1654 }
1655 print("%s: not responding; offline\n", d->unit->name);
1656 setstate(d, Doffline);
1657 return -1;
1658 }
1659
1660 static int
lockready(Drive * d)1661 lockready(Drive *d)
1662 {
1663 int i;
1664
1665 qlock(&d->portm);
1666 while ((i = waitready(d)) == 1) { /* could wait forever? */
1667 qunlock(&d->portm);
1668 esleep(1);
1669 qlock(&d->portm);
1670 }
1671 return i;
1672 }
1673
1674 static int
flushcache(Drive * d)1675 flushcache(Drive *d)
1676 {
1677 int i;
1678
1679 i = -1;
1680 if(lockready(d) == 0)
1681 i = ahciflushcache(&d->portc);
1682 qunlock(&d->portm);
1683 return i;
1684 }
1685
1686 static int
iariopkt(SDreq * r,Drive * d)1687 iariopkt(SDreq *r, Drive *d)
1688 {
1689 int n, count, try, max, flag, task, wormwrite;
1690 char *name;
1691 uchar *cmd, *data;
1692 Aport *p;
1693 Asleep as;
1694
1695 cmd = r->cmd;
1696 name = d->unit->name;
1697 p = d->port;
1698
1699 aprint("ahci: iariopkt: %04#ux %04#ux %c %d %p\n",
1700 cmd[0], cmd[2], "rw"[r->write], r->dlen, r->data);
1701 if(cmd[0] == 0x5a && (cmd[2] & 0x3f) == 0x3f)
1702 return sdmodesense(r, cmd, d->info, d->infosz);
1703 r->rlen = 0;
1704 count = r->dlen;
1705 max = 65536;
1706
1707 try = 0;
1708 retry:
1709 data = r->data;
1710 n = count;
1711 if(n > max)
1712 n = max;
1713 ahcibuildpkt(&d->portm, r, data, n);
1714 switch(waitready(d)){
1715 case -1:
1716 qunlock(&d->portm);
1717 return SDeio;
1718 case 1:
1719 qunlock(&d->portm);
1720 esleep(1);
1721 goto retry;
1722 }
1723 /* d->portm qlock held here */
1724
1725 ilock(d);
1726 d->portm.flag = 0;
1727 iunlock(d);
1728 p->ci = 1;
1729
1730 as.p = p;
1731 as.i = 1;
1732 d->intick = MACHP(0)->ticks;
1733 d->active++;
1734
1735 while(waserror())
1736 ;
1737 /* don't sleep here forever */
1738 tsleep(&d->portm, ahciclear, &as, 3*1000);
1739 poperror();
1740 if(!ahciclear(&as)) {
1741 qunlock(&d->portm);
1742 print("%s: ahciclear not true after 3 seconds\n", name);
1743 r->status = SDcheck;
1744 return SDcheck;
1745 }
1746
1747 d->active--;
1748 ilock(d);
1749 flag = d->portm.flag;
1750 task = d->port->task;
1751 iunlock(d);
1752
1753 if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && d->state == Dready){
1754 d->port->ci = 0;
1755 ahcirecover(&d->portc);
1756 task = d->port->task;
1757 flag &= ~Fdone; /* either an error or do-over */
1758 }
1759 qunlock(&d->portm);
1760 if(flag == 0){
1761 if(++try == 10){
1762 print("%s: bad disk\n", name);
1763 r->status = SDcheck;
1764 return SDcheck;
1765 }
1766 /*
1767 * write retries cannot succeed on write-once media,
1768 * so just accept any failure.
1769 */
1770 wormwrite = 0;
1771 switch(d->unit->inquiry[0] & SDinq0periphtype){
1772 case SDperworm:
1773 case SDpercd:
1774 switch(cmd[0]){
1775 case 0x0a: /* write (6?) */
1776 case 0x2a: /* write (10) */
1777 case 0x8a: /* long write (16) */
1778 case 0x2e: /* write and verify (10) */
1779 wormwrite = 1;
1780 break;
1781 }
1782 break;
1783 }
1784 if (!wormwrite) {
1785 print("%s: retry\n", name);
1786 goto retry;
1787 }
1788 }
1789 if(flag & Ferror){
1790 if((task&Eidnf) == 0)
1791 print("%s: i/o error task=%#ux\n", name, task);
1792 r->status = SDcheck;
1793 return SDcheck;
1794 }
1795
1796 data += n;
1797
1798 r->rlen = data - (uchar*)r->data;
1799 r->status = SDok;
1800 return SDok;
1801 }
1802
1803 static int
iario(SDreq * r)1804 iario(SDreq *r)
1805 {
1806 int i, n, count, try, max, flag, task;
1807 vlong lba;
1808 char *name;
1809 uchar *cmd, *data;
1810 Aport *p;
1811 Asleep as;
1812 Ctlr *c;
1813 Drive *d;
1814 SDunit *unit;
1815
1816 unit = r->unit;
1817 c = unit->dev->ctlr;
1818 d = c->drive[unit->subno];
1819 if(d->portm.feat & Datapi)
1820 return iariopkt(r, d);
1821 cmd = r->cmd;
1822 name = d->unit->name;
1823 p = d->port;
1824
1825 if(r->cmd[0] == 0x35 || r->cmd[0] == 0x91){
1826 if(flushcache(d) == 0)
1827 return sdsetsense(r, SDok, 0, 0, 0);
1828 return sdsetsense(r, SDcheck, 3, 0xc, 2);
1829 }
1830
1831 if((i = sdfakescsi(r, d->info, d->infosz)) != SDnostatus){
1832 r->status = i;
1833 return i;
1834 }
1835
1836 if(*cmd != 0x28 && *cmd != 0x2a){
1837 print("%s: bad cmd %.2#ux\n", name, cmd[0]);
1838 r->status = SDcheck;
1839 return SDcheck;
1840 }
1841
1842 lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
1843 count = cmd[7]<<8 | cmd[8];
1844 if(r->data == nil)
1845 return SDok;
1846 if(r->dlen < count * unit->secsize)
1847 count = r->dlen / unit->secsize;
1848 max = 128;
1849
1850 try = 0;
1851 retry:
1852 data = r->data;
1853 while(count > 0){
1854 n = count;
1855 if(n > max)
1856 n = max;
1857 ahcibuild(d, cmd, data, n, lba);
1858 switch(waitready(d)){
1859 case -1:
1860 qunlock(&d->portm);
1861 return SDeio;
1862 case 1:
1863 qunlock(&d->portm);
1864 esleep(1);
1865 goto retry;
1866 }
1867 /* d->portm qlock held here */
1868 ilock(d);
1869 d->portm.flag = 0;
1870 iunlock(d);
1871 p->ci = 1;
1872
1873 as.p = p;
1874 as.i = 1;
1875 d->intick = MACHP(0)->ticks;
1876 d->active++;
1877
1878 while(waserror())
1879 ;
1880 /* don't sleep here forever */
1881 tsleep(&d->portm, ahciclear, &as, 3*1000);
1882 poperror();
1883 if(!ahciclear(&as)) {
1884 qunlock(&d->portm);
1885 print("%s: ahciclear not true after 3 seconds\n", name);
1886 r->status = SDcheck;
1887 return SDcheck;
1888 }
1889
1890 d->active--;
1891 ilock(d);
1892 flag = d->portm.flag;
1893 task = d->port->task;
1894 iunlock(d);
1895
1896 if(task & (Efatal<<8) ||
1897 task & (ASbsy|ASdrq) && d->state == Dready){
1898 d->port->ci = 0;
1899 ahcirecover(&d->portc);
1900 task = d->port->task;
1901 }
1902 qunlock(&d->portm);
1903 if(flag == 0){
1904 if(++try == 10){
1905 print("%s: bad disk\n", name);
1906 r->status = SDeio;
1907 return SDeio;
1908 }
1909 print("%s: retry blk %lld\n", name, lba);
1910 goto retry;
1911 }
1912 if(flag & Ferror){
1913 print("%s: i/o error task=%#ux @%,lld\n",
1914 name, task, lba);
1915 r->status = SDeio;
1916 return SDeio;
1917 }
1918
1919 count -= n;
1920 lba += n;
1921 data += n * unit->secsize;
1922 }
1923 r->rlen = data - (uchar*)r->data;
1924 r->status = SDok;
1925 return SDok;
1926 }
1927
1928 /*
1929 * configure drives 0-5 as ahci sata (c.f. errata).
1930 * what about 6 & 7, as claimed by marvell 0x9123?
1931 */
1932 static int
iaahcimode(Pcidev * p)1933 iaahcimode(Pcidev *p)
1934 {
1935 dprint("iaahcimode: %#ux %#ux %#ux\n", pcicfgr8(p, 0x91), pcicfgr8(p, 92),
1936 pcicfgr8(p, 93));
1937 pcicfgw16(p, 0x92, pcicfgr16(p, 0x92) | 0x3f); /* ports 0-5 */
1938 return 0;
1939 }
1940
1941 static void
iasetupahci(Ctlr * c)1942 iasetupahci(Ctlr *c)
1943 {
1944 /* disable cmd block decoding. */
1945 pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~(1<<15));
1946 pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~(1<<15));
1947
1948 c->lmmio[0x4/4] |= 1 << 31; /* enable ahci mode (ghc register) */
1949 c->lmmio[0xc/4] = (1 << 6) - 1; /* 5 ports. (supposedly ro pi reg.) */
1950
1951 /* enable ahci mode and 6 ports; from ich9 datasheet */
1952 pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);
1953 }
1954
1955 static int
didtype(Pcidev * p)1956 didtype(Pcidev *p)
1957 {
1958 switch(p->vid){
1959 case Vintel:
1960 if((p->did & 0xfffc) == 0x2680)
1961 return Tesb;
1962 /*
1963 * 0x27c4 is the intel 82801 in compatibility (not sata) mode.
1964 */
1965 if (p->did == 0x1e02 || /* c210 */
1966 p->did == 0x24d1 || /* 82801eb/er */
1967 (p->did & 0xfffb) == 0x27c1 || /* 82801g[bh]m ich7 */
1968 p->did == 0x2821 || /* 82801h[roh] */
1969 (p->did & 0xfffe) == 0x2824 || /* 82801h[b] */
1970 (p->did & 0xfeff) == 0x2829 || /* ich8/9m */
1971 (p->did & 0xfffe) == 0x2922 || /* ich9 */
1972 p->did == 0x3a02 || /* 82801jd/do */
1973 (p->did & 0xfefe) == 0x3a22 || /* ich10, pch */
1974 (p->did & 0xfff8) == 0x3b28) /* pchm */
1975 return Tich;
1976 break;
1977 case Vatiamd:
1978 if(p->did == 0x4380 || p->did == 0x4390 || p->did == 0x4391){
1979 print("detected sb600 vid %#ux did %#ux\n", p->vid, p->did);
1980 return Tsb600;
1981 }
1982 break;
1983 case Vmarvell:
1984 if (p->did == 0x9123)
1985 print("ahci: marvell sata 3 controller has delusions "
1986 "of something on unit 7\n");
1987 break;
1988 }
1989 if(p->ccrb == Pcibcstore && p->ccru == Pciscsata && p->ccrp == 1){
1990 print("ahci: Tunk: vid %#4.4ux did %#4.4ux\n", p->vid, p->did);
1991 return Tunk;
1992 }
1993 return -1;
1994 }
1995
1996 static int
newctlr(Ctlr * ctlr,SDev * sdev,int nunit)1997 newctlr(Ctlr *ctlr, SDev *sdev, int nunit)
1998 {
1999 int i, n;
2000 Drive *drive;
2001
2002 ctlr->ndrive = sdev->nunit = nunit;
2003 ctlr->mport = ctlr->hba->cap & ((1<<5)-1);
2004
2005 i = (ctlr->hba->cap >> 20) & ((1<<4)-1); /* iss */
2006 print("#S/sd%c: %s: %#p %s, %d ports, irq %d\n", sdev->idno,
2007 Tname(ctlr), ctlr->physio, descmode[i], nunit, ctlr->pci->intl);
2008 /* map the drives -- they don't all need to be enabled. */
2009 n = 0;
2010 ctlr->rawdrive = malloc(NCtlrdrv * sizeof(Drive));
2011 if(ctlr->rawdrive == nil) {
2012 print("ahci: out of memory\n");
2013 return -1;
2014 }
2015 for(i = 0; i < NCtlrdrv; i++) {
2016 drive = ctlr->rawdrive + i;
2017 drive->portno = i;
2018 drive->driveno = -1;
2019 drive->sectors = 0;
2020 drive->serial[0] = ' ';
2021 drive->ctlr = ctlr;
2022 if((ctlr->hba->pi & (1<<i)) == 0)
2023 continue;
2024 drive->port = (Aport*)(ctlr->mmio + 0x80*i + 0x100);
2025 drive->portc.p = drive->port;
2026 drive->portc.pm = &drive->portm;
2027 drive->driveno = n++;
2028 ctlr->drive[drive->driveno] = drive;
2029 iadrive[niadrive + drive->driveno] = drive;
2030 }
2031 for(i = 0; i < n; i++)
2032 if(ahciidle(ctlr->drive[i]->port) == -1){
2033 dprint("ahci: %s: port %d wedged; abort\n",
2034 Tname(ctlr), i);
2035 return -1;
2036 }
2037 for(i = 0; i < n; i++){
2038 ctlr->drive[i]->mode = DMsatai;
2039 configdrive(ctlr->drive[i]);
2040 }
2041 return n;
2042 }
2043
2044 static SDev*
iapnp(void)2045 iapnp(void)
2046 {
2047 int n, nunit, type;
2048 ulong io;
2049 Ctlr *c;
2050 Pcidev *p;
2051 SDev *head, *tail, *s;
2052 static int done;
2053
2054 if(done++)
2055 return nil;
2056
2057 memset(olds, 0xff, sizeof olds);
2058 p = nil;
2059 head = tail = nil;
2060 while((p = pcimatch(p, 0, 0)) != nil){
2061 type = didtype(p);
2062 if (type == -1 || p->mem[Abar].bar == 0)
2063 continue;
2064 if(niactlr == NCtlr){
2065 print("ahci: iapnp: %s: too many controllers\n",
2066 tname[type]);
2067 break;
2068 }
2069 c = iactlr + niactlr;
2070 s = sdevs + niactlr;
2071 memset(c, 0, sizeof *c);
2072 memset(s, 0, sizeof *s);
2073 io = p->mem[Abar].bar & ~0xf;
2074 c->physio = (uchar *)io;
2075 c->mmio = vmap(io, p->mem[Abar].size);
2076 if(c->mmio == 0){
2077 print("ahci: %s: address %#luX in use did=%#x\n",
2078 Tname(c), io, p->did);
2079 continue;
2080 }
2081 c->lmmio = (ulong*)c->mmio;
2082 c->pci = p;
2083 c->type = type;
2084
2085 s->ifc = &sdiahciifc;
2086 s->idno = 'E' + niactlr;
2087 s->ctlr = c;
2088 c->sdev = s;
2089
2090 if(Intel(c) && p->did != 0x2681)
2091 iasetupahci(c);
2092 nunit = ahciconf(c);
2093 // ahcihbareset((Ahba*)c->mmio);
2094 if(Intel(c) && iaahcimode(p) == -1)
2095 break;
2096 if(nunit < 1){
2097 vunmap(c->mmio, p->mem[Abar].size);
2098 continue;
2099 }
2100 n = newctlr(c, s, nunit);
2101 if(n < 0)
2102 continue;
2103 niadrive += n;
2104 niactlr++;
2105 if(head)
2106 tail->next = s;
2107 else
2108 head = s;
2109 tail = s;
2110 }
2111 return head;
2112 }
2113
2114 static char* smarttab[] = {
2115 "unset",
2116 "error",
2117 "threshold exceeded",
2118 "normal"
2119 };
2120
2121 static char *
pflag(char * s,char * e,uchar f)2122 pflag(char *s, char *e, uchar f)
2123 {
2124 uchar i;
2125
2126 for(i = 0; i < 8; i++)
2127 if(f & (1 << i))
2128 s = seprint(s, e, "%s ", flagname[i]);
2129 return seprint(s, e, "\n");
2130 }
2131
2132 static int
iarctl(SDunit * u,char * p,int l)2133 iarctl(SDunit *u, char *p, int l)
2134 {
2135 char buf[32];
2136 char *e, *op;
2137 Aport *o;
2138 Ctlr *c;
2139 Drive *d;
2140
2141 c = u->dev->ctlr;
2142 if(c == nil) {
2143 print("iarctl: nil u->dev->ctlr\n");
2144 return 0;
2145 }
2146 d = c->drive[u->subno];
2147 o = d->port;
2148
2149 e = p+l;
2150 op = p;
2151 if(d->state == Dready){
2152 p = seprint(p, e, "model\t%s\n", d->model);
2153 p = seprint(p, e, "serial\t%s\n", d->serial);
2154 p = seprint(p, e, "firm\t%s\n", d->firmware);
2155 if(d->smartrs == 0xff)
2156 p = seprint(p, e, "smart\tenable error\n");
2157 else if(d->smartrs == 0)
2158 p = seprint(p, e, "smart\tdisabled\n");
2159 else
2160 p = seprint(p, e, "smart\t%s\n",
2161 smarttab[d->portm.smart]);
2162 p = seprint(p, e, "flag\t");
2163 p = pflag(p, e, d->portm.feat);
2164 }else
2165 p = seprint(p, e, "no disk present [%s]\n", diskstates[d->state]);
2166 serrstr(o->serror, buf, buf + sizeof buf - 1);
2167 p = seprint(p, e, "reg\ttask %#lux cmd %#lux serr %#lux %s ci %#lux "
2168 "is %#lux; sig %#lux sstatus %06#lux\n",
2169 o->task, o->cmd, o->serror, buf,
2170 o->ci, o->isr, o->sig, o->sstatus);
2171 if(d->unit == nil)
2172 panic("iarctl: nil d->unit");
2173 p = seprint(p, e, "geometry %llud %lud\n", d->sectors, d->unit->secsize);
2174 return p - op;
2175 }
2176
2177 static void
runflushcache(Drive * d)2178 runflushcache(Drive *d)
2179 {
2180 long t0;
2181
2182 t0 = MACHP(0)->ticks;
2183 if(flushcache(d) != 0)
2184 error(Eio);
2185 dprint("ahci: flush in %ld ms\n", MACHP(0)->ticks - t0);
2186 }
2187
2188 static void
forcemode(Drive * d,char * mode)2189 forcemode(Drive *d, char *mode)
2190 {
2191 int i;
2192
2193 for(i = 0; i < nelem(modename); i++)
2194 if(strcmp(mode, modename[i]) == 0)
2195 break;
2196 if(i == nelem(modename))
2197 i = 0;
2198 ilock(d);
2199 d->mode = i;
2200 iunlock(d);
2201 }
2202
2203 static void
runsmartable(Drive * d,int i)2204 runsmartable(Drive *d, int i)
2205 {
2206 if(waserror()){
2207 qunlock(&d->portm);
2208 d->smartrs = 0;
2209 nexterror();
2210 }
2211 if(lockready(d) == -1)
2212 error(Eio);
2213 d->smartrs = smart(&d->portc, i);
2214 d->portm.smart = 0;
2215 qunlock(&d->portm);
2216 poperror();
2217 }
2218
2219 static void
forcestate(Drive * d,char * state)2220 forcestate(Drive *d, char *state)
2221 {
2222 int i;
2223
2224 for(i = 0; i < nelem(diskstates); i++)
2225 if(strcmp(state, diskstates[i]) == 0)
2226 break;
2227 if(i == nelem(diskstates))
2228 error(Ebadctl);
2229 setstate(d, i);
2230 }
2231
2232 /*
2233 * force this driver to notice a change of medium if the hardware doesn't
2234 * report it.
2235 */
2236 static void
changemedia(SDunit * u)2237 changemedia(SDunit *u)
2238 {
2239 Ctlr *c;
2240 Drive *d;
2241
2242 c = u->dev->ctlr;
2243 d = c->drive[u->subno];
2244 ilock(d);
2245 d->mediachange = 1;
2246 u->sectors = 0;
2247 iunlock(d);
2248 }
2249
2250 static int
iawctl(SDunit * u,Cmdbuf * cmd)2251 iawctl(SDunit *u, Cmdbuf *cmd)
2252 {
2253 char **f;
2254 Ctlr *c;
2255 Drive *d;
2256 uint i;
2257
2258 c = u->dev->ctlr;
2259 d = c->drive[u->subno];
2260 f = cmd->f;
2261
2262 if(strcmp(f[0], "change") == 0)
2263 changemedia(u);
2264 else if(strcmp(f[0], "flushcache") == 0)
2265 runflushcache(d);
2266 else if(strcmp(f[0], "identify") == 0){
2267 i = strtoul(f[1]? f[1]: "0", 0, 0);
2268 if(i > 0xff)
2269 i = 0;
2270 dprint("ahci: %04d %#ux\n", i, d->info[i]);
2271 }else if(strcmp(f[0], "mode") == 0)
2272 forcemode(d, f[1]? f[1]: "satai");
2273 else if(strcmp(f[0], "nop") == 0){
2274 if((d->portm.feat & Dnop) == 0){
2275 cmderror(cmd, "no drive support");
2276 return -1;
2277 }
2278 if(waserror()){
2279 qunlock(&d->portm);
2280 nexterror();
2281 }
2282 if(lockready(d) == -1)
2283 error(Eio);
2284 nop(&d->portc);
2285 qunlock(&d->portm);
2286 poperror();
2287 }else if(strcmp(f[0], "reset") == 0)
2288 forcestate(d, "reset");
2289 else if(strcmp(f[0], "smart") == 0){
2290 if(d->smartrs == 0){
2291 cmderror(cmd, "smart not enabled");
2292 return -1;
2293 }
2294 if(waserror()){
2295 qunlock(&d->portm);
2296 d->smartrs = 0;
2297 nexterror();
2298 }
2299 if(lockready(d) == -1)
2300 error(Eio);
2301 d->portm.smart = 2 + smartrs(&d->portc);
2302 qunlock(&d->portm);
2303 poperror();
2304 }else if(strcmp(f[0], "smartdisable") == 0)
2305 runsmartable(d, 1);
2306 else if(strcmp(f[0], "smartenable") == 0)
2307 runsmartable(d, 0);
2308 else if(strcmp(f[0], "state") == 0)
2309 forcestate(d, f[1]? f[1]: "null");
2310 else{
2311 cmderror(cmd, Ebadctl);
2312 return -1;
2313 }
2314 return 0;
2315 }
2316
2317 static char *
portr(char * p,char * e,uint x)2318 portr(char *p, char *e, uint x)
2319 {
2320 int i, a;
2321
2322 p[0] = 0;
2323 a = -1;
2324 for(i = 0; i < 32; i++){
2325 if((x & (1<<i)) == 0){
2326 if(a != -1 && i - 1 != a)
2327 p = seprint(p, e, "-%d", i - 1);
2328 a = -1;
2329 continue;
2330 }
2331 if(a == -1){
2332 if(i > 0)
2333 p = seprint(p, e, ", ");
2334 p = seprint(p, e, "%d", a = i);
2335 }
2336 }
2337 if(a != -1 && i - 1 != a)
2338 p = seprint(p, e, "-%d", i - 1);
2339 return p;
2340 }
2341
2342 /* must emit exactly one line per controller (sd(3)) */
2343 static char*
iartopctl(SDev * sdev,char * p,char * e)2344 iartopctl(SDev *sdev, char *p, char *e)
2345 {
2346 ulong cap;
2347 char pr[25];
2348 Ahba *hba;
2349 Ctlr *ctlr;
2350
2351 #define has(x, str) if(cap & (x)) p = seprint(p, e, "%s ", (str))
2352
2353 ctlr = sdev->ctlr;
2354 hba = ctlr->hba;
2355 p = seprint(p, e, "sd%c ahci port %#p: ", sdev->idno, ctlr->physio);
2356 cap = hba->cap;
2357 has(Hs64a, "64a");
2358 has(Hsalp, "alp");
2359 has(Hsam, "am");
2360 has(Hsclo, "clo");
2361 has(Hcccs, "coal");
2362 has(Hems, "ems");
2363 has(Hsal, "led");
2364 has(Hsmps, "mps");
2365 has(Hsncq, "ncq");
2366 has(Hssntf, "ntf");
2367 has(Hspm, "pm");
2368 has(Hpsc, "pslum");
2369 has(Hssc, "slum");
2370 has(Hsss, "ss");
2371 has(Hsxs, "sxs");
2372 portr(pr, pr + sizeof pr, hba->pi);
2373 return seprint(p, e,
2374 "iss %ld ncs %ld np %ld; ghc %#lux isr %#lux pi %#lux %s ver %#lux\n",
2375 (cap>>20) & 0xf, (cap>>8) & 0x1f, 1 + (cap & 0x1f),
2376 hba->ghc, hba->isr, hba->pi, pr, hba->ver);
2377 #undef has
2378 }
2379
2380 static int
iawtopctl(SDev *,Cmdbuf * cmd)2381 iawtopctl(SDev *, Cmdbuf *cmd)
2382 {
2383 int *v;
2384 char **f;
2385
2386 f = cmd->f;
2387 v = 0;
2388
2389 if (f[0] == nil)
2390 return 0;
2391 if(strcmp(f[0], "debug") == 0)
2392 v = &debug;
2393 else if(strcmp(f[0], "idprint") == 0)
2394 v = &prid;
2395 else if(strcmp(f[0], "aprint") == 0)
2396 v = &datapi;
2397 else
2398 cmderror(cmd, Ebadctl);
2399
2400 switch(cmd->nf){
2401 default:
2402 cmderror(cmd, Ebadarg);
2403 case 1:
2404 *v ^= 1;
2405 break;
2406 case 2:
2407 if(f[1])
2408 *v = strcmp(f[1], "on") == 0;
2409 else
2410 *v ^= 1;
2411 break;
2412 }
2413 return 0;
2414 }
2415
2416 SDifc sdiahciifc = {
2417 "iahci",
2418
2419 iapnp,
2420 nil, /* legacy */
2421 iaenable,
2422 iadisable,
2423
2424 iaverify,
2425 iaonline,
2426 iario,
2427 iarctl,
2428 iawctl,
2429
2430 scsibio,
2431 nil, /* probe */
2432 nil, /* clear */
2433 iartopctl,
2434 iawtopctl,
2435 };
2436