diff --git a/sys/dev/ahci.c b/sys/dev/ahci.c index 91afb21..33fb999 100644 --- a/sys/dev/ahci.c +++ b/sys/dev/ahci.c @@ -48,16 +48,105 @@ typedef struct AHCIPort uint32_t _rsvd2; // *Reserved* } AHCIPort; +#define AHCIPORT_CMD_ICCMASK 0xF0000000 /* Interface Communication Control */ +#define AHCIPORT_CMD_ICCSLUMBER 0x60000000 /* ICC Slumber */ +#define AHCIPORT_CMD_ICCPARTIAL 0x20000000 /* ICC Partial */ +#define AHCIPORT_CMD_ICCACTIVE 0x10000000 /* ICC Active */ +#define AHCIPORT_CMD_ICCIDLE 0x00000000 /* ICC Idle */ +#define AHCIPORT_CMD_ASP 0x08000000 /* Aggressive Slumber/Partial */ +#define AHCIPORT_CMD_ALPE 0x04000000 /* Aggressive Link PM Enable */ +#define AHCIPORT_CMD_DLAE 0x02000000 /* Drive LED on ATAPI Enable */ +#define AHCIPORT_CMD_ATAPI 0x01000000 /* Device is ATAPI */ +#define AHCIPORT_CMD_CPD 0x00100000 /* Cold Presence Detection */ +#define AHCIPORT_CMD_ISP 0x00080000 /* Interlock Switch Attached */ +#define AHCIPORT_CMD_HPCP 0x00040000 /* Hot Plug Capable Port */ +#define AHCIPORT_CMD_PMA 0x00020000 /* Port Multiplier Attached */ +#define AHCIPORT_CMD_CPS 0x00010000 /* Cold Presence State */ +#define AHCIPORT_CMD_CR 0x00008000 /* Command List Running */ +#define AHCIPORT_CMD_FR 0x00004000 /* FIS Receive Running */ +#define AHCIPORT_CMD_ISS 0x00002000 /* Interlock Switch State */ +#define AHCIPORT_CMD_FRE 0x00000010 /* FIS Receive Enable */ +#define AHCIPORT_CMD_CLO 0x00000008 /* Command List Override */ +#define AHCIPORT_CMD_POD 0x00000004 /* Power On Device */ +#define AHCIPORT_CMD_SUD 0x00000002 /* Spin-Up Device */ +#define AHCIPORT_CMD_ST 0x00000001 /* Start */ + #define AHCI_ABAR 5 #define AHCI_PORT_OFFSET 0x100 #define AHCI_PORT_LENGTH 0x80 #define AHCI_MAX_PORTS 32 +#define AHCI_MAX_CMDS 32 +/* + * Request Structures + */ + +typedef struct AHCICommandHeader +{ + uint32_t descInfo; + uint32_t cmdStatus; + uint64_t ctba; + uint64_t _rsvd[2]; +} AHCICommandHeader; + +typedef struct AHCICommandList +{ + AHCICommandHeader cmds[AHCI_MAX_CMDS]; +} AHCICommandList; + +/* + * AHCIPRDT - Physical Region Descriptor Table + */ +typedef struct AHCIPRDT +{ + uint64_t dba; // Data Base Address + uint32_t _rsvd; + uint32_t descInfo; // Description Information +} AHCIPRDT; + +/* + * AHCICommandTable + * This structure is exactly one machine page in size, we fill up the page + * with PRDT entries. AHCI supports up to 64K PRDT entries but on x86 we + * limit this to 248. + */ +typedef struct AHCICommandTable +{ + uint8_t cfis[64]; // Command FIS + uint8_t acmd[32]; // ATAPI Command + uint8_t _rsvd[32]; + AHCIPRDT prdt[248]; // Physical Region Descriptor Table +} AHCICommandTable; + +/* + * Response Structures + */ + +typedef struct AHCIRecvFIS +{ + uint8_t dsfis[0x1c]; + uint8_t _rsvd0[0x4]; + uint8_t psfis[0x14]; + uint8_t _rsvd1[0xc]; + uint8_t rfis[0x14]; + uint8_t _rsvd2[0x4]; + uint8_t sdbfis[0x8]; + uint8_t ufis[0x40]; + uint8_t _rsvd3[0x60]; +} AHCIRecvFIS; + +/* + * AHCI + * Exceeds a single page need to use heap + */ typedef struct AHCI { PCIDevice dev; AHCIHostControl *hc; AHCIPort *port[AHCI_MAX_PORTS]; + AHCICommandList *clst[AHCI_MAX_PORTS]; + AHCICommandTable *ctbl[AHCI_MAX_PORTS][AHCI_MAX_CMDS]; + AHCIRecvFIS *rfis[AHCI_MAX_PORTS]; } AHCI; void AHCI_Configure(PCIDevice dev); @@ -97,6 +186,29 @@ AHCI_Init(uint32_t bus, uint32_t slot, uint32_t func) void AHCI_ResetPort(AHCI *ahci, int port) { + volatile AHCIPort *p = ahci->port[port]; + uint32_t cmd = p->cmd; + uint32_t cmd_mask = AHCIPORT_CMD_ST | AHCIPORT_CMD_CR | + AHCIPORT_CMD_FRE | AHCIPORT_CMD_FR; + + // Wait for controller to be idle + if (cmd & cmd_mask != 0) { + int tries; + for (tries = 0; tries < 2; tries++) { + cmd = cmd & ~(AHCIPORT_CMD_ST | AHCIPORT_CMD_FRE); + p->cmd = cmd; + // sleep 500ms + cmd = p->cmd; + if (cmd & cmd_mask != 0) { + kprintf("AHCI: failed to reset port %d\n", port); + } + } + } + + // Reset error + p->serr = 0xFFFFFFFF; + + // } void