| 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