Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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
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
252
esleep(int ms)
253
{
254
	if(waserror())
255
		return;
256
	tsleep(&up->sleep, return0, 0, ms);
257
	poperror();
258
}
259
 
260
static int
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
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
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 *
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
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
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
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
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
364
asleep(int ms)
365
{
366
	if(up == nil)
367
		delay(ms);
368
	else
369
		esleep(ms);
370
}
371
 
372
static int
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
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
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
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
455
gbit16(void *a)
456
{
457
	uchar *i;
458
 
459
	i = a;
460
	return i[1]<<8 | i[0];
461
}
462
 
463
static ulong
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
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
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
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
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
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
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
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
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*
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
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
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
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
769
ahcienable(Ahba *h)
770
{
771
	h->ghc |= Hie;
772
}
773
 
774
static void
775
ahcidisable(Ahba *h)
776
{
777
	h->ghc &= ~Hie;
778
}
779
 
780
static int
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
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
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
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
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
896
clearci(Aport *p)
897
{
898
	if(p->cmd & Ast) {
899
		p->cmd &= ~Ast;
900
		p->cmd |=  Ast;
901
	}
902
}
903
 
904
static void
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
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
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
1029
setstate(Drive *d, int state)
1030
{
1031
	ilock(d);
1032
	d->state = state;
1033
	iunlock(d);
1034
}
1035
 
1036
static void
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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*
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*
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
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
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
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
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
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
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
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
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
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*
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 *
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
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
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
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
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
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
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
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 *
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*
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
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
};