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