text: /** @file
    Header file for AHCI mode of ATA host controller.
  
    Copyright (c) 2010 - 2020, Intel Corporation. All rights reserved.<BR>
    SPDX-License-Identifier: BSD-2-Clause-Patent
  
  **/
  
  #ifndef __ATA_HC_AHCI_MODE_H__
  #define __ATA_HC_AHCI_MODE_H__
  
  #define EFI_AHCI_BAR_INDEX  0x05
  
  #define EFI_AHCI_CAPABILITY_OFFSET  0x0000
  #define   EFI_AHCI_CAP_SAM          BIT18
  #define   EFI_AHCI_CAP_SSS          BIT27
  #define   EFI_AHCI_CAP_S64A         BIT31
  #define EFI_AHCI_GHC_OFFSET         0x0004
  #define   EFI_AHCI_GHC_RESET        BIT0
  #define   EFI_AHCI_GHC_IE           BIT1
  #define   EFI_AHCI_GHC_ENABLE       BIT31
  #define EFI_AHCI_IS_OFFSET          0x0008
  #define EFI_AHCI_PI_OFFSET          0x000C
  
  #define EFI_AHCI_MAX_PORTS  32
  
  #define AHCI_CAPABILITY2_OFFSET  0x0024
  #define   AHCI_CAP2_SDS          BIT3
  #define   AHCI_CAP2_SADM         BIT4
  
  typedef struct {
    UINT32    Lower32;
    UINT32    Upper32;
  } DATA_32;
  
  typedef union {
    DATA_32    Uint32;
    UINT64     Uint64;
  } DATA_64;
  
  //
  // Refer SATA1.0a spec section 5.2, the Phy detection time should be less than 10ms.
  // Add a bit of margin for robustness.
  //
  #define  EFI_AHCI_BUS_PHY_DETECT_TIMEOUT  15
  //
  // Refer SATA1.0a spec, the FIS enable time should be less than 500ms.
  //
  #define  EFI_AHCI_PORT_CMD_FR_CLEAR_TIMEOUT  EFI_TIMER_PERIOD_MILLISECONDS(500)
  //
  // Refer SATA1.0a spec, the bus reset time should be less than 1s.
  //
  #define  EFI_AHCI_BUS_RESET_TIMEOUT  EFI_TIMER_PERIOD_SECONDS(1)
  
  #define  EFI_AHCI_ATAPI_DEVICE_SIG     0xEB140000
  #define  EFI_AHCI_ATA_DEVICE_SIG       0x00000000
  #define  EFI_AHCI_PORT_MULTIPLIER_SIG  0x96690000
  #define  EFI_AHCI_ATAPI_SIG_MASK       0xFFFF0000
  
  //
  // Each PRDT entry can point to a memory block up to 4M byte
  //
  #define EFI_AHCI_MAX_DATA_PER_PRDT  0x400000
  
  #define EFI_AHCI_FIS_REGISTER_H2D           0x27         // Register FIS - Host to Device
  #define   EFI_AHCI_FIS_REGISTER_H2D_LENGTH  20
  #define EFI_AHCI_FIS_REGISTER_D2H           0x34         // Register FIS - Device to Host
  #define   EFI_AHCI_FIS_REGISTER_D2H_LENGTH  20
  #define EFI_AHCI_FIS_DMA_ACTIVATE           0x39         // DMA Activate FIS - Device to Host
  #define   EFI_AHCI_FIS_DMA_ACTIVATE_LENGTH  4
  #define EFI_AHCI_FIS_DMA_SETUP              0x41         // DMA Setup FIS - Bi-directional
  #define   EFI_AHCI_FIS_DMA_SETUP_LENGTH     28
  #define EFI_AHCI_FIS_DATA                   0x46         // Data FIS - Bi-directional
  #define EFI_AHCI_FIS_BIST                   0x58         // BIST Activate FIS - Bi-directional
  #define   EFI_AHCI_FIS_BIST_LENGTH          12
  #define EFI_AHCI_FIS_PIO_SETUP              0x5F         // PIO Setup FIS - Device to Host
  #define   EFI_AHCI_FIS_PIO_SETUP_LENGTH     20
  #define EFI_AHCI_FIS_SET_DEVICE             0xA1         // Set Device Bits FIS - Device to Host
  #define   EFI_AHCI_FIS_SET_DEVICE_LENGTH    8
  
  #define EFI_AHCI_D2H_FIS_OFFSET  0x40
  #define EFI_AHCI_DMA_FIS_OFFSET  0x00
  #define EFI_AHCI_PIO_FIS_OFFSET  0x20
  #define EFI_AHCI_SDB_FIS_OFFSET  0x58
  #define EFI_AHCI_FIS_TYPE_MASK   0xFF
  #define EFI_AHCI_U_FIS_OFFSET    0x60
  
  //
  // Port register
  //
  #define EFI_AHCI_PORT_START                  0x0100
  #define EFI_AHCI_PORT_REG_WIDTH              0x0080
  #define EFI_AHCI_PORT_CLB                    0x0000
  #define EFI_AHCI_PORT_CLBU                   0x0004
  #define EFI_AHCI_PORT_FB                     0x0008
  #define EFI_AHCI_PORT_FBU                    0x000C
  #define EFI_AHCI_PORT_IS                     0x0010
  #define   EFI_AHCI_PORT_IS_DHRS              BIT0
  #define   EFI_AHCI_PORT_IS_PSS               BIT1
  #define   EFI_AHCI_PORT_IS_DSS               BIT2
  #define   EFI_AHCI_PORT_IS_SDBS              BIT3
  #define   EFI_AHCI_PORT_IS_UFS               BIT4
  #define   EFI_AHCI_PORT_IS_DPS               BIT5
  #define   EFI_AHCI_PORT_IS_PCS               BIT6
  #define   EFI_AHCI_PORT_IS_DIS               BIT7
  #define   EFI_AHCI_PORT_IS_PRCS              BIT22
  #define   EFI_AHCI_PORT_IS_IPMS              BIT23
  #define   EFI_AHCI_PORT_IS_OFS               BIT24
  #define   EFI_AHCI_PORT_IS_INFS              BIT26
  #define   EFI_AHCI_PORT_IS_IFS               BIT27
  #define   EFI_AHCI_PORT_IS_HBDS              BIT28
  #define   EFI_AHCI_PORT_IS_HBFS              BIT29
  #define   EFI_AHCI_PORT_IS_TFES              BIT30
  #define   EFI_AHCI_PORT_IS_CPDS              BIT31
  #define   EFI_AHCI_PORT_IS_CLEAR             0xFFFFFFFF
  #define   EFI_AHCI_PORT_IS_FIS_CLEAR         0x0000000F
  #define   EFI_AHCI_PORT_IS_ERROR_MASK        (EFI_AHCI_PORT_IS_INFS | EFI_AHCI_PORT_IS_IFS | EFI_AHCI_PORT_IS_HBDS | EFI_AHCI_PORT_IS_HBFS | EFI_AHCI_PORT_IS_TFES)
  #define   EFI_AHCI_PORT_IS_FATAL_ERROR_MASK  (EFI_AHCI_PORT_IS_IFS | EFI_AHCI_PORT_IS_HBDS | EFI_AHCI_PORT_IS_HBFS | EFI_AHCI_PORT_IS_TFES)
  
  #define EFI_AHCI_PORT_IE                  0x0014
  #define EFI_AHCI_PORT_CMD                 0x0018
  #define   EFI_AHCI_PORT_CMD_ST_MASK       0xFFFFFFFE
  #define   EFI_AHCI_PORT_CMD_ST            BIT0
  #define   EFI_AHCI_PORT_CMD_SUD           BIT1
  #define   EFI_AHCI_PORT_CMD_POD           BIT2
  #define   EFI_AHCI_PORT_CMD_CLO           BIT3
  #define   EFI_AHCI_PORT_CMD_FRE           BIT4
  #define   EFI_AHCI_PORT_CMD_CCS_MASK      (BIT8 | BIT9 | BIT10 | BIT11 | BIT12)
  #define   EFI_AHCI_PORT_CMD_CCS_SHIFT     8
  #define   EFI_AHCI_PORT_CMD_FR            BIT14
  #define   EFI_AHCI_PORT_CMD_CR            BIT15
  #define   EFI_AHCI_PORT_CMD_MASK          ~(EFI_AHCI_PORT_CMD_ST | EFI_AHCI_PORT_CMD_FRE | EFI_AHCI_PORT_CMD_COL)
  #define   EFI_AHCI_PORT_CMD_PMA           BIT17
  #define   EFI_AHCI_PORT_CMD_HPCP          BIT18
  #define   EFI_AHCI_PORT_CMD_MPSP          BIT19
  #define   EFI_AHCI_PORT_CMD_CPD           BIT20
  #define   EFI_AHCI_PORT_CMD_ESP           BIT21
  #define   EFI_AHCI_PORT_CMD_ATAPI         BIT24
  #define   EFI_AHCI_PORT_CMD_DLAE          BIT25
  #define   EFI_AHCI_PORT_CMD_ALPE          BIT26
  #define   EFI_AHCI_PORT_CMD_ASP           BIT27
  #define   EFI_AHCI_PORT_CMD_ICC_MASK      (BIT28 | BIT29 | BIT30 | BIT31)
  #define   EFI_AHCI_PORT_CMD_ACTIVE        (1 << 28 )
  #define EFI_AHCI_PORT_TFD                 0x0020
  #define   EFI_AHCI_PORT_TFD_MASK          (BIT7 | BIT3 | BIT0)
  #define   EFI_AHCI_PORT_TFD_BSY           BIT7
  #define   EFI_AHCI_PORT_TFD_DRQ           BIT3
  #define   EFI_AHCI_PORT_TFD_ERR           BIT0
  #define   EFI_AHCI_PORT_TFD_ERR_MASK      0x00FF00
  #define EFI_AHCI_PORT_SIG                 0x0024
  #define EFI_AHCI_PORT_SSTS                0x0028
  #define   EFI_AHCI_PORT_SSTS_DET_MASK     0x000F
  #define   EFI_AHCI_PORT_SSTS_DET          0x0001
  #define   EFI_AHCI_PORT_SSTS_DET_PCE      0x0003
  #define   EFI_AHCI_PORT_SSTS_SPD_MASK     0x00F0
  #define EFI_AHCI_PORT_SCTL                0x002C
  #define   EFI_AHCI_PORT_SCTL_DET_MASK     0x000F
  #define   EFI_AHCI_PORT_SCTL_MASK         (~EFI_AHCI_PORT_SCTL_DET_MASK)
  #define   EFI_AHCI_PORT_SCTL_DET_INIT     0x0001
  #define   EFI_AHCI_PORT_SCTL_DET_PHYCOMM  0x0003
  #define   EFI_AHCI_PORT_SCTL_SPD_MASK     0x00F0
  #define   EFI_AHCI_PORT_SCTL_IPM_MASK     0x0F00
  #define   EFI_AHCI_PORT_SCTL_IPM_INIT     0x0300
  #define   EFI_AHCI_PORT_SCTL_IPM_PSD      0x0100
  #define   EFI_AHCI_PORT_SCTL_IPM_SSD      0x0200
  #define EFI_AHCI_PORT_SERR                0x0030
  #define   EFI_AHCI_PORT_SERR_RDIE         BIT0
  #define   EFI_AHCI_PORT_SERR_RCE          BIT1
  #define   EFI_AHCI_PORT_SERR_TDIE         BIT8
  #define   EFI_AHCI_PORT_SERR_PCDIE        BIT9
  #define   EFI_AHCI_PORT_SERR_PE           BIT10
  #define   EFI_AHCI_PORT_SERR_IE           BIT11
  #define   EFI_AHCI_PORT_SERR_PRC          BIT16
  #define   EFI_AHCI_PORT_SERR_PIE          BIT17
  #define   EFI_AHCI_PORT_SERR_CW           BIT18
  #define   EFI_AHCI_PORT_SERR_BDE          BIT19
  #define   EFI_AHCI_PORT_SERR_DE           BIT20
  #define   EFI_AHCI_PORT_SERR_CRCE         BIT21
  #define   EFI_AHCI_PORT_SERR_HE           BIT22
  #define   EFI_AHCI_PORT_SERR_LSE          BIT23
  #define   EFI_AHCI_PORT_SERR_TSTE         BIT24
  #define   EFI_AHCI_PORT_SERR_UFT          BIT25
  #define   EFI_AHCI_PORT_SERR_EX           BIT26
  #define   EFI_AHCI_PORT_ERR_CLEAR         0xFFFFFFFF
  #define EFI_AHCI_PORT_SACT                0x0034
  #define EFI_AHCI_PORT_CI                  0x0038
  #define EFI_AHCI_PORT_SNTF                0x003C
  #define AHCI_PORT_DEVSLP                  0x0044
  #define   AHCI_PORT_DEVSLP_ADSE           BIT0
  #define   AHCI_PORT_DEVSLP_DSP            BIT1
  #define   AHCI_PORT_DEVSLP_DETO_MASK      0x000003FC
  #define   AHCI_PORT_DEVSLP_MDAT_MASK      0x00007C00
  #define   AHCI_PORT_DEVSLP_DITO_MASK      0x01FF8000
  #define   AHCI_PORT_DEVSLP_DM_MASK        0x1E000000
  
  #define AHCI_COMMAND_RETRIES  5
  
  #pragma pack(1)
  //
  // Command List structure includes total 32 entries.
  // The entry data structure is listed at the following.
  //
  typedef struct {
    UINT32    AhciCmdCfl   : 5; // Command FIS Length
    UINT32    AhciCmdA     : 1; // ATAPI
    UINT32    AhciCmdW     : 1; // Write
    UINT32    AhciCmdP     : 1; // Prefetchable
    UINT32    AhciCmdR     : 1; // Reset
    UINT32    AhciCmdB     : 1; // BIST
    UINT32    AhciCmdC     : 1; // Clear Busy upon R_OK
    UINT32    AhciCmdRsvd  : 1;
    UINT32    AhciCmdPmp   : 4;  // Port Multiplier Port
    UINT32    AhciCmdPrdtl : 16; // Physical Region Descriptor Table Length
    UINT32    AhciCmdPrdbc;      // Physical Region Descriptor Byte Count
    UINT32    AhciCmdCtba;       // Command Table Descriptor Base Address
    UINT32    AhciCmdCtbau;      // Command Table Descriptor Base Address Upper 32-BITs
    UINT32    AhciCmdRsvd1[4];
  } EFI_AHCI_COMMAND_LIST;
  
  //
  // This is a software constructed FIS.
  // For data transfer operations, this is the H2D Register FIS format as
  // specified in the Serial ATA Revision 2.6 specification.
  //
  typedef struct {
    UINT8    AhciCFisType;
    UINT8    AhciCFisPmNum  : 4;
    UINT8    AhciCFisRsvd   : 1;
    UINT8    AhciCFisRsvd1  : 1;
    UINT8    AhciCFisRsvd2  : 1;
    UINT8    AhciCFisCmdInd : 1;
    UINT8    AhciCFisCmd;
    UINT8    AhciCFisFeature;
    UINT8    AhciCFisSecNum;
    UINT8    AhciCFisClyLow;
    UINT8    AhciCFisClyHigh;
    UINT8    AhciCFisDevHead;
    UINT8    AhciCFisSecNumExp;
    UINT8    AhciCFisClyLowExp;
    UINT8    AhciCFisClyHighExp;
    UINT8    AhciCFisFeatureExp;
    UINT8    AhciCFisSecCount;
    UINT8    AhciCFisSecCountExp;
    UINT8    AhciCFisRsvd3;
    UINT8    AhciCFisControl;
    UINT8    AhciCFisRsvd4[4];
    UINT8    AhciCFisRsvd5[44];
  } EFI_AHCI_COMMAND_FIS;
  
  typedef enum {
    SataFisD2H = 0,
    SataFisPioSetup,
    SataFisDmaSetup
  } SATA_FIS_TYPE;
  
  //
  // ACMD: ATAPI command (12 or 16 bytes)
  //
  typedef struct {
    UINT8    AtapiCmd[0x10];
  } EFI_AHCI_ATAPI_COMMAND;
  
  //
  // Physical Region Descriptor Table includes up to 65535 entries
  // The entry data structure is listed at the following.
  // the actual entry number comes from the PRDTL field in the command
  // list entry for this command slot.
  //
  typedef struct {
    UINT32    AhciPrdtDba;      // Data Base Address
    UINT32    AhciPrdtDbau;     // Data Base Address Upper 32-BITs
    UINT32    AhciPrdtRsvd;
    UINT32    AhciPrdtDbc   : 22; // Data Byte Count
    UINT32    AhciPrdtRsvd1 : 9;
    UINT32    AhciPrdtIoc   : 1; // Interrupt on Completion
  } EFI_AHCI_COMMAND_PRDT;
  
  //
  // Command table data structure which is pointed to by the entry in the command list
  //
  typedef struct {
    EFI_AHCI_COMMAND_FIS      CommandFis;       // A software constructed FIS.
    EFI_AHCI_ATAPI_COMMAND    AtapiCmd;         // 12 or 16 bytes ATAPI cmd.
    UINT8                     Reserved[0x30];
    EFI_AHCI_COMMAND_PRDT     PrdtTable[65535];     // The scatter/gather list for data transfer
  } EFI_AHCI_COMMAND_TABLE;
  
  //
  // Received FIS structure
  //
  typedef struct {
    UINT8     AhciDmaSetupFis[0x1C];        // Dma Setup Fis: offset 0x00
    UINT8     AhciDmaSetupFisRsvd[0x04];
    UINT8     AhciPioSetupFis[0x14];        // Pio Setup Fis: offset 0x20
    UINT8     AhciPioSetupFisRsvd[0x0C];
    UINT8     AhciD2HRegisterFis[0x14];     // D2H Register Fis: offset 0x40
    UINT8     AhciD2HRegisterFisRsvd[0x04];
    UINT64    AhciSetDeviceBitsFis;         // Set Device Bits Fix: offset 0x58
    UINT8     AhciUnknownFis[0x40];         // Unknown Fis: offset 0x60
    UINT8     AhciUnknownFisRsvd[0x60];
  } EFI_AHCI_RECEIVED_FIS;
  
  typedef struct {
    UINT8     Madt        : 5;
    UINT8     Reserved_5  : 3;
    UINT8     Deto;
    UINT16    Reserved_16;
    UINT32    Reserved_32 : 31;
    UINT32    Supported   : 1;
  } DEVSLP_TIMING_VARIABLES;
  
  #pragma pack()
  
  typedef struct {
    EFI_AHCI_RECEIVED_FIS     *AhciRFis;
    EFI_AHCI_COMMAND_LIST     *AhciCmdList;
    EFI_AHCI_COMMAND_TABLE    *AhciCommandTable;
    EFI_AHCI_RECEIVED_FIS     *AhciRFisPciAddr;
    EFI_AHCI_COMMAND_LIST     *AhciCmdListPciAddr;
    EFI_AHCI_COMMAND_TABLE    *AhciCommandTablePciAddr;
    UINT64                    MaxCommandListSize;
    UINT64                    MaxCommandTableSize;
    UINT64                    MaxReceiveFisSize;
    VOID                      *MapRFis;
    VOID                      *MapCmdList;
    VOID                      *MapCommandTable;
  } EFI_AHCI_REGISTERS;
  
  /**
    This function is used to send out ATAPI commands conforms to the Packet Command
    with PIO Protocol.
  
    @param PciIo              The PCI IO protocol instance.
    @param AhciRegisters      The pointer to the EFI_AHCI_REGISTERS.
    @param Port               The number of port.
    @param PortMultiplier     The number of port multiplier.
    @param Packet             A pointer to EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET structure.
  
    @retval EFI_SUCCESS       send out the ATAPI packet command successfully
                              and device sends data successfully.
    @retval EFI_DEVICE_ERROR  the device failed to send data.
  
  **/
  EFI_STATUS
  EFIAPI
  AhciPacketCommandExecute (
    IN  EFI_PCI_IO_PROTOCOL                         *PciIo,
    IN  EFI_AHCI_REGISTERS                          *AhciRegisters,
    IN  UINT8                                       Port,
    IN  UINT8                                       PortMultiplier,
    IN  EFI_EXT_SCSI_PASS_THRU_SCSI_REQUEST_PACKET  *Packet
    );
  
  /**
    Start command for give slot on specific port.
  
    @param  PciIo              The PCI IO protocol instance.
    @param  Port               The number of port.
    @param  CommandSlot        The number of CommandSlot.
    @param  Timeout            The timeout value of start, uses 100ns as a unit.
  
    @retval EFI_DEVICE_ERROR   The command start unsuccessfully.
    @retval EFI_TIMEOUT        The operation is time out.
    @retval EFI_SUCCESS        The command start successfully.
  
  **/
  EFI_STATUS
  EFIAPI
  AhciStartCommand (
    IN  EFI_PCI_IO_PROTOCOL  *PciIo,
    IN  UINT8                Port,
    IN  UINT8                CommandSlot,
    IN  UINT64               Timeout
    );
  
  /**
    Stop command running for giving port
  
    @param  PciIo              The PCI IO protocol instance.
    @param  Port               The number of port.
    @param  Timeout            The timeout value of stop, uses 100ns as a unit.
  
    @retval EFI_DEVICE_ERROR   The command stop unsuccessfully.
    @retval EFI_TIMEOUT        The operation is time out.
    @retval EFI_SUCCESS        The command stop successfully.
  
  **/
  EFI_STATUS
  EFIAPI
  AhciStopCommand (
    IN  EFI_PCI_IO_PROTOCOL  *PciIo,
    IN  UINT8                Port,
    IN  UINT64               Timeout
    );
  
  #endif
  