// Copyright 2016 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #pragma once #include #include #include #define AHCI_MAX_PORTS 32 #define AHCI_MAX_COMMANDS 32 #define AHCI_MAX_PRDS ((PAGE_SIZE / sizeof(zx_paddr_t)) + 1) #define AHCI_MAX_PAGES AHCI_MAX_PRDS // one page less of 2M because of unnaligned offset #define AHCI_MAX_BYTES (2 * 1024 * 1024) #define AHCI_PRD_MAX_SIZE 0x400000 // 4mb static_assert(PAGE_SIZE <= AHCI_PRD_MAX_SIZE, "page size must be less than PRD max size\n"); #define AHCI_PORT_INT_CPD (1 << 31) #define AHCI_PORT_INT_TFE (1 << 30) #define AHCI_PORT_INT_HBF (1 << 29) #define AHCI_PORT_INT_HBD (1 << 28) #define AHCI_PORT_INT_IF (1 << 27) #define AHCI_PORT_INT_INF (1 << 26) #define AHCI_PORT_INT_OF (1 << 24) #define AHCI_PORT_INT_IPM (1 << 23) #define AHCI_PORT_INT_PRC (1 << 22) #define AHCI_PORT_INT_DI (1 << 7) #define AHCI_PORT_INT_PC (1 << 6) #define AHCI_PORT_INT_DP (1 << 5) #define AHCI_PORT_INT_UF (1 << 4) #define AHCI_PORT_INT_SDB (1 << 3) #define AHCI_PORT_INT_DS (1 << 2) #define AHCI_PORT_INT_PS (1 << 1) #define AHCI_PORT_INT_DHR (1 << 0) #define AHCI_PORT_INT_ERROR (AHCI_PORT_INT_TFE | AHCI_PORT_INT_HBF | AHCI_PORT_INT_HBD | \ AHCI_PORT_INT_IF | AHCI_PORT_INT_INF | AHCI_PORT_INT_OF | \ AHCI_PORT_INT_IPM | AHCI_PORT_INT_PRC | AHCI_PORT_INT_PC | \ AHCI_PORT_INT_UF) #define AHCI_PORT_INT_MASK (AHCI_PORT_INT_ERROR | AHCI_PORT_INT_DP | AHCI_PORT_INT_SDB | \ AHCI_PORT_INT_DS | AHCI_PORT_INT_PS | AHCI_PORT_INT_DHR) #define AHCI_PORT_CMD_ST (1 << 0) #define AHCI_PORT_CMD_SUD (1 << 1) #define AHCI_PORT_CMD_POD (1 << 2) #define AHCI_PORT_CMD_FRE (1 << 4) #define AHCI_PORT_CMD_FR (1 << 14) #define AHCI_PORT_CMD_CR (1 << 15) #define AHCI_PORT_CMD_ATAPI (1 << 24) #define AHCI_PORT_CMD_ICC_ACTIVE (1 << 28) #define AHCI_PORT_CMD_ICC_MASK (0xf << 28) #define AHCI_PORT_TFD_DATA_REQUEST (1 << 3) #define AHCI_PORT_TFD_BUSY (1 << 7) #define AHCI_PORT_SIG_SATA 0x101 #define AHCI_PORT_SSTS_DET_PRESENT 3 #define AHCI_PORT_SCTL_IPM_ACTIVE (1 << 8) #define AHCI_PORT_SCTL_IPM_PARTIAL (2 << 8) #define AHCI_PORT_SCTL_DET_MASK 0xf #define AHCI_PORT_SCTL_DET_INIT 1 typedef struct { uint32_t clb; // command list base address 1024-byte aligned uint32_t clbu; // command list base address upper 32 bits uint32_t fb; // FIS base address 256-byte aligned uint32_t fbu; // FIS base address upper 32 bits uint32_t is; // interrupt status uint32_t ie; // interrupt enable uint32_t cmd; // command and status uint32_t reserved0; // reserved uint32_t tfd; // task file data uint32_t sig; // signature uint32_t ssts; // SATA status uint32_t sctl; // SATA control uint32_t serr; // SATA error uint32_t sact; // SATA active uint32_t ci; // command issue uint32_t sntf; // SATA notification uint32_t fbs; // FIS-based switching control uint32_t devslp; // device sleep uint32_t reserved1[10]; // reserved uint32_t vendor[4]; // vendor specific } __attribute__((packed)) ahci_port_reg_t; #define AHCI_CAP_NCQ (1 << 30) #define AHCI_GHC_HR (1 << 0) #define AHCI_GHC_IE (1 << 1) #define AHCI_GHC_AE (1 << 31) typedef struct { uint32_t cap; // host capabilities uint32_t ghc; // global host control uint32_t is; // interrupt status uint32_t pi; // ports implemented uint32_t vs; // version uint32_t ccc_ctl; // command completion coalescing control uint32_t ccc_ports; // command completion coalescing ports uint32_t em_loc; // enclosure management location uint32_t em_ctl; // enclosure management control uint32_t cap2; // host capabilities extended uint32_t bohc; // BIOS/OS handoff control and status uint32_t reserved[29]; // reserved uint32_t vendor[24]; // vendor specific registers ahci_port_reg_t ports[32]; // port control registers } __attribute__((packed)) ahci_hba_t; typedef struct { union { struct { uint16_t cfl : 5; // command FIS length uint16_t a : 1; // ATAPI uint16_t w : 1; // write uint16_t p : 1; // prefetchable uint16_t r : 1; // reset uint16_t b : 1; // build in self test uint16_t c : 1; // clear busy upon R_OK uint16_t rsvd : 1; uint16_t pmp : 4; // port multiplier port uint16_t prdtl; // PRDT length } __attribute__((packed)); uint32_t prdtl_flags_cfl; } __attribute__((packed)); uint32_t prdbc; // PRD byte count uint32_t ctba; // command table base address 128-byte aligned uint32_t ctbau; // command table base address upper 32 bits uint32_t reserved[4]; // reserved } __attribute__((packed)) ahci_cl_t; typedef struct { uint8_t dsfis[0x1c]; // DMA setup FIS uint8_t reserved1[0x4]; uint8_t psfis[0x14]; // PIO setup FIS uint8_t reserved2[0x0c]; uint8_t rfis[0x14]; // D2H register FIS uint8_t reserved3[0x4]; uint8_t sdbfis[0x8]; // set device bits FIS uint8_t ufis[0x40]; // unknown FIS uint8_t reserved4[0x60]; } __attribute__((packed)) ahci_fis_t; typedef struct { uint8_t cfis[0x40]; // command FIS uint8_t acmd[0x20]; // ATAPI command uint8_t reserved[0x20]; // reserved } __attribute__((packed)) ahci_ct_t; typedef struct { uint32_t dba; // data base address 2-byte aligned uint32_t dbau; // data base address upper 32 bits uint32_t reserved; // reserved uint32_t dbc; // byte count max 4mb } __attribute__((packed)) ahci_prd_t; static_assert(sizeof(ahci_cl_t) == 0x20, "unexpected command list size"); static_assert(sizeof(ahci_fis_t) == 0x100, "unexpected fis size"); static_assert(sizeof(ahci_ct_t) == 0x80, "unexpected command table header size"); static_assert(sizeof(ahci_prd_t) == 0x10, "unexpected prd entry size");