/*
 * Copyright (c) 2012 Petr Jerman
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * - The name of the author may not be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/** @file
 * Header for AHCI driver (AHCI 1.3 specification).
 */

#ifndef __AHCI_HW_H__
#define __AHCI_HW_H__

#include <stdint.h>

/*----------------------------------------------------------------------------*/
/*-- AHCI standard constants -------------------------------------------------*/
/*----------------------------------------------------------------------------*/

/** AHCI standard 1.3 - maximum ports. */
#define AHCI_MAX_PORTS  32

/*----------------------------------------------------------------------------*/
/*-- AHCI PCI Registers ------------------------------------------------------*/
/*----------------------------------------------------------------------------*/

/** AHCI PCI register Identifiers offset. */
#define AHCI_PCI_ID     0x00
/** AHCI PCI register Command offset. */
#define AHCI_PCI_CMD    0x04
/** AHCI PCI register Device Status offset. */
#define AHCI_PCI_STS    0x06
/** AHCI PCI register Revision ID offset. */
#define AHCI_PCI_RID    0x08
/** AHCI PCI register Class Codes offset. */
#define AHCI_PCI_CC     0x09
/** AHCI PCI register Cache Line Size offset. */
#define AHCI_PCI_CLS    0x0C
/** AHCI PCI register Master Latency Timer offset. */
#define AHCI_PCI_MLT    0x0D
/** AHCI PCI register Header Type offset. */
#define AHCI_PCI_HTYPE  0x0E
/** AHCI PCI register Built In Self Test (Optional) offset. */
#define AHCI_PCI_BIST   0x0F
/** AHCI PCI register Other Base Address Registres (Optional). */
#define AHCI_PCI_BAR0   0x10
/** AHCI PCI register Other Base Address Registres (Optional). */
#define AHCI_PCI_BAR1   0x14
/** AHCI PCI register Other Base Address Registres (Optional). */
#define AHCI_PCI_BAR2   0x18
/** AHCI PCI register Other Base Address Registres (Optional). */
#define AHCI_PCI_BAR3   0x1C
/** AHCI PCI register Other Base Address Registres (Optional). */
#define AHCI_PCI_BAR4   0x20
/** AHCI PCI register AHCI Base Address offset. */
#define AHCI_PCI_ABAR   0x24
/** AHCI PCI register Subsystem Identifiers offset. */
#define AHCI_PCI_SS     0x2C
/** AHCI PCI register Expansion ROM Base Address (Optional) offset. */
#define AHCI_PCI_EROM   0x30
/** AHCI PCI register Capabilities Pointer offset. */
#define AHCI_PCI_CAP    0x34
/** AHCI PCI register Interrupt Information offset. */
#define AHCI_PCI_INTR   0x3C
/** AHCI PCI register Min Grant (Optional) offset. */
#define AHCI_PCI_MGNT   0x3E
/** AHCI PCI register Max Latency (Optional) offset. */
#define AHCI_PCI_MLAT   0x3F

/** AHCI PCI register Identifiers. */
typedef struct {
	/** Indicates the company vendor assigned by the PCI SIG. */
	uint16_t vendorid;
	/** Indicates what device number assigned by the vendor */
	uint16_t deviceid;
} ahci_pcireg_id_t;

/** AHCI PCI register Command. */
typedef union {
	struct {
		/** I/O Space Enable. */
		unsigned int iose : 1;
		/** Memory Space Enable. */
		unsigned int mse : 1;
		/** Bus Master Enable. */
		unsigned int bme : 1;
		/** Special Cycle Enable. */
		unsigned int sce : 1;
		/** Memory Write and Invalidate Enable. */
		unsigned int mwie : 1;
		/** VGA Palette Snooping Enable. */
		unsigned int vga : 1;
		/** Parity Error Response Enable. */
		unsigned int pee : 1;
		/** Wait Cycle Enable. */
		unsigned int wcc : 1;
		/** SERR# Enable. */
		unsigned int see : 1;
		/** Fast Back-to-Back Enable. */
		unsigned int fbe : 1;
		/** Interrupt Disable - disables the HBA from generating interrupts.
		 * This bit does not have any effect on MSI operation.
		 */
		unsigned int id : 1;
		/** Reserved. */
		unsigned int reserved : 5;
	};
	uint16_t u16;
} ahci_pcireg_cmd_t;

/** AHCI PCI register Command - Interrupt Disable bit. */
#define AHCI_PCIREG_CMD_ID  0x0400

/** AHCI PCI register Command - Bus Master Enable bit. */
#define AHCI_PCIREG_CMD_BME  0x0004

/** AHCI PCI register Device status. */
typedef union {
	struct {
		/** Reserved. */
		unsigned int reserved1 : 3;
		/** Indicate the interrupt status of the device (1 = asserted). */
		unsigned int is : 1;
		/** Indicates presence of capatibility list. */
		unsigned int cl : 1;
		/** 66 Mhz capable. */
		unsigned int c66 : 1;
		/** Reserved. */
		unsigned int reserved2 : 1;
		/** Fast back to back capable. */
		unsigned int fbc : 1;
		/** Master data parity error detected. */
		unsigned int dpd : 1;
		/** Device select timing. */
		unsigned int devt : 2;
		/** Signaled target abort. */
		unsigned int sta : 1;
		/** Received target abort. */
		unsigned int rta : 1;
		/** Received master abort. */
		unsigned int rma : 1;
		/** Signaled system error. */
		unsigned int sse : 1;
		/** Detected parity error. */
		unsigned int dpe : 1;
	};
	uint16_t u16;
} ahci_pcireg_sts_t;

/** AHCI PCI register Revision ID. */
typedef struct {
	/** Indicates stepping of the HBA hardware. */
	uint8_t u8;
} ahci_pcireg_rid_t;

/** AHCI PCI register Class Codes. */
typedef struct {
	/** Programing interface, when set to 01h and the scc is set to 06h,
	 * indicates that this an AHCI HBA major revision 1.
	 */
	uint8_t pi;
	/** When set to 06h, indicates that is a SATA device. */
	uint8_t scc;
	/** Value 01 indicates that is a mass storage device. */
	uint8_t bcc;
} ahci_pcireg_cc_t_t;

/** AHCI PCI register Cache Line Size. */
typedef struct {
	/** Cache line size for use with the memory write and invalidate command. */
	uint8_t u8;
} ahci_pcireg_cls_t;

/** AHCI PCI register Master Latency Timer. */
typedef struct {
	/** Master latency timer,indicates the number of clocks the HBA is allowed
	 * to acts as master on PCI.
	 */
	uint8_t u8;
} ahci_pcireg_mlt_t;

/** AHCI PCI register Header Type. */
typedef union {
	struct {
		/** Header layout. */
		unsigned int hl : 7;
		/** Multi function device flag. */
		unsigned int mfd : 1;
	};
	uint8_t u8;
} ahci_pciregs_htype_t;

/** AHCI PCI register Built in self test. */
typedef union {
	struct {
	/** Indicates the completion status of BIST
	 * non-zero value indicates a failure.
	 */
	unsigned int cc : 4;
	/** Reserved. */
	unsigned int reserved : 2;
	/** Software sets this bit to 1 to invoke BIST,
	 * the HBA clears this bit to 0 when BIST is complete.
	 */
	unsigned int sb : 1;
	/** BIST capable. */
	unsigned int bc : 1;
	};
	uint8_t u8;
} ahci_pciregs_bist_t;

/** AHCI PCI register AHCI Base Address <BAR 5>. */
typedef union {
	struct {
		/** Indicates a request for register memory space. */
		unsigned int rte : 1;
		/** Indicates the this range can be mapped anywhere in 32-bit address
		 * space.
		 */
		unsigned int tp : 2;
		/** Indicate that this range is not prefetchable. */
		unsigned int pf : 1;
		/** Reserved. */
		unsigned int reserved : 9;
		/** Base address of registry memory space. */
		unsigned int ba : 19;
	};
	uint32_t u32;
} ahci_pciregs_abar_t;

/** AHCI PCI register Subsystem Identifiers. */
typedef struct
{
	/** Sub system vendor identifier. */
	uint8_t ssvid;
	/** Sub system identifier. */
	uint8_t ssid;
} ahci_pcireg_ss_t;

/** AHCI PCI registers Expansion ROM Base Address. */
typedef struct
{
	/** Indicates the base address of the HBA expansion ROM. */
	uint32_t u32;
} ahci_pcireg_erom_t;

/** AHCI PCI register Capabilities Pointer. */
typedef struct
{
	/** Indicates the first capability pointer offset. */
	uint8_t u8;
} ahci_pcireg_cap_t;

/** AHCI PCI register Interrupt Information. */
typedef struct
{
	/* Software written value to indicate which interrupt vector
	 * the interrupt is connected to.
	 */
	uint8_t iline;
	/** This indicates the interrupt pin the HBA uses. */
	uint8_t ipin;
} ahci_pcireg_intr;

/** AHCI PCI register Min Grant (Optional). */
typedef struct
{
	/** Indicates the minimum grant time that the device
	 * wishes grant asserted.
	 */
	uint8_t u8;
} ahci_pcireg_mgnt_t;

/** AHCI PCI register Max Latency (Optional). */
typedef struct
{
	/** Indicates the maximum latency that the device can withstand. */
	uint8_t u8;
} ahci_pcireg_mlat_t;

/*----------------------------------------------------------------------------*/
/*-- AHCI Memory Registers ---------------------------------------------------*/
/*----------------------------------------------------------------------------*/

/** Number of pages for ahci memory registers. */
#define AHCI_MEMREGS_PAGES_COUNT  8

/** AHCI Memory register Generic Host Control - HBA Capabilities. */
typedef union {
	struct {
		/** Number of Ports. */
		unsigned int np : 5;
		/** Supports External SATA. */
		unsigned int sxs : 1;
		/** Enclosure Management Supported. */
		unsigned int ems : 1;
		/** Command Completion Coalescing Supported. */
		unsigned int cccs : 1;
		/** Number of Command Slots. */
		unsigned int ncs : 5;
		/** Partial State Capable. */
		unsigned int psc : 1;
		/** Slumber State Capable. */
		unsigned int ssc : 1;
		/** PIO Multiple DRQ Block. */
		unsigned int pmd : 1;
		/** FIS-based Switching Supported. */
		unsigned int fbss : 1;
		/** Supports Port Multiplier. */
		unsigned int spm : 1;
		/** Supports AHCI mode only. */
		unsigned int sam : 1;
		/** Reserved. */
		unsigned int reserved : 1;
		/** Interface Speed Support. */
		unsigned int iss : 4;
		/** Supports Command List Override. */
		unsigned int sclo : 1;
		/** Supports Activity LED. */
		unsigned int sal : 1;
		/** Supports Aggressive Link Power Management. */
		unsigned int salp : 1;
		/** Supports Staggered Spin-up. */
		unsigned int sss : 1;
		/** Supports Mechanical Presence Switch. */
		unsigned int smps : 1;
		/** Supports SNotification Register. */
		unsigned int ssntf : 1;
		/** Supports Native Command Queuing. */
		unsigned int sncq : 1;
		/** Supports 64-bit Addressing. */
		unsigned int s64a : 1;
	};
	uint32_t u32;
} ahci_ghc_cap_t;

/** AHCI Memory register Generic Host Control Global Host Control. */
typedef union {
	struct {
		/** HBA Reset. */
		unsigned int hr : 1;
		/** Interrupt Enable. */
		unsigned int ie : 1;
		/** MSI Revert to Single Message. */
		unsigned int mrsm : 1;
		/** Reserved. */
		unsigned int reserved : 28;
		/** AHCI Enable. */
		unsigned int ae : 1;
	};
	uint32_t u32;
} ahci_ghc_ghc_t;

/** AHCI Enable mask bit. */
#define AHCI_GHC_GHC_AE  0x80000000

/** AHCI Interrupt Enable mask bit. */
#define AHCI_GHC_GHC_IE  0x00000002

/** AHCI Memory register Interrupt pending register. */
typedef uint32_t ahci_ghc_is_t;

/** AHCI GHC register offset. */
#define AHCI_GHC_IS_REGISTER_OFFSET  2

/** AHCI ports registers offset. */
#define AHCI_PORTS_REGISTERS_OFFSET  64

/** AHCI port registers size. */
#define AHCI_PORT_REGISTERS_SIZE  32

/** AHCI port IS register offset. */
#define AHCI_PORT_IS_REGISTER_OFFSET  4

/** AHCI Memory register Ports implemented. */
typedef struct {
	/** If a bit is set to 1, the corresponding port
	 * is available for software use.
	 */
	uint32_t u32;
} ahci_ghc_pi_t;

/** AHCI Memory register AHCI version. */
typedef struct {
	/** Indicates the minor version */
	uint16_t mnr;
	/** Indicates the major version */
	uint16_t mjr;
} ahci_ghc_vs_t;

/** AHCI Memory register Command completion coalesce control. */
typedef union {
	struct {
		/** Enable CCC features. */
		unsigned int en : 1;
		/** Reserved. */
		unsigned int reserved : 2;
		/** Interrupt number for CCC. */
		unsigned int intr : 5;
		/** Number of command completions that are necessary to cause
		 * a CCC interrupt.
		 */
		uint8_t cc;
		/** Timeout value in  ms. */
		uint16_t tv;
	};
	uint32_t u32;
} ahci_ghc_ccc_ctl_t;

/** AHCI Memory register Command completion coalescing ports. */
typedef struct
{
	/** If a bit is set to 1, the corresponding port is
	 * part of the command completion coalescing feature.
	 */
	uint32_t u32;
} ahci_ghc_ccc_ports_t;

/** AHCI Memory register Enclosure management location. */
typedef struct
{
	/** Size of the transmit message buffer area in dwords. */
	uint16_t sz;
	/*
	 * Offset of the transmit message buffer area in dwords
	 * from the beginning of ABAR
	 */
	uint16_t ofst;
} ahci_ghc_em_loc;

/** AHCI Memory register Enclosure management control. */
typedef union {
	struct {
		/** Message received. */
		unsigned int mr : 1;
		/** Reserved. */
		unsigned int reserved : 7;
		/** Transmit message. */
		unsigned int tm : 1;
		/** Reset. */
		unsigned int rst : 1;
		/** Reserved. */
		unsigned int reserved2 : 6;
		/** LED message types. */
		unsigned int led : 1;
		/** Support SAFT-TE message type. */
		unsigned int safte : 1;
		/** Support SES-2 message type. */
		unsigned int ses2 : 1;
		/** Support SGPIO register. */
		unsigned int sgpio : 1;
		/** Reserved. */
		unsigned int reserved3 : 4;
		/** Single message buffer. */
		unsigned int smb : 1;
		/**  Support transmitting only. */
		unsigned int xmt : 1;
		/** Activity LED hardware driven. */
		unsigned int alhd : 1;
		/** Port multiplier support. */
		unsigned int pm : 1;
		/** Reserved. */
		unsigned int reserved4 : 4;
	};
	uint32_t u32;
} ahci_ghc_em_ctl_t;

/** AHCI Memory register HBA capatibilities extended. */
typedef union {
	struct {
		/** HBA support BIOS/OS handoff mechanism,
		 * implemented BOHC register.
		 */
		unsigned int boh : 1;
		/** Support for NVMHCI register. */
		unsigned int nvmp : 1;
		/** Automatic partial to slumber transition support. */
		unsigned int apst : 1;
		/** Reserved. */
		unsigned int reserved : 29;
	};
	uint32_t u32;
} ahci_ghc_cap2_t;

/** AHCI Memory register BIOS/OS Handoff control and status. */
typedef union {
	struct {
		/** BIOS Owned semaphore. */
		unsigned int bos : 1;
		/** OS Owned semaphore. */
		unsigned int oos : 1;
		/** SMI on OS ownership change enable. */
		unsigned int sooe : 1;
		/** OS ownership change. */
		unsigned int ooc : 1;
		/** BIOS Busy. */
		unsigned int bb : 1;
		/** Reserved. */
		unsigned int reserved : 27;
	};
	uint32_t u32;
} ahci_ghc_bohc_t;

/** AHCI Memory register Generic Host Control. */
typedef struct
{
	/** Host Capabilities */
	uint32_t cap;
	/** Global Host Control */
	uint32_t ghc;
	/** Interrupt Status */
	ahci_ghc_is_t is;
	/** Ports Implemented */
	uint32_t pi;
	/** Version */
	uint32_t vs;
	/** Command Completion Coalescing Control */
	uint32_t ccc_ctl;
	/** Command Completion Coalescing Ports */
	uint32_t ccc_ports;
	/** Enclosure Management Location */
	uint32_t em_loc;
	/** Enclosure Management Control */
	uint32_t em_ctl;
	/** Host Capabilities Extended */
	uint32_t cap2;
	/** BIOS/OS Handoff Control and Status */
	uint32_t bohc;
} ahci_ghc_t;

/** AHCI Memory register Port x Command List Base Address. */
typedef union {
	struct {
		/** Reserved. */
		unsigned int reserved : 10;
		/** Command List Base Address (CLB) - Indicates the 32-bit base physical
		 * address for the command list for this port. This base is used when
		 * fetching commands to execute. The structure pointed to by this
		 * address range is 1K-bytes in length. This address must be 1K-byte
		 * aligned as indicated by bits 09:00 being read only.
		 */
		unsigned int clb : 22;
	};
	uint32_t u32;
} ahci_port_clb_t;

/** AHCI Memory register Port x Command List Base Address Upper 32-Bits. */
typedef struct {
	/** Command List Base Address Upper (CLBU): Indicates the upper 32-bits
	 * for the command list base physical address for this port. This base
	 * is used when fetching commands to execute. This register shall
	 * be read only for HBAs that do not support 64-bit addressing.
	 */
	uint32_t u32;
} ahci_port_clbu_t;

/** AHCI Memory register Port x FIS Base Address. */
typedef union {
	struct {
		/** Reserved. */
		unsigned int reserved : 8;
		/** FIS Base Address (FB) - Indicates the 32-bit base physical address
		 * for received FISes. The structure pointed to by this address range
		 * is 256 bytes in length. This address must be 256-byte aligned as
		 * indicated by bits 07:00 being read only. When FIS-based switching
		 * is in use, this structure is 4KB in length and the address shall be
		 * 4KB aligned.
		 */
		unsigned int fb : 24;
	};
	uint32_t u32;
} ahci_port_fb_t;

/** AHCI Memory register Port x FIS Base Address Upper 32-Bits. */
typedef struct {
	/** FIS Base Address Upper (FBU) - Indicates the upper 32-bits
	 * for the received FIS base physical address for this port. This register
	 * shall be read only for HBAs that do not support 64-bit addressing.
	 */
	uint32_t u32;
} ahci_port_fbu_t;

/** AHCI Memory register Port x Interrupt Status. */
typedef uint32_t ahci_port_is_t;

#define AHCI_PORT_IS_DHRS  (1 << 0)
#define AHCI_PORT_IS_PSS   (1 << 1)
#define AHCI_PORT_IS_DSS   (1 << 2)
#define AHCI_PORT_IS_SDBS  (1 << 3)
#define AHCI_PORT_IS_UFS   (1 << 4)
#define AHCI_PORT_IS_DPS   (1 << 5)
#define AHCI_PORT_IS_PCS   (1 << 6)
#define AHCI_PORT_IS_DMPS  (1 << 7)

#define AHCI_PORT_IS_PRCS  (1 << 22)
#define AHCI_PORT_IS_IPMS  (1 << 23)
#define AHCI_PORT_IS_OFS   (1 << 24)
#define AHCI_PORT_IS_INFS  (1 << 26)
#define AHCI_PORT_IS_IFS   (1 << 27)
#define AHCI_PORT_IS_HDBS  (1 << 28)
#define AHCI_PORT_IS_HBFS  (1 << 29)
#define AHCI_PORT_IS_TFES  (1 << 30)
#define AHCI_PORT_IS_CPDS  (1 << 31)

#define AHCI_PORT_END_OF_OPERATION \
	(AHCI_PORT_IS_DHRS | \
	AHCI_PORT_IS_SDBS )

#define AHCI_PORT_IS_ERROR \
	(AHCI_PORT_IS_UFS | \
	AHCI_PORT_IS_PCS | \
	AHCI_PORT_IS_DMPS | \
	AHCI_PORT_IS_PRCS | \
	AHCI_PORT_IS_IPMS | \
	AHCI_PORT_IS_OFS | \
	AHCI_PORT_IS_INFS | \
	AHCI_PORT_IS_IFS | \
	AHCI_PORT_IS_HDBS | \
	AHCI_PORT_IS_HBFS | \
	AHCI_PORT_IS_TFES | \
	AHCI_PORT_IS_CPDS)

#define AHCI_PORT_IS_PERMANENT_ERROR \
	(AHCI_PORT_IS_PCS | \
	AHCI_PORT_IS_DMPS | \
	AHCI_PORT_IS_PRCS | \
	AHCI_PORT_IS_IPMS | \
	AHCI_PORT_IS_CPDS )

/** Evaluate end of operation status from port interrupt status.
 *
 * @param port_is Value of port interrupt status.
 *
 * @return Indicate end of operation status.
 *
 */
static inline int ahci_port_is_end_of_operation(ahci_port_is_t port_is)
{
	return port_is & AHCI_PORT_END_OF_OPERATION;
}

/** Evaluate error status from port interrupt status.
 *
 * @param port_is Value of port interrupt status.
 *
 * @return Indicate error status.
 *
 */
static inline int ahci_port_is_error(ahci_port_is_t port_is)
{
	return port_is & AHCI_PORT_IS_ERROR;
}

/** Evaluate permanent error status from port interrupt status.
 *
 * @param port_is Value of port interrupt status.
 *
 * @return Indicate permanent error status.
 *
 */
static inline int ahci_port_is_permanent_error(ahci_port_is_t port_is)
{
	return port_is & AHCI_PORT_IS_PERMANENT_ERROR;
}

/** Evaluate task file error status from port interrupt status.
 *
 * @param port_is Value of port interrupt status.
 *
 * @return Indicate error status.
 *
 */
static inline int ahci_port_is_tfes(ahci_port_is_t port_is)
{
	return port_is & AHCI_PORT_IS_TFES;
}

/** AHCI Memory register Port x Interrupt Enable. */
typedef union {
	struct {
		/** Device to Host Register FIS Interrupt Enable. */
		unsigned int dhre : 1;
		/** PIO Setup FIS Interrupt Enable. */
		unsigned int pse : 1;
		/** DMA Setup FIS Interrupt Enable. */
		unsigned int dse : 1;
		/** Set Device Bits Interrupt Eenable. */
		unsigned int sdbe : 1;
		/** Unknown FIS Interrupt Enable. */
		unsigned int ufe : 1;
		/** Descriptor Processed Interrupt Enable. */
		unsigned int dpe : 1;
		/** Port Change Interrupt Enable. */
		unsigned int pce : 1;
		/** Device Mechanical Presence Enable. */
		unsigned int dmpe : 1;
		/** Reserved. */
		unsigned int reserved1 : 14;
		/** PhyRdy Change Interrupt Enable. */
		unsigned int prce : 1;
		/** Incorrect Port Multiplier Enable. */
		unsigned int ipme : 1;
		/** Overflow Status Enable. */
		unsigned int ofe : 1;
		/** Reserved. */
		unsigned int reserved2 : 1;
		/** Interface Non-fatal Error Enable. */
		unsigned int infe : 1;
		/** Interface Fatal Error Enable. */
		unsigned int ife : 1;
		/** Host Bus Data Error Enable. */
		unsigned int hbde : 1;
		/** Host Bus Fatal Error Enable. */
		unsigned int hbfe : 1;
		/** Task File Error Enable. */
		unsigned int tfee : 1;
		/** Cold Port Detect Enable. */
		unsigned int cpde : 1;
	};
	uint32_t u32;
} ahci_port_ie_t;

/** AHCI Memory register Port x Command and Status. */
typedef union {
	struct {
		/** Start - when set, the HBA may process the command list. */
		unsigned int st : 1;
		/** Spin-Up Device. */
		unsigned int sud : 1;
		/** Power On Device. */
		unsigned int pod : 1;
		/** Command List Override. */
		unsigned int clo : 1;
		/** FIS Receive Enable. */
		unsigned int fre : 1;
		/** Reserved. */
		unsigned int reserved : 3;
		/** Current Command Slot. */
		unsigned int ccs : 5;
		/** Mechanical Presence Switch State. */
		unsigned int mpss : 1;
		/** FIS Receive Running. */
		unsigned int fr : 1;
		/** Command List Running. */
		unsigned int cr : 1;
		/** Cold Presence State. */
		unsigned int cps : 1;
		/** Port Multiplier Attached. */
		unsigned int pma : 1;
		/** Hot Plug Capable Port. */
		unsigned int hpcp : 1;
		/** Mechanical Presence Switch Attached to Port. */
		unsigned int mpsp : 1;
		/** Cold Presence Detection. */
		unsigned int cpd : 1;
		/** External SATA Port. */
		unsigned int esp : 1;
		/** FIS-based Switching Capable Port. */
		unsigned int fbscp : 1;
		/** Automatic Partial to Slumber Transitions Enabled. */
		unsigned int apste : 1;
		/** Device is ATAPI. */
		unsigned int atapi : 1;
		/** Drive LED on ATAPI Enable. */
		unsigned int dlae : 1;
		/** Aggressive Link Power Management Enable. */
		unsigned int alpe : 1;
		/** Aggressive Slumber / Partial. */
		unsigned int asp : 1;
		/** Interface Communication Control.
		 * Values:
		 * 7h - fh Reserved,
		 * 6h Slumber - This shall cause the HBA to request a transition
		 * of the interface to the Slumber state,
		 * 3h - 5h Reserved,
		 * 2h Partial - This shall cause the HBA to request a transition
		 * of the interface to the Partial state,
		 * 1h Active,
		 * 0h No-Op / Idle.
		 */
		unsigned int icc : 4;
	};
	uint32_t u32;
} ahci_port_cmd_t;

/** AHCI Memory register Port x Task File Data. */
typedef union {
	struct {
		/** Status (STS): Contains the latest copy of the task file
		 * status register.
		 */
		uint8_t sts;
		/** Error (ERR) - Contains the latest copy of the task file
		 * error register.
		 */
		uint8_t err;
		/** Reserved. */
		uint16_t reserved;
	};
	uint32_t u32;
} ahci_port_tfd_t;

/** AHCI Memory register Port x Signature. */
typedef union {
	struct {
		/** Sector Count Register */
		uint8_t sector_count;
		/** LBA Low Register */
		uint8_t lba_lr;
		/** LBA Mid Register */
		uint8_t lba_mr;
		/** LBA High Register */
		uint8_t lba_hr;
	};
	uint32_t u32;
} ahci_port_sig_t;

/** AHCI Memory register Port x Serial ATA Status (SCR0: SStatus). */
typedef union {
	struct {
		/** Device Detection */
		unsigned int det : 4;
		/** Current Interface Speed */
		unsigned int spd : 4;
		/** Interface Power Management */
		unsigned int ipm : 4;
		/** Reserved. */
		unsigned int reserved : 20;
	};
	uint32_t u32;
} ahci_port_ssts_t;

/** Device detection active status. */
#define AHCI_PORT_SSTS_DET_ACTIVE  3

/** AHCI Memory register Port x Serial ATA Control (SCR2: SControl). */
typedef union {
	struct {
		/** Device Detection Initialization */
		unsigned int det : 4;
		/** Speed Allowed */
		unsigned int spd : 4;
		/** Interface Power Management Transitions Allowed */
		unsigned int ipm : 4;
		/** Reserved. */
		unsigned int reserved : 20;
	};
	uint32_t u32;
} ahci_port_sctl_t;

/** AHCI Memory register Port x Port x Serial ATA Error (SCR1: SError). */
typedef struct {
	/** Error (ERR) - The ERR field contains error information for use
	 * by host software in determining the appropriate response to the
	 * error condition.
	 */
	uint16_t err;
	/** Diagnostics (DIAG) - Contains diagnostic error information for use
	 * by diagnostic software in validating correct operation or isolating
	 * failure modes.
	 */
	uint16_t diag;
} ahci_port_serr_t;

/** AHCI Memory register Port x Serial ATA Active (SCR3: SActive). */
typedef struct {
	/** Device Status - Each bit corresponds to the TAG and
	 * command slot of a native queued command, where bit 0 corresponds
	 * to TAG 0 and command slot 0.
	 */
	uint32_t u32;
} ahci_port_sact_t;

/** AHCI Memory register Port x Command Issue. */
typedef struct {
	/** Commands Issued - Each bit corresponds to a command slot,
	 *  where bit 0 corresponds to command slot 0.
	 */
	uint32_t u32;
} ahci_port_ci_t;

/** AHCI Memory register Port x Serial ATA Notification
 * (SCR4: SNotification).
 */
typedef struct {
	/** PM Notify (PMN): This field indicates whether a particular device with
	 * the corresponding PM Port number issued a Set Device Bits FIS
	 * to the host with the Notification bit set.
	 */
	uint16_t pmn;
	/** Reserved. */
	uint16_t reserved;
} ahci_port_sntf_t;

/** AHCI Memory register Port x FIS-based Switching Control.
 * This register is used to control and obtain status
 * for Port Multiplier FIS-based switching.
 */
typedef union {
	struct {
		/** Enable */
		unsigned int en : 1;
		/** Device Error Clear */
		unsigned int dec : 1;
		/** Single Device Error */
		unsigned int sde : 1;
		/** Reserved. */
		unsigned int reserved1 : 5;
		/** Device To Issue */
		unsigned int dev : 1;
		/** Active Device Optimization */
		unsigned int ado : 1;
		/** Device With Error */
		unsigned int dwe : 1;
		/** Reserved. */
		unsigned int reserved2 : 1;
	};
	uint32_t u32;
} ahci_port_fbs_t;

/** AHCI Memory register Port. */
typedef volatile struct
{
	/** Port x Command List Base Address. */
	uint32_t pxclb;
	/** Port x Command List Base Address Upper 32-Bits. */
	uint32_t pxclbu;
	/** Port x FIS Base Address. */
	uint32_t pxfb;
	/** Port x FIS Base Address Upper 32-Bits. */
	uint32_t pxfbu;
	/** Port x Interrupt Status. */
	ahci_port_is_t pxis;
	/** Port x Interrupt Enable. */
	uint32_t pxie;
	/** Port x Command and Status. */
	uint32_t pxcmd;
	/** Reserved. */
	uint32_t reserved1;
	/** Port x Task File Data. */
	uint32_t pxtfd;
	/**  Port x Signature. */
	uint32_t pxsig;
	/** Port x Serial ATA Status (SCR0: SStatus). */
	uint32_t pxssts;
	/** Port x Serial ATA Control (SCR2: SControl). */
	uint32_t pxsctl;
	/** Port x Serial ATA Error (SCR1: SError). */
	uint32_t pxserr;
	/** Port x Serial ATA Active (SCR3: SActive). */
	uint32_t pxsact;
	/** Port x Command Issue. */
	uint32_t pxci;
	/** Port x Serial ATA Notification (SCR4: SNotification). */
	uint32_t pxsntf;
	/** Port x FIS-based Switching Control. */
	uint32_t pxfbs;
	/** Reserved. */
	uint32_t reserved2[11];
	/** Port x Vendor Specific. */
	uint32_t pxvs[4];
} ahci_port_t;

/** AHCI Memory Registers. */
typedef volatile struct {
	/** Generic Host Control. */
	ahci_ghc_t ghc;
	/** Reserved. */
	uint32_t reserved[13];
	/** Reserved for NVMHCI. */
	uint32_t reservedfornvmhci[16];
	/** Vendor Specific registers. */
	uint32_t vendorspecificsregs[24];
	/** Ports. */
	ahci_port_t ports[AHCI_MAX_PORTS];
} ahci_memregs_t;

/** AHCI Command header entry.
 *
 * This structure is not an AHCI register.
 *
 */
typedef volatile struct {
	/** Flags. */
	uint16_t flags;
	/** Physical Region Descriptor Table Length. */
	uint16_t prdtl;
	/** Physical Region Descriptor Byte Count. */
	uint32_t bytesprocessed;
	 /** Command Table Descriptor Base Address. */
	uint32_t cmdtable;
	/** Command Table Descriptor Base Address Upper 32-bits. */
	uint32_t cmdtableu;
} ahci_cmdhdr_t;

/** Clear Busy upon R_OK (C) flag. */
#define AHCI_CMDHDR_FLAGS_CLEAR_BUSY_UPON_OK  0x0400

/** Write operation flag. */
#define AHCI_CMDHDR_FLAGS_WRITE  0x0040

/** 2 DW length command flag. */
#define AHCI_CMDHDR_FLAGS_2DWCMD  0x0002

/** 5 DW length command flag. */
#define AHCI_CMDHDR_FLAGS_5DWCMD  0x0005

/** AHCI Command Physical Region Descriptor entry.
 *
 * This structure is not an AHCI register.
 *
 */
typedef volatile struct {
	/** Word aligned 32-bit data base address. */
	uint32_t data_address_low;
	/** Upper data base address, valid only for 64-bit HBA addressing. */
	uint32_t data_address_upper;
	/** Reserved. */
	uint32_t reserved1;
	/** Data byte count */
	unsigned int dbc : 22;
	/** Reserved */
	unsigned int reserved2 : 9;
	/** Set Interrupt on each operation completion */
	unsigned int ioc : 1;
} ahci_cmd_prdt_t;

#endif
