# Ahci

## Function Table

| Address | Name | Description |
|---------|------|-------------|
|  | **AhciDriverEntryPoint** |  |
|  | **AhciDriverBindingSupported** |  |
|  | **AhciDriverBindingStart** |  |
|  | **AhciDriverBindingStop** |  |
|  | **AhciGetDriverName** |  |
|  | **AhciGetComponentName** |  |
|  | **AhciInitController** |  |
|  | **AhciStopController** |  |
|  | **AhciInitializePortRegisters** |  |
|  | **AhciAllocateMemory** |  |
|  | **AhciCreatePort** |  |
|  | **AhciEnumerateDevice** |  |
|  | **AhciIdentifySataPort** |  |
|  | **AhciIdentifyPmPort** |  |
|  | **AhciSetPortInterfacePower** |  |
|  | **AhciConfigureDevice** |  |
|  | **AhciSetTransferMode** |  |
|  | **AhciSetFeatureRwDmaSetup** |  |
|  | **AhciReadCapacity** |  |
|  | **AhciBlockIoGetMediaInfo** |  |
|  | **AhciBlockIoGetDevicePath** |  |
|  | **AhciBlockIoFlush** |  |
|  | **AhciBlockIoReadBlocks** |  |
|  | **AhciBlockIoRwDispatch** |  |
|  | **AhciBlockIoRwExDispatch** |  |
|  | **AhciSetupBlockIoMedia** |  |
|  | **AhciGetMediaInfo** |  |
|  | **AhciDetectPartitionType** |  |
|  | **AhciParsePartitionEntry** |  |
|  | **AhciInitTaskFile** |  |
|  | **AhciCopyMem** |  |
|  | **AhciSetupCmdHeader** |  |
|  | **AhciSetupCmdTable** |  |
|  | **AhciSetupPrdTable** |  |
|  | **AhciStartCommand** |  |
|  | **AhciWaitCommandComplete** |  |
|  | **AhciAtaSoftReset** |  |
|  | **AhciNonDataCommand** |  |
|  | **AhciDmaCommand** |  |
|  | **AhciPacketCommand** |  |
|  | **AhciSataPhyCommand** |  |
|  | **AhciCheckMediaType** |  |
|  | **AhciDetectMedia** |  |
|  | **AhciReadLba** |  |
|  | **AhciWriteLba** |  |
|  | **AhciReadVerify** |  |
|  | **AhciPortReset** |  |
|  | **AhciSoftReset** |  |
|  | **AhciResetPort** |  |
|  | **AhciResetPmPorts** |  |
|  | **AhciPollPortReady** |  |
|  | **AhciReadPortStatus** |  |
|  | **AhciClearPortError** |  |
|  | **AhciSetAhciMode** |  |
|  | **AhciMmioPollReady** |  |
|  | **AhciMmioPollRead** |  |
|  | **AhciPreparePortAccess** |  |
|  | **AhciAcquirePortAccess** |  |
|  | **AhciBlockIo2Read** |  |
|  | **AhciBlockIo2Write** |  |
|  | **AhciDebugPrint** |  |
|  | **AhciDebugPrint2** |  |
|  | **AhciDebugTrace** |  |
|  | **AhciAssert** |  |
|  | **AhciDebugLevelEnabled** |  |
|  | **AhciGetDebugInterface** |  |
|  | **AhciCacheDebugProtocol** |  |
|  | **AhciTestProtocol** |  |
|  | **AhciCompareDevicePath** |  |
|  | **AhciReadUint32Le** |  |
|  | **AhciIsDevicePathNode** |  |
|  | **AhciZeroMem** |  |
|  | **AhciBlockIoRead** |  |
|  | **AhciBlockIoWrite** |  |
|  | **AhciNonBlockingRead** |  |
|  | **AhciNonBlockingWrite** |  |
| Global | **system table pointers** |  |
| EFI_HANDLE | **gImageHandle = NULL;              // +0x8DE8** |  |
| Cached | **boot services table pointer** |  |
| EFI_BOOT_SERVICES | ***gBS_Cached = NULL;               // +0x8E08** |  |
| EFI_HANDLE | **gControllerHandle = NULL;        // +0x8CE0** |  |
| HOB | **list pointer** |  |
| VOID | ***gHobList = NULL;                // +0x8E00** |  |
| Forward | **declarations for EFI_BLOCK_IO_PROTOCOL interface** |  |
| EFI_BLOCK_IO_PROTOCOL | **gBlockIoTemplate = {** |  |
| Media | **- filled per-port** |  |
| Reset | **not used** |  |
| EFI_DRIVER_BINDING_PROTOCOL | **instance** |  |
| EFI_DRIVER_BINDING_PROTOCOL | **gAhciDriverBinding = {** |  |
| Version | **NULL,                       // ImageHandle** |  |
| DriverBindingHandle | **};** |  |
| EFI_COMPONENT_NAME2_PROTOCOL | **gAhciComponentName2 = {** |  |
| EFI_ATA_PASS_THRU_PROTOCOL | **instance (stub - minimal implementation)** |  |
| EFI_ATA_PASS_THRU_PROTOCOL | **gAhciAtaPassThru = {** |  |
| Driver | **name strings** |  |
| CHAR16 | ***gAhciDriverName[] = {** |  |
| Save | **global system table pointers** |  |
| gImageHandle | **= ImageHandle;** |  |
| Cache | **protocol pointers for faster access** |  |
| gBS_Cached | **= gBS;** |  |
| Get | **HOB list for platform configuration** |  |
| AhciGetHobList | **(ImageHandle);** |  |
| Clear | **global controller state** |  |
| gAhciControllerBase | **= 0;** |  |
| Install | **driver binding, component name, and ATA pass thru protocols** |  |
| on | **a new driver handle** |  |
| gControllerHandle | **= NULL;** |  |
| Check | **if ATA Pass Thru is already installed (another driver claimed it)** |  |
| Status | **= gBS->OpenProtocol (** |  |
| Open | **PCI I/O protocol** |  |
| Read | **PCI config space to check for AHCI class code** |  |
| Status | **= PciIo->Pci.Read (** |  |
| Check | **for AHCI (Mass Storage Controller - SATA) class code** |  |
| Class | **Code = 0x01 (Mass Storage), Subclass = 0x06 (SATA)** |  |
| Programming | **Interface = 0x01 (AHCI)** |  |
| if | **(Pci.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE ||** |  |
| If | **not AHCI, check if the IDE Controller Init protocol is installed** |  |
| Query | **the IDE Controller Init to see if any channels support AHCI** |  |
| Primary | **&Supports** |  |
| SATA | **channel found via IDE controller init protocol** |  |
| return | **EFI_SUCCESS;** |  |
| Open | **required protocols** |  |
| Optionally | **open IDE Controller Init protocol** |  |
| Allocate | **the AHCI_CONTROLLER private structure** |  |
| Controller | **= (AHCI_CONTROLLER *)gBS->AllocatePool (** |  |
| Initialize | **the controller (enable PCI bus master, MMIO, etc.)** |  |
| Status | **= AhciInitController (** |  |
| Read | **the Ports Implemented (PI) register to find active ports** |  |
| MaxPorts | **= 32;** |  |
| Enumerate | **this port - first initialize port registers, then create port** |  |
| Status | **= AhciInitializePortRegisters (Controller, Port);** |  |
| Enumerate | **device on this port (without port multiplier)** |  |
| Status | **= AhciEnumerateDevice (** |  |
| Get | **our private controller structure** |  |
| Stop | **each port and free resources** |  |
| for | **(Entry = Controller->PortListHead.ForwardLink;** |  |
| If | **the port was configured, perform ATA soft reset** |  |
| if | **(Port->State == AHCI_PORT_STATE_READY &&** |  |
| Stop | **the controller hardware** |  |
| AhciStopController | **(Controller);** |  |
| Close | **protocols** |  |
| Free | **the controller structure** |  |
| if | **(Controller != NULL) {** |  |
| CONTROLLER | **INITIALIZATION** |  |
| Get | **the AHCI BAR (BAR5 typically)** |  |
| Status | **= PciIo->GetBarAttributes (** |  |
| Enable | **PCI bus master and memory space** |  |
| Status | **= PciIo->Attributes (** |  |
| Map | **the AHCI register BAR to CPU-accessible MMIO** |  |
| Read | **AHCI capabilities** |  |
| Capabilities | **= MmioRead32 (AhciBarAddr + AHCI_GHC_CAP);** |  |
| Clear | **global state** |  |
| gAhciControllerBase | **= AhciBarAddr;** |  |
| Initialize | **the port list** |  |
| Clear | **the global controller base so MMIO accesses fail-safe** |  |
| PORT | **MANAGEMENT** |  |
| Calculate | **the port register base** |  |
| PortRegBase | **= Controller->AhciRegBase + ((UINT64)Port + 2) * 0x80;** |  |
| Allocate | **memory for the command list (1K aligned, 1K minimum)** |  |
| and | **the FIS receive area (256 bytes aligned to 256)** |  |
| MemoryBase | **= AhciAllocateMemory (sizeof (AHCI_CMD_HEADER) * 32 +** |  |
| Program | **the port registers** |  |
| MmioWrite32 | **(PortRegBase + AHCI_PORT_REG_CLB, (UINT32)(MemoryBase & 0xFFFFFFFF));** |  |
| Store | **the BAR info in the port block** |  |
| Clear | **error registers** |  |
| MmioWrite32 | **(PortRegBase + AHCI_PORT_REG_SERR, 0xFFFFFFFF);** |  |
| Enable | **FIS receive and start the port** |  |
| MmioOr32 | **(PortRegBase + AHCI_PORT_REG_CMD** |  |
| Wait | **for the port to come ready** |  |
| AhciMmioPollReady | **(** |  |
| Align | **size to 4K boundary** |  |
| AlignedSize | **= ALIGN_VALUE (Size, SIZE_4KB);** |  |
| Zero | **the allocated memory** |  |
| ZeroMem | **((VOID *)(UINTN)PhysicalAddress, AlignedSize);** |  |
| Check | **if this port already exists in the list** |  |
| Already | **configured** |  |
| Allocate | **the port structure** |  |
| AhciPort | **= (AHCI_PORT *)gBS->AllocatePool (** |  |
| Initialize | **port fields** |  |
| Compute | **port register base** |  |
| Store | **AHCI BAR info for this port** |  |
| Link | **back to the controller** |  |
| Insert | **into the linked list** |  |
| InsertTailList | **(&Controller->PortListHead, &AhciPort->Link);** |  |
| Read | **the port signature to determine device type** |  |
| DEVICE | **ENUMERATION** |  |
| Check | **if we already have this port and it's good** |  |
| Create | **the port (or get existing one)** |  |
| Status | **= AhciCreatePort (Controller, PciIo, Port, PmPort);** |  |
| Find | **the port in the list again** |  |
| If | **it's a port multiplier, check the PM type** |  |
| if | **(AhciPort->PortType == AHCI_SIG_PM && AhciPort->MediaType == AHCI_MEDIA_TYPE_NONE) {** |  |
| Configure | **the device (soft reset, read capacity, etc.)** |  |
| if | **(AhciPort->MediaType != AHCI_MEDIA_TYPE_NONE) {** |  |
| Set | **device features** |  |
| Status | **= AhciSetDeviceFeature (AhciPort, Capacity);** |  |
| Set | **port interface power** |  |
| AhciSetPortInterfacePower | **(AhciPort);** |  |
| Initialize | **the task file for this device** |  |
| AhciInitTaskFile | **(AhciPort, PciIo, NULL, 0);** |  |
| Set | **up the Block I/O media** |  |
| Status | **= AhciSetupBlockIoMedia (AhciPort);** |  |
| Install | **Block I/O protocol on a new child handle** |  |
| Status | **= gBS->InstallMultipleProtocolInterfaces (** |  |
| Install | **Block I/O 2 protocol** |  |
| Install | **Block I/O 2 on child handle** |  |
| Status | **= gBS->InstallProtocolInterface (** |  |
| PORT | **IDENTIFICATION** |  |
| Reset | **the port** |  |
| Status | **= AhciPortReset (** |  |
| Poll | **for port ready** |  |
| Status | **= AhciPollPortReady (Port, NULL, 10, 0xFF);** |  |
| Set | **AHCI mode (enable FIS, start port)** |  |
| Status | **= AhciSetAhciMode (Port->Controller, PortNumber, Port->AhciBarBase);** |  |
| Clear | **port error status** |  |
| MmioWrite32 | **(Port->AhciBarBase + AHCI_PORT_REG_SERR, 0xFFFFFFFF);** |  |
| Send | **SATA Phy command to identify device on this PM port** |  |
| Status | **= AhciSataPhyCommand (Port, 0, 0, &PhyResult, 0);** |  |
| PORT | **POWER MANAGEMENT** |  |
| Enable | **Aggressive Link Power Management** |  |
| CmdValue | **= MmioRead32 (PortRegBase + AHCI_PORT_REG_CMD);** |  |
| Set | **Partial/Slumber timer** |  |
| MmioWrite32 | **(PortRegBase + 0x44, 0x00010001);  // PxDEVSLP** |  |
| DEVICE | **CONFIGURATION** |  |
| Prepare | **port for access** |  |
| Status | **= AhciPreparePortAccess (Port);** |  |
| Perform | **ATA soft reset** |  |
| Status | **= AhciAtaSoftReset (Port, TaskFile);** |  |
| Identify | **device** |  |
| if | **(Port->MediaType == AHCI_MEDIA_TYPE_ATAPI) {** |  |
| ATAPI | **- use IDENTIFY PACKET DEVICE** |  |
| Status | **= AhciSataPhyCommand (Port, 0xA1, 0, (UINT16 *)TaskFile, 0);** |  |
| ATA | **- send IDENTIFY DEVICE via SATA Phy path** |  |
| Status | **= AhciSataPhyCommand (Port, 0xEC, 0, (UINT16 *)TaskFile, 0);** |  |
| Set | **transfer mode** |  |
| Status | **= AhciSetTransferMode (Port);** |  |
| Enable | **RW DMA Setup** |  |
| Status | **= AhciSetFeatureRwDmaSetup (Port);** |  |
| Read | **capacity** |  |
| Status | **= AhciReadCapacity (Port);** |  |
| Determine | **best transfer mode from identify data** |  |
| if | **(Port->IdentifyData[201] & 0x20) {** |  |
| Ultra | **DMA supported - select highest UDMA mode** |  |
| TransferMode | **= ATA_TRANSFER_MODE_UDMA | 0x07;  // UDMA/133** |  |
| Multiword | **DMA** |  |
| TransferMode | **= ATA_TRANSFER_MODE_MULTI_DMA | 0x02;** |  |
| PIO | **mode** |  |
| TransferMode | **= ATA_TRANSFER_MODE_PIO_DEFAULT | 0x00;** |  |
| Build | **SET FEATURES task file** |  |
| SetMem | **(TaskFile, sizeof (TaskFile), 0);** |  |
| Execute | **the command** |  |
| return | **AhciAtaSoftReset (Port, TaskFile);** |  |
| Check | **if device supports RW DMA Setup** |  |
| if | **((Port->Controller->Capability & 0x4000000) == 0) {** |  |
| SubCommand | **= ATA_RW_DMA_SETUP_ENABLE;** |  |
| Build | **READ CAPACITY (or READ NATIVE MAX) task file** |  |
| READ | **DMA EXT** |  |
| Execute | **the non-data command** |  |
| Status | **= AhciNonDataCommand (Port, (UINT8 *)TaskFile, 0);** |  |
| Parse | **the response in the ATA registers** |  |
| BLOCK | **I/O INTERFACE** |  |
| Return | **a device path node for this port** |  |
| For | **AHCI, writes go directly to device, so flush is a no-op** |  |
| Verify | **media ID** |  |
| if | **(Media->MediaId != MediaId) {** |  |
| Validate | **buffer size is block-aligned** |  |
| if | **(BufferSize % Media->BlockSize != 0) {** |  |
| Check | **for valid LBA range** |  |
| if | **(Lba + BlockCount > Media->LastBlock + 1) {** |  |
| Validate | **parameters** |  |
| Check | **media status** |  |
| Status | **= AhciDetectMedia (Port);** |  |
| Perform | **the DMA operation** |  |
| if | **(IsWrite) {** |  |
| Check | **if the device is SSD (word 35 non-zero) or HDD** |  |
| if | **(Port->MediaType != AHCI_MEDIA_TYPE_NONE) {** |  |
| Check | **for extended sector sizes (512e / 4Kn)** |  |
| BlockSize | **= 512;** |  |
| Logical | **sector size > 512 bytes** |  |
| BlockSize | **= 2 * (Port->IdentifyData[269] | (Port->IdentifyData[271] << 16));** |  |
| Determine | **last block from identify data** |  |
| if | **((Port->IdentifyData[201] & 0x400) != 0) {** |  |
| LastBlock | **= Port->IdentifyData[235] - 1;** |  |
| Allocate | **and fill the media structure** |  |
| Media | **= (EFI_BLOCK_IO_MEDIA *)AhciAllocateZeroPool (sizeof (EFI_BLOCK_IO_MEDIA));** |  |
| Fill | **the Block I/O protocol instance** |  |
| EFI_BLOCK_IO_PROTOCOL | ***BlockIo;** |  |
| Fill | **the Block I/O 2 protocol instance** |  |
| EFI_BLOCK_IO2_PROTOCOL | ***BlockIo2;** |  |
| Configure | **LBA count and block size from identify data** |  |
| if | **((Port->IdentifyData[247] & 0xC000) == 0x4000 &&** |  |
| Logical | **sector size reported in word 247** |  |
| Maps | **media type values:** |  |
| ATAPI_REMOVABLE | **-> 16** |  |
| ATA_REMOVABLE | **-> 8** |  |
| ATAPI_FIXED | **-> 0** |  |
| return | **(EFI_STATUS)(UINTN)0;** |  |
| PARTITION | **DETECTION** |  |
| Check | **for GPT/ protective MBR or legacy MBR** |  |
| Read | **first sector for MBR analysis** |  |
| AhciParsePartitionEntry | **(NULL, 0x402, &PartitionType);** |  |
| EFI | **GPT partition** |  |
| MBR | **entries start at offset 0x1BE (446)** |  |
| Each | **entry is 16 bytes** |  |
| Entry | **= Mbr + 12;  // +0x1BE/4 = 446/4 = 111.5? Actually Mbr[446/4]** |  |
| Scan | **entries (max 4 for MBR)** |  |
| for | **(INTN i = 0; i < 4; i++) {** |  |
| Protective | **MBR (GPT)** |  |
| GPT | **return EFI_SUCCESS;** |  |
| ATA | **COMMAND EXECUTION** |  |
| Calculate | **CRC-16 over the task file for verification** |  |
| if | **(TaskFile != NULL && TaskFileSize > 0) {** |  |
| Process | **encoding** |  |
| Zero | **the command header** |  |
| ZeroMem | **(CmdHeader, sizeof (AHCI_CMD_HEADER));** |  |
| Clear | **reserved fields and set PM port** |  |
| PM | **port** |  |
| Set | **command table base address** |  |
| Clear | **CFL (will be set in AhciSetupCmdTable)** |  |
| Zero | **the command table** |  |
| ZeroMem | **(CmdTable, sizeof (AHCI_CMD_HEADER) + sizeof (AHCI_CMD_TABLE));** |  |
| Fill | **in the Register H2D FIS (type 0x27)** |  |
| FIS | **type: Register H2D** |  |
| ATA | **Command** |  |
| Features | **CmdTable->Cfis[4] = TaskFile[16];     // LBA Low** |  |
| LBA | **High** |  |
| LBA | **Mid** |  |
| LBA | **High (ext)** |  |
| count | **CmdTable->Cfis[10] = TaskFile[21];    // count (ext)** |  |
| sector | **count** |  |
| sector | **count (ext)** |  |
| device | **CmdTable->Cfis[15] = TaskFile[24];    // control** |  |
| Set | **command slot attributes** |  |
| Clear | **prefetch, set ATAPI if needed** |  |
| PRD | **starts at +128** |  |
| Clear | **PRD flags** |  |
| Set | **data buffer address** |  |
| Max | **PRD size is 4MB - 1 (0x3FFFFF)** |  |
| if | **(Remaining >= 0x400000) {** |  |
| 4MB | **- 1** |  |
| Set | **DBC (Data Byte Count) field in bits 0..21** |  |
| Clear | **interrupt bit (I=0)** |  |
| Advance | **//** |  |
| Each | **PRD is 16 bytes** |  |
| Check | **if we have room** |  |
| if | **(PrdIndex * 16 + 128 >= *((UINT32 *)Port->AhciBarBase + 14)) {** |  |
| Set | **command list override and start** |  |
| Clear | **SError, enable interrupts** |  |
| MmioOr32 | **(PortRegBase + AHCI_PORT_REG_SERR, 0x7FF0F03);** |  |
| Zero | **the FIS receive area** |  |
| ZeroMem | **((VOID *)(UINTN)Port->AhciBarBase, 256);** |  |
| Set | **start (ST) bit and command issue (CI)** |  |
| MmioOr32 | **(PortRegBase + AHCI_PORT_REG_CMD, AHCI_PXCMD_ST);** |  |
| Poll | **for CI to clear, with timeout** |  |
| do | **{** |  |
| Delay | **500us** |  |
| Check | **for errors** |  |
| Check | **error bits in SError** |  |
| if | **(CiValue & 0x7FA0F00) {** |  |
| Error | **condition detected** |  |
| goto | **ErrorExit;** |  |
| Check | **if CI cleared (command done)** |  |
| Check | **IS register for completion interrupt** |  |
| CiValue | **= MmioRead32 (PortRegBase + AHCI_PORT_REG_IS);** |  |
| Clear | **status bits** |  |
| Read | **the received FIS status** |  |
| Command | **completed - check task file** |  |
| CiValue | **= MmioRead32 (PortRegBase + AHCI_PORT_REG_TFD);** |  |
| Check | **status in received FIS** |  |
| Timeout | **expired** |  |
| Log | **the error** |  |
| ATA | **COMMAND BUILDING AND EXECUTION** |  |
| Build | **a RESET task file** |  |
| SetMem | **(PortReset, sizeof (PortReset), 0);** |  |
| Port | **reset** |  |
| Acquire | **port access** |  |
| Status | **= AhciAcquirePortAccess (Port, PortReset, FALSE);** |  |
| Reset | **PM ports** |  |
| AhciResetPmPorts | **(Port);** |  |
| Setup | **command header and table** |  |
| AhciSetupCmdHeader | **(Port, (AHCI_CMD_HEADER *)PortReset, (UINT64)PortReset);** |  |
| Start | **command and wait** |  |
| AhciStartCommand | **(Port->Controller, Port);** |  |
| Acquire | **exclusive port access** |  |
| Status | **= AhciAcquirePortAccess (Port, TaskFile, FALSE);** |  |
| Set | **up command header** |  |
| AhciSetupCmdHeader | **(Port, (AHCI_CMD_HEADER *)TaskFile, (UINT64)TaskFile);** |  |
| Set | **up command table (no data)** |  |
| AhciSetupCmdTable | **(Port, TaskFile, (UINT32 *)TaskFile, (AHCI_CMD_TABLE *)(TaskFile + 32));** |  |
| No | **PRD for non-data commands** |  |
| Start | **command** |  |
| Wait | **for completion** |  |
| Status | **= AhciWaitCommandComplete (Port, (UINT32)AHCI_COMMAND_TIMEOUT, FALSE);** |  |
| Status | **= AhciAcquirePortAccess (Port, TaskFile, TRUE);** |  |
| Setup | **command structures** |  |
| AhciSetupCmdHeader | **(Port, (AHCI_CMD_HEADER *)TaskFile, (UINT64)(TaskFile + 64));** |  |
| Check | **media type (may need to retry after reset)** |  |
| Status | **= AhciCheckMediaType (Port);** |  |
| Status | **= AhciWaitCommandComplete (Port, (UINT32)AHCI_COMMAND_TIMEOUT, TRUE);** |  |
| Status | **= AhciAcquirePortAccess (Port, (UINT8 *)TaskFile, TRUE);** |  |
| Setup | **command structures (with ATAPI flag)** |  |
| AhciSetupCmdHeader | **(Port, (AHCI_CMD_HEADER *)TaskFile, (UINT64)(TaskFile + 8));** |  |
| Status | **= AhciAcquirePortAccess (Port, NULL, FALSE);** |  |
| Build | **a register H2D FIS with the SATA command** |  |
| AhciSetupCmdHeader | **(Port, (AHCI_CMD_HEADER *)&PhyCmd, (UINT64)&PhyCmd);** |  |
| Wait | **for completion with port reset timeout** |  |
| Status | **= AhciWaitCommandComplete (Port, AHCI_PORT_RESET_TIMEOUT, FALSE);** |  |
| Check | **the identify data for DMA support** |  |
| Build | **a simple task file to check** |  |
| Reset | **port and check for device** |  |
| Status | **= AhciResetPort (Port);** |  |
| Try | **DMA to see if the device responds** |  |
| Status | **= AhciDmaCommand (Port, (UINT8 *)&Status, 0);** |  |
| READ | **/ WRITE LBA OPERATIONS** |  |
| 0x23 | **= 0x230023000000000LL encodes valid commands** |  |
| Valid | **read commands: 0x20,0x24,0x25,0xC4,0xC8,0xD0,0xD4** |  |
| Build | **the task file** |  |
| Command | **TaskFile[12] = 0x23;             // Sector count** |  |
| Execute | **non-data command to read** |  |
| return | **AhciNonDataCommand (Port, TaskFile, 0);** |  |
| Build | **the task file for DMA write** |  |
| Execute | **as packet/custom command** |  |
| Status | **= AhciPacketCommand (Port, (UINT64 *)TaskFile, 0);** |  |
| Execute | **READ VERIFY SECTOR(S) command** |  |
| Check | **for valid command based on LBA size** |  |
| if | **(*(UINT8 *)(TaskFile + 23) > 0x39) {** |  |
| PORT | **RESET AND CONTROL** |  |
| Clear | **ST (Start) bit to stop command processing** |  |
| Wait | **for command list and FIS receive to stop** |  |
| Perform | **COMINIT: set DET=1 in PxSCTL** |  |
| MmioWrite32 | **(PortRegBase + AHCI_PORT_REG_SCTL, 0x101);** |  |
| Clear | **DET** |  |
| MmioWrite32 | **(PortRegBase + AHCI_PORT_REG_SCTL, 0x100);** |  |
| Wait | **for device to come ready** |  |
| AhciPollPortReady | **((AHCI_PORT *)Controller, NULL, 10, 0xFF);** |  |
| Build | **the soft reset task file** |  |
| Set | **up command structures** |  |
| Build | **a reset task file** |  |
| Execute | **DMA command as reset** |  |
| Status | **= AhciDmaCommand (Port, TaskFile, 0);** |  |
| Reset | **each PM port** |  |
| PORT | **STATUS AND POLLING** |  |
| Poll | **for device detection (SSTS.DET = 3)** |  |
| Read | **port status** |  |
| StatusValue | **= MmioRead32 (PortRegBase + 0x24);  // PxSSTS** |  |
| SerrValue | **= MmioRead32 (PortRegBase + AHCI_PORT_REG_SERR);** |  |
| PhyRdy | **Change - clear error** |  |
| MmioWrite32 | **(PortRegBase + AHCI_PORT_REG_SERR, 0x100);** |  |
| Read | **status again after clearing** |  |
| StatusValue | **= MmioRead32 (PortRegBase + 0x24);** |  |
| Check | **device detection** |  |
| PollStatus | **= AhciReadPortStatus (Port, PortStatus, Port->Port, 0xFF, 0);** |  |
| Device | **detection in progress** |  |
| PollStatus | **= EFI_NOT_READY;** |  |
| Read | **TFD register for BSY/DRQ status** |  |
| if | **(ReadType == 1) {** |  |
| Read | **TFD** |  |
| Clear | **known error bits:** |  |
| 0x7FF0F03 | **= AHCI_PXIS_TFES | AHCI_PXIS_HBFS | AHCI_PXIS_HBDS |** |  |
| AHCI_PXIS_IFS | **| AHCI_PXIS_INFS | AHCI_PXIS_OFS |** |  |
| AHCI_PXIS_IPMS | **| AHCI_PXIS_PRCS | AHCI_PXIS_PCS |** |  |
| AHCI_PXIS_DMP | **| AHCI_PXIS_UFS** |  |
| ErrorBits | **= 0x7FF0F03;** |  |
| Direct | **port - write SError to clear all** |  |
| if | **(Port->Controller != NULL) {** |  |
| PxSERR | **via port register** |  |
| PM | **port - use Phy command** |  |
| AhciSataPhyCommand | **(Port, Flags, 1, (UINT16 *)&ErrorBits, 1);** |  |
| Enable | **FIS receive and start** |  |
| Wait | **for FIS receive to start** |  |
| MMIO | **POLLING OPERATIONS** |  |
| Read | **register** |  |
| 100us | **delay** |  |
| Poll | **for command completion with retries** |  |
| for | **(INTN retry = 500; retry > 0; retry--) {** |  |
| PORT | **ACCESS SYNCHRONIZATION** |  |
| Build | **a port access task file** |  |
| Send | **appropriate command based on media type:** |  |
| ATAPI | **uses IDENTIFY PACKET DEVICE (0xA1)** |  |
| ATA | **uses IDENTIFY DEVICE** |  |
| Execute | **as non-data command** |  |
| Status | **= AhciNonDataCommand (Port, TaskFile, 0);** |  |
| Check | **command register for errors** |  |
| Ensure | **the port is ready** |  |
| BLOCK | **I/O 2 (NON-BLOCKING) INTERFACE** |  |
| Fall | **through to blocking implementation.** |  |
| return | **EFI_UNSUPPORTED;** |  |
| DEBUG | **AND ASSERT SUPPORT** |  |
| Forward | **to UEFI DebugLib if debug protocol is active** |  |
| if | **(AhciDebugLevelEnabled ()) {** |  |
| Cache | **the debug protocol on first call** |  |
| AhciCacheDebugProtocol | **();** |  |
| Log | **the trace if debug is enabled** |  |
| Get | **debug interface and report assertion** |  |
| Read | **CMOS RTC register 0x4B (AHCI-specific debug mask)** |  |
| IoWrite8 | **(0x70, (IoRead8 (0x70) & 0x80) | 0x4B);** |  |
| PROTOCOL | **HELPERS** |  |
| Locate | **the AMI debug protocol** |  |
| Status | **= gBS->LocateProtocol (** |  |
| Try | **alternate method if debug protocol is a small interface** |  |
| if | **(gBS->Hdr.HeaderSize <= 0x10) {** |  |
| Cache | **debug protocol on first access** |  |
| if | **(gAhciDebugProtocol != NULL) {** |  |
| HOB | **AND HELPER FUNCTIONS** |  |
| Get | **HOB list from system table runtime services** |  |
| HobList | **= (VOID *)gST->BootServices;** |  |
| Check | **RemainingDevicePath** |  |
| if | **(RemainingDevicePath != NULL) {** |  |
| Try | **to open ATA Pass Thru protocol** |  |
| Test | **for IDE Controller Init protocol** |  |
| Check | **for PCI IO protocol** |  |
| Query | **for SATA channels** |  |
| Status | **= IdeInit->GetChannelInfo (IdeInit, 0, (UINT64 *)ChannelInfo);** |  |
| Compare | **with "en-US" language string** |  |
| return | **(DevicePath[0] == 'e' &&** |  |

---
*Generated by HR650X BIOS Decompilation Project*