1*9ef1f84bSDavid du Colombier /* 2*9ef1f84bSDavid du Colombier * advanced host controller interface (sata) 3*9ef1f84bSDavid du Colombier * © 2007 coraid, inc 4*9ef1f84bSDavid du Colombier */ 5*9ef1f84bSDavid du Colombier 6*9ef1f84bSDavid du Colombier /* ata errors */ 7*9ef1f84bSDavid du Colombier enum { 8*9ef1f84bSDavid du Colombier Emed = 1<<0, /* media error */ 9*9ef1f84bSDavid du Colombier Enm = 1<<1, /* no media */ 10*9ef1f84bSDavid du Colombier Eabrt = 1<<2, /* abort */ 11*9ef1f84bSDavid du Colombier Emcr = 1<<3, /* media change request */ 12*9ef1f84bSDavid du Colombier Eidnf = 1<<4, /* no user-accessible address */ 13*9ef1f84bSDavid du Colombier Emc = 1<<5, /* media change */ 14*9ef1f84bSDavid du Colombier Eunc = 1<<6, /* data error */ 15*9ef1f84bSDavid du Colombier Ewp = 1<<6, /* write protect */ 16*9ef1f84bSDavid du Colombier Eicrc = 1<<7, /* interface crc error */ 17*9ef1f84bSDavid du Colombier 18*9ef1f84bSDavid du Colombier Efatal = Eidnf|Eicrc, /* must sw reset */ 19*9ef1f84bSDavid du Colombier }; 20*9ef1f84bSDavid du Colombier 21*9ef1f84bSDavid du Colombier /* ata status */ 22*9ef1f84bSDavid du Colombier enum { 23*9ef1f84bSDavid du Colombier ASerr = 1<<0, /* error */ 24*9ef1f84bSDavid du Colombier ASdrq = 1<<3, /* request */ 25*9ef1f84bSDavid du Colombier ASdf = 1<<5, /* fault */ 26*9ef1f84bSDavid du Colombier ASdrdy = 1<<6, /* ready */ 27*9ef1f84bSDavid du Colombier ASbsy = 1<<7, /* busy */ 28*9ef1f84bSDavid du Colombier 29*9ef1f84bSDavid du Colombier ASobs = 1<<1|1<<2|1<<4, 30*9ef1f84bSDavid du Colombier }; 31*9ef1f84bSDavid du Colombier 32*9ef1f84bSDavid du Colombier /* pci configuration */ 33*9ef1f84bSDavid du Colombier enum { 34*9ef1f84bSDavid du Colombier Abar = 5, 35*9ef1f84bSDavid du Colombier }; 36*9ef1f84bSDavid du Colombier 37*9ef1f84bSDavid du Colombier /* 38*9ef1f84bSDavid du Colombier * ahci memory configuration 39*9ef1f84bSDavid du Colombier * 40*9ef1f84bSDavid du Colombier * 0000-0023 generic host control 41*9ef1f84bSDavid du Colombier * 0024-009f reserved 42*9ef1f84bSDavid du Colombier * 00a0-00ff vendor specific. 43*9ef1f84bSDavid du Colombier * 0100-017f port 0 44*9ef1f84bSDavid du Colombier * ... 45*9ef1f84bSDavid du Colombier * 1080-1100 port 31 46*9ef1f84bSDavid du Colombier */ 47*9ef1f84bSDavid du Colombier 48*9ef1f84bSDavid du Colombier /* cap bits: supported features */ 49*9ef1f84bSDavid du Colombier enum { 50*9ef1f84bSDavid du Colombier Hs64a = 1<<31, /* 64-bit addressing */ 51*9ef1f84bSDavid du Colombier Hsncq = 1<<30, /* ncq */ 52*9ef1f84bSDavid du Colombier Hssntf = 1<<29, /* snotification reg. */ 53*9ef1f84bSDavid du Colombier Hsmps = 1<<28, /* mech pres switch */ 54*9ef1f84bSDavid du Colombier Hsss = 1<<27, /* staggered spinup */ 55*9ef1f84bSDavid du Colombier Hsalp = 1<<26, /* aggressive link pm */ 56*9ef1f84bSDavid du Colombier Hsal = 1<<25, /* activity led */ 57*9ef1f84bSDavid du Colombier Hsclo = 1<<24, /* command-list override */ 58*9ef1f84bSDavid du Colombier Hiss = 1<<20, /* for interface speed */ 59*9ef1f84bSDavid du Colombier // Hsnzo = 1<<19, 60*9ef1f84bSDavid du Colombier Hsam = 1<<18, /* ahci-mode only */ 61*9ef1f84bSDavid du Colombier Hspm = 1<<17, /* port multiplier */ 62*9ef1f84bSDavid du Colombier // Hfbss = 1<<16, 63*9ef1f84bSDavid du Colombier Hpmb = 1<<15, /* multiple-block pio */ 64*9ef1f84bSDavid du Colombier Hssc = 1<<14, /* slumber state */ 65*9ef1f84bSDavid du Colombier Hpsc = 1<<13, /* partial-slumber state */ 66*9ef1f84bSDavid du Colombier Hncs = 1<<8, /* n command slots */ 67*9ef1f84bSDavid du Colombier Hcccs = 1<<7, /* coal */ 68*9ef1f84bSDavid du Colombier Hems = 1<<6, /* enclosure mgmt. */ 69*9ef1f84bSDavid du Colombier Hsxs = 1<<5, /* external sata */ 70*9ef1f84bSDavid du Colombier Hnp = 1<<0, /* n ports */ 71*9ef1f84bSDavid du Colombier }; 72*9ef1f84bSDavid du Colombier 73*9ef1f84bSDavid du Colombier /* ghc bits */ 74*9ef1f84bSDavid du Colombier enum { 75*9ef1f84bSDavid du Colombier Hae = 1<<31, /* enable ahci */ 76*9ef1f84bSDavid du Colombier Hie = 1<<1, /* " interrupts */ 77*9ef1f84bSDavid du Colombier Hhr = 1<<0, /* hba reset */ 78*9ef1f84bSDavid du Colombier }; 79*9ef1f84bSDavid du Colombier 80*9ef1f84bSDavid du Colombier typedef struct { 81*9ef1f84bSDavid du Colombier ulong cap; 82*9ef1f84bSDavid du Colombier ulong ghc; 83*9ef1f84bSDavid du Colombier ulong isr; 84*9ef1f84bSDavid du Colombier ulong pi; /* ports implemented */ 85*9ef1f84bSDavid du Colombier ulong ver; 86*9ef1f84bSDavid du Colombier ulong ccc; /* coaleasing control */ 87*9ef1f84bSDavid du Colombier ulong cccports; 88*9ef1f84bSDavid du Colombier ulong emloc; 89*9ef1f84bSDavid du Colombier ulong emctl; 90*9ef1f84bSDavid du Colombier } Ahba; 91*9ef1f84bSDavid du Colombier 92*9ef1f84bSDavid du Colombier enum { 93*9ef1f84bSDavid du Colombier Acpds = 1<<31, /* cold port detect status */ 94*9ef1f84bSDavid du Colombier Atfes = 1<<30, /* task file error status */ 95*9ef1f84bSDavid du Colombier Ahbfs = 1<<29, /* hba fatal */ 96*9ef1f84bSDavid du Colombier Ahbds = 1<<28, /* hba error (parity error) */ 97*9ef1f84bSDavid du Colombier Aifs = 1<<27, /* interface fatal §6.1.2 */ 98*9ef1f84bSDavid du Colombier Ainfs = 1<<26, /* interface error (recovered) */ 99*9ef1f84bSDavid du Colombier Aofs = 1<<24, /* too many bytes from disk */ 100*9ef1f84bSDavid du Colombier Aipms = 1<<23, /* incorrect prt mul status */ 101*9ef1f84bSDavid du Colombier Aprcs = 1<<22, /* PhyRdy change status Pxserr.diag.n */ 102*9ef1f84bSDavid du Colombier Adpms = 1<<7, /* mechanical presence status */ 103*9ef1f84bSDavid du Colombier Apcs = 1<<6, /* port connect diag.x */ 104*9ef1f84bSDavid du Colombier Adps = 1<<5, /* descriptor processed */ 105*9ef1f84bSDavid du Colombier Aufs = 1<<4, /* unknown fis diag.f */ 106*9ef1f84bSDavid du Colombier Asdbs = 1<<3, /* set device bits fis received w/ i bit set */ 107*9ef1f84bSDavid du Colombier Adss = 1<<2, /* dma setup */ 108*9ef1f84bSDavid du Colombier Apio = 1<<1, /* pio setup fis */ 109*9ef1f84bSDavid du Colombier Adhrs = 1<<0, /* device to host register fis */ 110*9ef1f84bSDavid du Colombier 111*9ef1f84bSDavid du Colombier IEM = Acpds|Atfes|Ahbds|Ahbfs|Ahbds|Aifs|Ainfs|Aprcs|Apcs|Adps| 112*9ef1f84bSDavid du Colombier Aufs|Asdbs|Adss|Adhrs, 113*9ef1f84bSDavid du Colombier Ifatal = Atfes|Ahbfs|Ahbds|Aifs, 114*9ef1f84bSDavid du Colombier }; 115*9ef1f84bSDavid du Colombier 116*9ef1f84bSDavid du Colombier /* serror bits */ 117*9ef1f84bSDavid du Colombier enum { 118*9ef1f84bSDavid du Colombier SerrX = 1<<26, /* exchanged */ 119*9ef1f84bSDavid du Colombier SerrF = 1<<25, /* unknown fis */ 120*9ef1f84bSDavid du Colombier SerrT = 1<<24, /* transition error */ 121*9ef1f84bSDavid du Colombier SerrS = 1<<23, /* link sequence */ 122*9ef1f84bSDavid du Colombier SerrH = 1<<22, /* handshake */ 123*9ef1f84bSDavid du Colombier SerrC = 1<<21, /* crc */ 124*9ef1f84bSDavid du Colombier SerrD = 1<<20, /* not used by ahci */ 125*9ef1f84bSDavid du Colombier SerrB = 1<<19, /* 10-tp-8 decode */ 126*9ef1f84bSDavid du Colombier SerrW = 1<<18, /* comm wake */ 127*9ef1f84bSDavid du Colombier SerrI = 1<<17, /* phy internal */ 128*9ef1f84bSDavid du Colombier SerrN = 1<<16, /* phyrdy change */ 129*9ef1f84bSDavid du Colombier 130*9ef1f84bSDavid du Colombier ErrE = 1<<11, /* internal */ 131*9ef1f84bSDavid du Colombier ErrP = 1<<10, /* ata protocol violation */ 132*9ef1f84bSDavid du Colombier ErrC = 1<<9, /* communication */ 133*9ef1f84bSDavid du Colombier ErrT = 1<<8, /* transient */ 134*9ef1f84bSDavid du Colombier ErrM = 1<<1, /* recoverd comm */ 135*9ef1f84bSDavid du Colombier ErrI = 1<<0, /* recovered data integrety */ 136*9ef1f84bSDavid du Colombier 137*9ef1f84bSDavid du Colombier ErrAll = ErrE|ErrP|ErrC|ErrT|ErrM|ErrI, 138*9ef1f84bSDavid du Colombier SerrAll = SerrX|SerrF|SerrT|SerrS|SerrH|SerrC|SerrD|SerrB|SerrW| 139*9ef1f84bSDavid du Colombier SerrI|SerrN|ErrAll, 140*9ef1f84bSDavid du Colombier SerrBad = 0x7f<<19, 141*9ef1f84bSDavid du Colombier }; 142*9ef1f84bSDavid du Colombier 143*9ef1f84bSDavid du Colombier /* cmd register bits */ 144*9ef1f84bSDavid du Colombier enum { 145*9ef1f84bSDavid du Colombier Aicc = 1<<28, /* interface communcations control. 4 bits */ 146*9ef1f84bSDavid du Colombier Aasp = 1<<27, /* aggressive slumber & partial sleep */ 147*9ef1f84bSDavid du Colombier Aalpe = 1<<26, /* aggressive link pm enable */ 148*9ef1f84bSDavid du Colombier Adlae = 1<<25, /* drive led on atapi */ 149*9ef1f84bSDavid du Colombier Aatapi = 1<<24, /* device is atapi */ 150*9ef1f84bSDavid du Colombier Aesp = 1<<21, /* external sata port */ 151*9ef1f84bSDavid du Colombier Acpd = 1<<20, /* cold presence detect */ 152*9ef1f84bSDavid du Colombier Ampsp = 1<<19, /* mechanical pres. */ 153*9ef1f84bSDavid du Colombier Ahpcp = 1<<18, /* hot plug capable */ 154*9ef1f84bSDavid du Colombier Apma = 1<<17, /* pm attached */ 155*9ef1f84bSDavid du Colombier Acps = 1<<16, /* cold presence state */ 156*9ef1f84bSDavid du Colombier Acr = 1<<15, /* cmdlist running */ 157*9ef1f84bSDavid du Colombier Afr = 1<<14, /* fis running */ 158*9ef1f84bSDavid du Colombier Ampss = 1<<13, /* mechanical presence switch state */ 159*9ef1f84bSDavid du Colombier Accs = 1<<8, /* current command slot 12:08 */ 160*9ef1f84bSDavid du Colombier Afre = 1<<4, /* fis enable receive */ 161*9ef1f84bSDavid du Colombier Aclo = 1<<3, /* command list override */ 162*9ef1f84bSDavid du Colombier Apod = 1<<2, /* power on dev (requires cold-pres. detect) */ 163*9ef1f84bSDavid du Colombier Asud = 1<<1, /* spin-up device; requires ss capability */ 164*9ef1f84bSDavid du Colombier Ast = 1<<0, /* start */ 165*9ef1f84bSDavid du Colombier 166*9ef1f84bSDavid du Colombier Arun = Ast|Acr|Afre|Afr, 167*9ef1f84bSDavid du Colombier }; 168*9ef1f84bSDavid du Colombier 169*9ef1f84bSDavid du Colombier /* ctl register bits */ 170*9ef1f84bSDavid du Colombier enum { 171*9ef1f84bSDavid du Colombier Aipm = 1<<8, /* interface power mgmt. 3=off */ 172*9ef1f84bSDavid du Colombier Aspd = 1<<4, 173*9ef1f84bSDavid du Colombier Adet = 1<<0, /* device detection */ 174*9ef1f84bSDavid du Colombier }; 175*9ef1f84bSDavid du Colombier 176*9ef1f84bSDavid du Colombier #define sstatus scr0 177*9ef1f84bSDavid du Colombier #define sctl scr2 178*9ef1f84bSDavid du Colombier #define serror scr1 179*9ef1f84bSDavid du Colombier #define sactive scr3 180*9ef1f84bSDavid du Colombier 181*9ef1f84bSDavid du Colombier typedef struct { 182*9ef1f84bSDavid du Colombier ulong list; /* PxCLB must be 1kb aligned. */ 183*9ef1f84bSDavid du Colombier ulong listhi; 184*9ef1f84bSDavid du Colombier ulong fis; /* 256-byte aligned */ 185*9ef1f84bSDavid du Colombier ulong fishi; 186*9ef1f84bSDavid du Colombier ulong isr; 187*9ef1f84bSDavid du Colombier ulong ie; /* interrupt enable */ 188*9ef1f84bSDavid du Colombier ulong cmd; 189*9ef1f84bSDavid du Colombier ulong res1; 190*9ef1f84bSDavid du Colombier ulong task; 191*9ef1f84bSDavid du Colombier ulong sig; 192*9ef1f84bSDavid du Colombier ulong scr0; 193*9ef1f84bSDavid du Colombier ulong scr2; 194*9ef1f84bSDavid du Colombier ulong scr1; 195*9ef1f84bSDavid du Colombier ulong scr3; 196*9ef1f84bSDavid du Colombier ulong ci; /* command issue */ 197*9ef1f84bSDavid du Colombier ulong ntf; 198*9ef1f84bSDavid du Colombier uchar res2[8]; 199*9ef1f84bSDavid du Colombier ulong vendor; 200*9ef1f84bSDavid du Colombier } Aport; 201*9ef1f84bSDavid du Colombier 202*9ef1f84bSDavid du Colombier enum { 203*9ef1f84bSDavid du Colombier /* 204*9ef1f84bSDavid du Colombier * Aport sstatus bits (actually states): 205*9ef1f84bSDavid du Colombier * 11-8 interface power management 206*9ef1f84bSDavid du Colombier * 7-4 current interface speed (generation #) 207*9ef1f84bSDavid du Colombier * 3-0 device detection 208*9ef1f84bSDavid du Colombier */ 209*9ef1f84bSDavid du Colombier Intslumber = 0x600, 210*9ef1f84bSDavid du Colombier Intpartpwr = 0x200, 211*9ef1f84bSDavid du Colombier Intactive = 0x100, 212*9ef1f84bSDavid du Colombier Intpm = 0xf00, 213*9ef1f84bSDavid du Colombier 214*9ef1f84bSDavid du Colombier Devphyoffline = 4, 215*9ef1f84bSDavid du Colombier Devphycomm = 2, /* phy communication established */ 216*9ef1f84bSDavid du Colombier Devpresent = 1, 217*9ef1f84bSDavid du Colombier Devdet = Devpresent | Devphycomm | Devphyoffline, 218*9ef1f84bSDavid du Colombier }; 219*9ef1f84bSDavid du Colombier 220*9ef1f84bSDavid du Colombier /* in host's memory; not memory mapped */ 221*9ef1f84bSDavid du Colombier typedef struct { 222*9ef1f84bSDavid du Colombier uchar *base; 223*9ef1f84bSDavid du Colombier uchar *d; 224*9ef1f84bSDavid du Colombier uchar *p; 225*9ef1f84bSDavid du Colombier uchar *r; 226*9ef1f84bSDavid du Colombier uchar *u; 227*9ef1f84bSDavid du Colombier ulong *devicebits; 228*9ef1f84bSDavid du Colombier } Afis; 229*9ef1f84bSDavid du Colombier 230*9ef1f84bSDavid du Colombier enum { 231*9ef1f84bSDavid du Colombier Lprdtl = 1<<16, /* physical region descriptor table len */ 232*9ef1f84bSDavid du Colombier Lpmp = 1<<12, /* port multiplier port */ 233*9ef1f84bSDavid du Colombier Lclear = 1<<10, /* clear busy on R_OK */ 234*9ef1f84bSDavid du Colombier Lbist = 1<<9, 235*9ef1f84bSDavid du Colombier Lreset = 1<<8, 236*9ef1f84bSDavid du Colombier Lpref = 1<<7, /* prefetchable */ 237*9ef1f84bSDavid du Colombier Lwrite = 1<<6, 238*9ef1f84bSDavid du Colombier Latapi = 1<<5, 239*9ef1f84bSDavid du Colombier Lcfl = 1<<0, /* command fis length in double words */ 240*9ef1f84bSDavid du Colombier }; 241*9ef1f84bSDavid du Colombier 242*9ef1f84bSDavid du Colombier /* in hosts memory; memory mapped */ 243*9ef1f84bSDavid du Colombier typedef struct { 244*9ef1f84bSDavid du Colombier ulong flags; 245*9ef1f84bSDavid du Colombier ulong len; 246*9ef1f84bSDavid du Colombier ulong ctab; 247*9ef1f84bSDavid du Colombier ulong ctabhi; 248*9ef1f84bSDavid du Colombier uchar reserved[16]; 249*9ef1f84bSDavid du Colombier } Alist; 250*9ef1f84bSDavid du Colombier 251*9ef1f84bSDavid du Colombier typedef struct { 252*9ef1f84bSDavid du Colombier ulong dba; 253*9ef1f84bSDavid du Colombier ulong dbahi; 254*9ef1f84bSDavid du Colombier ulong pad; 255*9ef1f84bSDavid du Colombier ulong count; 256*9ef1f84bSDavid du Colombier } Aprdt; 257*9ef1f84bSDavid du Colombier 258*9ef1f84bSDavid du Colombier typedef struct { 259*9ef1f84bSDavid du Colombier uchar cfis[0x40]; 260*9ef1f84bSDavid du Colombier uchar atapi[0x10]; 261*9ef1f84bSDavid du Colombier uchar pad[0x30]; 262*9ef1f84bSDavid du Colombier Aprdt prdt; 263*9ef1f84bSDavid du Colombier } Actab; 264*9ef1f84bSDavid du Colombier 265*9ef1f84bSDavid du Colombier enum { 266*9ef1f84bSDavid du Colombier Ferror = 1, 267*9ef1f84bSDavid du Colombier Fdone = 2, 268*9ef1f84bSDavid du Colombier }; 269*9ef1f84bSDavid du Colombier 270*9ef1f84bSDavid du Colombier enum { 271*9ef1f84bSDavid du Colombier Dllba = 1, 272*9ef1f84bSDavid du Colombier Dsmart = 1<<1, 273*9ef1f84bSDavid du Colombier Dpower = 1<<2, 274*9ef1f84bSDavid du Colombier Dnop = 1<<3, 275*9ef1f84bSDavid du Colombier Datapi = 1<<4, 276*9ef1f84bSDavid du Colombier Datapi16= 1<<5, 277*9ef1f84bSDavid du Colombier }; 278*9ef1f84bSDavid du Colombier 279*9ef1f84bSDavid du Colombier typedef struct { 280*9ef1f84bSDavid du Colombier QLock; 281*9ef1f84bSDavid du Colombier Rendez; 282*9ef1f84bSDavid du Colombier uchar flag; 283*9ef1f84bSDavid du Colombier uchar feat; 284*9ef1f84bSDavid du Colombier uchar smart; 285*9ef1f84bSDavid du Colombier Afis fis; 286*9ef1f84bSDavid du Colombier Alist *list; 287*9ef1f84bSDavid du Colombier Actab *ctab; 288*9ef1f84bSDavid du Colombier } Aportm; 289*9ef1f84bSDavid du Colombier 290*9ef1f84bSDavid du Colombier typedef struct { 291*9ef1f84bSDavid du Colombier Aport *p; 292*9ef1f84bSDavid du Colombier Aportm *pm; 293*9ef1f84bSDavid du Colombier } Aportc; 294