blob: 6614c0874a659eaa3c1776931f91a8b9c834bb25 [file] [log] [blame]
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
/*
* advanced host controller interface (sata)
* © 2007 coraid, inc
*/
/* ata errors */
enum {
Emed = 1 << 0, /* media error */
Enm = 1 << 1, /* no media */
Eabrt = 1 << 2, /* abort */
Emcr = 1 << 3, /* media change request */
Eidnf = 1 << 4, /* no user-accessible address */
Emc = 1 << 5, /* media change */
Eunc = 1 << 6, /* data error */
Ewp = 1 << 6, /* write protect */
Eicrc = 1 << 7, /* interface crc error */
Efatal = Eidnf | Eicrc, /* must sw reset */
};
/* ata status */
enum {
ASerr = 1 << 0, /* error */
ASdrq = 1 << 3, /* request */
ASdf = 1 << 5, /* fault, command specific */
ASdrdy = 1 << 6, /* ready, command specific */
ASbsy = 1 << 7, /* busy */
ASobs = 1 << 1 | 1 << 2 | 1 << 4,
};
/* pci configuration */
enum {
Abar = 5,
};
/*
* ahci memory configuration
*
* 0000-0023 generic host control
* 0024-009f reserved
* 00a0-00ff vendor specific.
* 0100-017f port 0
* ...
* 1080-1100 port 31
*/
/* Capability bits: supported features */
enum {
Hs64a = 1 << 31, /* 64-bit addressing */
Hsncq = 1 << 30, /* ncq */
Hssntf = 1 << 29, /* snotification reg. */
Hsmps = 1 << 28, /* mech pres switch */
Hsss = 1 << 27, /* staggered spinup */
Hsalp = 1 << 26, /* aggressive link pm */
Hsal = 1 << 25, /* activity led */
Hsclo = 1 << 24, /* command-list override */
Hiss = 1 << 20, /* for interface speed */
// Hsnzo = 1<<19,
Hsam = 1 << 18, /* ahci-mode only */
Hspm = 1 << 17, /* port multiplier */
// Hfbss = 1<<16,
Hpmb = 1 << 15, /* multiple-block pio */
Hssc = 1 << 14, /* slumber state */
Hpsc = 1 << 13, /* partial-slumber state */
Hncs = 1 << 8, /* n command slots */
Hcccs = 1 << 7, /* coal */
Hems = 1 << 6, /* enclosure mgmt. */
Hsxs = 1 << 5, /* external sata */
Hnp = 1 << 0, /* n ports */
};
/* GHC bits */
enum {
Hae = 1 << 31, /* enable ahci */
Hie = 1 << 1, /* " interrupts */
Hhr = 1 << 0, /* hba reset */
};
#define HBA_CAP 0x00 // Host Capabilities
#define HBA_GHC 0x04 // Global Host Control
#define HBA_ISR 0x08 // Interrupt Status Register
#define HBA_PI 0x0C // Ports Implemented
#define HBA_VS 0x10 // Version
#define HBA_CCC_CTL 0x14 // Command Completion Coalescing Control
#define HBA_CCC_PORTS 0x18 // Command Completion Coalescing Ports
#define HBA_EM_LOC 0x1C // Enclosure Management Location
#define HBA_EM_CTL 0x20 // Enclosure Management Control
#define HBA_CAP2 0x24 // Host Capabilities Extended
#define HBA_BOHC 0x28 // BIOS/OS Hand-Off Control and Status
/* Interrupt Status bits */
enum {
Acpds = 1 << 31, /* cold port detect status */
Atfes = 1 << 30, /* task file error status */
Ahbfs = 1 << 29, /* hba fatal */
Ahbds = 1 << 28, /* hba error (parity error) */
Aifs = 1 << 27, /* interface fatal §6.1.2 */
Ainfs = 1 << 26, /* interface error (recovered) */
Aofs = 1 << 24, /* too many bytes from disk */
Aipms = 1 << 23, /* incorrect prt mul status */
Aprcs = 1 << 22, /* PhyRdy change status Pxserr.diag.n */
Adpms = 1 << 7, /* mechanical presence status */
Apcs = 1 << 6, /* port connect diag.x */
Adps = 1 << 5, /* descriptor processed */
Aufs = 1 << 4, /* unknown fis diag.f */
Asdbs = 1 << 3, /* set device bits fis received w/ i bit set */
Adss = 1 << 2, /* dma setup */
Apio = 1 << 1, /* pio setup fis */
Adhrs = 1 << 0, /* device to host register fis */
IEM = Acpds | Atfes | Ahbds | Ahbfs | Ahbds | Aifs | Ainfs | Aprcs | Apcs |
Adps | Aufs | Asdbs | Adss | Adhrs,
Ifatal = Atfes | Ahbfs | Ahbds | Aifs,
};
/* SError bits */
enum {
SerrX = 1 << 26, /* exchanged */
SerrF = 1 << 25, /* unknown fis */
SerrT = 1 << 24, /* transition error */
SerrS = 1 << 23, /* link sequence */
SerrH = 1 << 22, /* handshake */
SerrC = 1 << 21, /* crc */
SerrD = 1 << 20, /* not used by ahci */
SerrB = 1 << 19, /* 10-tp-8 decode */
SerrW = 1 << 18, /* comm wake */
SerrI = 1 << 17, /* phy internal */
SerrN = 1 << 16, /* phyrdy change */
ErrE = 1 << 11, /* internal */
ErrP = 1 << 10, /* ata protocol violation */
ErrC = 1 << 9, /* communication */
ErrT = 1 << 8, /* transient */
ErrM = 1 << 1, /* recoverd comm */
ErrI = 1 << 0, /* recovered data integrety */
ErrAll = ErrE | ErrP | ErrC | ErrT | ErrM | ErrI,
SerrAll = SerrX | SerrF | SerrT | SerrS | SerrH | SerrC | SerrD | SerrB |
SerrW | SerrI | SerrN | ErrAll,
SerrBad = 0x7f << 19,
};
/* Command/Status register bits */
enum {
Aicc = 1 << 28, /* interface communcations control. 4 bits */
Aasp = 1 << 27, /* aggressive slumber & partial sleep */
Aalpe = 1 << 26, /* aggressive link pm enable */
Adlae = 1 << 25, /* drive led on atapi */
Aatapi = 1 << 24, /* device is atapi */
Aesp = 1 << 21, /* external sata port */
Acpd = 1 << 20, /* cold presence detect */
Ampsp = 1 << 19, /* mechanical pres. */
Ahpcp = 1 << 18, /* hot plug capable */
Apma = 1 << 17, /* pm attached */
Acps = 1 << 16, /* cold presence state */
Acr = 1 << 15, /* cmdlist running */
Afr = 1 << 14, /* fis running */
Ampss = 1 << 13, /* mechanical presence switch state */
Accs = 1 << 8, /* current command slot 12:08 */
Afre = 1 << 4, /* fis enable receive */
Aclo = 1 << 3, /* command list override */
Apod = 1 << 2, /* power on dev (requires cold-pres. detect) */
Asud = 1 << 1, /* spin-up device; requires ss capability */
Ast = 1 << 0, /* start */
Arun = Ast | Acr | Afre | Afr,
};
/* SControl register bits */
enum {
Aipm = 1 << 8, /* interface power mgmt. 3=off */
Aspd = 1 << 4,
Adis = 1 << 2, // Disable SATA interface and put Phy in offline mode
Adet = 1 << 0, /* device detection */
};
#define PORT_CLB 0x00 // Port Command List Base address
#define PORT_CLBU 0x04 // Port Command List Base address Upper 32-bits
#define PORT_FB 0x08 // Port FIS Base address
#define PORT_FBU 0x0C // Port FIS Base address Upper 32-bits
#define PORT_IS 0x10 // Port Interrupt Status
#define PORT_IE 0x14 // Port Interrupt Enable
#define PORT_CMD 0x18 // Port Command and status
#define PORT_RES1 0x1C // Reserved
#define PORT_TFD 0x20 // Port Task File Data
#define PORT_SIG 0x24 // Port Signature
#define PORT_SSTS 0x28 // Port Serial ATA Status (SCR0: SStatus)
#define PORT_SCTL 0x2C // Port Serial ATA Control (SCR2: SControl)
#define PORT_SERR 0x30 // Port Serial ATA Error (SCR1: SError)
#define PORT_SACT 0x34 // Port Serial ATA Active (SCR3: SActive)
#define PORT_CI 0x38 // Port Command Issue
#define PORT_SNTF 0x3C // Port Serial ATA Notification (SCR4: SNotification)
#define PORT_FBS 0x40 // Port FIS-Based Switching control
#define PORT_DEVSLP 0x44 // Port Device Sleep
#define PORT_RES2 0x48 // Reserved
#define PORT_VS 0x70 // Vendor Specific
enum {
/*
* Aport sstatus bits (actually states):
* 11-8 interface power management
* 7-4 current interface speed (generation #)
* 3-0 device detection
*/
Intslumber = 0x600,
Intpartpwr = 0x200,
Intactive = 0x100,
Intpm = 0xf00,
Devphyoffline = 4,
Devphycomm = 2, /* phy communication established */
Devpresent = 1,
Devdet = Devpresent | Devphycomm | Devphyoffline,
};
/* in host's memory; not memory mapped */
struct afis {
unsigned char *base;
unsigned char *d;
unsigned char *p;
unsigned char *r;
unsigned char *u;
uint32_t *devicebits;
};
// Command header flags
enum {
Lprdtl = 1 << 16, /* physical region descriptor table len */
Lpmp = 1 << 12, /* port multiplier port */
Lclear = 1 << 10, /* clear busy on R_OK */
Lbist = 1 << 9,
Lreset = 1 << 8,
Lpref = 1 << 7, /* prefetchable */
Lwrite = 1 << 6,
Latapi = 1 << 5,
Lcfl = 1 << 0, /* command fis length in double words */
};
// AHCI Command List Command Header
// Each header is an element in the list which is up to 32 elements long
#define ALIST_SIZE 0x20 // Size of the struct in memory, not for access
#define ALIST_FLAGS 0x00 // Flags and PRDTL (PRDT Length)
#define ALIST_LEN 0x04 // PRD byte count transferred
#define ALIST_CTAB 0x08 // Physical address of 128-bit aligned Command Table
#define ALIST_CTABHI 0x0C // CTAB physical address upper 32 bits
#define ALIST_RES 0x10 // Reserved
// AHCI Physical Region Descriptor Table Element
// Each of these elements is part of a table with up to 65,535 entries
#define APRDT_SIZE 0x10 // Size of the struct in memory, not for access
#define APRDT_DBA 0x00 // Data Base Address (physical)
#define APRDT_DBAHI 0x04 // Data Base Address upper 32 bits
#define APRDT_RES 0x08 // Reserved
#define APRDT_COUNT 0x0C // 31=Intr on Completion, 30:22=Reserved, 21:0=DBC
// AHCI Command Table
// Note that there is no fixed size specified - there are 1 to 65,535 PRDT's
// Size = ACTAB_PRDT + APRDT*N_APRDT
#define ACTAB_CFIS 0x00 // Command Frame Information Struct (up to 64 bytes)
#define ACTAB_ATAPI 0x40 // ATAPI Command (12 or 16 bytes)
#define ACTAB_RES 0x50 // Reserved
#define ACTAB_PRDT 0x80 // PRDT (up to 65,535 entries in spec, this has one)
// Portm flags (status flags?)
enum {
Ferror = 1,
Fdone = 2,
};
// Portm feature flags
enum {
Dllba = 1,
Dsmart = 1 << 1,
Dpower = 1 << 2,
Dnop = 1 << 3,
Datapi = 1 << 4,
Datapi16 = 1 << 5,
};
struct aportm {
qlock_t ql;
struct rendez Rendez;
unsigned char flag;
unsigned char feat;
unsigned char smart;
struct afis fis;
void *list;
void *ctab;
};
struct aportc {
void *p;
struct aportm *pm;
};