xref: /plan9/sys/src/9/pc/sdiahci.c (revision 58da3067adcdccaaa043d0bfde28ba83b7ced07d)
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